More efficient way of doing multiple if else statements - java

I have a double and I have multiple checks in if statements to check in the value is passed in is between two values. eg
double d = 5.0;
if(d >= 0.0 && d < 5.0)
{
return 0;
}
if(d >= 5.0 && d < 10.0)
{
return 1;
}
if(d >= 10.0 && d < 15.0)
{
return 2;
}
I have about 15 of these if checks and it seems very inefficient and thought id ask if there was a more efficient way of computing the return value?

If your bounds are completely arbitrary (unlike the example you have posted), then your idiom is almost as fast as you can get. You should just eliminate the redundant lower bound checks. First ensure that the result is positive and after that just test the upper bounds. If you use the ternary operator, and with proper formatting, you can get very concise and readable code:
if (d < 0) throw new IllegalArgumentException("Argument was negative");
if (d > UPPER_LIMIT) throw new IllegalArgumentException("Argument too large");
return d < THRESHOLD_0? 0
: d < THRESHOLD_1? 1
: d < THRESHOLD_2? 2
: d < THRESHOLD_3? 3
: 4;
If your bounds, however, are as regular as you have presented them in the example, and are not going to change, then it would of course pay off to exploit that regularity, for example
if (d < 0) throw new IllegalArgumentException("Argument was negative");
if (d > UPPER_LIMIT) throw new IllegalArgumentException("Argument too large");
return (int) (d / 5);

You can divide by 5 and return the integral answer.

Following should do the job:
return (int)(d / 5);
You might require a bound check for the lower limit (<0), so we can have a case as follows:
if (d > 0)
return (int)(d / 5);
throw new IllegalArgumentException("Argument was negative");

The other answers have simpler solutions, e.g. the modulo business. But in general, if all of your conditions are sequential and non-overlapping, you don't need multiple distinct if() tests - you just need a single if/else/else/... chain:
if (d >= 0 && d < 5.0) {
return 0;
} else if (d < 10.0) {
return 1;
} else if (d < 15) {
return 2;
} else {
throw("out of range"); // or whatever should happen.
}
There's no point in continually testing the "lower" bound of d. With the if/else structure, the lower bound is already taken care of by the previous test.

Depending on the value of d, you may need to alter it before dividing. Otherwise, the int result will be truncated (not rounded). Something like:
double d = 4.99999;
System.out.println((long)(d / 5)); // Prints out '0'
d += 0.1;
System.out.println((long)(d / 5)); // Prints out '1'

It looks like you're implementing floor division by 5. You can do that more concisely like this:
double d = 5.0;
return (int)d / 5;

My Approach to reduce If condition
import java.util.LinkedHashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Double number = 6.0;//number to search
Map<Double, Double> numberRange = new LinkedHashMap<Double, Double>();
numberRange.put(0.0, 5.0);
numberRange.put(5.0, 10.0);
numberRange.put(10.0, 15.0);
// And So on
int status = getStatusOfNumberInRange(number, numberRange);
System.out.println(status);
}
private static int getStatusOfNumberInRange(Double number, Map<Double, Double> numberRange) {
int countStatus = 0;
for (Double minNum : numberRange.keySet()) {
if (checkNumberInRange(minNum, numberRange.get(minNum), number)) {
break;
}
countStatus++;
}
return countStatus;
}
private static boolean checkNumberInRange(Double minNum, Double maxNum, Double number) {
if (number >= minNum && number < maxNum) {
return true;
}
return false;
}
}

Related

Is n a Ramanujan number--why am I getting errors in values near 2^63?

