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

Howard Hinnant hhinnant at apple.com
Thu Dec 1 11:43:27 PST 2011


On Dec 1, 2011, at 2:41 PM, Richard Smith wrote:

> 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
> 

Ok, thanks.  I'll be happy to commit patches along the lines of what Edward proposed.

Howard




More information about the cfe-dev mailing list