1

Java's Math.IEEERemainder function states:

The remainder value is mathematically equal to f1 - f2 × n, where n is the mathematical integer closest to the exact mathematical value of the quotient f1/f2, and if two mathematical integers are equally close to f1/f2, then n is the integer that is even


For the following:

double f1 = 0.1;
double f2 = 0.04;
System.out.println(Math.IEEEremainder(f1, f2));

The output is -0.019999999999999997
However, 0.1/0.04 = 2.5 which is equidistant from both the integers 2 and 3. Shouldn't we pick n = 2 here, resulting in 0.1 - 0.04*2 = 0.02, instead of -0.02 ?

user1925405
  • 332
  • 1
  • 5
  • 13
  • You can check the implementation of it in native c doe in open jdk source https://github.com/netroby/jdk9-dev/blob/master/jdk/src/java.base/share/native/libfdlibm/e_remainder.c – asela38 Jun 19 '18 at 02:53

1 Answers1

2

See: Is floating point math broken?

You would think that 0.1 / 0.04 would return exactly 2.5, but that's not true. According to this article, 0.1 cannot be accurately represented using IEEE 754, and is actually represented as 0.100000000000000005551....

In this case, the quotient is slightly higher due to that minuscule offset, which results in a value of 3 for n, as it's no longer equidistant between 2 and 3.

Computing it results in the following:

0.1 - 0.04 * 3 = 0.1 - 0.12 = -0.02 ~= -0.019999999999999997
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • Thanks Jacob ! That does make sense. Do you have any suggestions on what I could use to implement this standard ? BigDecimals ? Using `setScale()` to limit the number of decimal digits ? – user1925405 Jun 19 '18 at 02:19
  • 1
    `BigDecimal` will retain the precision and fix your problem; I'm sure you can figure it out :) – Jacob G. Jun 19 '18 at 02:21
  • Thanks ! However, `((3 - (0.1 / 0.04)) == ((0.1 / 0.04) - 2))` evaluates to `true`, and both `((3 - (0.1 / 0.04)) < ((0.1 / 0.04) - 2))` and `((3 - (0.1 / 0.04)) >((0.1 / 0.04) - 2))` evaluate to `false`. I find this surprising, since this comparison evaluates 2.5 to be equidistant from both 2 and 3 – user1925405 Jun 19 '18 at 17:33
  • Does this mean the Math.IEEEremainder() implementation is broken ? – user1925405 Jun 19 '18 at 17:39
  • No, it works exactly as specified, as some IEEE 754 floating points cannot be accurately represented with two's complement binary. – Jacob G. Jun 19 '18 at 17:44
  • But then why does the evaluation I posted earlier, imply 2.5 to be equidistant from both 2 and 3 ? – user1925405 Jun 19 '18 at 17:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/173419/discussion-between-user1925405-and-jacob-g). – user1925405 Jun 19 '18 at 18:00