1,265 * 10000 = 126499,99999999999?

Когда я умножаю 1.265 на 10000, я получаю 126499.99999999999 при использовании Javascript.

Почему это так?

11 ответов

Числа с плавающей точкой не могут правильно обрабатывать десятичные дроби во всех случаях. Проверять, выписываться

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

Например, 1/3 в основании 10 =.33333333333333333333333333, в то время как 1/3 в основании 3 равно.1, а в основании 2 равно.0101010101010101.

Если у вас нет полного понимания того, как работают разные базы, вот пример:

База 4 № 301.12. будет равно 3 * 4^2 + 0 * 4^1 + 1 * 4^0 + 1 * 4^-1 + 2 *4^-2= 3 * 4^2 +1+ 1 * 4^-1 + 2 * 4^-2=49,375 в базе 10.

Теперь проблемы с точностью в плавающей запятой происходят из-за ограниченного числа битов в значении. Числа с плавающей запятой состоят из 3 частей: знакового бита, экспоненты и мантиссы; скорее всего, в JavaScript используется 32 или 64-битный стандарт IEEE 754 с плавающей запятой. Для более простых вычислений мы будем использовать 32 бит, поэтому 1.265 в плавающей точке будет

Бит знака 0 (0 для положительного, 1 для отрицательного), показатель степени 0 (который со смещением 127 будет равен, т. Е. Экспонента + смещение, то есть 127 в двоичном формате без знака) 01111111 (тогда, наконец, у нас есть знаковое значение 1,265, т.е. с плавающей запятой Стандарт использует скрытое представление 1, поэтому наше двоичное представление 1.265 равно 1.01000011110101110000101, игнорируя 1:) 01000011110101110000101.

Итак, наше окончательное единственное (32-битное) представление IEEE 754 для 1.625:

Sign Bit(+)      Exponent (0)       Mantissa (1.625)
0                 01111111          01000011110101110000101

Теперь 1000 будет:

Знаковый бит (+) экспонента (9) Мантисса (1000) 0 10001000 11110100000000000000000

Теперь мы должны умножить эти два числа. Умножение с плавающей запятой состоит из повторного добавления скрытой 1 к обеим мантиссам, умножения двух мантисс, вычитания смещения из двух экспонент и последующего сложения этих двух экспонент. После этого мантисса должна снова нормализоваться.

Первый 1.01000011110101110000101*1.11110100000000000000000=10.0111100001111111111111111000100000000000000000 (это умножение - боль)

Теперь, очевидно, у нас есть показатель степени 9 + показатель степени 0, поэтому мы сохраняем 10001000 в качестве показателя степени, и наш знаковый бит остается, поэтому остается только нормализация.

Нам нужно, чтобы наша мантисса была в форме 1.000000, поэтому нам нужно один раз сместить ее вправо, что также означает, что мы должны увеличить наш показатель степени, доведя нас до 10001001, теперь, когда наша мантисса нормализована до 1.0011110000111111111111110000000000000000000000000. Он должен быть усечен до 23 бит, поэтому у нас останется 1.00111100001111111111111 (не включая 1, потому что он будет скрыт в нашем окончательном представлении), поэтому наш окончательный ответ, с которым мы остались, это

Sign Bit (+)   Exponent(10)   Mantissa
0              10001001       00111100001111111111111

Наконец, если мы переведем этот ответ обратно в десятичную, мы получим (+) 2^10 * (1+ 2^-3 + 2^-4 +2^-5+2^-6+2^-11+2^-12+2^-13+2^-14+2^-15+2^-16+2^-17+2^-18+2^-19+2^-20+2^-21+2^-22+2^-23)= +1264,99987792

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

Надеюсь это поможет.

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

С другой стороны, 126500 IS равен 126499.99999999....:)

Так же, как 1 равно 0,999999999....

Потому что 1 = 3 * 1/3 = 3 * 0,333333... = 0,999999999....

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

Чисто из-за неточностей представления с плавающей точкой.

Вы можете попробовать использовать Math.round:

var x = Math.round(1.265 * 10000);

Эти небольшие ошибки обычно вызваны точностью с плавающей запятой, используемой языком. Смотрите эту страницу википедии для получения дополнительной информации о проблемах точности с плавающей запятой.

Вы можете прочитать это.

Вот способ преодоления вашей проблемы, хотя, возможно, не очень симпатичный:

var correct = parseFloat((1.265*10000).toFixed(3));

// Here's a breakdown of the line of code:
var result = (1.265*10000);
var rounded = result.toFixed(3); // Gives a string representation with three decimals
var correct = parseFloat(rounded); // Convert string into a float 
                                   // (doesn't show decimals)

Если вам нужно решение, прекратите использовать числа с плавающей запятой или двойные числа и начните использовать BigDecimal. Проверьте реализацию BigDecimal http://stz-ida.de/html/oss/js_bigdecimal.html.en

Даже дополнения в движке MS JScript: WScript.Echo(1083.6-1023.6) дают 59.9999999

По той же причине, что 1/3 это 0,333333.....

Другие вопросы по тегам