0

I'm writing some testcases for a program using the GLib testing facilities. I want to assert that two floats have the same value, and g_assert_cmpfloat () seemed like an appropriate function for that. I used it like so:

g_assert_cmpfloat (10.0f, ==, 10.0f); 

(obviously with the constant values replaced with the actual values I'm checking equivalence for, but this is simpler and reproduces the issue)

The project I'm adding the testcases to is using -Wfloat-equal, which sensibly warns about the problems with comparing floats like this. But it makes me wonder, how am I supposed to assert that two floats are equal using this function then? I don't want to use g_assert_true () since that won't log the actual values of the two floats. I've seen the answers to Compare two floats, but I'm not sure how I implement them while still using this function.

For context, the testcase ensures that a string representation such as "4.25" gets properly converted to the equivalent floating point value properly.

How can I use g_assert_cmpfloat () with -Wfloat-equal to assert that two floats are equal without generating a compiler warning?

12
  • Is evaluating exact FP equality more reasonable for your tests than it is for other parts of the project? Because the most obvious answer is "don't do that." Commented Apr 29 at 21:22
  • 3
    ... and the natural alternative would be to instead use g_assert_cmpfloat_with_epsilon(), with a suitable epsilon. Commented Apr 29 at 21:30
  • You might want to soften your acceptance of equality for floats to allow eg +/- 2 ULP or you will likely find too many false mismatches where working numbers meant to be identical are ever so slightly different in the last few bits of the mantissa. For a,b check that at least one of them, b isn't zero and assert ( abs(1 - a/b), <, N*machine_eps) for your chosen tolerance of N ULP. Some similar helper functions may already exist on your platform. Commented Apr 29 at 21:36
  • Perhaps: a >= b && a <= b? Commented Apr 29 at 22:32
  • as per @JohnBollinger suggestion, use the g_assert_cmpfloat_with_epsilon, float.h has FLT_EPSILON defined as a starting point. Commented Apr 30 at 1:00

2 Answers 2

2

I want to assert that two floats have the same value, and g_assert_cmpfloat () seemed like an appropriate function for that. I used it like so:

g_assert_cmpfloat (10.0f, ==, 10.0f); 

... which asserts exact equality of two floating-point values.

The project I'm adding the testcases to is using -Wfloat-equal, which sensibly warns about the problems with comparing floats like this.

Sensibly indeed. There are special cases for which testing exact equality of FP values makes sense, but generally speaking, tests for exact FP equality are extremely sensitive to computational and implementation details, and exact equality is rarely what you really require anyway. So don't do that.

How can I use g_assert_cmpfloat () with -Wfloat-equal to assert that two floats are equal without generating a compiler warning?

You can't. Macros expand to ordinary code. In any case that satisfies that description, the macro expands to code that involves an == comparison of two FP values, which will trigger a warning. If you don't want that, then you need to choose a different kind of comparison.

You could make two uses of g_assert_cmpfloat () with different operators (from among <, <=, >, >=) to perform an approximate equality test, but as long as you're looking at GLib's assertion macros, I guess you have overlooked g_assert_cmpfloat_with_epsilon(), which provides for that type of bounded approximate equality test with a single macro invocation.

Sign up to request clarification or add additional context in comments.

3 Comments

Using a good epsilon is tricky as it often needs to scale to the magnitude of the operands. g_assert_cmpfloat_with_epsilon() needs guidance concerning epsilon. Unfortunately OP questions lacks details and a general answer is too long.
Agreed, @chux. But this is the answer the OP requested (in comments) to be written. Apparently they are satisfied that they can choose an epsilon appropriately.
"satisfied that they can choose an epsilon appropriately." --> Likely, yet such self-assessment is too often amiss.
1

How can I use g_assert_cmpfloat () with -Wfloat-equal to assert that two floats are equal without generating a compiler warning?

Use g_assert_cmpfloat with the smallest positive float: g_assert_cmpfloat_with_epsilon(x, y, FLT_TRUE_MIN).

This tests abs(x - y) < FLT_TRUE_MIN. The only result of abs (when applied to a float operand) that is less than FLT_TRUE_MIN is zero, so it tests x - y == 0. IEEE-754 floating-point is designed so that x - y == 0 if and only if x == y. So, with IEEE-754 floating-point arithmetic, g_assert_cmpfloat_with_epsilon(x, y, FLT_TRUE_MIN) is equivalent to g_assert_cmpfloat(x, y).

(This may fail if IEEE-754 arithmetic is not in use, including arithmetic that is mostly conforming to IEEE-754 but that flushes subnormal results to zero.)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.