Étant donné deux nombres à virgule flottante, je cherche un efficace façon de vérifier si elles ont le même signe, étant donné que si des deux valeurs est zéro (+0.0 ou -0.0), ils doivent être considérés comme ayant le même signe.Comment comparer efficacement le signe de deux valeurs à virgule flottante lors de la manipulation des zéros négatifs
Par exemple,
- SameSign (1.0, 2.0) doit renvoyer true
- SameSign (-1,0, -2,0) doit renvoyer true
- SameSign (-1,0, 2.0) devrait renvoyer false
- SameSign (0.0, 1.0) doit renvoyer true
- SameSign (0,0, -1,0) doit retourner true
- SameSign (-0,0, 1,0) doit retourner true
- SameSign (-0,0, -1,0) doit renvoyer true
Une implémentation naïve mais correcte de SameSign
en C++ serait:
bool SameSign(float a, float b)
{
if (fabs(a) == 0.0f || fabs(b) == 0.0f)
return true;
return (a >= 0.0f) == (b >= 0.0f);
}
en supposant que le modèle à virgule flottante IEEE, voici une variante de SameSign
qui compile le code de branches (au moins avec 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;
}
avec binary_cast
défini comme suit:
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;
}
Je cherche deux choses:
Une plus rapide, la mise en œuvre plus efficace des
SameSign
, en utilisant des astuces de bits, FPU astuces ou même SSE intrinsèques.Une extension efficace de
SameSign
à trois valeurs.
Edit:
J'ai fait quelques mesures de performance sur les trois variantes de SameSign
(les deux variantes décrites dans la question initiale, plus Etienne un). Chaque fonction a été exécutée 200 à 400 fois, sur toutes les paires de valeurs consécutives dans un tableau de 101 flottants remplis au hasard avec -1,0, -0,0, +0,0 et +1,0. Chaque mesure a été répétée 2000 fois et le temps minimum a été conservé (pour éliminer tous les effets de cache et les ralentissements induits par le système). Le code a été compilé avec Visual C++ 2008 SP1 avec l'optimisation maximale et la génération de code SSE2 activée. Les mesures ont été effectuées sur un Core 2 Duo P8600 2.4 Ghz.
Voici les synchronisations, sans compter les frais généraux de l'extraction des valeurs d'entrée provenant du réseau, l'appel de la fonction et la récupération du résultat (qui se montent à 6-7 clockticks):
- variante Naive: 15 tiques
- Bit variante magique: 13 tiques
- la variante de Stephens: 6 tiques
Toute langue particulière/plate-forme? –
Hé, merci pour la bonne question :) De préférence C/C++ sur x86. –
duplication possible de [comparant deux flottants pour voir s'ils sont tous deux négatifs, ou les deux positifs.] (Http://stackoverflow.com/questions/2013680/comparing-two-floats-to-see-if-theyre-both -negative-or-both-positive) – ChrisF