2011-10-05 3 views
6

Code suivant me donne 5,999999999999998 en résultat, mais bonne réponse est 6.de précision dans Erlang

Alpha = math:acos((4*4 + 5*5 - 3*3)/(2*4*5)) 
Area = 1/2 * 4 * 5 * math:sin(Alpha) 

Est-il possible d'obtenir 6?

+5

Vous n'êtes pas garanti d'obtenir des résultats exacts lorsque vous utilisez l'arithmétique en virgule flottante. Ce sujet a été couvert de nombreuses, nombreuses fois déjà. – Nayuki

Répondre

23

Vous avez exécuté un problème si commun qu'il a son propre site Web, What Every Programmer Should Know About Floating-Point Arithmetic. Le problème est dû à la façon dont l'arithmétique en virgule flottante fonctionne dans pratiquement tous les processeurs sur le marché qui supportent l'arithmétique FP; ce n'est pas spécifique à Erlang.

Si l'arithmétique à virgule flottante régulière ne vous donne pas la précision ou la précision dont vous avez besoin, vous pouvez utiliser une bibliothèque arithmétique de précision arbitraire à la place de l'arithmétique intégrée. Peut-être que la bibliothèque la plus connue est GMP, mais vous devez l'inclure dans NIFs pour l'utiliser depuis Erlang.

Il y a at least one pure-Erlang alternative, mais je n'en ai aucune expérience, donc je ne peux pas personnellement l'endosser.

+0

Ceci est certainement un incontournable pour quiconque fait de l'arithmétique en virgule flottante. – rvirding

+0

Un grand merci pour le lien – Yola

+0

@WarrenYoung Merci pour l'info, j'ai fait une recherche et j'ai trouvé ceci: https://github.com/tim/erlang-decimal Mais je ne suis pas sûr de savoir si est en développement actif, mais certains les gens ont des fourchettes avec des changements et de nouvelles fonctionnalités. – JHG

8

Le calcul est effectué à l'aide de l'arithmétique à virgule flottante standard sur votre matériel. Parfois, des erreurs d'arrondi apparaissent.

Avez-vous vraiment besoin de 15 chiffres de précision?

Pour obtenir une plus grande valeur « exacte » il y a plusieurs options:

> round(Area). % Will round to integer 
6 

ou vous pouvez arrondir une certaine précision

round(Area * 10000000)/10000000. 
6.0 

Si le but est d'imprimer la valeur, l'impression puis avec la sortie par défaut pour les flottants vous donne moins de précision.

io:format("~f~n", [Area]). 
6.000000 
ok 

ou avec une précision spécifique

io:format("~.14f~n", [Area]). 
6.00000000000000 
ok 

HTH