Так как некоторые другие уже объяснили, причина «ошибочного» округления - это проблема точности с плавающей запятой. Вы можете исследовать это, используя toExponential()
метод числа JavaScript.
(21480.905).toExponential(20)
#>"2.14809049999999988358e+4"
(21480.805).toExponential(20)
#>"2.14808050000000002910e+4"
Как вы можете видеть здесь 21480.905
, получает двойное представление, которое немного меньше 21480.905
, в то время как 21480.805
получает двойное представление, немного большее, чем исходное значение. Поскольку метод toFixed()
работает с двойным представлением и не имеет представления о вашем первоначальном предполагаемом значении, он делает все, что может и должен, с информацией, которую он имеет.
Один из способов обойти это - сдвинуть десятичную точку на необходимое вам десятичное число путем умножения, затем использовать стандарт Math.round()
, а затем снова сдвинуть десятичную точку обратно, либо делением, либо умножением на обратное значение. , Затем, наконец, мы вызываем метод toFixed()
, чтобы убедиться, что выходное значение заполнено нулями.
var x1 = 21480.905;
var x2 = -21480.705;
function round_up(x,nd)
{
var rup=Math.pow(10,nd);
var rdwn=Math.pow(10,-nd); // Or you can just use 1/rup
return (Math.round(x*rup)*rdwn).toFixed(nd)
}
function round_down(x,nd)
{
var rup=Math.pow(10,nd);
var rdwn=Math.pow(10,-nd);
return (Math.round(x*-rup)*-rdwn).toFixed(nd)
}
function round_tozero(x,nd)
{
return x>0?round_down(x,nd):round_up(x,nd)
}
console.log(x1,'up',round_up(x1,2));
console.log(x1,'down',round_down(x1,2));
console.log(x1,'to0',round_tozero(x1,2));
console.log(x2,'up',round_up(x2,2));
console.log(x2,'down',round_down(x2,2));
console.log(x2,'to0',round_tozero(x2,2));
Наконец:
Обнаружение подобной проблемы - это обычно хорошее время, чтобы сесть и долго думать о том, действительно ли вы используете правильный тип данных для вашей проблемы. Так как ошибки с плавающей запятой могут накапливаться при итеративном вычислении, и поскольку люди иногда странно чувствительны в отношении денег, магически исчезающих / появляющихся в ЦП, возможно, вам было бы лучше хранить денежные счетчики в целых «центах» (или некоторых других хорошо продуманных структура), а не с плавающей точкой «доллар».