1

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?

4
  • 1
    use a for loop as they are multiple of 5's and then return the index?? Commented Dec 8, 2014 at 17:37
  • They are doubles so you cant do a switch statement I thought? Commented Dec 8, 2014 at 17:40
  • Funkdoc - How do you propose to switch on a double? Commented Dec 8, 2014 at 17:40
  • Whenever you see yourself writing the same code with minor changes like increments of 5 in the conditions...use a loop just specify the change. No need to write the exact same come 15 times. Commented Dec 8, 2014 at 17:41

7 Answers 7

3

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);
Sign up to request clarification or add additional context in comments.

6 Comments

This seems better, in my actual code the range check is 22.5 so I take it I would divide by 22.5 instead of 5?
I used your shorter approach as the upper limit would be 360 so each if statement had a range of 22.5. I tested it there now at it seems to return the same answers that I got with all the if statements. Thanks very much!
Just out of curiosity, how many jumps (ifs) would one need to be slower than the double division with integer conversation? Or am I overestimating the cost of double divisions?
@MartinC. That's a very good observation: double comparison (subtraction) is very cheap and JMH tells me that the breakeven point is as high as 20 threshold comparisons. However, an important thing to factor in is that we're talking about a total of 7 nanoseconds for the one-liner division approach.
@MarkoTopolnik Thanks for the explanation. I agree with you that this won't be a "real-world" issue performance-wise, most probably (maybe more, if target is older ARM). Was just curious, as the initial question was to come up with a "more efficient solution" instead of 15 if/else.
|
1

You can divide by 5 and return the integral answer.

Comments

0

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");

1 Comment

Yeah on second though divide by 5 fits better.
0

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.

Comments

0

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'

Comments

0

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;

Comments

0

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;
  }


}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.