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?
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.
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;
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With