Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check a double's bit pattern is 0x0 in a C++11 constexpr?

I want to check that a given double/float variable has the actual bit pattern 0x0. Don't ask why, it's used in a function in Qt (qIsNull()) that I'd like to be constexpr.

The original code used a union:

union { double d; int64_t i; } u;
u.d = d;
return u.i == 0;

This doesn't work as a constexpr of course.

The next try was with reinterpret_cast:

return *reinterpret_cast<int64_t*>(&d) == 0;

But while that works as a constexpr in GCC 4.7, it fails (rightfully, b/c of pointer manipulation) in Clang 3.1.

The final idea was to go Alexandrescuesque and do this:

template <typename T1, typename T2>
union Converter {
    T1 t1;
    T2 t2;
    explicit constexpr Converter( T1 t1 ) : t1(t1) {}
    constexpr operator T2() const { return t2; }
};

// in qIsNull():
return Converter<double,int64_t>(d);

But that's not clever enough for Clang, either:

note: read of member 't2' of union with active member 't1' is not allowed in a constant expression
constexpr operator T2() const { return t2; }
                                       ^

Does anyone else have a good idea?

like image 273
Marc Mutz - mmutz Avatar asked Feb 17 '12 12:02

Marc Mutz - mmutz


3 Answers

I want to check that a given double/float variable has the actual bit pattern 0x0

But if it's constexpr then it's not checking any variable, it's checking the value that this variable is statically determined to hold. That's why you aren't supposed to pull pointer and union tricks, "officially" there isn't any memory to point at.

If you can persuade your implementation to do non-trapping IEEE division-by-zero, then you could do something like:

return (d == 0) && (1 / d > 0)

Only +/-0 are equal to 0. 1/-0 is -Inf, which isn't greater than 0. 1/+0 is +Inf, which is. But I don't know how to make that non-trapping arithmetic happen.

like image 172
Steve Jessop Avatar answered Nov 08 '22 12:11

Steve Jessop


It seems both clang++ 3.0 and g++ 4.7 (but not 4.6) treats std::signbit as constexpr.

return x == 0 && std::signbit(x) == 0;
like image 36
kennytm Avatar answered Nov 08 '22 10:11

kennytm


It is not possible to look at the underlying bit pattern of a double from within a constant expression. There was a defect in the C++11 standard which allowed such inspection by casting via a void*, but that was addressed by C++ core issue 1312.

As "proof", clang's constexpr implementation (which is considered to be complete) has no mechanism for extracting the representation of a constant double value (other than via non-standard vector operations, and even then there is currently no way to inspect the result).

As others have suggested, if you know you will be targeting a platform which uses IEEE-754 floating point, 0x0 corresponds to the value positive zero. I believe the only way to detect this, that works inside a constant expression in both clang and g++, is to use __builtin_copysign:

constexpr bool isPosZero(double d) {
  return d == 0.0 && __builtin_copysign(1.0, d) == 1.0;
}
like image 4
Richard Smith Avatar answered Nov 08 '22 11:11

Richard Smith