2010-08-09 5 views
32

Можно создать дубликат:
Is JavaScript’s Math broken?Почему добавление двух десятичных знаков в Javascript приводит к неправильному результату?

Почему JS ввернуть эту простую математику?

document.write(.1 + .2) // 0.3000000000000004 
document.write(.3 + .6) // 0.8999999999999999 

Первый пример больше, чем правильный результат, а второй меньше. ??? !! Как вы это исправите? Вы должны всегда преобразовывать десятичные числа в целые числа перед выполнением операций? Мне нужно только беспокоиться о добавлении (* и/не похоже, что у меня такая же проблема в моих тестах)?

Я просмотрел много мест для ответов. Некоторые учебники (например, формы корзины покупок) притворяются, что проблема не существует и просто добавляет ценности вместе. Гуру предоставляют сложные процедуры для различных математических функций или упоминают, что JS «делает плохую работу» мимоходом, но мне еще предстоит увидеть объяснение.

+0

Проверьте ответы на этот вопрос: http://stackoverflow.com/questions/588004/is-javascripts-math-broken –

+0

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

+0

Снова ?! Нам действительно нужно написать FAQ. –

ответ

6

Это не ограничение только на javascript, оно применимо ко всем вычислениям с плавающей запятой. Проблема в том, что 0,1 и 0,2 и 0,3 точно не представляются в виде флагов javascript (или C или Java и т. Д.). Таким образом, результат, который вы видите, обусловлен этой неточностями.

В частности, только определенные суммы степеней двух функций точно представляются. 0.5 = = 0.1b = 2^(- 1), 0.25 = 0.01b = (2^-2), 0.75 = 0.11b = (2^-1 + 2^-2) - все в порядке. Но 1/10 = 0.000110001100011..b может быть выражен только в виде бесконечной суммы степеней 2, которую язык отбрасывает в какой-то момент. Его это измельчение, которое вызывает эти незначительные ошибки.

4

От The Floating-Point Guide:

Почему не мои цифры, как 0,1 + 0,2 добавить до хорошей круглой 0,3 и вместо этого я получаю странный результат, как 0.30000000000000004?

Поскольку внутри, компьютеры используют формат (двоичная с плавающей точкой), что не может точно представлять ряд , как 0,1, 0,2 или 0,3 на всех.

При компиляции кода или истолковано, ваш «0,1» уже округлены до ближайшего числа в таком формате , что приводит к небольшой ошибки округления еще до того, происходит вычисление .

На сайте есть подробные объяснения, а также информация о том, как исправить проблему (и как решить, является ли это вообще проблемой в вашем случае).

+0

Упрощенный ответ. – hamzox

15

Это не проблема JS, а более общий компьютер.Плавающий номер не может хранить надлежащим образом всех десятичных чисел, потому что они хранят вещи в двоичном Например:

0.5 is store as b0.1 
but 0.1 = 1/10 so it's 1/16 + (1/10-1/16) = 1/16 + 0.0375 
0.0375 = 1/32 + (0.0375-1/32) = 1/32 + 00625 ... etc 

so in binary 0.1 is 0.00011... 

но это бесконечно. За исключением того, что компьютер должен остановиться в какой-то момент. Так что, если в нашем примере мы остановимся на 0,00011, то у нас будет 0.09375 вместо 0.1.

В любом случае дело в том, что это не зависит от языка, а от компьютера. В зависимости от языка, как вы показываете числа. Обычно число раундов языка соответствует приемлемому представлению. По-видимому, JS нет.

Так что вам нужно сделать (число в памяти достаточно точное) - это просто сказать JS, чтобы округлить «красивое» число при преобразовании их в текст.

Вы можете попробовать функцию sprintf, которая дает вам прекрасный контроль над тем, как отображать номер.