37 votes

Est-ce que l'arithmétique en virgule flottante est stable?

Je sais que les nombres en virgule flottante ont une précision et que les chiffres après la précision ne sont pas fiables.

Mais que se passe-t-il si l'équation utilisée pour calculer le nombre est la même? puis-je supposer que le résultat serait le même?

Par exemple, nous avons deux nombres flottants x et y . Pouvons-nous supposer que le résultat x/y de la machine 1 est exactement le même que le résultat de la machine 2? La comparaison IE == renverrait true

46voto

Jon Skeet Points 692016

Mais que faire si l'équation utilisée pour calculer le nombre est le même? puis-je supposer que le résultat serait le même?

Non, pas nécessairement.

En particulier, dans certaines situations, le JIT est autorisé à utiliser une plus juste représentation intermédiaire - par exemple, 80 bits lors de vos données d'origine est de 64 bits alors que dans d'autres situations, il ne sera pas. Qui peut entraîner de voir des résultats différents lorsque l'une des conditions suivantes est remplie:

  • Vous avez du code légèrement différent, par exemple en utilisant une variable locale au lieu d'un champ, qui peut changer si la valeur est stockée dans un registre ou pas. (C'est une relativement exemple évident; il y a d'autres beaucoup plus subtiles qui peuvent affecter des choses telles que l'existence d'un try bloc dans la méthode...)
  • Vous sont en cours d'exécution sur un processeur différent (j'ai utilisé afin d'observer les différences entre AMD et Intel; il peut y avoir des différences entre les différents Processeurs du même fabricant trop)
  • Vous sont en cours d'exécution avec différents niveaux d'optimisation (par exemple, sous un débogueur ou pas)

Le C# 5 spécifications de la section 4.1.6:

Les opérations à virgule flottante peut être réalisée avec une précision plus élevée que le type de résultat de l'opération. Par exemple, certaines architectures matérielles soutenir une "longue" ou "long double" à virgule flottante type avec plus de portée et de précision que le type double, et, implicitement, d'effectuer toutes les opérations à virgule flottante à l'aide de cette plus grande précision type. Seulement à un coût excessif du rendement de telles architectures matérielles d'opérations à virgule flottante avec moins de précision, et plutôt que d'exiger une mise en œuvre à renoncer à la fois en termes de performances et de précision, C# permet une plus grande précision type à être utilisé pour toutes les opérations à virgule flottante. Autres que de livrer des résultats plus précis, c'est rarement a des effets mesurables. Cependant, dans les expressions de la forme x * y / z, d'où la multiplication produit un résultat qui est à l'extérieur de la double portée, mais la division apporte le résultat provisoire de nouveau dans la double portée, le fait que l'expression est évaluée dans une gamme plus élevée peut provoquer une durée de raison d'être produites à la place d'un infini.

20voto

Eric Lippert Points 300275

Jon la réponse est, bien sûr, correct. Aucune réponse cependant l'avons dit comment vous pouvez vous assurer que arithmétique à virgule flottante est fait dans le montant de la précision garantie par la spécification et pas plus.

