2010-04-06 5 views
4

veux dire que je une fonction qui prend deux flotteurs (x et y), et je veux les comparer en utilisant pas leur représentation float mais leur représentation binaire comme 32 bits unsigned int. C'est-à-dire, un nombre comme -495.5 a la représentation de bit 0b11000011111001011100000000000000 ou 0xC3E5C000 comme float, et j'ai un unsigned int avec la même représentation de bit (correspondant à une valeur décimale 3286614016, dont je ne m'inquiète pas). Y at-il un moyen facile pour moi d'effectuer une opération comme <= sur ces flottants en utilisant uniquement les informations contenues dans leurs homologues respectifs unsigned int?dans leurs flotteurs Comparaison des représentations binaires

+0

Vous pouvez le faire en citant cpalmer ci-dessous, mais notez que la représentation int non signée des flottants IEEE ne se commande pas de la même manière que leurs valeurs flottantes équivalentes. -0.0 n'est pas la même chose que 0.0 par exemple, quand ils sont comparés comme ints non signés. –

+0

Vous avez une faute de frappe: il devrait être ['-459.5', pas' -495.5'] (http://ideone.com/9rbZMY) – jfs

Répondre

4

Vous devez effectuer une comparaison signée sauf si vous vous assurez que toutes les valeurs d'origine étaient positives. Vous devez utiliser un type entier de la même taille que le type à virgule flottante d'origine. Chaque puce peut avoir un format interne différent, de sorte que la comparaison de valeurs de puces différentes en tant que nombres entiers est susceptible de donner des résultats trompeurs.

La plupart des formats de float ressemblent à ceci: sxxxmmmm

s est un bit de signe
xxx est un exposant
mmmm est la mantisse

La valeur représentée sera alors quelque chose comme: 1mmm << (xxx-k)

1mmm parce qu'il y a un 1 premier bit implicite à moins que le val ue est zéro.

Si xxx < k alors ce sera un décalage de droite. k est proche, mais pas égal à la moitié de la plus grande valeur qui pourrait être exprimée par xxx. Il est ajusté pour la taille de la mantisse.Tout cela pour dire que, en ne tenant pas compte de NaN, la comparaison de valeurs à virgule flottante sous la forme d'entiers signés de même taille donnera des résultats significatifs. Ils sont conçus de telle sorte que les comparaisons à virgule flottante ne sont pas plus coûteuses que les comparaisons d'entiers. Il existe des optimisations de compilateur pour désactiver les vérifications NaN afin que les comparaisons soient des comparaisons entières directes si le format à virgule flottante de la puce le prend en charge.

En tant qu'entier, NaN est supérieur à l'infini supérieur aux valeurs finies. Si vous essayez une comparaison non signée, toutes les valeurs négatives seront plus grandes que les valeurs positives, tout comme les entiers signés non-signés.

+0

Je suis d'accord. J'ai fouetté quelques tests en utilisant les valeurs non signées en conjonction avec les bits de signe, qui, bien que tout à fait moche fonctionne totalement. – sczizzo

3

En un mot, non. IEEE 754 peut permettre certains types de hacks comme celui-ci, mais ils ne fonctionnent pas tout le temps et gèrent tous les cas, et certaines plates-formes n'utilisent pas cette norme à virgule flottante (comme x87 avec une précision de 80 bits). Si vous faites cela pour des raisons de performances, nous vous suggérons fortement de reconsidérer - s'il est plus rapide d'utiliser la comparaison entière, le compilateur le fera probablement pour vous, et si ce n'est pas le cas, vous payez pour un float à int conversion plusieurs fois, quand une simple comparaison peut être possible sans déplacer les flotteurs hors des registres.

+0

x87? Tu veux dire x86, n'est-ce pas? –

+0

Si IEEE 754 permet des hacks comme celui-ci (et c'est le cas), quand cela ne fonctionnerait-il pas? Quels cas ne gère-t-il pas? – Gabe

+2

@Martinho Fernandes: Non, je veux dire x87. http://en.wikipedia.org/wiki/X87 –

2

Peut-être que je suis une mauvaise interprétation de la question, mais je suppose que vous pourriez faire ceci:

bool compare(float a, float b) 
{ 
    return *((unsigned int*)&a) < *((unsigned int*)&b); 
} 

Mais cela suppose toutes sortes de choses et garantit également la question de savoir pourquoi vous voulez comparer les représentations au niveau du bit de deux flotteurs.

+0

Ah, le bon vieux cocher-through-pointers pirater. Laid, mais puissant. –

+2

Si vous allez faire cela au minimum, utilisez 'reinterpret_cast' pour le marquer comme le hack spécifique à la plate-forme. –

+0

@BillyONeal - la question est étiquetée comme C, C++ et Objective-C. 'reinterpret_cast' est approprié uniquement pour C++. –

3

Si vous ne vous souciez vraiment pas de la conversion, ce n'est pas trop difficile. Mais les résultats sont extrêmement non portables, et vous n'obtiendrez presque certainement pas une commande qui ressemble à ce que vous obtiendriez en comparant les flotteurs directement. Il suffit de comprendre les mises en garde, et choisissez votre deuxième type avec soin. C'est une excersize presque sans valeur à tout prix.

+1

+1 pour l'utilisation de reinterpert_cast. –

+0

Il est difficile d'utiliser reinterpret_cast en C. –

+0

@Richard Pennington: Remplacez-le par un cast de style C. Mais l'écriture par défaut devrait être la bonne distribution plutôt que l'ancienne, dans la mesure du possible, étant donné que les distributions de type C sont obsolètes. (Sauf si vous devez absolument avoir la compatibilité C ici) –