6

I have the following code :

Double x = 17.0;
Double y = 0.1;

double remainder = x.doubleValue() % y.doubleValue();

When I run this I get remainder = 0.09999999999999906

Any idea why??

I basically need to check that x is fully divisible by y. Can you suggest alternative ways to do that in java.

Thanks

skaffman
  • 398,947
  • 96
  • 818
  • 769
Jasmine
  • 61
  • 1
  • 2
  • 1
    Floating point arithmetic is only an approximation of real number arithmetic: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems – Jonas Bötel Apr 05 '11 at 13:13
  • That's accurate down to 14 significant digits. What more do you expect from double, which has about this much accuracy? – kaalus Nov 27 '21 at 12:08

3 Answers3

12

Because of how floating-point numbers are represented.

If you want exact values, use BigDecimal:

BigDecimal remainder = BigDecimal.valueOf(x).remainder(BigDecimal.valueOf(y));

Another way to to that is to multiple each value by 10 (or 100, 1000), cast to int, and then use %.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
4

You need to compare your result which allows for rounding error.

if (remainder < ERROR || remainder > 0.1 - ERROR)

Also, don't use Double when you mean to use double

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • This is the correct answer to use when your data really does come from float/double sources (and is not just discrete data masquerading as floating-point values), and you want to know whether `x` is "very close" to an exact multiple of `y`. – Ken Williams Jun 19 '15 at 21:48
2

Expecting precise results from double arithmetic is problematic on computers. The basic culprit is that us humans use base 10 mostly, whereas computers normally store numbers in base 2. There are conversion problems between the two.

This code will do what you want:

public static void main(String[] args) {
    BigDecimal x = BigDecimal.valueOf(17.0);
    BigDecimal y = BigDecimal.valueOf(0.1);

    BigDecimal remainder = x.remainder(y);
    System.out.println("remainder = " + remainder);

    final boolean divisible = remainder.equals(BigDecimal.valueOf(0.0));
    System.out.println("divisible = " + divisible);

}
Steve McLeod
  • 51,737
  • 47
  • 128
  • 184
  • 2
    Just a complement: you can use `BigDecimal.ZERO` instead of `valueOf(0.0)` for readability. If possible, better use the `new BigDecimal(String)` constructor since `valueOf(double)` still is exposed to precision/rounding errors. – user85421 Apr 05 '11 at 13:48