Правильно ли округлить javascript с точностью до двух знаков после запятой? - PullRequest
9 голосов
/ 21 июня 2010

В php у нас есть number_format(). Передав ему значение, например:

number_format(3.00 * 0.175, 2);

возвращает 0,53 , что я и ожидал.

Однако в JavaScript используется toFixed()

var num = 3.00 * 0.175;
num.toFixed(2);

возвращает 0,52 .

Хорошо, так что, возможно, toFixed не то, что я хочу ... Может быть, что-то вроде этого ...

var num = 3.17 * 0.175;
var dec = 2;
Math.round( Math.round( num * Math.pow( 10, dec + 1 ) ) / Math.pow( 10, 1 ) ) / Math.pow(10,dec);

Нет, это тоже не работает. Он вернется 0,56.

Как я могу получить number_format функцию в JavaScript, которая не дает неправильный ответ?

На самом деле я нашел реализацию number_format для js, http://phpjs.org/functions/number_format,, но она страдает от той же проблемы.

Что здесь происходит с округлением JavaScript? Чего мне не хватает?

Ответы [ 6 ]

12 голосов
/ 21 июня 2010

JavaScript плохо работает с числами с плавающей запятой (как и многие другие языки).

Когда я запускаю

3.000 * 0.175

В моем браузере я получаю

0.5249999999999999

Который не округляется до 0,525 с Math.round.Чтобы обойти это, вам нужно как-то умножить обе стороны до тех пор, пока они не станут целыми числами (это сравнительно легко, хотя знание некоторых хитростей поможет).

Поэтому для этого мы можем сказать что-то вроде этого:

function money_multiply (a, b) {
    var log_10 = function (c) { return Math.log(c) / Math.log(10); },
        ten_e  = function (d) { return Math.pow(10, d); },
        pow_10 = -Math.floor(Math.min(log_10(a), log_10(b))) + 1;
    return ((a * ten_e(pow_10)) * (b * ten_e(pow_10))) / ten_e(pow_10 * 2);
}

Это может показаться странным, но вот псевдокод:

get the lowest power of 10 of the arguments (with log(base 10))
add 1 to make positive powers of ten (covert to integers)
multiply
divide by conversion factor (to get original quantities)

Надеюсь, это то, что вы ищете.Вот пример прогона:

3.000 * 0.175
0.5249999999999999

money_multiply(3.000, 0.175);
0.525
3 голосов
/ 02 мая 2014

Почему все полномочия ??Почему бы просто не добавить немного less than 1/2 a cent и round:

(3.00 * 0.175 + 0.0049).toFixed(2)

Никогда еще бухгалтеры не жаловались на результат.

3 голосов
/ 21 июня 2010

Функция toFixed работает правильно. Усекает указанное количество цифр дроби.

1 голос
/ 21 июня 2010

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

Используя консоль firebug для тестирования, протоколируйте результат 3.00 * 0.175 с учетом 0.524999.... Таким образом, округление этого числа на самом деле правильно.

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

0 голосов
/ 06 августа 2013

Я знаю, что это старо, но так я обычно решаю проблему округления.Это можно легко вставить в функцию, но сейчас я просто добавлю простые переменные.Если это не работает, вы можете использовать money_format () или number_format () в качестве начала из php.js (более подробная информация ниже).

var n = (3.00 * 0.175);
n = Math.round(n * Math.pow(10, 3)) / Math.pow(10, 3);
Math.round(n*100)/100;

выходит на 0,53 (0,5249999999999999)

var n = (3.00 * 0.175);
n = Math.round(n * Math.pow(10, 3)) / Math.pow(10, 3);
Math.round(n*100)/100;

выходит на 0,56 (0,55475)

Похоже, что репо php.js сохраняетсяна GitHub https://github.com/kvz/phpjs, поэтому, если нет функции, которая не работает правильно, проблема может быть отправлена.

В любом случае, эта информация может помочь кому-то заглянуть позже.

0 голосов
/ 21 июня 2010

Почему вы просто не использовали Math.round( num * Math.pow( 10, dec ) ) / Math.pow( 10, dec) )?

РЕДАКТИРОВАТЬ: я вижу, проблема в том, что 3 * 0,175 дает вам 0,52499999999999991, что заставляет вас хотеть дополнительный шаг округления.Может быть, просто добавление небольшого количества будет работать:

Math.round( num * Math.pow( 10, dec ) + 0.000000001 ) / Math.pow( 10, dec) )

...