我正在使用toFixed
方法,但是该方法并没有按照预期运行。
parseFloat(19373.315).toFixed(2);
//19373.31 Chrome
期望输出:19373.32
parseFloat(9373.315).toFixed(2);
// 9373.32 Working fine
为什么第一个例子会向下取整,而第二个例子会向上取整?
我正在使用toFixed
方法,但是该方法并没有按照预期运行。
parseFloat(19373.315).toFixed(2);
//19373.31 Chrome
期望输出:19373.32
parseFloat(9373.315).toFixed(2);
// 9373.32 Working fine
(19373.315).toFixed(4)
的结果是19373.3150,但我仍然认为这是一个错误,即使这是“预期”的或“有意的”。在转换为固定字符串时,应该使用双精度和正确的四舍五入。我认为规范甚至也是这样说的。:\ - undefinedconst 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位时,这个“1”在第一个更大的值中丢失了。
0.0022002200220022002200220022002201
。哈哈 - undefinedtoString
函数似乎又正常工作了。 - undefined假定 toFixed 转换为 32 位浮点数; 使用此实用程序进行检查...
19373.315 在 32 位浮点格式中存储为 19373.314453125(误差为 -0.000546875)。
尽管 (19373.315).toFixed(4)
的结果为 19373.3150
。
即使这是“预期的”或“意图的”,我仍会将其报告为一个错误。
应该在舍入检查过程中使用双精度浮点数,以便在转换为固定字符串时进行正确的舍入。
我认为规范甚至都这样说。:\
在 V8 JavaScript 引擎源码中,Number.prototype.toFixed
函数调用了 此文件 中的 DoubleToFixedCString
...
可能存在一些不适当的优化...(正在调查中。)
我建议提交一个V8的附加测试用例,具体是19373.315。
(19373.3150).toFixed(39)
得到的结果是19373.314999999998690327629446983337402343750。
在将其四舍五入到2位小数时,只进行了一次舍入,使其变为19373.315 - 这是正确的,但不是在正确的数字上。
我认为这里应该再进行一次舍入,以捕捉这种边缘情况。我认为可能需要先舍入到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"
export const preciseRound = (value, exp) => {
/**
* Decimal adjustment of a number.
*
* @param {String} type The type of adjustment.
* @param {Number} value The number.
* @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
* @returns {Number} The adjusted value.
*/
function decimalAdjust(type, value, exp) {
// If the exp is undefined or zero...
if (typeof exp === "undefined" || +exp === 0) {
return Math[type](value);
}
value = +value;
exp = +exp;
// If the value is not a number or the exp is not an integer...
if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
return NaN;
}
// Shift
value = value.toString().split("e");
value = Math[type](+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp)));
// Shift back
value = value.toString().split("e");
return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp));
}
// You can use floor, ceil or round
return decimalAdjust("round", value, exp);
};
console.log(preciseRound(1.005, -2)); // <= 1.01
console.log(preciseRound(1.341, -2)); // <= 1.34
console.log(preciseRound(1.01, -2)); // <= 1.01
console.log(preciseRound(33.355, -2)); // <= 33.36
toFixed
是依赖于浏览器的:https://dev59.com/J3RB5IYBdhLWcg3wn4jc. - undefined