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

发布于 2024-11-18 09:25:33 字数 931 浏览 1 评论 0原文

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

我认为它一定与 Js 中数字的最大值有关(根据 这个问题),但这与浮点运算有关吗?如何?

我这么问是因为我编写了这个函数来使用千位分隔符格式化数字,并且希望防止这种情况发生。

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

Why is 10000000000000.126.toString() 1000000000000.127 and 100000000000.126.toString() not?

I think it must have something to do with the maximum value of a Number in Js (as per this SO question), but is that related to floating point operations and how?

I'm asking because I wrote this function to format a number using thousands separators and would like to prevent this.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小猫一只 2024-11-25 09:25:33

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

alert(0.1 + 0.2); // "0.30000000000000004"

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


更新:我没有尝试过,但您可以通过在获取字符串之前稍微操作一下值来解决此问题。例如,这适用于您的特定示例(live copy):

代码:

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));

结果:

10000000000000.126953125

...然后可以,当然,可以根据您的需要进行截断。当然,需要注意的是 10000000000000.126953125 != 10000000000000.126。但鉴于您看到的是 .127,我认为该船已经启航(例如,Number 已包含不精确的值)。我看不出有什么办法让你知道原件只去了三个地方,而不是 Number

我并不是说上面的内容在任何方面都是可靠的,你必须真正通过实践来证明它是可靠的(也就是说,我是)不在那里做一些愚蠢的事情。再说一次,由于您不知道精度最初在哪里,所以我不确定它有多大帮助。

Because not all numbers can be exactly represented with floating point (JavaScript uses double-precision 64-bit format IEEE 754 numbers), rounding errors come in. For instance:

alert(0.1 + 0.2); // "0.30000000000000004"

All numbering systems with limited storage (e.g., all numbering systems) have this issue, but you and I are used to dealing with our decimal system (which can't accurately represent "one third") and so are surprised by some of the different values that the floating-point formats used by computers can't accurately represent. This sort of thing is why you're seeing more and more "decimal" style types out there (Java has BigDecimal, C# has decimal, etc.), which use our style of number representation (at a cost) and so are useful for applications where rounding needs to align with our expectations more closely (such as financial apps).


Update: I haven't tried, but you may be able to work around this by manipulating the values a bit before you grab their strings. For instance, this works with your specific example (live copy):

Code:

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));

Result:

10000000000000.126953125

...which then can, of course, be truncated as you see fit. Of course, it's important to note that 10000000000000.126953125 != 10000000000000.126. But I think that ship had already sailed (e.g., the Number already contained an imprecise value), given that you were seeing .127. I can't see any way for you to know that the original went to only three places, not with Number.

I'm not saying the above is in any way reliable, you'd have to really put it through paces to prove it's (which is to say, I'm) not doing something stoopid there. And again, since you don't know where the precision ended in the first place, I'm not sure how helpful it is.

谁的新欢旧爱 2024-11-25 09:25:33

它是关于浮点数可以存储的有效十进制数字的最大数量。

如果您查看http://en.wikipedia.org/wiki/IEEE_754-2008您可以看到,双精度浮点数 (binary64) 可以存储大约 16 (15.95) 位十进制数字。

如果您的数字包含更多数字,您实际上会失去精度,您的示例就是这种情况。

It's about the maximum number of significant decimal digits a float can store.

If you look at http://en.wikipedia.org/wiki/IEEE_754-2008 you can see that a double precision float (binary64) can store about 16 (15.95) decimal digits.

If your number contains more digits you effectively lose precision, which is the case in your sample.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文