C# tronque automatiquement toute flotter à sa canonique 32 ou 64 bits de la représentation dans les circonstances suivantes:

  • Vous mettez dans un redondante cast explicite: x + y pourrait avoir x et y comme la plus élevée de la précision des nombres qui sont ensuite ajoutés. Mais (double)((double)x+(double)y) vous assure que tout est tronqué à 64 bits de précision avant et après les mathématiques qui se passe.
  • N'importe quel magasin à un champ d'instance d'une classe, champ statique, l'élément de tableau ou pointeur déréférencé toujours tronque. (Les magasins pour les habitants, les paramètres et les temporaires ne sont pas garantis pour tronquer; ils peuvent être enregistered. Les champs d'une structure peut-être sur le court-terme de la piscine, qui peut également être enregistered.)

Ces garanties ne sont pas faites par la spécification du langage, mais les implémentations doivent respecter ces règles. Microsoft implémentations de C# et le CLR ne.

C'est une douleur à écrire le code pour s'assurer que l'arithmétique à virgule flottante est prévisible en C#, mais il peut être fait. Notez que cela sera probablement ralentir votre arithmétique.

Les plaintes à propos de cette terrible situation doit être adressée à Intel, pas de Microsoft; ils sont ceux qui l'ont conçu puces de rendre prévisible l'arithmétique plus lent.

Aussi, notez que c'est une question fréquemment posée. Vous pourriez envisager de fermer ce comme un doublon de:

Pourquoi diffère en virgule flottante de précision en C# quand ils sont séparés par parenthèse et lorsqu'ils sont séparés par des déclarations?

Pourquoi est-ce à virgule flottante de calcul donnent des résultats différents sur différentes machines?

Le moulage d'un résultat de flotter dans la méthode de retour flotter la suite des changements

(.1f+.2f==.3f) != (.1f+.2f).Est égal à(.3f) Pourquoi?

Le fait de contraindre à virgule flottante pour être déterministe dans .NET?

C# XNA Visual Studio: Différence entre la "libération" et "debug" modes?

C# - Incompatible opération mathématique résultat sur 32 bits et 64 bits

Erreur d'arrondi en C#: résultats Différents sur un autre Pc

Étrange comportement du compilateur avec flotteur littéraux vs float variables

9voto

Patrick Hofman Points 22166

Non. Le résultat du calcul peut différer selon la CPU, car la mise en œuvre de l'arithmétique à virgule flottante peut différer selon le fabricant et la conception de la CPU. Je me souviens même d'un bug dans l'arithmétique en virgule flottante dans certains processeurs Intel, ce qui a gâché nos calculs.

Et puis, il y a une différence dans la façon dont le code est évalué par le compilateur JIT.

8voto

Marc Gravell Points 482669

Franchement, je ne m'attends pas à deux endroits dans la même base de code pour renvoyer la même chose pour x/y pour le même x et y - dans le même processus sur la même machine; elle peut dépendre de la façon dont exactement x et y obtenir optimisé par le compilateur / JIT - si elles sont enregistered différemment, ils peuvent avoir différents intermédiaires de précisions. Beaucoup d'opérations sont effectuées en utilisant plus de bits que vous attendez (registre de la taille); et exactement quand cela devient forcé vers le bas à 64 bits peut affecter le résultat. Le choix de ce "exactement où" peuvent dépend de ce qui se passe dans le code environnant.

3voto

Daniel Pryden Points 22167

En théorie, sur un IEEE 754 système conforme, la même opération avec les mêmes valeurs d'entrée est censé produire le même résultat.

Wikipédia résume cela:

La norme IEEE 754-1985 permis à de nombreuses variations dans les implémentations (telles que l'encodage de certaines valeurs et la détection de certaines exceptions). IEEE 754-2008 a renforcé ces, mais quelques différences subsistent (en particulier pour les formats binaires). La reproductibilité de la clause recommande que les normes linguistiques devrait fournir un moyen d'écrire reproductible des programmes (c'est à dire, les programmes qui produira le même résultat dans toutes les implémentations d'une langue), et décrit ce qui doit être fait pour obtenir des résultats reproductibles.

Comme d'habitude, cependant, la théorie est différente de la pratique. La plupart des langages de programmation courants, C# inclus, ne sont pas strictement conformes à la norme IEEE 754, et ne fournissent pas nécessairement un moyen d'écrire un reproductibles programme.

En outre, moderne CPU/Upc de le rendre un peu maladroit pour assurer le strict IEEE 754 de la conformité. Par défaut, ils fonctionneront avec "précision étendue", en stockant les valeurs avec plus de bits que d'un lit double en interne. Si vous voulez sémantique stricte vous avez besoin pour extraire des valeurs de la FPU en un PROCESSEUR inscrire, vérifier et gérer divers FPU exceptions, puis poussez les valeurs de retour en -- entre chaque MODE d'exploitation. En raison de cette maladresse, en stricte conformité a une perte de performance, même au niveau du matériel. Le C# standard choisi un plus "bâclée" l'exigence d'éviter l'imposition d'une pénalité sur les performances sur le cas le plus fréquent où les petites variations ne sont pas un problème.

Rien de cela n'est souvent un problème dans la pratique, car la plupart des programmeurs ont intériorisé l' (incorrect, ou au moins trompeuse) idée que les mathématiques à virgule flottante est inexact. En outre, les erreurs dont nous parlons ici sont tous très petits, afin qu'ils sont éclipsés par le plus commun de perte de précision causé par la conversion de décimal.

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