2015-03-04 1 views
2

Je suis en train de construire un programme permettant de convertir des valeurs doubles en format de valeur scientifique (mantisse, exposant). Puis j'ai remarqué le ci-dessouserreur de double précision lors de la conversion à la notation scientifique

369.7900000000000 -> 3.6978999999999997428 

68600000 -> 6.8599999999999994316 

J'ai remarqué le même modèle pour plusieurs autres valeurs également. L'erreur maximale est fractionnée

0.000 000 000 000 001 = 1*e-15

Je sais que l'inexactitude dans la représentation des valeurs doubles dans un ordinateur. Peut-on en conclure que l'erreur fractionnelle maximale que nous obtiendrions est 1*e-15? Qu'est-ce qui est important à ce sujet? Je suis passé à travers la plupart des questions sur le problème de précision à virgule flottante dans le débordement de pile, mais je n'ai pas vu sur l'erreur fractionnaire maximale en 64 bits.

Pour être clair sur le calcul que je fais, je l'ai mentionné mon extrait de code ainsi

double norm = 68600000; 
if (norm) 
{ 
    while (norm >= 10.0) 
    { 
     norm /= 10.0; 
     exp++; 
    } 
    while (norm < 1.0) 
    { 
     norm *= 10.0; 
     exp--; 
    } 
} 

Maintenant je

norm = 6.8599999999999994316; 
exp = 7 

Répondre

2

Le numéro que vous obtenez est lié à la machine epsilon pour la double type de données.

Un double a une longueur de 64 bits, avec 1 bit pour le signe, 11 bits pour l'exposant et 52 bits pour la fraction de mantisse. Une valeur de double est donnée par

1.mmmmm... * (2^exp) 

Avec seulement 52 bits pour la mantisse, toute valeur double ci-dessous 2^-52 sera complètement perdue lorsqu'il est ajouté à 1.0 en raison de sa faible importance. En binaire, 1.0 + 2^-52 serait

1.000...00 + 0.000...01 = 1.000.....01 

Il est évident que rien moins ne changerait pas la valeur de 1.0. Vous pouvez vérifier vous-même que 1.0 + 2^-53 == 1.0 dans un programme.

Ce nombre est appelé 2^-52 = 2.22e-16 epsilon machine et une borne supérieure de l'erreur relative qui se produit pendant une arithmétique à virgule flottante due à l'erreur d'arrondi avec double valeurs.

De même, float a 23 bits dans sa mantisse et donc sa machine epsilon est 2^-23 = 1.19e-7. La raison pour laquelle vous obtenez 1e-15 peut être parce que les erreurs s'accumulent pendant que vous effectuez de nombreuses opérations arithmétiques, mais je ne peux pas dire parce que je ne connais pas les calculs exacts que vous faites.


EDIT: J'ai regardé dans l'erreur relative à votre problème avec 68.600.000.

Tout d'abord, vous pourriez être intéressés de savoir que round-off erreur peut changer le résultat de votre calcul si vous cassez en étapes:

686.0/10.0  = 68.59999999999999431566 
686.0/10.0/10.0 = 6.85999999999999943157 
686.0/100.0  = 6.86000000000000031974 

Dans la première ligne, le plus proche double à 68,6 est inférieur à la valeur réelle, mais dans la troisième ligne, nous voyons le plus proche double à 6.86 est plus grand.

Si nous regardons l'erreur de abosolutee_abs = abs(v-v_approx) de votre programme, nous voyons qu'il est

6.8600000 - 6.85999999999999943156581139192 ~= 5.684e-16 

Cependant, la erreur relativee_abs = abs((v-v_approx)/ v) = abs(e_abs/v) serait

5.684e-16/6.86 ~= 8.286e-17 

Ce qui est en effet ci-dessous notre machine epsilon de 2.22e-16.

This est un papier célèbre que vous pouvez lire si vous voulez connaître tous les détails sur l'arithmétique à virgule flottante.

+0

merci @ eigenchris pour cette explication. Maintenant, j'ai légèrement l'idée. Mais je ne comprends toujours pas comment mon erreur fractionnaire est supérieure à 2.22e-16. Selon la définition de la machine epsilon mon erreur fractionnaire devrait être inférieure à 2.22e-16 n'est-ce pas? btw J'ai ajouté mon code à la question – vibz

+0

@vibz J'ai mis à jour ma réponse. L'erreur fractionnaire que j'ai eu était différente de la vôtre et est en dessous de la machine epsilon. Comment avez-vous calculé le vôtre? – eigenchris

+0

qui explique tout @ eigenchris.My calcul de l'erreur fracturale était incorrecte. Je vous remercie :) – vibz