2010-11-15 4 views
1

Possible en double:
How do I fix this Perl code so that 1.1 + 2.2 == 3.3?questions de comparaison Float en Perl

Je travaille sur un script Perl qui compare les chaînes représentant des modèles de gènes et imprime un résumé de la comparaison. Si les modèles de gènes correspondent parfaitement, j'imprime un résumé très concis, mais s'ils sont différents, le résumé est assez verbeux.

Le script examine la valeur d'une variable pour déterminer si elle doit faire le résumé succinct ou verbeux - si la variable est égale à 1, elle doit imprimer le résumé concis; sinon, il devrait imprimer le résumé verbeux.

Comme la valeur est numérique (un flottant), j'ai utilisé l'opérateur == pour faire la comparaison.

if($stats->{overall_simple_matching_coefficient} == 1) 
{ 
    print "Gene structures match perfectly!\n"; 
} 

Cela a fonctionné correctement pour tous mes tests et même pour la plupart des nouveaux cas je cours maintenant, mais je trouve un cas bizarre où la valeur était égale à 1, mais la comparaison ci-dessus a échoué. Je n'ai pas été en mesure de comprendre pourquoi la comparaison a échoué, et encore plus étrange, quand j'ai changé l'opérateur == à l'opérateur eq, cela a semblé fonctionner correctement.

Je pensais que le == était pour la comparaison numérique et eq était pour la comparaison de chaîne. Est-ce que j'ai râté quelque chose?

Mise à jour: Si j'imprimer la valeur juste avant la comparaison ...

printf("Test: '%f', '%d', '%s'\n", $stats->{overall_simple_matching_coefficient}, $stats->{overall_simple_matching_coefficient}, $stats->{overall_simple_matching_coefficient}); 

... Je reçois cela.

Test: '1.000000', '0', '1' 
+0

Que obtenez-vous si vous imprimez la valeur de '$ stats -> {overall_simple_matching_coefficient}' juste avant la comparaison? –

+0

Oh, je le faisais en fait plus tôt. Merci, je vais mettre ça en place. –

+0

Pas sûr de perl, ne l'utilisez pas beaucoup, mais dans bash au moins '==' est pour les chaînes et '-eq' est pour les numériques ... –

Répondre

9

La première chose que tout professeur de langage informatique doit enseigner tout langage informatique est que YOU CANNOT COMPARE FLOATS FOR EQUALIT Y. Cela est vrai de toute langue. L'arithmétique en virgule flottante n'est pas exacte, et deux flottants qui semblent identiques sont différents dans les chiffres insignifiants quelque part où vous ne pouvez pas le voir. Au lieu de cela, vous ne pouvez comparer que ce sont près les uns aux autres - comme

if (abs(stats->{overall_simple_matching_coefficient)-1) < 0.0001) 
+0

Merci pour le conseil. Le plus dur pour moi était de déterminer la tolérance/spécificité dont j'ai besoin, car pour les gènes longs, une valeur de 0,9999 pourrait être valide et distincte d'une valeur de 1,0000.Cependant, après en avoir un peu plus, la tolérance requise est juste une fonction de la longueur du gène (qui est une valeur entière). Si un gène a une longueur de 100, la tolérance requise est de 0,01. Si elle avait une longueur de 1000, j'ai besoin de .001, et ainsi de suite. –

+0

Mais cela ne répond toujours pas à ma question sur '==' vs 'eq'. Pourquoi 'eq' a-t-il fonctionné quand' == 'n'a pas fonctionné? –

+3

'eq' se compare à des chaînes - si la conversion du flottant en une chaîne supprime les chiffres insignifiants,' eq' les comparera égaux. Mais c'est une mauvaise chose sur laquelle compter - mieux vaut savoir de quel type de tolérance vous avez besoin et de le comparer avec cette tolérance. –

3

Qu'est-ce que vous obtenez si vous imprimez la valeur de $stats->{overall_simple_matching_coefficient} juste avant la comparaison? Si c'est 1, essayez printf avec un format de "%20.10f". Je suspecte fortement que vous ayez une erreur d'arrondi (moins de 1e-6) accumulée dans la variable et que la comparaison ne soit pas égale numériquement. Cependant, lorsqu'il est converti en chaîne, puisque l'erreur est à droite de la sixième décimale, et le format de chaîne par défaut est de six places, il compare égal.

+0

Merci de m'avoir aidé à visualiser le problème! –