Given a number, test to see if it is a Ramanujan number (defined in our course as the sum of two cubes two different ways). It must run in n^(1/3) time.
My code is working--sometimes. As test values approach 2^63 -1 I am getting some random errors.
Weirdly, I was passing this test for numbers in that range before I changed the starting value of a counter to fix a different bug. Can anyone tell me why this might be?
I set up a for loop to create values for a^3.
Then I set values for b=(n-a^3)^(1/3).
Then I test b to see if it is an integer. If so, break the loop.
Inserted an if test here to get the code to work, though I have NO IDEA WHY THIS IS NEEDED, and that's the gist of this question. This if statement sets up two different for loops for values above and below n=2^63
Second loop for n < 2^63, starts off with c=a+1 so I don't duplicate. It's the same as the first one.
Second loop for n > 2^63 starts off with c=a.
Why would this make a difference? Why isn't the same code working for smaller and larger numbers?
Sorry for the babyish code, I am just starting out, and a lot of functions are off limits in my course. (For example, I couldn't use floor() and was not allowed to write my own function for it, either).
public class Ramanujan {
public static boolean isRamanujan(long n) {
if (n <= 0) return false;
long a3 = 0;
long c3 = 0;
double b = 0;
double d = 0;
for (int a = 1; a < n; a++) {
a3 = (long) a * a * a;
if (a3 > n) break;
b = Math.cbrt(n - a3);
if (b == (int) b) break;
}
if (n > Math.pow(2, 62)) {
for (int c = (int) Math.cbrt(a3); c < n; c++) {
c3 = (long) c * c * c;
if (c3 > n) break;
d = Math.cbrt(n - c3);
if (d == (int) d) break;
}
}
else {
for (int c = (int) Math.cbrt(a3) + 1; c < n; c++) {
c3 = (long) c * c * c;
if (c3 > n) break;
d = Math.cbrt(n - c3);
if (d == (int) d) break;
}
}
if (a3 + (long) b * b * b == c3 + (long) d * d * d && b * b * b != c3)
return true;
return false;
}
public static void main(String[] args) {
long n = Long.parseLong(args[0]);
StdOut.println(isRamanujan(n));
}
}
Any insight as to why I needed to differentiate between larger and smaller numbers?
You'll get weird results when n exceeds the value a long can hold, i.e. Math.pow(2, 63) == Long.MAX_VALUE. At that point, n will experience a numerical overflow.
final long l = Long.MAX_VALUE; // == 2^63
System.out.println(l); // 9223372036854775807
System.out.println(l + 1); // -9223372036854775808
You get random errors for large int values because of arithmetic overflow when Math.cbrt(a3) or even Math.cbrt(n - a3) exceeds the range of type int. You should use type long for all integer variables to reduce this possibility and make sure intermediary results do not exceed the range of type long.
Here is a simpler implementation using a single loop, computing the number of ways:
public class Ramanujan {
public static boolean isRamanujan(long n) {
if (n <= 0) return false;
int count = 0;
for (long a = 1;; a++) {
long a3 = a * a * a;
if (a3 > n - a3) break;
long b = (long)Math.cbrt(n - a3);
if (a3 + b * b * b == n) count++;
}
return count >= 2;
}
public static void main(String[] args) {
if (args.length == 1) {
long n = Long.parseLong(args[0]);
StdOut.println(isRamanujan(n));
} else
if (args.length == 2) {
long n1 = Long.parseLong(args[0]);
long n2 = Long.parseLong(args[1]);
for (long n = n1; n <= n2; n++) {
if (isRamanujan(n))
StdOut.println(n);
if (n == Long.MAX_VALUE) // handle n2 == Long.MAX_VALUE
break;
}
} else {
StdOut.println("usage: Ramanujan n1 [n2]");
}
}
}
The largest number a long can hold (in Java) is (2 ^ 63) - 1 (Long.MAX_VALUE).
Why are you calculating Math.cbrt(a3) ? If a3 = a * a * a, then you already know what
Math.cbrt(a3) is.
There is a problem in your code if n > 9223372036854774272
Math.cbrt of 9223372036854774273 is 2097152
and if you cube that you get a negative number because of overflow.
The issue is with multiplying variables a and c of type int to calculate the cube. Need to cast each of the variable to long that is being multiplied.
Example, a3 = (long) a * (long) a * (long) a;

Calculating how far a robot will move in Java

I'm working on a project for school that requires me to move a robot. How far the robot will move each second (variable t) is calculated by the function below.
The first function is easy. The 2nd and 3rd on the other are where I'm stuck. How would I write F(t-1)? Below is what I have so far.
if (t == 0) {
distance = 2;
} else if (t > 0 && <=6 || t > 12) {
// No clue on how to write the 2nd distance equation.
} else if (t >= 7 && <=12) {
// No clue on how to write the 3rd distance equation.
}
Recursion really isn't necessary to solve this.
Note that in each of the non-zero time cases, F(t) = F(t-1) + something.
So you can simply do:
double f = 2; /* Initial value at t=0 */
for (int t = 1; t <= maxT; ++t) { // maxT is the maximum value of t.
if (t <= 6 || t > 12) {
f += /* something for case 2 */;
} else {
f += /* something for case 3 */;
}
}
System.out.println(f);
You can do this with recursion, but you will get a StackOverflowError if maxT becomes modestly large; by contrast, using a loop will work for arbitrarily large maxT (modulo floating point errors).
As pointed out by #Andreas, you can do this without looping over all values of t:
double f = 2 * (maxT + 1);
for (int t = 7; t <= maxT && t <= 12; ++t) {
f += log(t) - 2;
}
and you can eliminate that loop too by precomputing the values.
This is a problem which involves the use of recursion. By and large, pay close attention to the notation Ft-1, since that refers to an evaluation of the specific function at t-1.
I won't write out all of the code, but I'll give you some of the basics:
When t = 0, return 2. This is your base case.
When t is between 0 and 6 inclusive or greater than 12, return an evaluation of the function at t-1 and add 2.
When t is between 7 and 12 both inclusive, return an evaluation of the function at t-1 and add log2(t).
Here's something to get you at least started in the right direction.
public double evaluateDistance(int t) {
if(t == 0) {
return 2;
} else if(t > 0 && t <= 6) || (t > 12) {
// Think about this - it would involve another call to evaluateDistance, but what is t again?
} else if(t >= 7 && t <= 12) {
// Another evaluation involving the function.
// For free, the change of base operation you'll need to get base-2 evaluation for the log:
return ??? + Math.log(t)/Math.log(2);
}
}
Think I figured it out. Sorry if I wasn't clear on what I needed, just needed to figure out how to write the equations in the function. Think I figured it out though.
public double move()
{
int t = 0;
if(t == 0) // After the first second, robot moves 2
{
distance = 2;
}
else if(t > 0 && t <= 6 || t > 12) // From seconds 0 to 6 and after 12, robot moves distance equation
{
distance = (2*t)+2;
}
else if(t >= 7 && t <= 12) // From seconds 7 to 12, robot moves distances equation
{
distance = (2*t)+(Math.log(t)/Math.log(2));
}
position = position + distance;
return position;
}
}

