L'idée reçue selon laquelle les nombres à virgule flottante ne peuvent pas être comparés pour vérifier leur égalité est inexacte. Les nombres à virgule flottante ne sont pas différents des nombres entiers : Si vous évaluez "a == b", vous obtiendrez vrai s'il s'agit de nombres identiques et faux sinon (étant entendu que deux NaN ne sont évidemment pas des nombres identiques).
Le problème réel est le suivant : Si j'ai effectué des calculs et que je ne suis pas sûr que les deux nombres que je dois comparer sont exactement corrects, que faire ? Ce problème est le même pour les nombres à virgule flottante que pour les nombres entiers. Si vous évaluez l'expression entière "7/3*3", la comparaison ne sera pas égale à "7*3/3".
Supposons donc que nous demandions "Comment comparer des entiers pour vérifier leur égalité" dans une telle situation. Il n'y a pas de réponse unique ; ce que vous devez faire dépend de la situation spécifique, notamment du type d'erreurs que vous avez et de ce que vous voulez obtenir.
Voici quelques choix possibles.
Si vous voulez obtenir un résultat "vrai" si les nombres mathématiquement exacts sont égaux, vous pouvez essayer d'utiliser les propriétés des calculs que vous effectuez pour prouver que vous obtenez les mêmes erreurs dans les deux nombres. Si cela est possible, et que vous comparez deux nombres résultant d'expressions qui donneraient des nombres égaux si elles étaient calculées exactement, alors vous obtiendrez un résultat "vrai" à partir de la comparaison. Une autre approche consiste à analyser les propriétés des calculs et à prouver que l'erreur ne dépasse jamais un certain montant, peut-être un montant absolu ou un montant relatif à l'une des entrées ou à l'une des sorties. Dans ce cas, vous pouvez demander si les deux nombres calculés diffèrent au maximum de cette quantité, et renvoyer "vrai" s'ils sont dans l'intervalle. Si vous ne pouvez pas prouver une limite d'erreur, vous pouvez deviner et espérer le meilleur. Une façon de le faire est d'évaluer de nombreux échantillons aléatoires et de voir quel type de distribution vous obtenez dans les résultats.
Bien sûr, puisque nous n'avons fixé comme condition que vous obteniez "true" si les résultats mathématiquement exacts sont égaux, nous avons laissé ouverte la possibilité que vous obteniez "true" même s'ils sont inégaux. (En fait, nous pouvons satisfaire l'exigence en retournant toujours "vrai". Cela rend le calcul simple mais n'est généralement pas souhaitable, je discuterai donc de l'amélioration de la situation ci-dessous).
Si vous voulez obtenir un résultat "faux" si les nombres mathématiquement exacts ne sont pas égaux, vous devez prouver que votre évaluation des nombres donne des nombres différents si les nombres mathématiquement exacts ne sont pas égaux. Cela peut être impossible à des fins pratiques dans de nombreuses situations courantes. Considérons donc une alternative.
Une condition utile pourrait être que nous obtenions un "faux" résultat si les nombres mathématiquement exacts diffèrent de plus d'une certaine quantité. Par exemple, nous allons peut-être calculer la trajectoire d'une balle lancée dans un jeu vidéo et nous voulons savoir si elle a touché une batte. Dans ce cas, nous voulons certainement obtenir la réponse "vrai" si la balle frappe la chauve-souris, et nous voulons obtenir la réponse "faux" si la balle est loin de la chauve-souris, et nous pouvons accepter une réponse "vrai" incorrecte si la balle, dans une simulation mathématiquement exacte, a manqué la chauve-souris mais est à un millimètre de la frapper. Dans ce cas, nous devons prouver (ou deviner/estimer) que notre calcul de la position de la balle et de la position de la chauve-souris a une erreur combinée d'au plus un millimètre (pour toutes les positions d'intérêt). Cela nous permettrait de toujours renvoyer "faux" si la balle et la batte sont séparées de plus d'un millimètre, de renvoyer "vrai" si elles se touchent, et de renvoyer "vrai" si elles sont suffisamment proches pour être acceptables.
Ainsi, la façon dont vous décidez ce qu'il faut retourner lorsque vous comparez des nombres à virgule flottante dépend beaucoup de votre situation spécifique.
Quant à la manière de prouver les limites d'erreur pour les calculs, cela peut être un sujet compliqué. Toute implémentation à virgule flottante utilisant la norme IEEE 754 en mode round-to-nearest renvoie le nombre à virgule flottante le plus proche du résultat exact pour toute opération de base (notamment la multiplication, la division, l'addition, la soustraction, la racine carrée). (En cas d'égalité, arrondissez de manière à ce que le bit le plus bas soit pair). (Faites particulièrement attention à la racine carrée et à la division ; l'implémentation de votre langage pourrait utiliser des méthodes non conformes à la norme IEEE 754 pour celles-ci). Grâce à cette exigence, nous savons que l'erreur dans un seul résultat est au plus égale à la moitié de la valeur du bit le moins significatif. (Si c'était plus, l'arrondi serait passé à un autre nombre qui se situe dans la moitié de la valeur).
La suite devient nettement plus compliquée ; l'étape suivante consiste à effectuer une opération dont l'une des entrées comporte déjà une erreur. Pour les expressions simples, ces erreurs peuvent être suivies tout au long des calculs pour atteindre une limite sur l'erreur finale. Dans la pratique, cela ne se fait que dans quelques situations, comme le travail sur une bibliothèque de mathématiques de haute qualité. Et, bien sûr, vous avez besoin d'un contrôle précis sur les opérations qui sont effectuées. Les langages de haut niveau laissent souvent beaucoup de latitude au compilateur, de sorte que vous pouvez ne pas savoir dans quel ordre les opérations sont effectuées.
On pourrait écrire (et on écrit) beaucoup plus sur ce sujet, mais je dois m'arrêter là. En résumé, la réponse est la suivante : Il n'existe pas de routine de bibliothèque pour cette comparaison parce qu'il n'y a pas de solution unique qui réponde à la plupart des besoins et qui vaille la peine d'être intégrée dans une routine de bibliothèque. (Si la comparaison avec un intervalle d'erreur relatif ou absolu vous suffit, vous pouvez le faire simplement sans routine de bibliothèque).
0 votes
@tolomea : Puisque cela dépend de votre application, de vos données et de votre domaine de problème -- et qu'il ne s'agit que d'une ligne de code -- pourquoi y aurait-il une "fonction de bibliothèque standard" ?
15 votes
@S.Lott :
all
,any
,max
,min
sont toutes deux essentiellement des fonctions à une ligne, et elles ne sont pas seulement fournies dans une bibliothèque, ce sont des fonctions intégrées. Les raisons de la BDFL ne sont donc pas si importantes. La ligne de code que la plupart des gens écrivent est assez peu sophistiquée et ne fonctionne souvent pas, ce qui est une raison forte pour fournir quelque chose de mieux. Bien sûr, tout module fournissant d'autres stratégies devrait également fournir des avertissements décrivant quand elles sont appropriées, et plus important encore quand elles ne le sont pas. L'analyse numérique est difficile, et il n'est pas honteux que les concepteurs de langage ne cherchent pas à créer des outils pour l'aider.0 votes
@Steve Jessop. Ces fonctions orientées collection n'ont pas les dépendances d'application, de données et de domaine de problème que la virgule flottante possède. Ainsi, le "one-liner" n'est clairement pas aussi important que les véritables raisons. L'analyse numérique est difficile, et ne peut pas être une partie de première classe d'une bibliothèque de langage à usage général.
7 votes
@S.Lott : Je serais probablement d'accord si la distribution standard de Python n'incluait pas multiple pour les interfaces XML. Il est clair que le fait que des applications différentes aient besoin de faire quelque chose différemment n'empêche pas de mettre des modules dans l'ensemble de base pour le faire d'une manière ou d'une autre. Il existe certainement des astuces pour comparer des flottants qui sont souvent réutilisées, la plus basique étant un nombre spécifié d'ulp. Je ne suis donc que partiellement d'accord - le problème est que l'analyse numérique est difficile. Python pourrait en principe, fournir des outils pour faciliter quelque peu la tâche, de temps en temps. Je suppose que personne ne s'est porté volontaire.
0 votes
@Steve Jessop. Cela dépend trop de votre application, de vos données et de votre domaine de problème. Comme ça se résume à une ligne de code difficile à concevoir, les bibliothèques n'apportent pas grand-chose. Un livre comme Recettes numériques en Python apporterait plus qu'une bibliothèque qui banalise des problèmes difficiles.
0 votes
@S.Lott : Donc je suppose que la question est de savoir si le code dans ce livre vaut vraiment la peine d'être utilisé. Si c'est le cas, il n'y a pas de raison particulière pour qu'il ne puisse pas être une bibliothèque, bien que les personnes qui n'ont pas lu le livre puissent avoir des difficultés à l'utiliser correctement. Mais encore une fois, les personnes qui ne lisent pas un livre sur Unicode peuvent facilement se tromper dans l'utilisation de
str
correctement. Une fois que vous disposez d'une bibliothèque d'outils de valeur, la question de savoir s'il s'agit d'un noyau dur peut être évaluée selon les critères habituels. La différence entre, par exemple, le traitement de texte (très spécifique aux applications et aux données) et le traitement numérique est le nombre de personnes qui en ont besoin.4 votes
De même, "ça se résume à une ligne de code difficile à concevoir" - si c'est toujours une ligne de code une fois que vous le faites correctement, je pense que votre écran est plus large que le mien ;-). Quoi qu'il en soit, je pense que l'ensemble du domaine est assez spécialisé, dans le sens où le plus Les programmeurs (moi y compris) l'utilisent très rarement. En plus d'être difficile, elle ne va pas figurer en haut de la liste des bibliothèques les plus recherchées dans la plupart des langages.
1 votes
@S.Lott Jusqu'à présent, nous ne semblons avoir que deux solutions viables, dont l'une n'est valable que si l'on connaît la magnitude des entrées. Bien sûr, la ou les valeurs d'epsilon doivent être ajustées en fonction de l'application, mais ce sont des arguments.
0 votes
Vous voulez peut-être mettre à jour votre lien, randomascii.wordpress.com/2012/02/25/
0 votes
Je n'ai jamais eu de tels problèmes avec Matlab, pourquoi ?
0 votes
@bonobo Peut-être que vous n'essayez pas assez fort stackoverflow.com/questions/23824577/