Bad result from Java modulo operator?

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

I use Scala, but I'm sure this is just a problem with Java ... input values โ€‹โ€‹are doubled

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

The result of these lines is

 5.0 1.7763568394002505E-15 

This means that Java is doing the division correctly, but for some reason gets the wrong code, since modulo should be 0 for any separation task that resolves an integer ...

Is there a workaround for this?

Thanks!

+4
source share
4 answers

In 5.0, it is simply shown that the exact result, as Java understands, is closer to 5.0 than to any other double. This does not mean that the exact result of the operation is exactly 5.

Now, when you request a module, you can go to a much finer level of detail, because the result is not tied to part "5".

This is not a great explanation, but imagine that you have a decimal floating point type with 4 digits of precision. What is the result of 1000 / 99.99 and 1000% 99.99?

Well, the real result starts at 10.001001 - so you need to round it to 10.00. However, the remainder is 0.10, which you can express. So, again, it seems like splitting gives you an integer, but that is not entirely true.

With that in mind, keep in mind that your literal 5.6 is actually 5.599999999999999996447286321199499070644378662109375. Now itโ€™s clear that 28.0 (which * can be) is represented exactly divided by this number, not exactly 5.

EDIT: now, if you are doing the result with decimal floating point arithmetic using BigDecimal , the value is really 5.6, and there is no problem:

 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 } } 
+12
source

Arithmetic

First of all, the decimal number 5.6 cannot be represented exactly in binary floating point. It is rounded to the exact binary fraction 3152519739159347/2 49 .

The fact that 28.0 / 5.6 = 5.0 is because 5.0 is the closest double to the true result, where the true result is 5.0000000000000003172065784643 ....

As for 28.0% 5.6, the true result is exactly 1/2 49, which is approximately 1,776 ร— 10 & minus 15 therefore the calculation is correctly rounded.

Bypass

Why do you need a workaround? For most applications, keeping a very weak result is in order. Are you worried about displaying โ€œgoodโ€ results?

If you need absolutely accurate arithmetic, you will need to use some implementation of BigFraction.

Further reading

The topic of envelopes with a floating point is considered in various articles:

(in decreasing order of readability.)

+2
source

The result is not really 0, but it is pretty close (0.00000000000000177635 ...). The problem is that some decimal numbers cannot be represented exactly in binary format, so where the problem arises; I suspect the same result will be printed in C / C ++.

+2
source

This is my solution to verify that a double value is split into another using the modulo operator:

 public class DoubleOperation { public static final double EPSILON = 0.000001d; public static boolean equals(double val1, double val2) { return (Math.abs(val1 - val2) < EPSILON); } public static boolean divisible(double dividend, double divisor) { double divisionRemainder = dividend % divisor; return (equals(divisionRemainder, 0.0d) || equals(divisionRemainder, divisor)); } } 
0
source

All Articles