5

Possible Duplicate:
Retain precision with Doubles in java

Do you know the difference between these two operations in Java.

final double m1 = 11d / 1e9; // gives 1.1e-8
final double m2 = 11d * 1e-9; // gives 1.1000000000000001e-8

I see in the generated bytecode that the precompiled result of m2 is already not what I expected.
In the output of javap -verbose -c I can see the following value :

const #3 = double   1.1E-8d;
[...]
const #6 = double   1.1000000000000001E-8d;

When I use m1 or m2 in other expressions, I don't have the same result.

When I try the same thing in C, m1 and m2 is strictly 1.1e-8

I think my problem is in the way java handles double precision computation but I can't explain myself what I miss.

Community
  • 1
  • 1
Joker
  • 247
  • 3
  • 7

3 Answers3

3

There is no difference between Java and C, both respect the IEEE floating-point standard. The only difference can be the way you print it. The exact number 1.1e-8 is not representable as a double. The difference in output may be attributed to the details on how the error of representation was accumulated, and to what rounding is used to print the result.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • I think the difference is only in how much error was accumulated, where the second line just steps over the threshold that is printed. – Marko Topolnik Jul 16 '12 at 11:53
1

The difference you have is that 1e9 is exactly representable and 1e-9 which is not exactly representable. A small representation error results in an arithmetic error which you can see.

System.out.println(new BigDecimal(1e9));
System.out.println(new BigDecimal(1e-9));

prints

1000000000
1.0000000000000000622815914577798564188970686927859787829220294952392578125E-9

The difference is not whether you have used * or / but that you have used a whole number in one case and a fraction in the other.

System.out.println(11 * 1e9);
System.out.println(11 * 1e-9);

prints

1.1E10
1.1000000000000001E-8
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Ok that's the explanation for Java but now why when I execute the same code in C I have all precision I needed ? – Joker Jul 16 '12 at 12:17
  • The C compiler will optimise the code *much* further than `javac` will. This can mean that it could translate `/ 1e-9` to `* 1e9` because a) its faster and b) more accurate. Java's compiler does very little optimisations, this is left to the JIT which also means the de-optimised and optimised code must do the same thing, otherwise you would see a change in behaviour while the program is running. The conversion of a `double` to a String is different in C and Java as well, but it is less likely to be the cause of the difference. In both cases, they use the same FPU. – Peter Lawrey Jul 16 '12 at 12:20
  • 1
    Also the C compiler could make use of the 80bit floating point registers/computation your computer has. This is platform dependant and only available on x86/x64 processors. Java will behave the same on every platform so will only use 64-bit floating point even if 80-bit floating point is available. – Peter Lawrey Jul 16 '12 at 12:23
0

If you use BigDecimal as below :

BigDecimal a=new BigDecimal(1e-9);
BigDecimal b=new BigDecimal(11);
System.out.println(a.multiply(b).toString());

you will see that your number is

1.10000000000000006850975060355784206078677556206457666121423244476318359375E-8

JVM rounds up your number and change it to :

1.1000000000000001e-8
Pooya
  • 4,385
  • 6
  • 45
  • 73