Est calcul en virgule flottante cassé?

considère le code suivant:

0.1 + 0.2 == 0.3  ->  false
0.1 + 0.2         ->  0.30000000000000004

pourquoi ces inexactitudes se produisent-elles?

2350
demandé sur Rann Lifshitz 2009-02-26 00:39:02

27 réponses

Binaire à virgule flottante les maths, c'est comme cela. Dans la plupart des langages de programmation, il est basé sur le IEEE 754 standard . JavaScript utilise une représentation en virgule flottante 64 bits, qui est la même que double de Java . Le nœud du problème est que les nombres sont représentés dans ce format comme un nombre entier fois une puissance de deux; nombres rationnels( tels que 0.1 , qui est 1/10 ) dont le dénominateur n'est pas une puissance de deux ne peut pas être représentée exactement.

pour 0.1 dans le format standard binary64 , la représentation peut s'écrire exactement comme

  • 0.1000000000000000055511151231257827021181583404541015625 en décimal, ou
  • 0x1.999999999999ap-4 in C99 hexfloat notation .

En revanche, le nombre rationnel 0.1 , qui est 1/10 , peut être écrit exactement comme

  • 0.1 en décimal, ou
  • 0x1.99999999999999...p-4 dans un analogue de la notation C99 hexfloat, où le ... représente une séquence sans fin de 9.

les constantes 0.2 et 0.3 dans votre programme seront aussi des approximations de leurs vraies valeurs. Il arrive que le plus proche double à 0.2 est plus grand que le nombre rationnel 0.2 , mais que le plus proche double 0.3 est plus petit que le nombre rationnel 0.3 . La somme de 0.1 et 0.2 finit par être plus grande que le nombre rationnel 0.3 et donc en désaccord avec la constante dans votre code.

un traitement assez complet des questions d'arithmétique à virgule flottante est ce que tout informaticien devrait savoir sur L'arithmétique à virgule flottante . Pour une explication plus facile à digérer, voir floating-point-gui.de .

1784
répondu Brian R. Bondy 2015-02-14 18:04:58

Un Concepteur de Matériel de point de vue

je crois que je devrais ajouter le point de vue d'un concepteur de matériel à ceci puisque je conçois et construis le matériel à virgule flottante. Connaître l'origine de l'erreur peut aider à comprendre ce qui se passe dans le logiciel, et finalement, j'espère que cela aide à expliquer les raisons pour lesquelles les erreurs de virgule flottante se produisent et semblent s'accumuler avec le temps.

1. Vue d'ensemble

du point de vue de l'ingénierie, la plupart des opérations à virgule flottante comportent un élément d'erreur puisque le matériel qui effectue les calculs à virgule flottante n'est tenu d'avoir une erreur que de moins de la moitié d'une unité à la dernière place. Par conséquent, beaucoup de matériel va s'arrêter à une précision qui est seulement nécessaire pour produire une erreur de moins de la moitié d'une unité à la dernière place pour un opération simple qui est particulièrement problématique en virgule flottante division. Ce qui constitue une opération unique dépend du nombre d'opérandes de l'unité. Pour la plupart, il est de deux, mais certaines unités prennent 3 opérandes ou plus. Pour cette raison, il n'y a aucune garantie que des opérations répétées donneront lieu à une erreur souhaitable puisque les erreurs s'additionnent au fil du temps.

2. Normes

la plupart des processeurs suivent la norme IEEE-754 mais certains utilisent des normes dénormalisées ou différentes . Par exemple, il n'y est un mode dénormalisé dans IEEE-754 qui permet la représentation de très petits nombres à virgule flottante au détriment de la précision. Ce qui suit, cependant, couvrira le mode normalisé de IEEE-754 qui est le mode de fonctionnement typique.

Dans la norme IEEE-754, les concepteurs de matériel sont autorisés à la valeur de l'erreur/epsilon, tant que c'est moins de la moitié d'une unité à la dernière place, et le résultat doit être inférieur à la moitié d'une unité à la dernière place pour une seule opération. Cela explique pourquoi lorsqu'il y a des opérations répétées, les erreurs s'additionnent. Pour la double précision IEEE-754, c'est le 54ème bit, puisque 53 bits sont utilisés pour représenter la partie numérique (normalisée), également appelée le mantissa, du nombre de virgule flottante (par exemple le 5.3 en 5.3e5). Les sections suivantes traitent plus en détail des causes des erreurs matérielles sur diverses opérations en virgule flottante.

3. Cause de L'erreur D'arrondissement dans la Division

le la cause principale de l'erreur dans la division en virgule flottante est les algorithmes de division utilisés pour calculer le quotient. La plupart des systèmes informatiques calculent la division en utilisant la multiplication par l'inverse, principalement dans Z=X/Y , Z = X * (1/Y) . Une division est calculée itérativement, c'est-à-dire que chaque cycle calcule quelques bits du quotient jusqu'à ce que la précision désirée soit atteinte, ce qui pour IEEE-754 est n'importe quoi avec une erreur de moins d'une unité à la dernière place. Le tableau des réciproques de Y (1 / Y) est connu sous le nom de table de sélection des quotients (QST) dans la division lente, et la taille en bits de la table de sélection des quotients est habituellement la largeur de la radix, ou un certain nombre de bits du quotient calculé dans chaque itération, plus quelques bits de garde. Pour la norme IEEE-754, double précision (64 bits), ce serait la taille du rayon du diviseur, plus quelques bits de garde k, où k>=2 . Ainsi, par exemple, une Table de sélection typique de Quotient pour un diviseur qui calcule 2 bits du quotient à la fois (radix 4) serait 2+2= 4 bits (plus quelques bits optionnels).

3.1 erreur D'arrondissement dans la Division: Approximation de la réciproque

ce qui est réciproque dans la table de sélection des quotients dépend de la méthode de division : division lente telle que la division SRT, ou division rapide telle que la Division Goldschmidt; chaque entrée est modifiée selon l'algorithme de division dans une tentative d'obtenir le plus bas possible erreur. Dans tous les cas, cependant, tous les réciproques sont approximations de la réciproque réelle et introduire un certain élément d'erreur. Les méthodes de division lente et de division rapide calculent le quotient de façon itérative, c'est-à-dire qu'un certain nombre de bits du quotient sont calculés à chaque étape, puis le résultat est soustrait du dividende, et le diviseur répète les étapes jusqu'à ce que l'erreur soit inférieure à la moitié d'une unité à la dernière place. Les méthodes de division lente calculent un nombre de chiffres du quotient dans chaque étape et sont généralement moins coûteux à construire, et les méthodes de division rapide calculent un nombre variable de chiffres par étape et sont généralement plus coûteux à construire. La partie la plus importante des méthodes de division est que la plupart d'entre eux reposent sur la multiplication répétée par une approximation d'un réciproque, de sorte qu'ils sont susceptibles d'erreur.

