1

While debugging some code, I came across x87 behavior that I don't understand. Consider the following program:

#include <iostream>
using namespace std;

double test1(double x,double y)
{
   __asm {
        fld x
        fsin
        fld y
        fsin
        fsubp st(1),st(0)
   }
}

int main(int argc, char* argv[])
{
    cout << test1( 1, 1)<<endl;
    return 0;
}

Everything is fine here, the output is 0. Now we slightly modify the test function so that the intermediate result is stored in memory:

double test2(double x,double y)
{
    double tmp;
   __asm {
        fld x
        fsin
        fld y
        fsin
        fstp tmp
        fld tmp
        fsubp st(1),st(0)
   }
}

Now the output is 1.78893e-18. This result can be explained by rounding the intermediate value stored in memory. But I don’t understand why the result is non-zero even if the precision of x87 floating-point calculations is set to double or single and regardless of rounding mode:

double test3(double x,double y)
{
        // Double precision, 
        // round toward zero
    unsigned short cw = 0xe7f;
    double tmp;
    __asm {
        fldcw cw
        fld x
        fsin
        fld y
        fsin
        fstp tmp
        fld tmp
        fsubp st(1),st(0)
   }
}

The fsubp instruction should consider the precision mode and ignore unnecessary bits, right? Why, then, is the result non-zero in any rounding mode? After all, in at least one of the rounding modes, rounded bits must match?

AVK
  • 2,130
  • 3
  • 15
  • 25

1 Answers1

0

In x87, numbers are stored in long double. Casting to double by fstp lose some precision.

l4m2
  • 1,157
  • 5
  • 17