Can the standard Ackermann be optimized?

The standard Ackermann formula as written in Java:
public static int ack(int x, int y) {
if (x == 0) {
return y + 1;
} else if (y == 0) {
return ack(x-1, 1);
} else {
// perforce (x > 0) && (y > 0)
return ack(x-1, ack(x,y-1));
}
}
I've been wondering - is there a faster version to implement this? I'm thinking maybe there is by using an accumulator or a loop.
Yes, for example by "cheating". If m is 5 or higher, none of the results can be represented by an int. For m = 4, only the n < 2 cases can be represented. For m < 4, there are simple closed formula's based on n.
Everything else would overflow anyway, so let's pretend those cases don't even happen (or you could throw an error or whatever).
Not tested:
int Ackerman(int m, int n) {
switch (m) {
case 0:
return n + 1;
case 1:
return n + 2;
case 2:
return n * 2 + 3;
case 3:
return (int)((1L << (n + 3)) - 3);
case 4:
return n == 0 ? 13 : 65533;
}
}
I can tell you one thing... int will not suffice for very many values of x and y
If you're going to be calling the function repetitively, you can create a int[][] array to store various values so you can look them up the second+ time around and only need to compute it once. But as for speeding up a single execution... not sure.
This variation is faster:
public static int ack(int x, int y) {
while (x != 0) {
y = y == 0 ? 1 : ack(x, y - 1);
x--;
}
return y + 1;
}

multiplying using + and - in java