4. Erreurs d'arrondissement dans D'autres opérations: troncature

une autre cause des erreurs d'arrondissement dans toutes les opérations sont les différents modes de troncature de la réponse finale que L'IEEE-754 permet. Il y a troncature, rond vers zéro, rond vers le plus proche (par défaut), rond vers le bas, et rond vers le haut. Toutes les méthodes d'introduire un élément de l'erreur de moins d'une unité à la dernière place pour une seule opération. Avec le temps et les opérations répétées, la troncature ajoute aussi de façon cumulative à l'erreur résultante. Cette erreur de troncature est particulièrement problématique dans l'exponentiation, qui implique une certaine forme de multiplication répétée.

5. Opérations Répétées

étant donné que le matériel qui fait les calculs en virgule flottante n'a qu'à produire un résultat avec une erreur de moins de la moitié d'une unité à la dernière place pour une seule opération, l'erreur augmentera au cours des opérations répétées si on ne l'observe pas. C'est la raison pour laquelle dans les calculs qui nécessitent une erreur bornée, les mathématiciens utilisent des méthodes telles que l'utilisation de la ronde à la plus proche chiffre pair à la dernière place de IEEE-754, parce que, au fil du temps, les erreurs sont plus susceptibles de s'annuler mutuellement, et arithmétique intervalle combiné avec des variations de la IEEE 754 modes d'arrondissement pour prédire les erreurs d'arrondissement, et de les corriger. En raison de sa faible erreur relative par rapport aux autres modes d'arrondi, rond au chiffre pair le plus proche (dans le dernier place), est le mode d'arrondi par défaut de IEEE-754.

notez que le mode d'arrondi par défaut , arrondi au chiffre pair le plus proche à la dernière place , garantit une erreur de moins de la moitié d'une unité à la dernière place pour une opération. L'utilisation de la troncature, du round-up, et du round-down seul peut entraîner une erreur qui est supérieure à la moitié d'une unité à la dernière place, mais moins d'une unité à la dernière place, de sorte que ces modes ne sont pas recommandés sauf S'ils sont utilisés en arithmétique D'intervalle.

6. Résumé

en bref, la raison fondamentale pour les erreurs dans les opérations flottantes est une combinaison de la troncature dans le matériel, et la troncature d'un réciproque dans le cas de la division. Puisque la norme IEEE-754 exige seulement une erreur de moins de la moitié d'une unité à la dernière place pour une seule opération, les erreurs de virgule flottante sur les opérations répétées s'additionneront à moins que correct.

509
répondu KernelPanik 2018-04-13 16:42:24

quand vous vous convertissez .1 ou 1/10 à la base 2 (binaire) vous obtenez un motif de répétition après le point décimal, tout comme essayer de représenter 1/3 en base 10. La valeur n'est pas exacte, et donc vous ne pouvez pas faire des maths exactes avec elle en utilisant des méthodes normales de point flottant.

367
répondu Joel Coehoorn 2009-02-25 22:07:00

la plupart des réponses ici abordent cette question en termes techniques très secs. J'aimerais aborder cette question en des termes que les êtres humains normaux peuvent comprendre.

Imaginez que vous essayez de découper les pizzas. Vous avez un coupe-pizza robotique qui peut couper les tranches de pizza exactement en deux. Il peut couper une pizza entière en deux, ou il peut couper une tranche existante, mais dans tous les cas, la réduction de moitié est toujours exacte.

Ce coupeur de pizza a des mouvements très fins, et si vous commencez avec une pizza entière, puis couper en deux que, et continuer à couper en deux la plus petite tranche à chaque fois, vous pouvez faire la moitié de 53 fois avant la tranche est trop petite pour même ses capacités de haute précision. À ce moment-là, vous ne pouvez plus couper cette tranche très mince, mais vous devez l'inclure ou l'exclure telle quelle.

Maintenant, comment voulez-vous morceau toutes les tranches dans une telle manière qui permettrait d'ajouter jusqu'à un dixième (0.1) ou un cinquième (0,2) de pizza? Pensez vraiment cela, et essayer de travailler. Vous pouvez même essayer d'utiliser une vraie pizza, si vous avez un mythique précision de coupe-pizza à la main. :- )


les programmeurs les plus expérimentés, bien sûr, connaissent la vraie réponse, qui est qu'il n'y a aucun moyen de assembler un exact dixième ou cinquième de la pizza en utilisant ces tranches, peu importe comment finement vous les coupez. Vous pouvez faire un très bon le rapprochement, et si vous ajoutez le rapprochement de 0,1 avec le rapprochement de 0,2, vous obtenez une assez bonne approximation de 0,3, mais c'est toujours une approximation.

pour les numéros à double précision (qui est la précision qui vous permet de diviser votre pizza par deux 53 fois), les nombres immédiatement inférieur et supérieur à 0,1 sont 0,099999999999999999999167332731531132594682276248931884765625 et 0,100000000000000000000551115123257827021181583404541015625. Ce dernier est un peu plus proche de 0.1 que le premier, donc un analyseur numérique va, avec une entrée de 0.1, favoriser le second.

(la différence entre ces deux nombres est la" plus petite tranche " que nous devons décider d'inclure, ce qui introduit un biais vers le haut, ou d'exclure, ce qui introduit un biais vers le bas. Le terme technique pour cette plus petite tranche est un ulp .)

dans le cas de 0.2, les nombres sont tous les mêmes, juste à l'échelle par un facteur de 2. Encore une fois, nous sommes en faveur d'une valeur légèrement supérieure à 0,2.

noter que dans les deux cas, les approximations pour 0,1 et 0,2 ont un léger biais vers le haut. Si nous ajoutons suffisamment de ces biais, ils repousseront le nombre de plus en plus loin de ce que nous voulons, et en fait, dans le cas de 0.1 + 0.2, le biais est assez élevé pour que le nombre résultant ne soit plus le nombre le plus proche de 0.3.

