2011-07-03 62 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)個十進制數字。

如果您的電話號碼包含更多數字,則會有效地損失精確度,您的示例中就是這種情況。

相關問題