10

In trying to assign a NaN to a variable on an x64 processor

*dest = *(float*)&sourceNaN;

where

unsigned char sourceNaN[] = {00,00, 0xa0, 0x7f};

The floating point instructions fld and fstp (seen in the disassembly) change the 0xa0 byte to an 0xe0. Thus the destination has an extra bit set. Can someone explain why this is happening? This is a Windows application.

The assembly language code:

005C9B9C  mov         eax,dword ptr [ebp+10h]  
005C9B9F  fld         dword ptr [ebp-80h]  
005C9BA2  fstp        dword ptr [eax] 
Bruce
  • 2,230
  • 18
  • 34
  • 5
    Any reason you can't just assign from the [NaN constant](http://stackoverflow.com/questions/16691207/c-c-nan-constant-literal) directly? – tadman Dec 02 '14 at 21:26
  • 1
    I'm so confused here. You take the address, cast to a `float*`, and then dereference? Why? – Daniel Dec 02 '14 at 21:28
  • 4
    Why not do it differently is not the question. Why the resulting floating point sets the additional bit is. – Bruce Dec 02 '14 at 21:31
  • 3
    @Bruce - since you've looked at the disassembly (you know it exists and know how to find it), you should probably show the relevant code that was generated in addition to the C/C++ source. – jww Dec 02 '14 at 21:33
  • What's sourceNaN? It's probably not a float, otherwise you would not need nanf, nand, isnan etc. I suspect that when you cast to float* you and up picking up some garbage memory, thus the value change. – ventsyv Dec 02 '14 at 21:40
  • 1
    @ventsyv The question shows the *exact* bytes that make up `sourceNaN` already. –  Dec 02 '14 at 21:42

1 Answers1

11

0x7fa00000 is a signalling NaN ("sNaN"). 0x7fe00000 is a quiet NaN ("qNaN"). I haven't heard of this behavior under x86, but under ARM sNaNs get converted to the corresponding qNaNs when used in operations, alongside raising an FP exception (which is normally ignored). It looks like the same thing is happening here.

The good news is, they're both NaNs. Unless you're specifically relying on the signalling behavior, everything's going right.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • 6
    x86 also converts a signalling NaN into the equivalent quite NaN when encountering an SNaN while the invalid exception is masked. Otherwise it raises that exception when encountering an SNaN. An SNaN is "quietened" by setting the most significant fractional bit of the mantissa, which is bit 22 in an IEEE-754 single-precision number. – njuffa Dec 02 '14 at 22:41