Consider (both msvc15 and 16 i.e. Visual Studio 2017 & 2019) on a Xeon 15something:
int main()
{
unsigned int x;
uint8_t val;
float f;
x = _status87(); // x = 0 here, OK
f = -1.00e+9;
x = _status87(); // x = 0 here, OK
val = uint8_t(f); // val = 0 here, I can live with that
x = _status87(); // x = 0 here, OK
f = -1.00e+10;
val = uint8_t(f); // val = 0 here, I can live with that
x = _status87(); // x = 16 = _EM_INVALID, wtf?
}
It's obvious that some casts give the 'wrong' result, i.e. when you want to store a number that is more than what fits in a variable of a certain type, there is no way to store that value. My question is - why is the status flag of the floating point register set to 'invalid'? Over/underflow and/or inexact I could live with, by why 'invalid'? I can't find any definition anywhere of what specific CPU's consider 'invalid' floating point operations. I also can't find out why, with a mantissa 9 this register is not set (despite the value not fitting and the cast result being 0), but with a mantissa 10 it is flagged. It seems to me that no relevant maximum/minimum is being passed at that threshold.
More importantly (to me), is there a way for me to cast in a way so that the floating point register isn't touched, ever? The reason being that the code I'm working on relies (later on) on the register not being in an 'invalid' state, and I can't reasonably or reliably modify each use of that register flag check. But also just resetting the flag is error-prone (because of assumptions elsewhere, 'elsewhere' being code I can't touch). I've been looking at boost::numeric_cast but that doesn't seem to help any here, unless I'm missing something somewhere?
But in general, any help on how 'invalid' floating point operations work would be helpful.