2011-07-03 17 views
1

10000000000000.126.toString() 1000000000000.127と100000000000.126.toString()はなぜですか?なぜ10000000000000.126.toString()が1000000000000.127(そしてそれを防ぐために何ができますか)ですか?

私はJsの数値の最大値と何か関係があると思いますが(this SO question)、それは浮動小数点演算に関連していますか?

私は桁区切り文字を使用して数値をフォーマットするためにこの関数を書いたので、これを避けたいと思っています。

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

全て番号:すべての数値が正確に浮動小数点で表現することができないので

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の番号を使用します)限られた記憶容量を持つシステム(すべてのナンバリングシステムなど)ではこの問題がありますが、あなたと私は十進数システム(「1/3」を正確に表すことはできません)を扱うことに慣れています。コンピュータで使用される浮動小数点形式は正確に表現できません。この種のことは、数字表現のスタイルを(コストで)使っているので、そこにはより多くの「十進」スタイルタイプ(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に注意することが重要です。しかし、あなたは.127が見えていたので、すでに船が航行していたと思います(例えば、Numberに不正確な値が入っていたと思います)。 Numberではなく、オリジナルが3つの場所にしか流れていないことを知る方法はありません。

私はどのような方法信頼性にある以上、あなたがそこにSTOOPID何かをやっていない、本当にそれは(私は、と言うことです)です証明するためにペースを介してそれを置く必要があるだろうとは言いませんよ。また、精度が最初にどこで終了したのかわからないので、どの程度役立つのか分かりません。

+0

この質問への回答は本当にありがとうコミュニティWiki ... – Alnitak

+0

ありがとうT.J.、私はあなたの答えのために行くでしょう。あなたのコード(と他のコード)を手直ししていて、結果の文字列に '.126'の部分を表示するのは驚くほど難しいです。ああ、それはほとんどが私が言っている本当の人生の問題ではありませんが、それは面白い運動です。 – KooiInc

+1

これはバイナリ/小数点の問題ではありません。それは約16文字しか提供しないタイプに17桁の有効数字を入れようとする問題です。 – dan04

2

これは、floatが格納できる重要な10進数の最大数です。

http://en.wikipedia.org/wiki/IEEE_754-2008を見ると、倍精度浮動小数点(binary64)に約16(15.95)の10進数を格納できることがわかります。

数字に数字が含まれている場合は、サンプルの大文字と小文字が区別されます。

関連する問題