en particulier, 0,1 + 0,2 est vraiment 0.10000000000000000555111512312257827021181583404541015625 + 0.20000000000000001110223024626251565404236316680908203125 = 0.300000000000000000004440892098500626169452667236328125, alors que le nombre le plus proche de 0.3 est en fait 0.2999999999999999888977697537484345957576368336819091796875.


P.S .certains langages de programmation offrent également des coupe-pizza qui peuvent fendre les tranches en dixièmes exacts . Bien que de telles coupeuses à pizza sont rare, si vous avez accès à l'un, vous devez l'utiliser quand il est important d'être en mesure d'obtenir exactement un dixième et un cinquième de la tranche.

(Initialement posté sur Quora.)

239
répondu Chris Jester-Young 2014-11-22 04:44:18

à virgule Flottante, des erreurs d'arrondi. 0,1 ne peut pas être représenté aussi précisément dans la base-2 que dans la base-10 en raison du facteur de prime manquant de 5. Tout comme 1/3 prend un nombre infini de chiffres pour représenter en décimal, mais est "0.1" en base-3, 0.1 prend un nombre infini de chiffres en base-2 où il ne fait pas en base-10. Et les ordinateurs n'ont pas une quantité infinie de mémoire.

200
répondu Devin Jeanpierre 2009-02-25 21:41:23

en plus des autres réponses correctes, vous pouvez envisager l'échelle de vos valeurs pour éviter des problèmes avec l'arithmétique flottante.

par exemple:

var result = 1.0 + 2.0;     // result === 3.0 returns true

... au lieu de:

var result = 0.1 + 0.2;     // result === 0.3 returns false

l'expression 0.1 + 0.2 === 0.3 retourne false en JavaScript, mais heureusement l'arithmétique entière en virgule flottante est exacte, de sorte que les erreurs de représentation décimale peuvent être évitées par mise à l'échelle.

comme exemple pratique, pour éviter les problèmes de virgule flottante où l'exactitude est primordiale, il est recommandé 1 pour manipuler l'argent comme un entier représentant le nombre de cents: 2550 cents au lieu de 25.50 dollars.


1 Douglas Crockford: JavaScript: The Good Parts : Annexe A - Terrible Parts (page 105) .

100
répondu Daniel Vassallo 2010-09-05 02:02:26

ma réponse est assez longue, donc je l'ai divisée en trois sections. Puisque la question porte sur les mathématiques à virgule flottante, j'ai mis l'accent sur ce que la machine fait réellement. Je l'ai également fait spécifique à la précision double (64 bits), mais l'argument s'applique également à toute arithmétique flottante.

préambule

An IEEE 754 double-precision binaire format à virgule flottante (binary64) nombre représente un numéro de la forme

valeur = (-1)^s * (1.m 51 m 50 ...m 2 m 1 m 0 ) 2 * 2 e-1023

en 64 bits:

  • Le premier bit est le signe bit : 1 si le nombre est négatif, 0 sinon 1 .
  • les 11 bits suivants sont le exposant , qui est offset par 1023. En d'autres termes, après la lecture des bits d'exposant d'un nombre double précision, 1023 doit être soustraite pour obtenir la puissance de deux.
  • les 52 bits restants sont le significand (ou de la mantisse). Dans le mantissa, un "implicite " 1. est toujours 2 omis car le bit le plus significatif de toute valeur binaire est 1 .

1 - IEEE 754 permet le concept d'un zéro signé - +0 et -0 sont traités différemment: 1 / (+0) est l'infini positif; 1 / (-0) est l'infini négatif. Pour des valeurs égales à zéro, la les morceaux de mantissa et d'exposant sont tous nuls. Note: les valeurs nulles (+0 et -0) ne sont pas explicitement classées comme dénormales 2 .

2 - ce n'est pas le cas pour les nombres denormaux , qui ont un exposant offset de zéro (et un implicite 0. ). La gamme des numéros de double précision dénormaux est d min ≤ / x / ≤ D max , où d min ( le plus petit nombre non nul) est 2 -1023 - 51 (≈ 4.94 * 10 -324 ) et d max (le plus grand nombre denormal, pour lequel le mantissa se compose entièrement de 1 s) est 2 -1023 + 1 - 2 -1023 - 51 (≈ 2.225 * 10 -308 ).


tourner un double numéro de précision en binaire

beaucoup de convertisseurs en ligne existent pour convertir un nombre de virgule flottante de double précision en binaire (par exemple à binaryconvert.com ), Mais voici quelques exemples de code C pour obtenir la représentation IEEE 754 pour un nombre de précision double (je sépare les trois parties avec des colons ( : ):

public static string BinaryRepresentation(double value)
{
    long valueInLongType = BitConverter.DoubleToInt64Bits(value);
    string bits = Convert.ToString(valueInLongType, 2);
    string leadingZeros = new string('0', 64 - bits.Length);
    string binaryRepresentation = leadingZeros + bits;

    string sign = binaryRepresentation[0].ToString();
    string exponent = binaryRepresentation.Substring(1, 11);
    string mantissa = binaryRepresentation.Substring(12);

    return string.Format("{0}:{1}:{2}", sign, exponent, mantissa);
}

pour en venir au fait: le question initiale

(Passer au bas pour la TL;version DR)

Cato Johnston (la question asker) s'est demandé pourquoi 0.1 + 0.2 != 0,3.

écrit en binaire (avec des colonnes séparant les trois parties), les IEEE 754 représentations des valeurs sont:

0.1 => 0:01111111011:1001100110011001100110011001100110011001100110011010
0.2 => 0:01111111100:1001100110011001100110011001100110011001100110011010

notez que le mantissa est composé de chiffres récurrents de 0011 . C'est clé pourquoi il y a une erreur pour le calcul de 0,1, 0,2 et 0,3 ne peut pas être représenté en binaire précisément dans un finis nombre de bits binaires, pas plus que 1/9, 1/3 ou 1/7 peut être représenté précisément dans décimales .

conversion des exposants en décimales, suppression de l'offset, et ajout de l'implicite 1 (entre crochets), 0.1 et 0.2 sont:

0.1 = 2^-4 * [1].1001100110011001100110011001100110011001100110011010
0.2 = 2^-3 * [1].1001100110011001100110011001100110011001100110011010

pour ajouter deux nombres, l'exposant doit être le même, i.e.:

0.1 = 2^-3 *  0.1100110011001100110011001100110011001100110011001101(0)
0.2 = 2^-3 *  1.1001100110011001100110011001100110011001100110011010
sum = 2^-3 * 10.0110011001100110011001100110011001100110011001100111

puisque la somme n'est pas de la forme 2 n * 1.{bbb} nous augmentons l'exposant de un et décalons le point décimal ( binaire ) pour obtenir:

sum = 2^-2 * 1.0011001100110011001100110011001100110011001100110011(1)

il y a maintenant 53 bits dans le mantissa (le 53e est entre crochets dans la ligne ci-dessus). La valeur par défaut mode d'arrondissement pour IEEE 754 est rond à la plus proche '- c.-à-d. si un nombre x tombe entre deux valeurs a et b , la valeur où le bit le moins significatif est Zéro est choisie.

a = 2^-2 * 1.0011001100110011001100110011001100110011001100110011
x = 2^-2 * 1.0011001100110011001100110011001100110011001100110011(1)
b = 2^-2 * 1.0011001100110011001100110011001100110011001100110100

notez que a et b ne diffèrent que dans le dernier bit; ...0011 + 1 = ...0100 . Dans ce cas, la valeur avec le bit le moins significatif de Zéro est b , donc la somme est:

sum = 2^-2 * 1.0011001100110011001100110011001100110011001100110100

TL; DR

Écrit 0.1 + 0.2 dans la norme IEEE 754 représentation binaire (avec des points de séparer les trois parties) et en le comparant à 0.3 , c'est (j'ai mis les bits distincts entre crochets):