I have to make a multiplication function without the * or / operators. I have already made a method like this.
for(int i=0; i < number1; i++){
result += number2;
}
System.Out.println(result);
Now, here is my problem: It was fine until my lecturer change the topic, where the multiplication method must be can multiply decimal value. I had no idea how I can make multiplication method which can work on decimal value with just + and - operator.
yeah you can use log for the multiplication.
log(a*b)=log(a)+log(b)
and then find out the exponential value of log(a)+log(b)
and then you can convert the sign..
for example:
-9*8=-72
log(9*8)=log(9)+log(8)=2.19+2.07=4.27
e^4.27=72
now there is only one -ve no. then it is -72
else it's 72
I'm writing the function for:
void multiply(int num1,int num2)
{
int counter=0;
if(num1<0)
{counter++;num1+=num1+num1;}
if(num2<0)
{counter++;num2+=num2+num2;}
double res=Math.log(num1)+Math.log(num2);
int result=(int)Math.exp(res);
if(counter%2==0)
System.out.println("the result is:"+result);
else
System.out.println("the result is:-"+result);
}
hope this will help you....
You take the decimal numbers and move the decimal point step by step until there is an int left: 0.041 -> 1. step 0.41 -> 2. step 4.1 -> 3. step 41
multiplying 0.041 * 3 could be done by doing the above step 3 times, multiplying 41 * 3 = 123. For the result you take the 123 and undu the steps: 1. 12.3, 2. 1.23, 3. 0.123. There is your result: 0.123 = 0.041 * 3.
Edit:
To determine the number of decimals for each number, you might find the answer in this question: How many decimal Places in A Double (Java)
Answers show within others two ways to solve this quite easy: putting the number to a String and checking where in this String the "."-DecimalPoint occurs, or using the BigDecimal type which has a scale()-Method returning the number of decimals.
You shouldn't expect whole perfect code: But here is a hint to achieve this.
Try to use recursion technique instead for loops.
public double multiplyMe(double x, double y)
{
if(y == 0 || x == 0)
return 0;
if(y > 0 && x > 0 )
return (x + multiplyMe(x, y-1)); // multiply positive
if(y < 0 || x < 0 )
return - multiplyMe(x, -y); // multiply negative
}
one more way by using log:
10 raise to power ( sum of log10(x) and log10(y) )
This approach might be easier to understand. You have to add a b times, or equivalently, b a times. In addition, you need to handle 4 different cases where a and b can be either positive or negative.
public int multiply(int a, int b){
int result = 0;
if (a < 0 && b < 0){
for (int i = a; i <= -1; i++)
result-=b;
}
else if (a < 0){
for (int i = 1; i <= b; i++)
result+=a;
}
else if (b < 0){
for (int i = 1; i <= a; i++)
result+=b;
}
else {
for (int i = 1; i <= b; i++)
result+=a;
}
return result;
}
public static void main(String[] args){
System.out.println(multiply(3,-13)); // -39
}

Java pow implementation with Integer.MIN_VALUE as exponent

I am implementing a pow function in Java, and I am wondering how do we deal with Integer.MIN_VALUE as a exponent ? Do we just treat it as a special case ?
Because I tried to compare the result with the standard Java.lang.Math API and I get a couple different result. The following is the list of comparison
//this will print "1.0 vs 0.0"
System.out.println(pow(2,Integer.MIN_VALUE) + " vs " + Math.pow(2,Integer.MIN_VALUE));
//this will print "1.0 vs 1.0"
System.out.println(pow(1,Integer.MIN_VALUE) + " vs " + Math.pow(1,Integer.MIN_VALUE));
public double pow(double base, int exp){
double result = 1.0;
boolean pos = false;
if(exp == 0) return result;
if(exp > 0){
pos = true;
exp *= -1;
}
while(exp > 0){
if((exp & 1) == 1){
result *= base;
}
base *= base;
exp /= 2;
}
if(!pos){
result = 1/result;
}
return result;
}
So I am wondering if Integer.MIN_VALUE is a special case where I have to have a if statement for checking it.
if(exp == Integer.MIN_VALUE && base > 1) return 0.0;
Based on this line:
exp *= -1;
it seems that it might have to be a special case. There are certainly ways to implement this without that special case, but because -1 * Integer.MIN_VALUE cannot be stored in an int, you will get a bug if you do not handle it separately.
Yeah, you've got the problem that Integer.MIN_VALUE * -1 == Integer.MIN_VALUE. You could either special-case it, or you could deal with it another way. Indeed, one possible solution would be to make exp negative when it's positive, instead of the other way around; you'd just use -exp instead of exp.
On my system I have
-2147483648
2147483647
For Integer.MIN_VALUE and Integer.MAX_VALUE respectively. So you should see the problem in the line
exp *= -1;
Well, the real issue is that, since the sign doesn't flip on the MIN_VALUE, the sign cascades to the exp/2. and the 'negative power' case applies. If we split it, it's easier:
public double myPow(double x, int n) {
double result = 1.00000;
boolean negative = false;
if(n <0) {
negative = true;
n= -n;
}
result=power(x,n);
if(negative) {
result = 1/result;
}
return result;
}
private double power(double a, int n) {
if(n ==0 || a==1) return 1;// a^0 = 1, 1^n = 1
double x=power(a,n/2);
if(n%2 == 0) return x*x;
else return a*x*x;
}

Categories

Resources