Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java vs C floating point: "x * x" differs from "pow(x,2)"?

Why is this true? Java appears to produce a result with a small discrepancy when multiplying two floats compared to C and even the Java Math.pow method.

Java:

float a = 0.88276923;

double b = a * a;   // b becomes 0.779281497001648  <---- what???
b = Math.pow(a,2);  // b becomes 0.7792815081874238

C:

float a = 0.88276923;

double b = a * a;   // b becomes 0.7792815081874238
pow(a,2);           // b becomes 0.7792815081874238

Update: Per Ed S.'s comment, I have also found that the C behavior changes depending on the compiler. Using gcc it appears to match the Java behavior. Using visual studio (depending on your target platform) it can produce the results seen above or those seen in Java. Ugh.

like image 283
mark Avatar asked Apr 17 '12 23:04

mark


People also ask

Does math POW return a double Java?

pow Example. The method raises a to the power of b and returns the result as double. In other words, a is multiplied by itself b times.

Which is more precise float or double Java?

Float and doubleDouble is more precise than float and can store 64 bits, double of the number of bits float can store. Double is more precise and for storing large numbers, we prefer double over float.


1 Answers

As pst and trutheality have already wisely noted, C is promoting the float to a double before the multiplication. Actually, they are promoted to an 80-bit extended precision value when they are pushed onto the stack. Here is the assembler output (VS2005 x86 C89)

    double b = a * a;
00411397  fld         dword ptr [a] 
0041139A  fmul        dword ptr [a] 
0041139D  fstp        qword ptr [b] 

The FLD Instruction

The FLD instruction loads a 32 bit, 64 bit, or 80 bit floating point value onto the stack. This instruction converts 32 and 64 bit operands to an 80 bit extended precision value before pushing the value onto the floating point stack.


Interestingly, if I build to target x64, the movss instruction is used and you get a value of 0.779281497001648 as the result, i.e., what you are seeing in your java example. Give it a try.

like image 196
Ed S. Avatar answered Sep 29 '22 10:09

Ed S.