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?
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?
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?
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