-5

Neither 0.1d, 0.2d or 0.3d can be represented exactly in binary.

Why is 0.1D + 0.1D == 0.2D true in Java?

the 64-bit binary number is how to become 0.1,0.2,0.3?????Where is the code?

pppp
  • 17
  • 1
  • 1
    That's not really a duplicate - the op seems to already know that not all decimal numbers can be represented exactly by a double... – assylias Mar 22 '16 at 09:55
  • 1
    nearest_float(x)+nearest_float(x)=nearest_float(2*x) is allways true in IEEE 754 whatever the language. We can't explain why in a comment... Maybe the question was closed prematurely. – aka.nice Mar 22 '16 at 11:07
  • @aka.nice reopened if you want to add an answer. – assylias Mar 22 '16 at 11:19

2 Answers2

2

Suppose that x is the exact decimal.
nearest_float(x) is the conversion to floating point.
It rounds to nearest representable floating point value, tie to even.
ulp(nearest_float(x)) is the unit of least precision of the floating point value (i.e. the value of smallest bit of significand).
x + y denotes the exact arithmetic operation, same for - * /.
nearest_float(x)+nearest_float(y) is the exact sum of float approximations.
nearest_float(nearest_float(x)+nearest_float(y)) is the floating point operation.

Operation nearest_float(x)+nearest_float(x) is strictly equivalent to nearest_float(x)*2, and the operation nearest_float(x)*2 is exact, except the rare case of floating point overflow: it's just a shift of the exponent, nearest_float(2*nearest_float(x))=2*nearest_float(x)..

We have this property: abs(nearest_float(x)-x) <= ulp(nearest_float(x))/2.

We can multiply both sides of inequality by 2: abs(2*nearest_float(x)-2*x) <= ulp(2*nearest_float(x))/2.

Most often, there is a single value in this interval, exceptionnally two values in case of exact tie, but the exact tie will be resolved same as for the case of x (only the exponent changed, not the significand). Near binade boundaries, there might be 2 floats in above interval too, but resolution will also be to the same significand.
Thus it means that 2*nearest_float(x) is the right candidate for nearest_float(2*x)

So in any language based on IEEE 754 floating point, with round to nearest, tie to even rounding mode (the default mode), and correctly rounded literal values (meaning that 0.1 will effectively return the nearest float to 1/10) you'll have the property 0.3+0.3==0.6, 0.07+0.07==0.14, 3.14+3.14==6.28, x+x==2*x whatever the value of x.

More surprisignly, you even have more funny properties like this one Is 3*x+x always exact?

Community
  • 1
  • 1
aka.nice
  • 8,465
  • 1
  • 25
  • 39
  • why I define double d = 0.2,and the value I see is 0.2,not 0.200000000000000011102230246251565404236316680908203125. – pppp Mar 24 '16 at 02:03
  • You see 0.2 because Double.toString "rounds" the double. To see the exact value use a BigDecimal like in my example. – assylias Mar 24 '16 at 08:31
  • @成一丁 You have at most 2^64 different floating point values (in which many nans). It's a finite subset of Rational fractions. So many decimals will round to the same float. What you see is the SHORTEST decimal representation that would round to the same floating point value, not the exact fraction value. – aka.nice Mar 24 '16 at 08:33
1

If you run:

System.out.println(new BigDecimal(0.1d + 0.1d));
System.out.println(new BigDecimal(0.2d));
System.out.println(0.1d + 0.1d == 0.2d); //true

you'll see that both statements print 0.200000000000000011102230246251565404236316680908203125.

In other words, 0.1d + 0.1d == 0.2d is true but neither is strictly equal to the decimal number 0.2.

On the other hand, the first two lines below don't print the same number and 0.1d + 0.1d + 0.1d == 0.3d is false:

System.out.println(new BigDecimal(0.1d + 0.1d + 0.1d));
System.out.println(new BigDecimal(0.3d));
System.out.println(0.1d + 0.1d + 0.1d == 0.3d); //false
assylias
  • 297,541
  • 71
  • 621
  • 741