[cfe-dev] [libcxx/test] Floating point comparisons

Richard Smith richard at metafoo.co.uk
Thu Dec 1 11:41:13 PST 2011


On Thu, December 1, 2011 19:09, Howard Hinnant wrote:
> On Dec 1, 2011, at 1:54 PM, Edward Meewis wrote:
>> I am experimenting with libcxx on FreeBSD and got a lot of asserts on
>> floating point comparisons, most notably in 'libcxx/test/containers/unord',
>> e.g.:
>>
>>
>> Assertion failed: (c.load_factor() == (float)c.size()/c.bucket_count()),
>> function main, file assign_move.pass.cpp, line 71.
>>
>> Switching on optimization makes them go away. I'm guessing one of the
>> values gets promoted from a float to a double somewhere, which makes the
>> comparison fail.
>>
>> The question is: do the lvalue and rvalue need to be exactly the same? I
>> think it would be better to use something like:
>>
>> assert(fabs(c.load_factor() - (float)c.size()/c.bucket_count()) <
>> FLT_EPSILON);
>>
>>
>> to sidestep the issue. It also has the benefit of being more implementation
>> independent?
>
> Before changing this I'd like to understand the issue, just to make sure we
> wouldn't be hiding a bug.
>
> load_factor() is computed (in <__hash_table>) as:
>
> _LIBCPP_INLINE_VISIBILITY float load_factor() const _NOEXCEPT
> {
> size_type __bc = bucket_count(); return __bc != 0 ? (float)size() / __bc : 0.f;
>  }
>
>
> which is precisely how the test is computed too.  So I currently do not
> understand the cause of the assert.
>
> And just to head off the discussion that one should never compare floating
> point with equality:  I'm aware of how floating point works.  But I also know
> that it is deterministic, down to the very last bit.

Not so fast. See C++98[expr]p10 / C++11[expr]p11, "The values of the
floating operands and the results of floating expressions may be
represented in greater
precision and range than that required by the type". There's no requirement
that the compiler do this in a consistent way, or even do it the same way
every time the same expression is evaluated.

(In practice, the result of the computation on, say, x86 will depend on
whether the computation is performed using the 80-bit x87 FPU registers or one
of the more modern 64-bit registers, whether extended precision is enabled,
which rounding mode is set, whether FPU 80-bit registers got spilled to 64-bit
stack slots, etc.)

Richard




More information about the cfe-dev mailing list