Dato due numeri in virgola mobile, sto cercando un modo efficiente per verificare se hanno lo stesso segno, dato che se c'è ne dei due valori è zero (+0.0 o -0.0), dovrebbero essere considerati con lo stesso segno.Come confrontare in modo efficiente il segno di due valori in virgola mobile mentre si gestiscono gli zeri negativi
Per esempio,
- SameSign (1.0, 2.0) dovrebbe restituire true
- SameSign (-1,0, -2,0) deve restituire true
- SameSign (-1,0, 2.0) dovrebbe restituire false
- SameSign (0.0, 1.0) deve restituire true
- SameSign (0.0, -1.0) deve restituire true 01.235.164,106 mila
- SameSign (-0.0, 1.0) deve restituire true
- SameSign (-0.0, -1.0) deve restituire true
Un'implementazione naive ma corretta SameSign
in C++ sarebbe:
bool SameSign(float a, float b)
{
if (fabs(a) == 0.0f || fabs(b) == 0.0f)
return true;
return (a >= 0.0f) == (b >= 0.0f);
}
Assumendo il modello IEEE in virgola mobile, ecco una variante di SameSign
che compila codice branchless (almeno con Visual C++ 2008):
bool SameSign(float a, float b)
{
int ia = binary_cast<int>(a);
int ib = binary_cast<int>(b);
int az = (ia & 0x7FFFFFFF) == 0;
int bz = (ib & 0x7FFFFFFF) == 0;
int ab = (ia^ib) >= 0;
return (az | bz | ab) != 0;
}
con binary_cast
definiti come segue:
template <typename Target, typename Source>
inline Target binary_cast(Source s)
{
union
{
Source m_source;
Target m_target;
} u;
u.m_source = s;
return u.m_target;
}
Sto cercando due cose:
Un più veloce, più efficace attuazione del
SameSign
, utilizzando trucchi bit, FPU trucchi o anche intrinseci SSE.Un'estensione efficiente di
SameSign
a tre valori.
Edit:
Ho fatto alcune misurazioni delle prestazioni sulle tre varianti di SameSign
(le due varianti descritte nella domanda iniziale, più di uno) di Stephen. Ogni funzione è stata eseguita 200-400 volte, su tutte le coppie di valori consecutivi in un array di 101 float riempiti a caso con -1.0, -0.0, +0.0 e +1.0. Ogni misura è stata ripetuta 2000 volte e il tempo minimo è stato mantenuto (per eliminare tutti gli effetti della cache e i rallentamenti indotti dal sistema). Il codice è stato compilato con Visual C++ 2008 SP1 con ottimizzazione massima e generazione di codice SSE2 abilitata. Le misurazioni sono state effettuate su un Core 2 Duo P8600 2.4 Ghz.
Ecco gli orari, senza contare il sovraccarico di recupero valori di input dalla matrice, chiamando la funzione e recuperare il risultato (che ammontano a 6-7 clockticks):
- variante naive: 15 zecche
- Bit variante magica: 13 zecche
- variante di Stephens: 6 zecche
Qualsiasi particolare linguaggio/piattaforma? –
Ehi, grazie per la bella domanda :) Preferibilmente C/C++ su x86. –
possibile duplicato di [confrontare due float per vedere se sono entrambi negativi, o entrambi positivi.] (Http://stackoverflow.com/questions/2013680/comparing-two-floats-to-see-if-theyre-oth -negativo-o-entrambi-positivo) – ChrisF