2015-10-01 2 views
0

мы знаем, что cos (2mPI) = 1 для каждого целого числа m. Однако, я получаю следующий выход.погрешность поплавковой точки math.cos погрешность

value of m = 1.000000e+01 and value of cos(2*m*pi) = 1.000000000000000 
value of m = 1.000000e+02 and value of cos(2*m*pi) = 1.000000000000000 
value of m = 1.000000e+03 and value of cos(2*m*pi) = 1.000000000000000 
value of m = 1.000000e+04 and value of cos(2*m*pi) = 1.000000000000000 
value of m = 1.000000e+05 and value of cos(2*m*pi) = 1.000000000000000 
value of m = 1.000000e+06 and value of cos(2*m*pi) = 1.000000000000000 
value of m = 1.000000e+07 and value of cos(2*m*pi) = 1.000000000000000 
value of m = 1.000000e+08 and value of cos(2*m*pi) = 0.999999999999997 
value of m = 1.000000e+09 and value of cos(2*m*pi) = 0.999999999999998 
value of m = 1.000000e+10 and value of cos(2*m*pi) = 0.999999999989970 
value of m = 1.000000e+11 and value of cos(2*m*pi) = 0.999999999564035 
value of m = 1.000000e+12 and value of cos(2*m*pi) = 0.999999854510183 
value of m = 1.000000e+13 and value of cos(2*m*pi) = 0.999985451053279 
value of m = 1.000000e+14 and value of cos(2*m*pi) = 0.999742535619873 
value of m = 1.000000e+15 and value of cos(2*m*pi) = 0.888410566323832 
value of m = 1.000000e+16 and value of cos(2*m*pi) = 0.718430574337184 
value of m = 1.000000e+17 and value of cos(2*m*pi) = -0.438105159926831 
value of m = 1.000000e+18 and value of cos(2*m*pi) = 0.176561618304251 
value of m = 1.000000e+19 and value of cos(2*m*pi) = -0.114036978390490 
value of m = 1.000000e+20 and value of cos(2*m*pi) = 0.689416156299807 

Почему мы не всегда вычисляем правильный выход? поскольку значение m становится больше, изменение приближения значительно. Не уверен, какой тип ошибки с плавающей точкой вызывает это. Любая помощь?

+1

Добро пожаловать в точность с плавающей запятой. Вы также можете посмотреть, как здесь вычисляется косинус. По предположению, это, вероятно, расширение сортов с определенной точностью, а большие значения аргументов ('x') заставят это расширение создавать большие неточности. – Evert

+0

Связанные: http://stackoverflow.com/questions/2284860/how-does-c-compute-sin-and-other-math-functions – Evert

+3

@Olaf: YAW. 'sin' и' cos' математически определены для всех действительных чисел (действительно, для всех комплексных чисел). Но то, что вы сказали об ошибках округления, верно. – TonyK

ответ

4

Возможно, это связано с тем, что значение самого ПИ (его компьютерное представление, а не математическое значение) не является точным.

Это может быть 3.141592653589 (это все, что я могу запомнить с головы), но если у вас нет бесконечного количества бит для его хранения (или вы используете символическую, а не двоично-кодированную форму), это будет никогда быть полностью точным.

И, умножая его на большие целые числа, погрешность может значительно увеличиться.

Капризы представлений с плавающей запятой хорошо известны до такой степени, что вы можете получить только пятнадцать цифр точности из представления двойной точности IEEE754. Дайте PI требуется около ... ну ... бесконечное количество бит, что-то нужно дать.


Я не совсем уверен, какого рода приложение будет использовать значение как 1020π и я не претендую знать вашу ситуацию, но вы можете хотите дать некоторую мысль, пытаясь зажать значение к более «разумному» диапазону, например [0,2π).

+0

Это только одно из упражнений в учебнике, которое я нашел. Я думаю, что переполнение точки с плавающей точкой также способствует этой неточности. Когда 2 * m * pi становятся слишком большими, чтобы быть приблизительными в стандартной компьютерной системе. – boxy

+0

@rcgldr, осторожно, я не уверен * (хотя я не проверял исчерпывающе), что округление 'm/1.0' к нулю может работать во всех случаях.Это может быть ничем не отличаться от целочисленной математики '99/10', которая дала бы' 9', а не «более правильную» '10'. – paxdiablo

+0

@paxdiablo - удалил мой предыдущий комментарий. Хотя fmod (m, 1.0) должно приводить к 0.0 для любого целочисленного значения m, включая любые m> = 10^16 в двойной точности, это не сработает, если m не является целым значением. Из предыдущего потока [сокращение аргумента для огромных аргументов] (http://www.csee.umbc.edu/~phatak/645/supl/Ng-ArgReduction.pdf) объясняет один из подходов к решению этой проблемы. Относительно пределов двойной точности (2^52) +1> (2^52), но (2^53) +1 == (2^53). – rcgldr

2

Разница между ближайшим 64-битным числом с плавающей запятой до PI, который я назову piDouble, и точное значение PI, piExact, составляет около 1,22E-16. Разница m*piExact - m*piDouble == m*(piExact - piDouble) составляет около m*1.22E-16.

Функции, такие как косинус, оцениваются путем уменьшения угла до относительно небольшого диапазона углов, по которому библиотека имеет хорошее приближение к косинусу.

По мере того как m становится больше, m*1.22E-16 сначала становится достаточно большим, чтобы иметь значение, а затем доминировать в результате сокращения угла.

Смежные вопросы