0.1 + 0.2 => 0:01111111101:0011001100110011001100110011001100110011001100110[100]
0.3       => 0:01111111101:0011001100110011001100110011001100110011001100110[011]

converti en décimal, ces valeurs sont:

0.1 + 0.2 => 0.300000000000000044408920985006...
0.3       => 0.299999999999999988897769753748...

la différence est exactement 2 -54 , qui est ~5.5511151231258 × 10 -17 - insignifiant (pour de nombreuses applications) par rapport aux valeurs originales.

comparer les derniers bits d'un nombre de virgule flottante est intrinsèquement dangereux, comme toute personne qui lit le célèbre " ce que tout informaticien devrait savoir au sujet de L'arithmétique flottante " (qui couvre toutes les parties principales de cette réponse)

la plupart des calculatrices utilisent des chiffres de garde pour contourner ce problème, ce qui est la façon dont 0.1 + 0.2 donnerait 0.3 : les derniers bits sont arrondis.

82
répondu Wai Ha Lee 2017-05-23 11:55:18

nombres à virgule flottante stockés dans l'ordinateur se composent de deux parties, un entier et un exposant que la base est prise et multiplié par la partie entière.

si l'ordinateur fonctionnait dans la base 10, 0.1 serait 1 x 10⁻¹ , 0.2 serait 2 x 10⁻¹ , et 0.3 serait 3 x 10⁻¹ . Les maths entières sont faciles et exactes, donc ajouter 0.1 + 0.2 donnera évidemment 0.3 .

Ordinateurs ils ne travaillent pas à la base 10, mais à la base 2. Vous pouvez toujours obtenir des résultats exacts pour certaines valeurs, par exemple 0.5 est 1 x 2⁻¹ et 0.25 est 1 x 2⁻² , et leur addition donne des résultats 3 x 2⁻² , ou 0.75 . Exactement.

le problème vient avec des nombres qui peuvent être représentés exactement en base 10, mais pas en base 2. Ces chiffres doivent être arrondies à leur équivalent le plus proche. En supposant le format flottant IEEE 64 bits très courant, le nombre le plus proche de 0.1 est 3602879701896397 x 2⁻⁵⁵ , et le nombre le plus proche de 0.2 est 7205759403792794 x 2⁻⁵⁵ ; les additionner donne 10808639105689191 x 2⁻⁵⁵ , ou une valeur décimale exacte de 0.3000000000000000444089209850062616169452667236328125 . Les nombres à virgule flottante sont généralement arrondis pour l'affichage.

51
répondu Mark Ransom 2018-01-20 05:00:08

à virgule Flottante de l'erreur d'arrondi. De Ce Que Tout Informaticien Devrait Savoir Sur L'Arithmétique Flottante :

la compression infinie de nombres réels en un nombre fini de bits nécessite une représentation approximative. Bien qu'il y ait infiniment beaucoup d'entiers, dans la plupart des programmes le résultat des calculs d'entiers peut être stocké en 32 bits. En revanche, étant donné n'importe quel nombre fixe de bits, la plupart des calculs avec le réel les nombres produiront des quantités qui ne peuvent pas être représentées exactement en utilisant autant de bits. Par conséquent, le résultat d'un calcul flottant doit souvent être arrondis afin d'intégrer son sens de la représentation. Cette erreur d'arrondi est la caractéristique de calcul flottant.

42
répondu Brett Daniel 2017-12-27 00:38:28

ma solution:

function add(a, b, precision) {
    var x = Math.pow(10, precision || 2);
    return (Math.round(a * x) + Math.round(b * x)) / x;
}

précision se rapporte au nombre de chiffres que vous voulez conserver après le point décimal pendant l'addition.

30
répondu Justineo 2011-12-26 06:51:53

beaucoup de bonnes réponses ont été postées, mais j'aimerais en ajouter une autre.

tous les numéros ne peuvent pas être représentés par flotteurs / doubles Par exemple, le nombre "0.2" sera représenté par "0.200000003" en précision simple dans la norme IEEE754 float point.

modèle pour stocker des nombres réels sous le capot représentent des nombres flottants comme

enter image description here

même si vous pouvez taper 0.2 facilement, FLT_RADIX et DBL_RADIX est 2; pas 10 pour un ordinateur avec FPU qui utilise"norme IEEE pour L'arithmétique binaire à virgule flottante (ISO/IEEE Std 754-1985)".

il est donc un peu difficile de représenter exactement de tels nombres. Même si vous spécifiez cette variable explicitement, sans calcul intermédiaire.

27
répondu bruziuz 2017-12-27 06:59:19

quelques statistiques liées à cette fameuse question de double précision.

en ajoutant toutes les valeurs ( a + b ) en utilisant une étape de 0.1 (de 0.1 à 100) nous avons ~15% de chance d'erreur de précision . Notez que l'erreur peut donner des valeurs légèrement plus grandes ou plus petites. Voici quelques exemples:

0.1 + 0.2 = 0.30000000000000004 (BIGGER)
0.1 + 0.7 = 0.7999999999999999 (SMALLER)
...
1.7 + 1.9 = 3.5999999999999996 (SMALLER)
1.7 + 2.2 = 3.9000000000000004 (BIGGER)
...
3.2 + 3.6 = 6.800000000000001 (BIGGER)
3.2 + 4.4 = 7.6000000000000005 (BIGGER)

lorsqu'on soustrait toutes les valeurs ( a - b a > b ) en utilisant une étape de 0.1 (de 100 à 0.1) nous avons ~34% de chance d'erreur de précision . Voici quelques exemples:

0.6 - 0.2 = 0.39999999999999997 (SMALLER)
0.5 - 0.4 = 0.09999999999999998 (SMALLER)
...
2.1 - 0.2 = 1.9000000000000001 (BIGGER)
2.0 - 1.9 = 0.10000000000000009 (BIGGER)
...
100 - 99.9 = 0.09999999999999432 (SMALLER)
100 - 99.8 = 0.20000000000000284 (BIGGER)

*15% et 34% sont en effet énormes, donc toujours utiliser BigDecimal quand la précision est d'une grande importance. Avec 2 chiffres décimaux (étape 0.01) la situation s'aggrave un peu plus (18% et 36%).

24
répondu Konstantinos Chalkias 2017-08-04 08:41:25

non, pas cassé, mais la plupart des fractions décimales doivent être approximée

résumé

arithmétique à virgule flottante est exact, malheureusement, il ne correspond pas bien à notre représentation habituelle base-10 Nombre, il s'avère que nous lui donnons souvent entrée qui est légèrement hors de ce que nous avons écrit.

même des nombres simples comme 0,01, 0,02, 0,03, 0,04 ... 0,24 ne sont pas représentables exactement comme des fractions binaires. Si vous comptez jusqu'à 0,01, de .02,.03 ..., pas jusqu'à ce que vous obtenez à 0,25 vous obtiendrez la première fraction représentative en base 2 . Si vous avez essayé cela en utilisant FP, votre 0,01 aurait été légèrement off, de sorte que la seule façon d'ajouter 25 d'entre eux jusqu'à un bon 0,25 exact aurait exigé une longue chaîne de causalité impliquant des bits de garde et l'arrondissement. C'est difficile à prédire, alors nous levons nos mains et disons " FP est inexact", mais ce n'est pas vraiment vrai.

nous donnons constamment au matériel FP quelque chose qui semble simple en base 10 mais qui est une fraction répétitive en base 2.

Comment est-ce arrivé?

quand nous écrivons en décimal, chaque fraction (spécifiquement, chaque décimal se terminant) est un nombre rationnel de la forme

           a / (2 n x 5 m )

en binaire, on obtient seulement le terme 2 n , c'est-à-dire:

a / 2 n

donc en décimal, on ne peut pas représenter 1 / 3 . Parce que la base 10 inclut 2 comme prime facteur, chaque nombre que nous pouvons écrire comme une fraction binaire aussi peut être écrit comme une fraction de base 10. Cependant, presque rien de ce que nous écrivons comme une fraction de base 10 peut être représenté en binaire. Dans la gamme de 0.01, 0.02, 0.03 ... 0.99, seulement trois nombres peuvent être représentés dans notre format FP: 0.25, 0.50, et 0.75, parce qu'ils sont 1/4, 1/2, et 3/4, tous les nombres avec un facteur principal en utilisant seulement le 2 n terme.

en base 10 nous ne pouvons pas représenter 1 / 3 . Mais en binaire, on ne peut pas faire 1 / 10 ou 1 / 3 .

ainsi, Alors que chaque fraction binaire peut être écrit en décimal, l'inverse n'est pas vrai. Et en fait la plupart des fractions décimales se répètent en binaire.

traiter avec elle

les développeurs sont généralement chargés de faire des comparaisons < epsilon , de meilleurs conseils pourraient être de arrondir aux valeurs intégrales (dans la bibliothèque C: round() et roundf(), c.-à-d. rester dans le format FP) et ensuite comparer. L'arrondissement à une longueur de fraction décimale spécifique résout la plupart des problèmes avec la sortie.

Aussi, sur le nombre réel croquant les constantes physiques de l'univers et toutes les autres mesures ne sont connues que par un nombre relativement restreint de figures significatives, de sorte que tout l'espace de problème était "inexact" de toute façon. FP "précision" n'est pas un problème dans ce type d'application.

toute la question se pose vraiment lorsque les gens essaient d'utiliser la FP pour compter les haricots. Il fonctionne, mais seulement si vous vous en tenez à integral valeurs, quel genre de défaites le point de l'utiliser. c'est pourquoi nous avons toutes ces bibliothèques de logiciels de fraction décimale.

j'aime la Pizza répondre par Chris , parce qu'il décrit le problème réel, pas seulement le handwaving sur "inexactitude". Si FP était simplement "inexact", nous pourrions corriger cela et l'aurions fait il y a des décennies. La raison pour laquelle nous ne l'avons pas est que le format FP est compact et rapide et c'est la meilleure façon de croquer beaucoup de chiffres. De plus, c'est un héritage de l'ère spatiale et de la course aux armements et des premières tentatives de résoudre de gros problèmes avec des ordinateurs très lents utilisant de petits systèmes de mémoire. (Parfois, "les noyaux magnétiques pour le stockage de 1-bit, mais c'est une autre histoire. )

Conclusion

si vous comptez juste les haricots à une banque, logiciel les solutions qui utilisent des représentations décimales de chaîne de caractères fonctionnent parfaitement. Mais on ne peut pas faire la chromodynamique quantique ou l'aérodynamique de cette façon.

22
répondu DigitalRoss 2018-10-10 22:43:27

avez-vous essayé la solution du ruban adhésif?

essayer de déterminer quand les erreurs se produisent et les corriger avec de courtes si les déclarations, ce n'est pas joli, mais pour certains problèmes, c'est la seule solution et c'est l'un d'eux.

 if( (n * 0.1) < 100.0 ) { return n * 0.1 - 0.000000000000001 ;}
                    else { return n * 0.1 + 0.000000000000001 ;}    

j'ai eu le même problème dans un projet de simulation scientifique en c#, et je peux vous dire que si vous ignorez l'effet papillon, il va se transformer en un grand dragon gras et vous mordre dans le a* *

20
répondu workoverflow 2013-06-19 18:50:36

ces nombres bizarres apparaissent parce que les ordinateurs utilisent le système de nombres binaires(base 2) à des fins de calcul, tandis que nous utilisons décimal(base 10).

