devger
devger

Reputation: 715

Understanding integral division

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?

Upvotes: 0

Views: 1826

Answers (4)

dube
dube

Reputation: 5049

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

Upvotes: 2

KathyA.
KathyA.

Reputation: 681

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

Upvotes: 2

Eran
Eran

Reputation: 394156

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

Upvotes: 2

zubergu
zubergu

Reputation: 3726

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

Upvotes: 2

Related Questions