1

please tell me what to do in this code:

UnicodeString Str;
double        x, y;
double        z1, z2;

  x= 2.0;
  y= 5.0;

  z1= x/y;
  z2= x/y;

  if(z1>z2)
    Str= "> not ok\n";
  else
    Str= "> ok\n";

  Application->MessageBox(Str.c_str(), L"Info", MB_OK);

The result is ">not ok". Why????

it should be z1>z2= false; but it is true.

if i use the standard compiler than it is ok. But the clang compiler give wrong result.

the disassemble using CLang compiler (gives wrong result):

Unit1.cpp.24: if(z1>z2)
00403D7B DD8568FFFFFF     fld qword ptr [ebp-$00000098]
00403D81 DFE9             fucomip st(1)
00403D83 DDD8             fstp st(0)
00403D85 0F86E7000000     jbe $00403e72
00403D8B EB00             jmp $00403d8d
00403D8D 8B45B0           mov eax,[ebp-$50]

the disassemble using Standard compiler (gives right result):

Unit1.cpp.24: if(z1>z2)
004031C7 DD45AC           fld qword ptr [ebp-$54]
004031CA DD45A4           fld qword ptr [ebp-$5c]
004031CD D9C9             fxch st(1)
004031CF DAE9             fucompp 
004031D1 DFE0             fstsw ax
004031D3 F6C445           test ah,$45
004031D6 753D             jnz $00403215
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
H.K
  • 173
  • 8
  • Reopened. This is not about getting different results when calculating a value two different ways. It’s about getting different results when calculating a value the same way twice. The language definition requires the compiler to produce the same result. Getting a different result means that the code was compiled with a switch that sets a non-conforming mode. That’s quite common for floating-point math, but it’s not inherent in floating-point. – Pete Becker Nov 06 '18 at 21:42
  • 1
    that's why you should use SSE instead of x87. There are a lot of questions regarding the differences in results between the two: [Extended (80-bit) double floating point in x87, not SSE2 - we don't miss it?](https://stackoverflow.com/q/3206101/995714), [Difference in floating point arithmetics between x86 and x64](https://stackoverflow.com/q/22710272/995714), [std::pow produce different result in 32 bit and 64 bit application](https://stackoverflow.com/q/33887108/995714)... – phuclv Nov 07 '18 at 07:06
  • i am sorry. i have corrected the source. – H.K Nov 07 '18 at 07:10

1 Answers1

3

You’re right: those two results should be the same. Compilers usually, by default, run in a non-conforming mode for floating-point calculations, and that can lead to surprises like this one. what probably happened is that the code calculated 2.0 / 5.0 at higher-than-double precision, then stored the result in z1 after rounding it to fit in a double. Then it calculates 2.0 / 5.0 again, at higher-than-double precision, and compared that value (unrounded) with the rounded value that it stored earlier. It’s like calculating 1/3 as .333 and as .3333 and concluding that 1/3 does not equal 1/3.

Check your compiler settings for something related to fast floating-point.

EDIT: the generated assembler code from Clang shows this. One result was stored in memory (as a 64-bit value), and accessed through fld word ptr [epb - $00000098]. The other was computed and held in a register (as an 80-bit value), accessed through fucomip st(1).

Pete Becker
  • 74,985
  • 8
  • 76
  • 165