Точность в Erlang

#erlang #floating-point #precision

#erlang #с плавающей запятой #точность

Вопрос:

Следующий код дает мне результат 5,999999999999998, но правильный ответ — 6.

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

Возможно ли получить 6?

Комментарии:

1. Вы не гарантированно получите точные результаты при использовании арифметики с плавающей запятой. Эта тема уже обсуждалась много, много, много раз.

Ответ №1:

Вы столкнулись с проблемой, настолько распространенной, что у нее есть свой собственный веб-сайт, что каждый программист должен знать об арифметике с плавающей запятой. Проблема связана с тем, как арифметика с плавающей запятой работает практически во всех процессорах на рынке, которые поддерживают FP-арифметику; это не относится к Erlang.

Если обычная арифметика с плавающей запятой не дает вам необходимой точности или точности, вы можете использовать библиотеку арифметики произвольной точности вместо встроенной арифметики. Возможно, наиболее известной такой библиотекой является GMP, но вам придется обернуть ее в NIFs, чтобы использовать ее из Erlang.

Существует по крайней мере одна альтернатива на чистом Erlang, но у меня нет опыта работы с ней, поэтому я не могу лично ее одобрить.

Комментарии:

1. Это определенно необходимо прочитать всем, кто занимается арифметикой с плавающей запятой.

2. @WarrenYoung Спасибо за информацию, я искал и нашел это: github.com/tim/erlang-decimal Но я не уверен насчет того, находится ли он в активной разработке, но у некоторых людей есть форки с изменениями и новыми функциями.

Ответ №2:

Вычисление выполняется с использованием стандартной арифметики с плавающей запятой на вашем оборудовании. Иногда появляются ошибки округления.

Вам действительно нужно 15 цифр точности?

Чтобы получить более «точное» значение, существует несколько вариантов:

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

или вы могли бы округлить до некоторой точности

 round(Area * 10000000) / 10000000.
6.0
  

Если целью является печать значения, то печать с выводом по умолчанию для чисел с плавающей запятой дает вам меньшую точность.

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

или с определенной точностью

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

HTH