2017-06-22 5 views
1

Je suis aux prises avec des problèmes liés à la résolution des problèmes. précision à virgule flottante, et n'a pas pu trouver une solution.Gestion de la précision en virgule flottante

Voici un court exemple:

aa<-c(99.93029, 0.0697122) 
aa 
[1] 99.9302900 0.0697122 
aa[1] 
99.93029 
print(aa[1],digits=20) 
99.930289999999999 

Il semblerait que, sur le stockage du vecteur, R a converti les chiffres à quelque chose avec une représentation interne légèrement différente (oui, j'ai lu cercle 1 du " R inferno "et matériel similaire).

Comment puis-je forcer R à stocker les valeurs d'entrée exactement "telles quelles", sans modification?

Dans mon cas, mon problème est que les valeurs sont traitées de telle sorte que les petites erreurs très rapidement se développer:

aa[2]/(100-aa[1])*100 
[1] 100.0032 ## Should be 100, of course ! 
print(aa[2]/(100-aa[1])*100,digits=20) 
[1] 100.00315593171625 

Je dois trouver un moyen d'obtenir ma droite normalisation.

Merci

Il y a beaucoup de PS-questions sur ce site et ailleurs, discuter de la question de la perte apparente de précision, à savoir les numéros affichés correctement (mais stockés à droite). Ici, par exemple: How to stop read.table from rounding numbers with different degrees of precision in R? Ceci est un problème distinct, car le numéro est mal stocké (mais affiché à droite).

(version R 3.2.1 (18/06/2015), win 7 x64)

+0

Je crois que votre question ne concerne pas les tables de lecture, mais à propos de la précision numérique de R. https://stackoverflow.com/questions/24847918/extreme-numerical-values-in-floating-point-precision-in-r –

Répondre

1

précision en virgule flottante a toujours généré beaucoup de confusion. L'idée cruciale à retenir est la suivante: lorsque vous travaillez avec des doubles, il n'y a aucun moyen de stocker chaque nombre réel "tel quel", ou "exactement exact" - le mieux que vous pouvez stocker est l'approximation disponible la plus proche. Donc, lorsque vous tapez (dans R ou n'importe quelle autre langue moderne) quelque chose comme x = 99.93029, vous obtiendrez ce nombre représenté par 99.930289999999999. Maintenant, quand vous vous attendez à a + b pour être "exactement 100", vous êtes inexact en termes. Le mieux que vous pouvez obtenir est "100 jusqu'à N chiffres après la virgule" et j'espère que N est assez grand. Dans votre cas, il serait correct de dire 99.9302900 + 0.0697122 est 100 avec 5 points décimaux de précision. Naturellement, en multipliant cette égalité par 10^k vous perdrez plus de k chiffres de précision.

Ainsi, il y a deux solutions ici:

a. Pour obtenir plus de précision dans la sortie, fournissez plus de précision dans l'entrée.

bb <- c(99.93029, 0.06971) 
print(bb[2]/(100-bb[1])*100, digits = 20) 
[1] 99.999999999999119 

b. Si la double précision ne suffit pas (peut se produire dans des algorithmes complexes), utilisez des packages qui fournissent des opérations de précision numériques supplémentaires.Par exemple, le paquet gmp.

+0

Pour la clarification, cela aide beaucoup à régler le problème dans les bons termes! Cependant, je ne comprends pas la différence entre votre exemple en utilisant bb et le mien avec aa? Comment fournissez-vous "plus de précision dans l'entrée" dans ce cas? – jfmoyen

+0

@jfmoyen 'sum (aa)' est 100.0000022, alors que 'sum (bb)' vaut 100 jusqu'à 10^-15. Une autre façon est 'cc <- c (99.9302878, 0.0697122)'. – tonytonov

+0

Désolé, j'avais oublié cela, merci. – jfmoyen

0

Je suppose que vous avez mal compris ici. C'est le même cas où R stocke la valeur correcte mais la valeur est affichée en conséquence à la valeur de l'option choisie en l'affichant. Pour Ex:

# the output of below will be: 
> print(99.930289999999999,digits=20) 
[1] 99.930289999999999395 

Mais

# the output of: 
> print(1,digits=20) 
[1] 1 

également

> print(1.1,digits=20) 
[1] 1.1000000000000000888 
+0

Hmmmmmmm yeees ... Je vois ce que vous voulez dire par le dernier exemple est similaire à la mienne. Mais ceci implique que 1 est stocké exactement comme 1, et 1.1 est stocké comme 1.1 + 1e-16, n'est-ce pas? Je suppose que ce n'est pas prévisible/pas sous le contrôle de l'utilisateur. Je peux avoir quelques chiffres «bons», et certains «faux». Je peux comprendre cela, mais alors comment suggéreriez-vous que je guérisse le problème (et, en particulier, obtenir 'a2/(100-a1) = 1', ou en effet assez proche de 1)? – jfmoyen

+0

@jfmoyen, la fonction 'signif' va-t-elle résoudre le problème d'arrondi' round (aa [2]/(100-aa [1]), chiffres = 1) 'à 1 travail dans votre cas? – parth

+0

@jfmoyen .. vous n'avez pas besoin d'inclure l'option digit pendant l'impression. il suffit d'utiliser '> print (a2/(100-a1) = 1)' '[1] 100' – ihm017

0

En plus des réponses précédentes, je pense qu'une bonne conférence concernant le sujet serait

R Inferno, par P.Burns

http://www.burns-stat.com/documents/books/the-r-inferno/

+1

Je suis conscient de cela, je l'ai mentionné dans ma question initiale :-) Malheureusement, l '"Inferno" ne suggère pas de solutions ... – jfmoyen

+0

Ooops: D En fait, il n'y a pas de solution (simple) en général. Mais au moins, il suggère que c'est un problème connu :) –