Bizarre floating-point behavior with vs. without extra variables, why?

后端 未结 4 509
终归单人心
终归单人心 2021-01-18 01:27

When I run the following code in VC++ 2013 (32-bit, no optimizations):

#include 
#include 
#include 

double mulpow         


        
4条回答
  •  生来不讨喜
    2021-01-18 02:34

    You are converting out-of-range double values to unsigned long long. This is not allowed in standard C++, and Visual C++ appears to treat it really badly in SSE2 mode: it leaves a number on the FPU stack, eventually overflowing it and making later code that uses the FPU fail in really interesting ways.

    A reduced sample is

    double d = 1E20;
    unsigned long long ull[] = { d, d, d, d, d, d, d, d };
    if (floor(d) != floor(d)) abort();
    

    This aborts if ull has eight or more elements, but passes if it has up to seven.

    The solution is not to convert floating point values to an integer type unless you know that the value is in range.

    4.9 Floating-integral conversions [conv.fpint]

    A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type. [ Note: If the destination type is bool, see 4.12. -- end note ]

    The rule that out-of-range values wrap when converted to an unsigned type only applies if the value as already of some integer type.

    For whatever it's worth, though, this doesn't seem like it's intentional, so even though the standard permits this behaviour, it may still be worth reporting this as a bug.

提交回复
热议问题