JavaScript, правильно окружающий к двум десятичным числам, невозможным?

В 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.

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

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

Что продолжается здесь окружающий JavaScript? Что я пропускаю?

10
задан Paul D. Waite 22 June 2010 в 00:19
поделиться

4 ответа

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
13
ответ дан 3 December 2019 в 19:31
поделиться

Почему вы просто не использовали 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))

0
ответ дан 3 December 2019 в 19:31
поделиться

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

3
ответ дан 3 December 2019 в 19:31
поделиться

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

Использование консоли firebug для тестирования, запись результата 3,00 * 0,175 при 0,524999 ... . Так что округление этого числа в меньшую сторону действительно правильно.

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

1
ответ дан 3 December 2019 в 19:31
поделиться