Javascript 破碎的toFixed实现

Javascript 破碎的toFixed实现,javascript,Javascript,javascript的“Number.toFixed”的默认实现似乎有点不完整 console.log((8.555).toFixed(2)); // returns 8.56 console.log((8.565).toFixed(2)); // returns 8.57 console.log((8.575).toFixed(2)); // returns 8.57 console.log((8.585).toFixed(2)); // returns 8.59 我

javascript的“Number.toFixed”的默认实现似乎有点不完整

console.log((8.555).toFixed(2));    // returns 8.56
console.log((8.565).toFixed(2));    // returns 8.57
console.log((8.575).toFixed(2));    // returns 8.57
console.log((8.585).toFixed(2));    // returns 8.59
我需要一个更加一致的舍入方法

在8.500和8.660之间的范围内,以下数字不能正确地四舍五入

8.575
8.635
8.645
8.655
我试着按照如下方式修复原型实现,但这只是实现的一半。有人能提出任何改变,使它更加一致地工作吗

Number.prototype.toFixed = function(decimalPlaces) {
    var factor = Math.pow(10, decimalPlaces || 0);
    var v = (Math.round(this * factor) / factor).toString();
    if (v.indexOf('.') >= 0) {
        return v + factor.toString().substr(v.length - v.indexOf('.'));
    }
    return v + '.' + factor.toString().substr(1);
};

这是因为浮点错误

(8.575).toFixed(20)
(8.575).toFixed(3)
进行比较,想象一下这个命题:
8.575
,其中real是一个虚函数,它可以创建一个具有无限精度的实数

也就是说,原始数字不是预期的,并且已经引入了不精确性

我能想到的一个快速的“可行方法”是:乘以1000(或视情况而定),得到
toFixed(0)
(仍然有一个限制,但很荒谬),然后以十进制形式返回


祝您编码愉快。

谢谢您的回答。我的实现几乎可以工作,但在某些情况下由于浮点错误而无法工作

我职能中的这一行是罪魁祸首: 数学四舍五入(此*因子)

(在Number.prototype上,所以“this”是数字); 8.575*100等于857.4999999999,依次向下舍入。 通过将该行更改为以下内容来纠正此问题: Math.round(Math.round(这个*因子*100)/100)

我的整个解决方案现在更改为:

Number.prototype.toFixed = function(decimalPlaces) {
    var factor = Math.pow(10, decimalPlaces || 0);
    var v = (Math.round(Math.round(this * factor * 100) / 100) / factor).toString();
    if (v.indexOf('.') >= 0) {
        return v + factor.toString().substr(v.length - v.indexOf('.'));
    }
    return v + '.' + factor.toString().substr(1);
};


也许它会帮助某些人,这是固定的流行formatMoney()函数,但有正确的舍入

Number.prototype.formatMoney = function() {
  var n = this,
  decPlaces = 2,
  decSeparator = ",",
  thouSeparator = " ",
  sign = n < 0 ? "-" : "",
  i = parseInt(n = Math.abs(+n || 0)) + "",
  j = (j = i.length) > 3 ? j % 3 : 0,
  decimals = Number(Math.round(n +'e'+ decPlaces) +'e-'+ decPlaces).toFixed(decPlaces),
  result = sign + (j ? i.substr(0, j) + thouSeparator : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thouSeparator) + (decPlaces ? decSeparator + Math.abs(decimals-i).toFixed(decPlaces).slice(2) : "");
  return result;
};

(9.245).formatMoney(); // returns 9,25
(7.5).formatMoney();   // returns 7,50
(8.575).formatMoney(); // returns 8,58
Number.prototype.formatMoney=function(){
var n=这个,
decPlaces=2,
decSeparator=“,”,
千分之一“,
符号=n<0?-:“”,
i=parseInt(n=Math.abs(+n | | 0))+“”,
j=(j=i.length)>3?j%3:0,
小数=数字(数学四舍五入(n+'e'+小数点)+'e-'+小数点)。固定(小数点),
结果=符号+(j?i.substr(0,j)+千分位数:)+i.substr(j)。替换(/(\d{3})(?=\d)/g,“$1”+千分位数)+(小数点?小数点分隔符+数学.abs(小数点-i)。固定(小数点)。切片(2):”;
返回结果;
};
(9.245).格式货币();//返回9,25
(7.5).格式货币();//返回7,50
(8.575).格式货币();//返回8,58

一致的解决方案是在四舍五入之前为每个数字添加一个固定公差(ε)。它应该很小,但不能太小

例如,对于
eps=1e-9
,这:

console.log((8.555).toFixed(2));    // returns 8.56
console.log((8.565).toFixed(2));    // returns 8.57
console.log((8.575).toFixed(2));    // returns 8.57
console.log((8.585).toFixed(2));    // returns 8.59
变成这样:

console.log((8.555 + eps).toFixed(2));    // returns 8.56
console.log((8.565 + eps).toFixed(2));    // returns 8.57
console.log((8.575 + eps).toFixed(2));    // returns 8.58
console.log((8.585 + eps).toFixed(2));    // returns 8.59

我可以想象这是一个浮点精度错误。类似?这可能与浮点问题有关,我刚刚在Chromium V12.0上尝试了上面的示例,得到了以下结果:8.55 8.56 8.57 8.59。因此,您的里程可能会因JavaScript实现的不同而有所不同。为什么不使用由修改的Mozilla实现呢?这是一个单行程序,实际上是在其中一个答案中建议的。当然,我不能在重写同一个函数时使用“toFixed”。我不得不坚持使用“数学圆”,但你的回答为我指明了正确的方向。Ty@Joshua:是的,你可以。只需将toFixed`的一个副本存储在一个变量中,然后
apply()。
console.log((8.555 + eps).toFixed(2));    // returns 8.56
console.log((8.565 + eps).toFixed(2));    // returns 8.57
console.log((8.575 + eps).toFixed(2));    // returns 8.58
console.log((8.585 + eps).toFixed(2));    // returns 8.59