Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bad result from Java modulo operator?

I suspect this has been asked before, but can't seem to find a question that matches...

I'm using Scala, but I'm pretty sure this is just a Java problem... input values are doubles

println(28.0 / 5.6) 
println(28.0 % 5.6)

The result of these lines is

5.0 
1.7763568394002505E-15 

Which means that Java is performing the division correctly, but for some reason getting the modulo wrong, since the modulo should be 0 for any division problem that resolves to a whole number...

Is there a workaround for this?

Thanks!

like image 818
Sam Dealey Avatar asked Dec 03 '22 01:12

Sam Dealey


1 Answers

The 5.0 just shows that the precise result as Java understands it is closer to 5.0 than it is to any other double. That doesn't mean the precise result of the operation is exactly 5.

Now when you ask for the modulus, you're able to down to a much finer level of detail, because the result isn't pinned to having the "5" part.

That's not a great explanation, but imagine you had a decimal floating point type with 4 digits of precision. What's the result of 1000 / 99.99 and 1000 % 99.99?

Well, the real result starts with 10.001001 - so you have to round that to 10.00. However, the remainder is 0.10, which you can express. So again, it looks like the division gives you a whole number, but it doesn't quite.

With that in mind, bear in mind that your literal of 5.6 is actually 5.5999999999999996447286321199499070644378662109375. Now clearly 28.0 (which *can) be represented exactly divided by that number isn't exactly 5.

EDIT: Now if you perform the result with decimal floating point arithmetic using BigDecimal, the value really is exactly 5.6, and there are no problems:

import java.math.BigDecimal;

public class Test {
    public static void main(String[] args) {
        BigDecimal x = new BigDecimal("28.0");
        BigDecimal y = new BigDecimal("5.6");

        BigDecimal div = x.divide(y);
        BigDecimal rem = x.remainder(y);

        System.out.println(div); // Prints 5
        System.out.println(rem); // Prints 0.0
    }
}
like image 175
Jon Skeet Avatar answered Dec 17 '22 00:12

Jon Skeet