我正在使用toFixed
,但该方法无法按预期运行
parseFloat(19373.315).toFixed(2);
//19373.31 Chrome
预期产出:19373.32
parseFloat(9373.315).toFixed(2);
// 9373.32 Working fine
为什么第一个例子向下舍入,而第二个例子向上舍入?
答案 0 :(得分:5)
问题是大多数小数部分的二进制浮点表示不准确。 19373.315的内部表示实际上可能类似于19373.314999999,所以固定为四舍五入,而19373.315可能是19373.315000001,这就是四舍五入。
答案 1 :(得分:1)
为什么第一个例子向下舍入,而第二个例子向上舍入?
查看内存中两个值的二进制表示。
const farr = new Float64Array(2);
farr[0] = 19373.315;
farr[1] = 9373.315;
const uarr = new Uint32Array(farr.buffer);
console.log(farr[0], uarr[1].toString(2).padStart(32, 0) + uarr[0].toString(2).padStart(32, 0));
console.log(farr[1], uarr[3].toString(2).padStart(32, 0) + uarr[2].toString(2).padStart(32, 0));

如果不深入细节,我们可以看到第二个值有一个额外的' 1'最后,当它适合64位时,它会在第一个较大的值中丢失。
答案 2 :(得分:0)
假设固定的强制转换为32位浮点数; Check with this utility...
19373.315以32位浮点格式存储为19373.314453125(错误-0.000546875)。
尽管(19373.315).toFixed(4)
19373.3150
出现了{。}}。
即使这是“预期的”或“预期的”,我仍然会将其报告为错误。
在舍入检查期间应该使用double,因此在转换为固定字符串时应该使用正确的舍入。
我认为规范甚至这么说。 :\
在V8 javascript引擎来源中,Number.prototype.toFixed
函数在this file中调用DoubleToFixedCString
...
那里可能有一些不恰当的优化......(调查一下。)
我建议专门提交additional test case for V8和19373.315。
(19373.3150).toFixed(39)
收益率19373.314999999998690327629446983337402343750。
舍入发生一次以使其达到19373.315 - 这是正确的 - 但在舍入到2位数时不是正确的数字。
我认为这应该在这里进行四舍五入以捕捉这样的边缘情况。我认为它可能需要舍入到n+1
个数字,然后再转到n
个数字。也许有其他一些聪明的方法可以解决它。
function toFixedFixed(a,n) {
return (a|0) + parseFloat((a % 1).toFixed(n+1)).toFixed(n).substr(1);
}
console.log(toFixedFixed(19373.315,2)); // "19373.32"
console.log(toFixedFixed(19373.315,3)); // "19373.315"
console.log(toFixedFixed(19373.315,4)); // "19373.3150"
console.log(toFixedFixed(19373.315,37)); // "19373.3149999999986903276294469833374023438"
console.log(toFixedFixed(19373.315,38)); // "19373.31499999999869032762944698333740234375"
console.log(toFixedFixed(19373.315,39)); // "19373.314999999998690327629446983337402343750"
(根据我对Vahid Rahmani回答的评论,谁是正确的。)
答案 3 :(得分:0)
其他答案已经解释了为什么,我建议使用像numeral.js这样的库,它会像你期望的那样对事物进行处理。