signe rapide en C ++ float ... sont là toutes les dépendances de la plate-forme dans ce code?

StackOverflow https://stackoverflow.com/questions/2508436

Question

Recherche en ligne, j'ai trouvé la routine suivante pour calculer le signe d'un flotteur au format IEEE. Cela pourrait facilement être étendu à un double aussi.

// returns 1.0f for positive floats, -1.0f for negative floats, 0.0f for zero
inline float fast_sign(float f) {
    if (((int&)f & 0x7FFFFFFF)==0) return 0.f; // test exponent & mantissa bits: is input zero?
    else {
        float r = 1.0f;
        (int&)r |= ((int&)f & 0x80000000); // mask sign bit in f, set it in r if necessary
        return r;
    }
}

( Source : `` signe rapide pour 32 bits flotte '' , Peter Schoffhauzer)

Je suis fatigué d'utiliser cette routine, même si, en raison des opérations binaires de bits. Je dois mon code pour travailler sur des machines avec différents ordres d'octets, mais je ne suis pas sûr à quel point cette norme IEEE les spécifie, comme je ne pouvais pas trouver la version la plus récente, publiée cette année. Quelqu'un peut-il me dire si cela va fonctionner, quel que soit l'ordre des octets de la machine?

Merci, Patrick

Était-ce utile?

La solution

Comment pensez-vous fabs() et fabsf() sont implémentés sur votre système, ou pour que les comparaisons en la matière avec une constante 0? Si ce n'est pas par ops au niveau du bit, il est tout à fait peut-être parce que les auteurs du compilateur ne pense pas que ce serait plus vite.

Les problèmes de portabilité avec ce code sont les suivants:

  1. int float et pourraient ne pas avoir le même boutisme ou même de la même taille. De là aussi, les masques peuvent se tromper.
  2. float pourrait ne pas être la représentation IEEE
  3. Vous briser les règles strictes d'aliasing. Le compilateur est autorisé à supposer qu'un pointeur / référence à un flotteur et un pointeur / référence à un int ne peut pas pointent vers le même emplacement mémoire. Ainsi, par exemple, la norme ne garantit pas que r est initialisé avec 1.0 avant qu'il ne soit modifié dans la ligne suivante. Il pourrait réorganiser les opérations. Ce n'est pas vaine spéculation, et à la différence (1) et (2) il est non défini, non défini par l'implémentation, de sorte que vous ne pouvez pas nécessairement il suffit de regarder vers le haut de votre compilateur. Avec l'optimisation assez, je l'ai vu GCC sauter l'initialisation des variables flottantes qui sont référencées uniquement par un pointeur punned type.

Je voudrais tout d'abord faire la chose évidente et examiner le code émis. Seulement si cela semble douteux il vaut la peine de penser à faire autre chose. Je n'ai aucune raison particulière de penser que je sais plus sur la représentation de chars que bitwise mon compilateur ne; -)

inline float fast_sign(float f) {
    if (f > 0) return 1;
    return (f == 0) ? 0 : -1;
    // or some permutation of the order of the 3 cases
}

[Edit: en fait, GCC ne fait quelque chose d'un repas que même avec -O3. Le code émis est pas nécessairement lent, mais il n'utilise ops à virgule flottante de sorte qu'il ne sait pas qu'il est rapide. L'étape suivante est de comparer, tester si l'alternative est plus rapide sur un compilateur vous pouvez poser vos mains sur, et si oui, en faire quelque chose que les gens de portage de votre code peut permettre un #define ou autre, selon les résultats de leur propre référence.]

Autres conseils

Ne pas oublier que, pour déplacer une valeur en virgule flottante à partir d'un registre FPU à un registre entier nécessite une écriture RAM suivie d'une lecture.

Avec flottante code de point, vous serez toujours mieux regarder la plus grande image:

Some floating point code
Get sign of floating point value
Some more floating point code

Dans le scénario ci-dessus, en utilisant la FPU pour déterminer le signe serait plus rapide car il n'y aura pas de lecture / écriture en tête 1 . Le processeur Intel FPU peut faire:

FLDZ
FCOMP

qui définit les indicateurs de code de condition pour > 0, < 0 et == 0 et peut être utilisé avec FCMOVcc.

Inlining ci-dessus dans le code FPU bien écrit va battre toutes les manipulations de bits entier et ne sera pas une perte de précision 2 .

Notes:

  1. Le Intel IA32 a une optimisation de lecture après écriture où il ne sera pas attendre que les données soient engagés à RAM / cache, mais il suffit d'utiliser directement la valeur. Il annule toujours le cache bien donc il y a un effet d'entraînement sur.
  2. Le processeur Intel FPU est 80bits interne, flotteurs sont 32 et 64 doubles, donc la conversion de flotter / double pour recharger comme un entier va perdre quelques bits de précision. Ce sont des morceaux importants que vous cherchez des transitions vers 0.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top