2014-02-12 3 views
0

Я пытаюсь понять эту проблему с плавающей точкой в ​​javascript. Это пример того, что я хочу сделать:Ошибка ошибки с плавающей запятой

var x1 = 0 
for(i=0; i<10; i++) 
{ 
    x1+= 0.2  
} 

Однако в таком виде я получаю ошибку округления, 0,2 -> 0,4 ​​-> 0,600 ... 001 делает это.

Я пробовал parseFloat, toFixed и Math.round предложил другие темы, но никто из них не работал для меня. Так есть кто-нибудь, кто мог бы сделать эту работу, потому что я чувствую, что у меня закончились варианты.

+1

Привет и добро пожаловать в SO. Я думаю, что это поможет, если вы разместите свои попытки и почему они были неудовлетворительными, поэтому мы лучше понимаем, как вам помочь. – Tibos

+0

Когда вы используете с плавающей запятой, вы должны признать, что в арифметике есть ошибки округления, и вы должны разработать свой код для работы с этим. Поскольку значение .6 не является точно представимым в двоичной с плавающей запятой, никакой код вообще не приведет к созданию двоичного объекта с плавающей запятой, имеющего точно значение .6. Вы должны признать, что будут ошибки. Вы не указали, какая проблема вызывает эти ценности. –

+0

Тибос: Да, я, вероятно, должен был (в первый раз это сделал), возможно, я был одержим, пытаясь понять, как получить ровно 0,6. Эрик: Спасибо, что я не могу получить 0,6, помог мне изменить свой код и нарисовать реальную проблему. Что означало, что значение x1 использовалось при доступе к значению массива и в% == 0, в результате чего мои операторы if не запускались. Так что спасибо, я новичок в мире кодирования и stackoverflow, поэтому мне жаль, если я немного инструмент. – Ranth

ответ

0

Вы можете почти всегда игнорировать ошибки «с плавающей запятой» во время выполнения вычислений - они не будут иметь никакого значения для конечного результата, если вы действительно не заботитесь о 17-й значащей цифре или около того.

Вам обычно нужно только беспокоиться о округлении, когда вы отображаете те значения, для которых .toFixed(1) будет делать все хорошо.

Что бы ни случилось, вы просто не можете принудить число 0,6 точно к этому значению. Ближайший IEEE 754 с двойной точностью точно 0,59999999999999997779553950749686919152736663818359375, что при отображении в типичных пределах точности в JS отображаются как 0.5999999999999999778

Действительно JS не может даже сказать, что +0,5999999999999999778! == (например) +0,5999999999999999300, так как их двоичное представление одно и то же ,

+0

@EricPostpischil Ваше изменение не подходит. Значение, которое я дал, является ближайшим возможным с помощью Javascript Number (двойная точность IEEE 754). – Alnitak

+0

Спасибо, я думаю, что я был одержим, пытаясь получить ровно 0,6, принимая, что заставило меня изменить код, чтобы это разрешить. – Ranth

+0

@ Алнитак: Нет, это значение не является ближайшим возможным. Это значение может отображаться при отображении этого количества цифр, но это не фактическое значение. Это должно быть очевидно, так как это двоичная с плавающей запятой, и каждая двоичная с плавающей запятой заканчивается на 5 в качестве последней значащей цифры. (.5, .25, .125, .0625, ...). Значение, введенное мной, представляет собой фактическое значение, указанное в IEEE 754. Это точно 5404319552844595/9007199254740992. (Знаменатель равен 2 ** 53.) –

0

В зависимости от того, что вы делаете, вы можете использовать арифметику с фиксированной запятой вместо плавающей запятой. Например, если вы делаете финансовые расчеты в долларах с суммой, которая всегда кратно 0,01 доллара, вы можете переключиться на использование центов внутри страны, а затем конвертировать в доллары (и из) только при отображении значений пользователю (или чтении ввода от пользователь). Для более сложных сценариев вы можете использовать арифметическую библиотеку с фиксированной точкой.

0

Чтобы лучше понять, как ошибки округления накапливаются, и получить более глубокое представление о том, что Происходило на более низком уровне, вот небольшой explanantion:
я буду считать, что IEEE 754 двойной стандарт точности используется базовой программной/аппаратной , с режимом округления по умолчанию (от округлой до ближайшей четной).

1/5 может быть записан в основании 2 с рисунком повторяя бесконечно

0.00110011001100110011001100110011001100110011001100110011... 

Но с плавающей точкой, то мантисса - начиная с наиболее значимыми 1 бит - должна быть округлена до конечного числа бит (53)

Так что есть небольшая ошибка округления при представлении 0.2 в двоичной системе:

0.0011001100110011001100110011001100110011001100110011010 

Вернуться к десятичному представлению, эта ошибка округления соответствует с до небольшого избытка 0.000000000000000011102230246251565404236316680908203125 выше 1/5

Первая операция затем точна, поскольку 0,2 ± 0,2, как 2 * 0,2, и, таким образом, не вносит дополнительную погрешность, это как сдвигая точку фракции:

0.0011001100110011001100110011001100110011001100110011010 
+ 0.0011001100110011001100110011001100110011001100110011010 
    --------------------------------------------------------- 
    0.0110011001100110011001100110011001100110011001100110100 

Но, конечно, избыток выше 2/5 удваивается 0.00000000000000002220446049250313080847263336181640625

Третья операция 0,2 + 0,2 + 0,2 приведет к этому двоичного числа

0.011001100110011001100110011001100110011001100110011010 
+ 0.0011001100110011001100110011001100110011001100110011010 
    --------------------------------------------------------- 
    0.1001100110011001100110011001100110011001100110011001110 

Но, к сожалению, это требует 54 бит мантиссы (промежуток между ведущим 1 и задней 1), так что другой ошибки округления необходимо представить результат в виде двойной:

0.10011001100110011001100110011001100110011001100110100 

Обратите внимание, что номер был закругленный верхний, так как по умолчанию поплавков округляется до ближайшего даже в случае идеального галстука. Мы уже имели ошибку избытком, так везло, последовательные ошибки сделал аккумулировать, а не аннулируют ...

Так избыток выше 3/5 теперь 0,000000000000000088817841970012523233890533447265625

Вы могли бы сократить немного в этом накопление ошибок, с использованием

x1 = i/5.0 

так как 5 представлена ​​именно в поплавка (101,0 в двоичной системе, 3 мантисса биты являются достаточно), и так как это также будет случай I (до 2^53), имеется один округление при выполнении разделения, а затем IEEE 754 гарантирует, что вы получите максимально возможное представление.

, например, 3/5.0 представлен как:

0.10011001100110011001100110011001100110011001100110011 

Назад к десятичной, значение по умолчанию представлено 0.00000000000000002220446049250313080847263336181640625 под 3/5

Обратите внимание, что обе ошибки очень маленькие, но во втором случай 3/5.0, в четыре раза меньше по величине 0,2 + 0,2 + 0,2.

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