Why java +=
get wrong result, and how can I prevent this problem? (for example any way show warning
in IDE?)
I tried eclipse & IntelliJ but both not show any warning.
Sample code:
{
long a = 20000000000000000L;
double b = 90.0;
a += b;
System.out.println(a); // 20000000000000088 NG
}
{
long a = 10000000000000000L;
double b = 90.0;
a += b;
System.out.println(a); // 10000000000000090 OK
}
{
long a = 20000000000000000L;
double b = 90.0;
a += (long) b;
System.out.println(a); // 20000000000000090 OK
}
According to the JLS, this compound assignment expression
a += b;
is equivalent to
a = (long) (a + b);
Since b
is a double
, binary numeric promotion occurs before the addition happens. Both operands are converted to double
values and the addition happens with floating point arithmetic.
The value 20000000000000090
cannot be represented exactly as a double
and therefore you lose precision, getting 20000000000000088
instead. It then gets cast back to a long
which has enough precision to represent 20000000000000088
.
Your second snippet produces 10000000000000090
which can be represented exactly as a double
.
Your third snippet is equivalent to
a = (long) (a + (long) b);
which uses integer arithmetic. 20000000000000090
can be represented as a long
.
I don't know of any tools to warn you about this.
Related:
Java uses 64-bit IEEE floating point numbers, which use 53 binary digits to represent the significant. In the first example,
{
long a = 20000000000000000L;
double b = 90.0;
a += b;
System.out.println(a); // 20000000000000088 NG
}
Here the variable a
is converted to a double that must use an exponent greater than 1 to represent it, and it will no longer be an exact representation of the value 20000000000000000L.
In this example, it is possible to represent a
using only the significand and an exponent of 1.
{
long a = 10000000000000000L;
double b = 90.0;
a += b;
System.out.println(a); // 10000000000000090 OK
}
In this example, b
is explicitly converted to a long, avoiding the need to convert a
to a double and perform floating point arithmetic.
{
long a = 20000000000000000L;
double b = 90.0;
a += (long) b;
System.out.println(a); // 20000000000000090 OK
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With