Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

comparing floating point numbers in C for unit testing

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.

like image 793
Michael Conlen Avatar asked Dec 28 '22 00:12

Michael Conlen


1 Answers

Comparing floating point values is hard. Mixing in strings isn't going to make things any better, and certainly doesn't introduce the small amount of leeway that epsilon would.

Have a look at this article: Comparing Floating Point Numbers, 2012 Edition. For my money, ULP is the way to go. There are some nasty edge cases, but you can probably ignore most of them.

Edit: 31 May Having thought about this a bit more, I think what you are asking is "If exactly the same steps are used to calculate a float in the test function and in the function under test, will the answer be exactly the same - so that I don't need to worry about +/- some small error?"

The answer is yes, they will be the same. But in that case you have rendered the unit test pointless because if there is a mistake in the code under test then the same mistake will necessarily be present in the test function.

By the way, don't get distracted by the use of memcmp(&x, &y, sizeof(x)). This just tests that exactly the same bits are set in both values. If that is true, then x == y will necessarily be true. Stick with x == y.

like image 74
Ian Goldby Avatar answered Feb 12 '23 13:02

Ian Goldby