So I'm using CUnit to do unit testing. I expect something like
float x;
x = atof("17.99");
And I want to test this with an assert; obviously with some small epsilon I could
CU_ASSERT(abs(x - atof("17.99")) < epsilon);
However I'm considering
r = atof("17.99");
CU_ASSERT(0 == memcmp(&x, &r, sizeof(float));
This does appear to work. I wish to use this to avoid having to manually set epsilon on each test based on the values. In the above case 1e-6 should be sufficient; however if the value is 1e-10 using epsilon of 1e-6 may not catch a problem. The more choices the developer has to make the more room for error.
My questions are: Should this technique be stable on posix systems? That is, if the two floating point numbers being compared are generated by exactly the same steps should their internal representation be exactly the same.
edit: More to the point I'd eventually like a CU_ASSERT_FLOAT_EQUAL macro.
So the answer appears to be no.
The reason is that even if you use an identical series of computations in computing each variable, if there is any code between the steps of computing the value you may induce different rounding errors, as noted by the note in @AProgrammer's response.
The issue is that while you might declare a n-bit floating point it may be stored in a larger register (The x87 uses an 80 bit register). If the value is pushed off the register and into memory to free the register for other operations, the value is then truncated (rounded? Where did my notes go...). When the value is brought back on to the register that lost precision carries through the rest of the computation.
On the other hand another piece of code may go through the exact same steps in computing the value; however if the value is not pushed off the register (or is pushed off at a different place...) then you get a different truncation when it is stored in memory again.
All this is IEEE approved according to the notes from the gcc mailing lists/bug reports.
Since I haven't touched a register since the 80386, I can only guess at what the modern x86 and amd_64 processors have; but I'm guessing without hints to gcc that for the x86 it's using a basic x87 register set or a basic SSE register set.
So the rule of thumb to use fabs(x-y) < epsilon; holds, which for CUnit is provided for in double format (and one could easily write a float version of the macro if one wanted to be as anal about things as I have a habit of getting) as noted by the post which @Martin Beckett commented on.