2011-07-03 44 views
1

为什么10000000000000.126.toString() 1000000000000.127和100000000000.126.toString()不是?为什么10000000000000.126.toString()1000000000000.127(以及我能做些什么来防止它)?

我认为它必须与Js中一个数字的最大值有关(按照this SO question),但是这与浮点运算有关吗?

我在问,因为我写了这个函数来使用数千个分隔符来格式化一个数字,并且想要阻止这个。

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 
+3

这是因为我们的老朋友浮点精度。 – deceze

+1

[为什么C浮点类型修改输出的实际输入125.1到125.099998?](http://stackoverflow.com/questions/6532502/why-does-ac-floating-point-type-modify - 实际输入125-1至125-099998-o)和**许多其他** – Alnitak

+0

@Alnitak,我知道,但另外我正在寻找一种方法来防止它。我仍然在寻找相关的答案,真的。 – KooiInc

回答

7

因为不是所有的数字可以精确地用浮点来表示(JavaScript使用双精度64位格式的IEEE 754号),舍入误差进来。比如:

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

所有编号有限存储的系统(例如所有的编号系统)都有这个问题,但你和我习惯于处理我们的十进制系统(它不能准确表示“三分之一”),所以对于一些不同的值计算机使用的浮点格式无法准确表示。这种事情就是为什么你会看到越来越多的“小数”风格类型(Java有BigDecimal,C#有decimal等),它们使用我们的数字表示风格(有代价),所以对于四舍五入需要更紧密地与我们的期望相一致的应用程序(如金融应用程序)。


更新:我还没有尝试过,但你可以通过你抢他们的字符串操作前值的位来解决这一点。例如,这与您的具体的例子(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。但是我认为那艘船已经航行了(例如,Number已经包含一个不准确的值),因为你看到了.127。我看不出有什么办法让你知道原来只有三个地方,而不是Number

我不是说上面是以任何方式可靠的,你要真把它通过的步伐,以证明它的(这是说,我)没有做什么stoopid那里。再说一次,既然你不知道精度在哪里结束,我不知道它有多大的帮助。

+0

这个问题的答案真的应该去社区维基... – Alnitak

+0

谢谢T.J.,我会去你的答案。一直在修改你的(和其他代码),很难在结果字符串中显示“.126”部分。嗯,我认为这不是真正的生活问题,但这是一个有趣的练习。 – KooiInc

+1

这不是一个二进制/十进制问题。这是一个试图将17位有效数字放在仅提供大约16位的类型中的问题。 – dan04

2

这是关于float可以存储的最大有效小数位数的最大值。

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

如果您的电话号码包含更多数字,则会有效地损失精确度,您的示例中就是这种情况。

相关问题