为什么10000000000000.126.toString()1000000000000.127(我能做些什么来阻止它)?

Koo*_*Inc 1 javascript floating-point numbers

为什么是10000000000000.126.toString()1000000000000.127而100000000000.126.toString()不是?

我认为它必须与Js中的Number的最大值有关(根据这个SO问题),但这与浮点运算有何关系?

我问,因为我写了这个函数来使用数千个分隔符格式化数字,并希望防止这种情况.

function th(n,sep) {
    sep = sep || '.';
    var dec = n.toString().split(/[,.]/),
        nArr = dec[0].split(''),
        isDot = /\./.test(sep);
    return function tt(n) {
              return n.length > 3 ?
               tt(n.slice(0,n.length-3)).concat(n.slice(n.length-3).join('')) :
               [n.join('')]
            ;
        }(nArr)
        .join(sep)
        + (dec[1] ? (isDot?',':'.') + dec[1] : '');
}
sep1000(10000000000000.126); //=> 10.000.000.000.000,127
sep1000(1000000000000.126); //=> 1.000.000.000.000,126
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 7

因为并非所有数字都可以用浮点精确表示(JavaScript使用双精度64位格式IEEE 754数字),所以会出现舍入错误.例如:

alert(0.1 + 0.2); // "0.30000000000000004"
Run Code Online (Sandbox Code Playgroud)

存储有限的所有编号系统(例如,所有编号系统)都有这个问题,但是你和我习惯于处理我们的十进制系统(它不能准确地代表"三分之一"),因此对一些不同的系统感到惊讶计算机使用的浮点格式无法准确表示的值.这就是为什么你会看到越来越多的"十进制"样式类型(Java有BigDecimal,C#decimal等等),它们使用我们的数字表示形式(代价),因此对于那些应用程序非常有用四舍五入需要更紧密地符合我们的期望(例如金融应用程序).


更新:我还没试过,但你可以通过在获取字符串之前稍微操纵值来解决这个问题.例如,这适用于您的具体示例(实时副本):

码:

function display(msg) {
  var p = document.createElement('p');
  p.innerHTML = msg;
  document.body.appendChild(p);
}

function preciseToString(num) {
  var floored = Math.floor(num),
      fraction = num - floored,
      rv,
      fractionString,
      n;

  rv = String(floored);
  n = rv.indexOf(".");
  if (n >= 0) {
    rv = rv.substring(0, n);
  }
  fractionString = String(fraction);
  if (fractionString.substring(0, 2) !== "0.") {
     return String(num); // punt
  }
  rv += "." + fractionString.substring(2);
  return rv;
}

display(preciseToString(10000000000000.126));
Run Code Online (Sandbox Code Playgroud)

结果:

10000000000000.126953125

......当然,你可以根据自己的意愿将其截断.当然,重要的是要注意到这一点10000000000000.126953125 != 10000000000000.126.但是我认为这艘船已经航行(例如,Number已经包含了一个不精确的价值),鉴于你所看到的.127.我看不出有什么方法让你知道原来只去了三个地方,而不是Number.

我并不是说上面的内容在任何方面都是可靠的,你必须真正地通过步伐来证明它(也就是说,我)没有在那里做一些stoopid.再说一遍,既然你不知道精度在哪里结束,我不确定它有多大帮助.