## I was working on something and saw this oddity, thought I would share it.

\$ ./a.out
in.val = 86.3115158 -> Its a valid floating point number
out1.val = nan -> Swapped it and now its a NaN! That's OK swap it back.
out2.val = 86.4365158 -> What, its not the same number???
in.m = {0x7f, 0x9f, 0xac, 0x42} -> Notice the second number is 0x9f
out1.m = {0x42, 0xac, 0xdf, 0x7f} -> But in the flipped version it became 0xdf?
out2.m = {0x7f, 0xdf, 0xac, 0x42} -> So, this can't be the same number.

The error comes from when I swaped the first number 86.3115158, its flipped version produced a NaN.
That would be OK if the flipped version just returned the same number, but that is not the case!
I surmised that when I assign the NaN value to another float, the 'a' bit in the register was
changed to indicate a Quiet NaN http://en.wikipedia.org/wiki/NaN#Floating_point

So, I changed the byteSwap function to not return the result but just modify the input.
in.val = 86.3115158 -> Its a valid float.
in.val = nan -> Swapped it and now its a NaN!
in.val = 86.3115158 -> Swap it back and its OK!

Because I don't do an assignment to a float it works.
\$

## Here is the code

``````#include <string>
#include <iostream>
#include <iomanip>

//-------------------------------------------------------------------------
// Swap stuff
template <class T> inline void byteSwap2(T& v) {
union {
T val;
char m[sizeof(T)];
} in, tmp;
in.val = v;
for (unsigned int j(1); j <= sizeof(T); j++) {
tmp.m[j-1] = in.m[sizeof(T)-j];
}
memcpy(&v,tmp.m,sizeof(T));
return;
}

//-------------------------------------------------------------------------
// Swap stuff
template <class T> inline T byteSwap(const T& v) {
unsigned int j(1);
union {
T val;
char m[sizeof(T)];
} in, tmp;
in.val = v;
//----------------------------------------------------------------------
// Swap the data
for (; j <= sizeof(T); j++)
tmp.m[j-1] = in.m[sizeof(T)-j];
return (tmp.val);
}
//-------------------------------------------------------------------------
// Print stuff
void printIt(const char *name,char o[],int s){
unsigned int j(0);
std::cout << name << "   = {";
for (; j<s-1; j++)
std::cout << std::hex << std::showbase << int(o[j]&0xff) << ", ";
std::cout << int(o[j]&0xff) << "}";
}
int main(){
unsigned int j(0);
union {
float val;
char m[sizeof(float)];
} in,out1,out2;

//----------------------------------------------------------------------
// I need a specific value for the floating point number, so in order
// to get it exact I load it like this
in.m[0] = 0x7f, in.m[1] = 0x9f, in.m[2] = 0xac, in.m[3] = 0x42;

//----------------------------------------------------------------------
// in.val is a valid floating point number
std::cout << std::setprecision(9) << "in.val   = " << in.val;
std::cout << "                -> Its a valid floating point number" << std::endl;
//----------------------------------------------------------------------
// Swap the number
out1.val = byteSwap(in.val);
//----------------------------------------------------------------------
// Print out result, its a NaN?
std::cout << "out1.val = " << out1.val;
std::cout << "                       -> Swapped it and now its a NaN!  That's OK swap it back." << std::endl;
//----------------------------------------------------------------------
// That OK, swap it back
out2.val = byteSwap(out1.val);
std::cout << "out2.val = " << out2.val;
std::cout << "                -> What, its not the same number???" << std::endl;

printIt("in.m  ", in.m,sizeof(out1.m));
std::cout << "  -> Notice the second number is 0x9f" << std::endl;
printIt("out1.m", out1.m,sizeof(out1.m));
std::cout << "  -> But in the flipped version it became 0xdf?" << std::endl;
printIt("out2.m", out2.m,sizeof(out1.m));
std::cout << "  -> So, this can't be the same number." << std::endl;

std::cout << "\nThe error comes from when I swaped the first number "
<< in.val << ", its flipped version produced a NaN.\n"
<< "That would be OK if the flipped version just returned the"
<< " same number, but that is not the case!\n"
<< "I surmised that when I assign the NaN value to another "
<< "float, the 'a' bit in the register was\n"
<< "changed to indicate a Quiet NaN http://en.wikipedia.org/wiki/NaN#Floating_point\n\n"
<< "\nSo, I changed the byteSwap function to not return the "
<< "result but just modify the input." << std::endl;

//----------------------------------------------------------------------
// Print out valid floating point number
std::cout << "in.val   = " << in.val;
std::cout << "                -> Its a valid float." << std::endl;
//----------------------------------------------------------------------
// Swap the number
byteSwap2(in.val);
//----------------------------------------------------------------------
// Print out result, its a NaN?
std::cout << "in.val   = " << in.val;
std::cout << "                       -> Swapped it and now its a NaN!" << std::endl;
//----------------------------------------------------------------------
// Swap the number
byteSwap2(in.val);
//----------------------------------------------------------------------
// Print out result, its correct
std::cout << "in.val   = " << in.val;
std::cout << "                -> Swap it back and its OK!" << std::endl;

std::cout << "\nBecause I don't do an assignment to a float it works." << std::endl;

return 0;
}
``````

Edited by histrungalot: format

2
Contributors
2
Replies
3
Views
5 Years
Discussion Span
Last Post by histrungalot

With what compiler did you get this? I don't think this is necessarily standard-compliant behavior.

gcc version 4.1.2 20080704

``````vendor_id       : GenuineIntel
model name      : Intel(R) Xeon(R) CPU   E5645  @ 2.40GHz
cpu MHz         : 2400.265
cache size      : 12288 KB
``````

Would it be a function of the compiler or hardware? I was guessing that when the floating point register gets loaded with the NaN, the register changed that bit to indicate quite NaN.
Thoughts?