il y a une majorité de nombres fractionnels qui ne peuvent être représentés avec précision ni en binaire, ni en décimal, ni les deux. Résultat-un nombre arrondi (mais précis) de résultats.

15
répondu Piyush S528 2013-10-14 16:45:17

puis-je juste ajouter; les gens supposent toujours qu'il s'agit d'un problème d'ordinateur, mais si vous comptez avec vos mains (base 10), vous ne pouvez pas obtenir (1/3+1/3=2/3)=true à moins que vous avez l'infini pour ajouter 0.333... à 0.333... donc, tout comme pour le problème (1/10+2/10)!==3/10 en base 2, vous le tronquez à 0.333 + 0.333 = 0.666 et probablement l'arrondir à 0.667 ce qui serait aussi techniquement inexact.

compte en ternaire, et les tiers ne sont pas un problème si - peut-être une certaine course avec 15 doigts sur chaque main demanderait pourquoi votre calcul décimal a été cassé...

14
répondu 2018-03-26 22:00:40

plusieurs des nombreux doublons de cette question s'interrogent sur les effets de l'arrondi en virgule flottante sur des nombres spécifiques. Dans la pratique, il est plus facile de se faire une idée de son fonctionnement en examinant les résultats exacts des calculs d'intérêt plutôt qu'en lisant simplement à ce sujet. Certaines langues fournissent des moyens de le faire - comme convertir un float ou double en BigDecimal en Java.

Puisqu'il s'agit d'une question de langue-agnostique, il faut outils linguistiques, tels qu'un convertisseur décimal À virgule flottante .

L'appliquant aux nombres dans la question, traités comme doubles:

0.1 converts to 0.1000000000000000000555111512312257827021181583404541015625,

0.2 converties en 0.200000000000000011102230246251565404236316680908203125,

0.3 convertis en 0.299999999999999988897769753748434595763683319091796875, et

0.3000000000000000004 convertit en 0.300000000000000000444089209850062616169452667236328125.

L'addition des deux premiers nombres manuellement ou dans une calculatrice décimale telle que calculatrice de pleine précision , montre la somme exacte des entrées réelles est 0.3000000000000000001665334536937773481063544750213623046875.

S'il est arrondi à l'équivalent de 0,3 de l'erreur d'arrondi serait 0.0000000000000000277555756156289135105907917022705078125. L'arrondissement jusqu'à l'équivalent de 0.3000000000000000004 donne aussi l'erreur d'arrondissement 0.0000000000000000277555756156289135105907917022705078125. Le briseur de cravate rond-à-pair s'applique.

revenant au convertisseur flottant, l'hexadécimal brut pour 0.30000000000000004 est 3fd333333333333334, qui se termine par un chiffre pair et est donc le résultat correct.

13
répondu Patricia Shanahan 2017-11-22 16:18:30

étant Donné que personne ne l'a mentionné...

certains langages de haut niveau tels que Python et Java sont dotés d'outils pour surmonter les limites des points flottants binaires. Par exemple:

  • python's decimal module et Java BigDecimal classe , qui représentent des nombres internes avec notation décimale (par opposition à notation binaire). Les deux ont une précision limitée, ainsi, ils sont toujours sujets à des erreurs, mais ils résolvent les problèmes les plus courants avec l'arithmétique binaire à virgule flottante.

    les décimales sont très belles quand on traite avec de l'argent: dix cents plus vingt cents sont toujours exactement trente cents:

    >>> 0.1 + 0.2 == 0.3
    False
    >>> Decimal('0.1') + Decimal('0.2') == Decimal('0.3')
    True
    

    Python decimal module est basé sur standard IEEE 854-1987 .

  • Python fractions module et Apache Common BigFraction class . Les deux représentent des nombres rationnels comme (numerator, denominator) paires et ils peuvent donner des résultats plus précis que l'arithmétique virgule flottante décimale arithmétique.

aucune de ces solutions n'est parfaite (surtout si nous regardons les performances, ou si nous avons besoin d'une très haute précision), mais ils résolvent tout de même un grand nombre de problèmes avec l'arithmétique binaire à virgule flottante.

12
répondu Andrea Corbellini 2015-08-21 15:03:35

le genre de calcul à virgule flottante qui peut être mis en œuvre dans un ordinateur numérique utilise nécessairement une approximation des nombres réels et des opérations sur eux. (La version standard compte plus de cinquante pages de documentation et dispose d'un comité pour traiter de ses errata et autres améliorations.)

cette approximation est un mélange d'approximations de différentes sortes, dont chacune peut être ignorée ou soigneusement prise en compte en raison de sa façon spécifique de dévier de l'exactitude. Il s'agit également d'un certain nombre de cas exceptionnels explicites, tant au niveau du matériel que du logiciel, que la plupart des gens passent sous silence en prétendant ne pas remarquer.

si vous avez besoin d'une précision infinie (en utilisant le nombre π, Par exemple, au lieu d'un de ses nombreux stand-ins plus courts), vous devriez écrire ou utiliser un programme de mathématiques symboliques à la place.

mais si vous êtes d'accord avec l'idée que parfois flottant-point les maths sont floues dans la valeur et la logique et les erreurs peuvent s'accumuler rapidement, et vous pouvez écrire vos exigences et vos tests pour tenir compte de cela, alors votre code peut souvent se débrouiller avec ce qui est dans votre FPU.

9
répondu Blair Houghton 2016-07-03 07:45:02

juste pour le plaisir, j'ai joué avec la représentation des flotteurs, en suivant les définitions de la norme C99 et j'ai écrit le code ci-dessous.

le code imprime la représentation binaire des flotteurs en 3 groupes séparés

SIGN EXPONENT FRACTION

et après cela il imprime une somme, que, une fois additionnée avec assez de précision, il montrera la valeur qui existe vraiment dans le matériel.

donc quand vous écrivez float x = 999... , le compilateur transformera ce nombre en représentation bit imprimée par la fonction xx de sorte que la somme imprimée par la fonction yy soit égale au nombre donné.

En réalité, cette somme n'est qu'une approximation. Pour le nombre 999 999 999 le compilateur insérera dans la représentation en bits du flotteur le nombre 1.000.000.000

après le code j'attache une session de console, dans laquelle je calcule la somme des termes pour les deux constantes (moins PI et 999999999) qui existe réellement dans le matériel, inséré par le compilateur.

