9 Stimmen

Wie zu überprüfen, ein Double-Bit-Muster ist 0x0 in einem C++11 constexpr?

Ich möchte überprüfen, ob eine bestimmte Double/Float-Variable das aktuelle Bitmuster 0x0 hat. Fragen Sie nicht warum, es wird in einer Funktion in Qt verwendet ( qIsNull() ), die ich gerne sein möchte constexpr .

Der ursprüngliche Code verwendete eine Vereinigung:

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

Das funktioniert nicht als constexpr natürlich.

Der nächste Versuch war mit reinterpret_cast :

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

Das funktioniert zwar als constexpr in GCC 4.7, es scheitert (zu Recht, b/c von Zeigermanipulation) in Clang 3.1.

Die letzte Idee war, dies auf alexandrinische Art und Weise zu tun:

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

Aber auch das ist für Clang nicht clever genug:

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

Hat sonst noch jemand eine gute Idee?

1 Stimmen

Ich vermute, es gibt noch andere Bitmuster, die ebenfalls eine Fließkomma-0 darstellen, die Sie nicht finden wollen?

2 Stimmen

Es gibt genau zwei Bitmuster, die 0 darstellen, nämlich 000...000 und 100...000. Das erste Bit ist das Vorzeichenbit. Das zweite Bitmuster wird manchmal auch als "negative Null" bezeichnet.

2 Stimmen

Vielleicht return d == 0 && 1/d > 0; ? ( de.wikipedia.org/wiki/Signed_zero#Vergleiche )

6voto

Steve Jessop Punkte 264569

Ich möchte überprüfen, ob eine gegebene Double/Float-Variable das aktuelle Bitmuster 0x0 hat

Aber wenn es constexpr dann prüft es keine variabel prüft es die Wert dass diese Variable statisch festgelegt ist. Deshalb sollten Sie keine Zeiger- und Union-Tricks anwenden, denn "offiziell" gibt es keinen Speicher, auf den man zeigen könnte.

Wenn Sie Ihre Implementierung überreden können, nicht-trapping IEEE Division durch Null zu tun, dann könnten Sie etwas wie tun:

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

Nur +/-0 gleich 0 sind. 1/-0 es -Inf die nicht größer als 0 ist. 1/+0 es +Inf das ist. Aber ich weiß nicht, wie diese nicht-einfangende Arithmetik zustande kommt.

5voto

kennytm Punkte 488916

Es scheint, dass sowohl clang++ 3.0 als auch g++ 4.7 (aber nicht 4.6) behandelt werden std::signbit als constexpr .

return x == 0 && std::signbit(x) == 0;

4voto

Richard Smith Punkte 13137

Es ist nicht möglich, das zugrunde liegende Bitmuster einer double innerhalb eines konstanten Ausdrucks. Es gab einen Fehler im C++11-Standard, der eine solche Überprüfung durch Casting über eine void* aber das wurde von C++ Kernproblem 1312 .

Als "Beweis" dient clang's constexpr Implementierung (die als vollständig angesehen wird) hat keinen Mechanismus zur Extraktion der Darstellung einer Konstante double Wert (außer über nicht standardisierte Vektoroperationen, und selbst dann gibt es derzeit keine Möglichkeit, das Ergebnis zu überprüfen).

Wie bereits von anderen vorgeschlagen, sollten Sie wissen, dass Sie eine Plattform anvisieren, die IEEE-754 Gleitkomma verwendet, 0x0 entspricht dem positiven Wert Null. Ich glaube, die einzige Möglichkeit, dies zu erkennen, die sowohl in clang als auch in g++ innerhalb eines konstanten Ausdrucks funktioniert, ist die Verwendung von __builtin_copysign :

constexpr bool isPosZero(double d) {
  return d == 0.0 && __builtin_copysign(1.0, d) == 1.0;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X