247 votes

Quelqu'un peut-il expliquer ce comportement étrange avec flotteurs signés en c# ?

Voici l’exemple avec commentaires :

Alors, que pensez-vous à ce sujet ?

390voto

SLaks Points 391154

Le bug est dans les deux lignes suivantes de l' System.ValueType: (je suis entré dans la source de référence)

if (CanCompareBits(this)) 
    return FastEqualsCheck(thisObj, obj);

(Les deux méthodes sont [MethodImpl(MethodImplOptions.InternalCall)])

Lorsque tous les champs sont de 8 octets, CanCompareBits , à tort, renvoie true, résultant en un bit à bit de comparaison de deux différents, mais sémantiquement identiques, les valeurs.

Lorsque au moins un des champs n'est pas 8 octets de large, CanCompareBits retourne false, et le code de produit à utiliser la réflexion pour une boucle sur les champs et appelez - Equals pour chaque valeur, qui traite correctement -0.0 comme égal à 0.0.

Voici la source pour CanCompareBits de SSCLI:

FCIMPL1(FC_BOOL_RET, ValueTypeHelper::CanCompareBits, Object* obj)
{
    WRAPPER_CONTRACT;
    STATIC_CONTRACT_SO_TOLERANT;

    _ASSERTE(obj != NULL);
    MethodTable* mt = obj->GetMethodTable();
    FC_RETURN_BOOL(!mt->ContainsPointers() && !mt->IsNotTightlyPacked());
}
FCIMPLEND

59voto

Ben M Points 14458

J'ai trouvé la réponse à http://blogs.msdn.com/xiangfan/archive/2008/09/01/magic-behind-valuetype-equals.aspx.

Le coeur est la source de commenter CanCompareBits, ValueType.Equals utilise pour déterminer s'il faut utiliser memcmp-style de comparaison:

Le commentaire de CanCompareBits dit "Retourne true si la valuetype n' contenir pointeur et est étroitement emballé". Et FastEqualsCheck utilisation "comparateur de mémoire" pour accélérer la comparaison.

L'auteur poursuit en affirmant exactement le problème décrit par l'OP:

Imaginez que vous avez une structure qui ne contient qu'un float. Ce qui va se produire si l'un contient +0.0, et les autres contient -0.0? Ils devraient être les de même, mais le sous-jacent binaire représentation sont différents. Si vous nid d'une autre structure, qui l'emportent la méthode Equals, que l'optimisation échoueront également.

52voto

Eric Lippert Points 300275

Vilx la conjecture est correcte. Ce "CanCompareBits" ne se vérifie pour voir si le type de la valeur en question est "serrée" dans la mémoire. Une serrés struct est comparé en comparant simplement les bits binaires de la structure; un vaguement emballé structure est comparée en appelant est Égal pour tous les membres.

C'est ce qui explique SLaks' observation, qu'il repros avec les structures qui sont toutes des chambres doubles; ces structures sont toujours serrés.

Malheureusement, comme nous l'avons vu ici, qui introduit une différence sémantique, car au niveau du bit de comparaison de doubles et correspond à la comparaison des doubles donne des résultats différents.

22voto

Vilx- Points 37939

La moitié d’une réponse :

Réflecteur nous dit que `` fait quelque chose comme ceci :

Malheureusement les deux et (les deux méthodes statiques) sont extern ( `` ) et n’ont aucune source disponible.

Retour à deviner pourquoi un cas peut être comparé par bits, et l’autre ne peut (alignement des questions peut-être ?)

18voto

Matthew Flaschen Points 131723

Il ** donne vrai pour moi, avec gmcs du Mono 2.4.2.3.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X