32,48 * 10 = 324,79999999999995 в вычислениях javascript

var quantity = $(this).find('td:eq(2) input').val()*1;
var unitprice = $(this).find('td:eq(3) input').val()*1;
var totaltax = 0;
$(this).find('td:eq(4) input[name^=taxamount]').each(function(){
    totaltax = (totaltax*1)+($(this).val()*1);
});
var subtotal = (unitprice+totaltax);
alert(subtotal+' is unit subtotal, to mulitply by '+quantity);
var total = subtotal*quantity;
$(this).find('td:last').html('$'+total);

В этом случае, основываясь на моем DOM, все результаты являются целыми числами (особенно потому, что я применяю модификатор *1 к значениям, чтобы гарантировать, что они являются числами, а не строками).

В данном случае это значения, возвращенные в первых 7 строках приведенного выше кода (и проверенные с помощью команды оповещения).

Когда я умножаю промежуточный итог*количество на итоговую переменную, общий результат: всего: 324,79999999999995

Итак, в конце я получаю td:last, заполненный на 324,79999999999995 долларов, а не на 324,80 долларов, что было бы более правильным.

Странно, я знаю. Я пробовал всевозможные предупреждения в разных точках, чтобы убедиться, что не было ошибок и т. Д.


person jeffkee    schedule 09.08.2011    source источник
comment
нет, это не странно. простая арифметика с плавающей запятой.   -  person Karoly Horvath    schedule 10.08.2011
comment
Добро пожаловать в мир арифметики с плавающей запятой.   -  person zzzzBov    schedule 10.08.2011
comment
арифметика с плавающей запятой: download.oracle.com/docs/ cd/E19957-01/806-3568/   -  person BrokenGlass    schedule 10.08.2011
comment
См. здесь   -  person bfavaretto    schedule 10.08.2011
comment
Не следует полагаться на числа с плавающей запятой для денежных расчетов. @Sparky - я думаю, что название неправильное - оно должно быть 32.48 * 10.   -  person Anurag    schedule 10.08.2011
comment
Что со всеми отрицательными голосами. Не все рождаются с врожденными знаниями о вычислениях с плавающей запятой. И Джеффки продемонстрировал, что он пытался выяснить, в чем причина проблемы, прежде чем задавать вопрос.   -  person Dunes    schedule 10.08.2011
comment
Спасибо, Дюны, если бы я был знатоком программирования, меня бы не было на этом сайте. Кроме того, это может пополнить багаж знаний. Кто знает, Google может поднять это больше. Когда я занимался поиском, он был больше связан с теоремой, и всплыли некоторые статьи с экшн-скриптами, которые не помогли. Кроме того, я не мог быть уверен, что просто округлю его вверх/вниз (что я, очевидно, знаю, как это сделать), если это все равно будет неправильным способом, поэтому я спросил.   -  person jeffkee    schedule 10.08.2011


Ответы (7)


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

Глянь сюда:

Как справиться с точностью чисел с плавающей запятой в JavaScript?

person Trevor    schedule 09.08.2011
comment
Спасибо за действительно практичное решение. Некоторым из этих парней на этом сайте нравится казаться умным с двусмысленными и снисходительными ответами, которые на самом деле не помогают мне в выполнении моей задачи и дальнейшем обучении ... - person jeffkee; 10.08.2011

Об этом спрашивали миллиард раз.

Прочтите: Что должен знать каждый специалист по информатике о вычислениях с плавающей запятой Арифметика

person Vinicius Kamakura    schedule 09.08.2011
comment
Вы собираете все свои очки репутации, ища этот вопрос, лол? - person Will03uk; 10.08.2011
comment
@ Will03uk Нет, но это возможно! Это спрашивают по крайней мере 5 раз в день :P - person Vinicius Kamakura; 10.08.2011
comment
Длинная статья, но я понял. Спасибо. Однако не помогает ответить на вопрос как. Я уже нашел что-то в этом роде, не был уверен в лучшем решении для javascript. - person jeffkee; 10.08.2011

Так работают числа с плавающей запятой. Ничего странного здесь не происходит.

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

person duffymo    schedule 09.08.2011

В этом и прелесть арифметики с плавающей запятой — некоторые десятичные числа с основанием 10 не могут быть представлены в двоичном виде.

http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

person Dunes    schedule 09.08.2011

Компьютеры не могут очень хорошо обрабатывать десятичные числа в двоичном формате, поскольку в реальной математике существует буквально бесконечное количество значений, например, между 0,01 и 0,02. Поэтому им нужно хранить приближения, и когда вы выполняете арифметические действия с этими приближениями, результаты могут немного отличаться от истинного результата.

Вы можете исправить это с помощью (Math.round(total*100)/100).toFixed(2);

person Paul    schedule 09.08.2011

Как уже упоминалось, это то, как это должно работать. Предлагаемый обходной путь можно найти ниже:

var v = "324.32999999999995";

function roundFloat(n, d) {             
    var a= Math.pow(10, d);             
    var b= Math.round(n * a) / a;
    return b;         
}

$("body").append(roundFloat(v,3));

Где v будет заменено на желаемое значение.

Вы можете просмотреть рабочий пример по адресу: http://jsfiddle.net/QZXhc/.

person RobB    schedule 09.08.2011
comment
Круто, это замечательная функция, которую можно добавить в мой фреймворк! Бесконечно благодарен. Интересно, в jQuery уже есть что-то подобное? - person jeffkee; 10.08.2011

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

person Im0rtality    schedule 09.08.2011