Геометрические методы Javascript: Ноль не совсем ноль, не так ли? - PullRequest
4 голосов
/ 27 сентября 2011

В простой геометрической программе , написанной на Javascript и Canvas, когда я установил угол на 270 ° (1½π), я ожидал, что Math.cos ( θ ) перейдет кнуль.Вектор расположен прямо вниз от центра, на декартовой сетке нет расстояния x.Вместо этого я получаю это:

demo_angle = 270
ang = demo_angle * Math.PI / 180
x = Math.cos(ang) 
console.log(x)
> -1.836909530733566e-16

Чтобы увидеть вывод математических функций, просмотрите консоль.Исходный код виден (в coffeescript) на один уровень выше в URL.

Мне пришлось определить в своем коде «любое число, абсолютное значение которого меньше 1e-15, следует считать нулевым», ноэто действительно неудовлетворительно.Излишне говорить, что когда я пытаюсь сделать математику с таким небольшим значением x, тем более что я пытаюсь использовать x в качестве знаменателя в расчете наклона, а затем выполняю некоторые квадратичные манипуляции, я в конечном итоге придумываю цифры, которыепревышать Number.MAX_VALUE (или Number.MIN_VALUE).

Я знаю, что математика с плавающей запятой на уровне ассемблера является чем-то вроде темного искусства, но такие результаты кажутся более странными, чем приемлемые.Любые намеки на то, что я должен делать?

Ответы [ 2 ]

9 голосов
/ 27 сентября 2011

Проблема не в том, что «ноль - это не совсем ноль».Наоборот, ноль - это , в точности ноль .

Проблема, с которой вы сталкиваетесь, заключается в том, что 3π / 2 не представляется в виде числа с плавающей запятой.Таким образом, вы на самом деле берете косинус значения, которое не совсем равно 3π / 2.Насколько велика эта ошибка представления?Примерно 1.8e-16, который является источником ошибки, которую вы видите в косинусе.

Некоторые языки решают эту проблему, предоставляя такие функции, как sinpi и cospi, которые неявно масштабируют свои аргументы с коэффициентомиз π;это один из способов получения точных результатов.Очевидно, это не вариант для вас, потому что в JavaScript нет таких функций.Вы можете свернуть свои собственные, если хотите, используя симметрию этих функций, или вы можете просто ограничить «почти ноль» значения до нуля, как вы сейчас.Ни один из них не является особенно удовлетворительным, но оба, вероятно, будут работать для ваших целей.

3 голосов
/ 27 сентября 2011

Проблема в том, что Math.PI точно не равен Pi, а вместо этого является номером формы m * 2 ^ e с 2 ^ 52 <= m <2 ^ 53, ближайшим к нему. </p>

Затем умножение на 270 приводит к небольшой ошибке округления.

Затем деление на 180 вызывает еще одну ошибку округления.

Таким образом, ваше значение ang не совсем равно 3* Pi / 2, и в результате вы получите не тот 0, который ожидаете.

Сам расчет на самом деле сделан очень точно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...