4

I'm programming an application for calculate some geometrical transformations, and while I was testing the program, I founded something strange: I launched a test in two different machines, Z400 workstation with an Intel® Xeon® Processor W3550 and Z800 workstation with an Intel® Xeon® Processor X5560, and I got different results for one operation:

double x = 24.169408798217777 * sin(0.59420877837561048) / sin(0.97658754841928608)

With the Z400 I got x=16.330508228047432

While the Z800 throws this value x=16.330508228047435

The value differs on the last digit, and I make lot of calculations with that value, so it results inconvenient.

I tried using sinl in order to get more precission, but I got the same value all the times for each workstation. What's wrong with it? How I can fix it?

Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
Brujah
  • 53
  • 6
  • See http://stackoverflow.com/questions/18056677/opencl-double-precision-different-from-cpu-double-precision/18058130#18058130 – Sven Aug 05 '13 at 14:11
  • 2
    No, they are the same value. The only thing you have to fix is the code that converts the result into a string. Never display more than 15 digits. – Hans Passant Aug 05 '13 at 14:11
  • What happens if you compare the values? – imreal Aug 05 '13 at 14:13
  • @Hans: Are you saying the two machines where using different output? I do agree that the results are probably identical within what we can reasonably expect, but different FPU's will sometimes produce different results, because the microcode and/or FPU logic is different. This should however not affect the actual result other than the lever last it - bit is probably what we're seeing here [floating point to string will typically produce some "noise" you run off the end of valid bits, because the value is not always a number that ends up "nice" in when dividing/multiplying by 10]. – Mats Petersson Aug 05 '13 at 14:22
  • @HansPassant The values are nearly equals, yeah, but it inserts on my code an accumulative error that leads on worst values with each iteration (on my tests I got differences on the two last digits, and was light tests) so I fear that it may affect significantly while launching heavy tests. – Brujah Aug 05 '13 at 14:25
  • @Nick I compared the values, and are treated like different ones – Brujah Aug 05 '13 at 14:25
  • @Brujah: To make it unambiguous, can you provide the hex representations of both values instead? Both processors use the same IEEE754 representation. Either the hex representations are exactly identical or the values truly differ. – MSalters Aug 05 '13 at 15:22
  • @Brujah if your algorithm is numerically unstable in the first place (as you seem to imply), then you also need to think whether it actually means anything. A computer only has finite precision, so you are getting an approximate value in the first place... now if the result depends on such minor changes, does it actually mean anything? – wendazhou Aug 05 '13 at 15:24

2 Answers2

2

The results of the 2 calculations differ by 1 decimal digit as you noted and 1 binary digit as shown below. The Z400 is closer the correct answer. sin() calculation is not obliged to be accurate to the last binary bit, but to within 1 bit. Good sin() implementation are correct to the last bit**. Your Z800 is not as good.

printf("%a\n", 16.330508228047432);
printf("%a\n", 16.330508228047435);
printf("%a\n", 24.169408798217777 * sin(0.59420877837561048) / sin(0.97658754841928608));  // my PC eclipse

0x1.0549c2fee85cbp+4
0x1.0549c2fee85ccp+4
0x1.0549c2fee85cbp+4

** Accuracy requirements are not a C++ requirement so much as an IEEE floating point one. Trig functions s/b accurate within 1 ulp (unit last place). Good trig libraries are accurate within 0.5 ulp (unit last place) - the best possible answer.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • So it means that I can't get a better value, and I need to truncate the numbers in order to get the same ones on both machines? – Brujah Aug 05 '13 at 14:59
  • Truncation will not get always you the same answer. Compare .xxx1000 to .xxx0999 and truncating the last 3 decimal places. Answer are the same to 1 part in a 1e7, but have different truncation results. Rounding also exhibits the same issue. One solution is to tolerate a minimal relative difference. About 1 part in 9e15. (DBL_EPSILON) – chux - Reinstate Monica Aug 05 '13 at 15:12
  • @Brujah Consider checking `sin(0.5942...8)` and `sin(0.9765...8)` on your 2 machines. Insure at least 1 difference to validate this answer is in fact a correct answer for your situation. – chux - Reinstate Monica Aug 05 '13 at 15:36
1

As a guess, I'm going to suggest that this is related to certain processors calculating floating point values in 80 bit registers (instead of 64 bit) and only reducing the precision as late as possible.

On GCC, you can disable this (which will cause all your math to be done in 64 bits, and also potentially cause it to be slightly slower) with -ffloat-store.

There are some additional suggestion on this answer that may be able to help as well if the 80 bit register is the actual problem.

Community
  • 1
  • 1
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173