#include <stdio.h>
#include <limits.h>

void
xx(float *x)
{
    unsigned char i = sizeof(*x)*CHAR_BIT-1;
    do {
        switch (i) {
        case 31:
             printf("sign:");
             break;
        case 30:
             printf("exponent:");
             break;
        case 23:
             printf("fraction:");
             break;

        }
        char b=(*(unsigned long long*)x&((unsigned long long)1<<i))!=0;
        printf("%d ", b);
    } while (i--);
    printf("\n");
}

void
yy(float a)
{
    int sign=!(*(unsigned long long*)&a&((unsigned long long)1<<31));
    int fraction = ((1<<23)-1)&(*(int*)&a);
    int exponent = (255&((*(int*)&a)>>23))-127;

    printf(sign?"positive" " ( 1+":"negative" " ( 1+");
    unsigned int i = 1<<22;
    unsigned int j = 1;
    do {
        char b=(fraction&i)!=0;
        b&&(printf("1/(%d) %c", 1<<j, (fraction&(i-1))?'+':')' ), 0);
    } while (j++, i>>=1);

    printf("*2^%d", exponent);
    printf("\n");
}

void
main()
{
    float x=-3.14;
    float y=999999999;
    printf("%lu\n", sizeof(x));
    xx(&x);
    xx(&y);
    yy(x);
    yy(y);
}

Voici une session de console dans laquelle je calcule la valeur réelle du flotteur qui existe dans le matériel. J'ai utilisé bc pour imprimer la somme des termes délivrée par le programme principal. On peut insérer cette somme en python repl ou quelque chose de similaire aussi.

