0

I have the following piece of code:

public static final long KILOMETER_IN_METERS = 1000;

public static int getKilometers(int distanceInMeter) {
    return (int) Math.floor(distanceInMeter / KILOMETER_IN_METERS);
}

And for the line with the return statement Sonar says:

Integral division result cast to double or float

Here is the full description of this bug.


As far as I understand, it says there is int/int division whose result could be a floating value, but I could be wrong.
How can I handle this case correctly?

Limon Monte
  • 52,539
  • 45
  • 182
  • 213
devger
  • 703
  • 4
  • 12
  • 26

4 Answers4

2

There is no need to use Math.floor here. Math.floor is an operation on double, and it does nothing when you supply an int to it.

Returns the largest (closest to positive infinity)
double value that is less than or equal to the argument and is equal to a mathematical integer. Special cases:

  • If the argument value is already equal to a mathematical integer, then the result is the same as the argument.
  • If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument.

(Source)

The integer division already has the same logical behavior of Math.floor, i.e. it truncates the remainder of the division operation. int/int always returns an int.

For example, 100/3 would return 33, and 40/50 would return 0.

Simply use this code :

public static int getKilometers(int distanceInMeter) {
    return distanceInMeter / KILOMETER_IN_METERS;
}
Eran
  • 387,369
  • 54
  • 702
  • 768
  • Hah, you expanded your answer while I was expanding your answer. :) – KathyA. Oct 07 '14 at 14:48
  • Thank you Eran, but I have constant of **long** type and in result of `return distanceInMeter / KILOMETER_IN_METERS;` I've got exception because int expected, but long found. – devger Oct 07 '14 at 14:50
  • @josser Well, there's no reason for your constant to be a long, since its value is quite small. If it must be long, you'll need the casting to int. – Eran Oct 07 '14 at 14:51
  • Yep, you are right - it's enough just to be an integer. As for Math.floor - seems it unnecessary to use it here. Thanks. – devger Oct 07 '14 at 14:54
2

That's because Math.floor takes double as an argument, and integer by integer division is already an integer. So all the casting sonar whines about is done there, and not on your explicit cast to int.

Here's doc for floor: http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#floor%28double%29

zubergu
  • 3,646
  • 3
  • 25
  • 38
2

To expand on Eran's answer, here's what you're doing:

distanceInMeter / KILOMETER_IN_METERS divides an integer by an integer. In Java, that result is a truncated integer. Then you're putting that into Math.floor, which takes a double. So Java is trying to help you out, by making your int into a double. Then you're casting the double returned by Math.floor back to an int.

If you've been following along, you may have noticed that you had your truncated int already. So your code needs to be simply:

public static int getKilometers(int distanceInMeter) {
    return distanceInMeter / KILOMETER_IN_METERS;
}
Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
KathyA.
  • 671
  • 6
  • 14
  • that code does not compile, KILOMETER_IN_METERS is a long. you would need to cast it to an int first. – dube Oct 07 '14 at 15:03
2

When you divide two integers, you will always get an integer, rounded down. if you divide distanceInMeter / KILOMETER_IN_METERS and then assign it to a double, it is first divided as integer, before assigned, so you get a rounded down value, cast to an double.

Sonar does not complain because of Math.floor - it complains because you casted an integer-division result (which itself is an rounded-down integer) into a double. Most of the time, this is an error (Why deliberately auto-round and immediately cast to a double afterwards)?

int distanceInMeter = 505;

double result = distanceInMeter / KILOMETER_IN_METERS;
System.out.println(result); // 0.0

double result2 = distanceInMeter * 1.0 / KILOMETER_IN_METERS;
System.out.println(result2); // 0.505

double result3 = ((double) distanceInMeter) / KILOMETER_IN_METERS;
System.out.println(result3); // 0.505

1.0 * distanceInMeter / KILOMETER_IN_METERS
((double)distanceInMeter) / KILOMETER_IN_METERS
Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
dube
  • 4,898
  • 2
  • 23
  • 41