2012-02-17 11 views
8

Voglio verificare che una determinata variabile double/float abbia il bit pattern effettivo 0x0. Non chiedere perché, è utilizzato in una funzione in Qt (qIsNull()) che mi piacerebbe essere constexpr.Come verificare il pattern a bit di un doppio è 0x0 in un constexpr C++ 11?

Il codice originale utilizzato un sindacato:

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

Questo non funziona come constexpr naturalmente.

Il tentativo successivo è stato con reinterpret_cast:

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

Ma mentre che funziona come un constexpr in GCC 4.7, non riesce (giustamente, b/c del puntatore manipolazione) in Clang 3.1.

L'idea finale è stato di andare Alexandrescuesque e fare questo:

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

Ma non è abbastanza intelligente per Clang, sia:

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

Qualcun altro ha una buona idea?

+1

Credo che ci sono altri schemi di bit che rappresentano anche una virgola mobile 0, che don vuoi trovare? –

+2

Esistono esattamente due modelli di bit che rappresentano 0. Sono 000 ... 000 e 100 ... 000. Il primo bit è il bit del segno. Il secondo schema di bit viene talvolta definito "zero negativo". – user763305

+2

Forse 'return d == 0 && 1/d> 0;'? (http://en.wikipedia.org/wiki/Signed_zero#Comparisons) –

risposta

6

voglio verificare che una data variabile doppia/float ha il modello 0x0 po 'effettiva

Ma se è constexpr allora non è controllare qualsiasi variabile , è controllare il valoreche questo la variabile è determinata staticamente da tenere. Ecco perché non si suppone che tu possa tirare a puntatori e trucchi sindacali, "ufficialmente" non c'è alcun ricordo a cui puntare.

Se si riesce a convincere l'implementazione di fare non intrappolando IEEE divisione per zero, allora si potrebbe fare qualcosa di simile:

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

Solo +/-0 sono uguali a 0. 1/-0 è -Inf, che isn' t maggiore di 0. 1/+0 è +Inf, che è. Ma non so come far succedere quell'aritmetica senza intrappolamento.

+0

L'implementazione di solito non è un trapping di default? –

+0

@Christian: su GCC con le opzioni della riga di comando di vanilla ottengo un errore in virgola mobile se divido per zero. –

+0

Aha, Ok. A proposito, se leggo correttamente puoi usare 'feholdecxept' da' '(C++ 11/C99) per entrare in modalità non trappola. E poiché usa C++ 11, questa potrebbe essere una bella aggiunta alla tua risposta (ma non dimenticare "#pragma STDC FENV_ACCESS ON" in questo caso). –

5

Sembra sia clang ++ 3.0 che g ++ 4.7 (ma non 4.6) tratta std::signbit come constexpr.

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

Clang 3.0 non implementa 'constexpr'? Comunque [c.math]/11 di C++ 11 afferma chiaramente che 'std :: signbit' non è' constexpr' :( –

4

Non è possibile osservare lo schema sottostante po 'di double dall'interno di un'espressione costante. C'era un difetto nello standard C++ 11 che consentiva tale ispezione mediante il casting tramite un void*, ma che era indirizzato da C++ core issue 1312.

Come "prova", l'implementazione di clang constexpr (che è considerata completa) non ha alcun meccanismo per estrarre la rappresentazione di un valore costante double (diverso da operazioni vettoriali non standard, e anche in questo caso non esiste attualmente alcun modo per ispezionare il risultato).

Come altri hanno suggerito, se si sa che si tratterà di una piattaforma che utilizza il virgola mobile IEEE-754, 0x0 corrisponde al valore zero positivo. Credo che l'unico modo per rilevare questo, che funziona all'interno di una costante espressione sia clang e g ++, è quello di utilizzare __builtin_copysign:

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