-- .../terra1/stub
@ qemacs f.c
-- .../terra1/stub
@ gcc f.c
-- .../terra1/stub
@ ./a.out
sign:1 exponent:1 0 0 0 0 0 0 fraction:0 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 1
sign:0 exponent:1 0 0 1 1 1 0 fraction:0 1 1 0 1 1 1 0 0 1 1 0 1 0 1 1 0 0 1 0 1 0 0 0
negative ( 1+1/(2) +1/(16) +1/(256) +1/(512) +1/(1024) +1/(2048) +1/(8192) +1/(32768) +1/(65536) +1/(131072) +1/(4194304) +1/(8388608) )*2^1
positive ( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
-- .../terra1/stub
@ bc
scale=15
( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
999999999.999999446351872

C'est ça. La valeur de 999999999 est en fait

999999999.999999446351872

vous pouvez également vérifier avec bc que -3,14 est également perturbée. N'oubliez pas de définir un facteur scale dans bc .

la somme affichée est ce qu'à l'intérieur du matériel. La valeur que vous obtenez en calculant dépend de l'échelle que vous définissez. J'ai mis le facteur scale à 15. Mathématiquement, avec une précision infinie, il semble qu'il soit 1.000.000.000.

9
répondu alinsoar 2017-12-27 02:00:04

afin d'offrir la meilleure solution je peux dire que j'ai découvert la méthode suivante:

parseFloat((0.1 + 0.2).toFixed(10)) => Will return 0.3

Laissez-moi vous expliquer pourquoi c'est la meilleure solution. Comme d'autres mentionnés dans les réponses ci-dessus, c'est une bonne idée d'utiliser la fonction Javascript toFixed() pour résoudre le problème. Mais vous allez sûrement rencontrer des problèmes.

Imaginez que vous allez additionner deux nombres flottants comme 0.2 et 0.7 le voici: 0.2 + 0.7 = 0.8999999999999999 .

votre résultat attendu était 0.9 cela signifie que vous avez besoin d'un résultat avec une précision de 1 chiffre dans ce cas. Vous auriez donc dû utiliser (0.2 + 0.7).tofixed(1) mais vous ne pouvez pas donner un certain paramètre toFixed() puisqu'elle dépend du nombre donné, par exemple

`0.22 + 0.7 = 0.9199999999999999`

dans cet exemple, vous avez besoin de précision à 2 chiffres donc il devrait être toFixed(2) , donc ce qui devrait être le paramétreur pour s'adapter à chaque flotteur donné nombre?

vous pourriez dire qu'il soit 10 dans chaque situation alors:

(0.2 + 0.7).toFixed(10) => Result will be "0.9000000000"

Merde! Qu'est-ce que tu vas faire avec ces zéros indésirables après 9h? Il est temps de le convertir pour le faire flotter comme vous le souhaitez:

parseFloat((0.2 + 0.7).toFixed(10)) => Result will be 0.9

maintenant que vous avez trouvé la solution, il est préférable de l'offrir comme une fonction comme celle-ci:

function floatify(number){
           return parseFloat((number).toFixed(10));
        }

essayons-le vous-même:

function floatify(number){
       return parseFloat((number).toFixed(10));
    }
 
function addUp(){
  var number1 = +$("#number1").val();
  var number2 = +$("#number2").val();
  var unexpectedResult = number1 + number2;
  var expectedResult = floatify(number1 + number2);
  $("#unexpectedResult").text(unexpectedResult);
  $("#expectedResult").text(expectedResult);
}
addUp();
input{
  width: 50px;
}
#expectedResult{
color: green;
}
#unexpectedResult{
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="number1" value="0.2" onclick="addUp()" onkeyup="addUp()"/> +
<input id="number2" value="0.7" onclick="addUp()" onkeyup="addUp()"/> =
<p>Expected Result: <span id="expectedResult"></span></p>
<p>Unexpected Result: <span id="unexpectedResult"></span></p>

Vous pouvez l'utiliser de cette façon:

var x = 0.2 + 0.7;
floatify(x);  => Result: 0.9

comme W3SCHOOLS suggère qu'il y a une autre solution aussi, vous pouvez multiplier et diviser pour résoudre le problème ci-dessus:

var x = (0.2 * 10 + 0.1 * 10) / 10;       // x will be 0.3

gardez à l'esprit que (0.2 + 0.1) * 10 / 10 ne fonctionnera pas du tout bien qu'il semble la même chose! Je préfère la première solution car je peux l'appliquer comme une fonction qui convertit le flotteur d'entrée en flotteur de sortie précis.

7
répondu Mohammad lm71 2018-10-13 08:27:16

une autre façon de regarder ceci: utilisé 64 bits pour représenter des nombres. En conséquence, il n'y a pas plus de 2**64 = 18.446.744.073.709.551.616 différents nombres peuvent être représentés avec précision.

cependant, les maths disent qu'il y a déjà une infinité de décimales entre 0 et 1. IEE 754 définit un encodage pour utiliser ces 64 bits efficacement pour un espace de nombre beaucoup plus grand plus NaN et + / - infini, de sorte qu'il ya des écarts entre les nombres représentés avec précision rempli avec des numéros seulement approximative.

malheureusement 0,3 se trouve dans un trou.

3
répondu noiv 2017-12-19 22:48:08

puisque ce fil ramifié un peu dans une discussion générale sur les implémentations flottantes actuelles j'ajouterais qu'il y a des projets sur la correction de leurs problèmes.

regardez https://posithub.org / par exemple, qui présente un type de numéro appelé posit (et son prédécesseur unum) qui promet d'offrir une meilleure précision avec moins de bits. Si mon interprétation est correcte, elle corrige aussi le genre de problèmes dans la question. Assez projet intéressant, la personne derrière elle est un mathématicien Dr John Gustafson . Le tout est open source, avec de nombreuses implémentations réelles en C / C++, Python, Julia et C# ( https://hastlayer.com/arithmetics ).

3
répondu Piedone 2018-04-12 17:26:20

"151940920 des Mathématiques".somme (javascript ) .... type d'opérateur de remplacement

.1 + .0001 + -.1 --> 0.00010000000000000286
Math.sum(.1 , .0001, -.1) --> 0.0001

Object.defineProperties(Math, {
    sign: {
        value: function (x) {
            return x ? x < 0 ? -1 : 1 : 0;
            }
        },
    precision: {
        value: function (value, precision, type) {
            var v = parseFloat(value), 
                p = Math.max(precision, 0) || 0, 
                t = type || 'round';
            return (Math[t](v * Math.pow(10, p)) / Math.pow(10, p)).toFixed(p);
        }
    },
    scientific_to_num: {  // this is from https://gist.github.com/jiggzson
        value: function (num) {
            //if the number is in scientific notation remove it
            if (/e/i.test(num)) {
                var zero = '0',
                        parts = String(num).toLowerCase().split('e'), //split into coeff and exponent
                        e = parts.pop(), //store the exponential part
                        l = Math.abs(e), //get the number of zeros
                        sign = e / l,
                        coeff_array = parts[0].split('.');
                if (sign === -1) {
                    num = zero + '.' + new Array(l).join(zero) + coeff_array.join('');
                } else {
                    var dec = coeff_array[1];
                    if (dec)
                        l = l - dec.length;
                    num = coeff_array.join('') + new Array(l + 1).join(zero);
                }
            }
            return num;
         }
     }
    get_precision: {
        value: function (number) {
            var arr = Math.scientific_to_num((number + "")).split(".");
            return arr[1] ? arr[1].length : 0;
        }
    },
    diff:{
        value: function(A,B){
            var prec = this.max(this.get_precision(A),this.get_precision(B));
            return +this.precision(A-B,prec);
        }
    },
    sum: {
        value: function () {
            var prec = 0, sum = 0;
            for (var i = 0; i < arguments.length; i++) {
                prec = this.max(prec, this.get_precision(arguments[i]));
                sum += +arguments[i]; // force float to convert strings to number
            }
            return Math.precision(sum, prec);
        }
    }
});

l'idée est d'utiliser des opérateurs mathématiques à la place pour éviter les erreurs de flotteurs

Math.diff(0.2, 0.11) == 0.09 // true
0.2 - 0.11 == 0.09 // false

notez aussi que les mathématiques.diff et en Mathématiques.somme de détection automatique de la précision à utiliser

"151930920 des Mathématiques".sum accepte n'importe quel nombre d'arguments

2
répondu bortunac 2018-04-21 12:13:46

une autre question a été nommée en double à celle-ci:

dans C++, pourquoi le résultat de cout << x est-il différent de la valeur qu'un débogueur affiche pour x ?

la variable x dans la question est une variable float .

un exemple serait

float x = 9.9F;

le débogueur affiche 9.89999962 , la sortie de cout l'opération est 9.9 .

la réponse s'avère être que la précision par défaut de cout pour float est 6, donc il arrondit à 6 chiffres décimaux.

voir ici pour référence

2
répondu Arkadiy 2018-06-15 13:26:07

Sine Python 3.5 vous pouvez utiliser la fonction math.isclose() dans les conditions if

import math

if math.isclose(0.1 + 0.2, 0.3, abs_tol=0.01):
    pass
2
répondu nauer 2018-08-08 08:47:36

c'était en fait une réponse pour cette question -- qui a été fermée comme une copie de cette question, alors que j'étais en train de rassembler cette réponse, donc maintenant je ne peux pas la poster là... alors je vais poster ici à la place!


résumé de la Question:

sur le feuille de travail 10^-8/1000 et 10^-11 évaluer comme égale tandis que dans VBA ils ne le font pas.

sur la feuille de travail, les chiffres sont en défaut à la Notation scientifique.

si vous changez les cellules pour un format de nombre ( Ctrl + 1 ) de Number avec 15 décimal points, vous obtenez:

=10^-11 returns 0.000000000010000
=10^(-8/1000) returns 0.981747943019984

donc, ils ne sont certainement pas la même... l'un est à peu près zéro et l'autre à peu près un.

Excel N'a pas été conçu pour traiter avec extrêmement petits nombres - au moins pas avec le stock installer. Il y a des add-ins pour aider à améliorer la précision.


Excel a été conçu conformément à la norme IEEE pour L'arithmétique binaire à virgule flottante ( IEEE 754 ). La norme définit comment les nombres à virgule flottante sont calculées et stockées. La norme IEEE 754 est largement utilisée parce qu'elle permet-les nombres à virgule flottante d'être stockés dans une quantité raisonnable d'espace et les calculs peuvent se produire relativement rapidement.

l'avantage de la représentation flottante par rapport à la représentation en points fixes est qu'elle peut supporter une gamme de valeurs plus large. Par exemple, une représentation à point fixe qui a 5 chiffres décimaux avec le virgule placée après le troisième chiffre peut représenter les nombres 123.34 , 12.23 , 2.45 , etc. tandis que la représentation en virgule flottante avec une précision de 5 chiffres peut représenter 1.2345, 12345, 0.00012345,etc. De même, la représentation en virgule flottante permet également des calculs sur une vaste gamme d'ordres de grandeur tout en maintenant la précision. Par exemple,

img


Autres Références:

2
répondu ashleedawg 2018-10-02 03:42:06