2011-09-17 18 views
26

私は二重の"138630.78380386264"を持っていますが、小数点に変換したいのですが、キャストするか、Convert.ToDecimal()を使用して精度を失います。C#二倍から十進精度の損失

何が起こっているのですか?小数とダブルの両方がこの番号を保持することができます:

また

enter image description here

double doub = double.Parse("138630.78380386264"); 
decimal dec = decimal.Parse("138630.78380386264"); 
string decs = dec.ToString("F17"); 
string doubse =DoubleConverter.ToExactString(doub); 
string doubs = doub.ToString("F17"); 

decimal decC = (decimal) doub; 
string doudeccs = decC.ToString("F17"); 
decimal decConv = Convert.ToDecimal(doub); 
string doudecs = decConv.ToString("F17"); 

:どのように私は、二重のToString()は、デバッガが示すように、同じ結果をプリントアウトして入手できますか?例えば138630.78380386264

+0

[C#の10進数から2倍数への変換では差が生じる](http://stackoverflow.com/questions/1584314/conversion-of-a-decimal-to-double-number-in- c-results-in-a-difference) –

+1

Well Convert.ToDecimal(somedouble)はsomedouble(10進)と正確に等しいので、そこに驚きはありません。なぜ私はそのキャストが最後の数字を下に丸めるのか分からない。 – harold

+0

@haroldあなたはだまされました。それは最も近いものに丸めます。 double値は386264で終了し、15小文字の小数点は3863で終わります。 –

答えて

23

138630.78380386264は、倍精度で正確に表現できません。最も近い倍精度の数値(hereが見つかりました)は138630.783803862635977566242218017578125です。これはあなたの発見と一致します。

小数点への変換に精度が含まれない理由を尋ねます。 documentation for Convert.ToDecimal()は答えを持っています:

このメソッドから返されるDecimal値には、最大15桁の有効数字が含まれています。 valueパラメータに15桁以上の有効桁が含まれている場合、最も近い値に丸めて丸めます。次の例は、Convert.ToDecimal(Double)メソッドが四捨五入を使用して15桁の有効数字を持つDecimal値を返す方法を示しています。

15桁の有効数字に最も近い値に丸められたdouble値は、上記のとおり正確に138630.783803863です。

+0

なぜ小数点への変換で精度が上がりませんか? – GreyCloud

+0

これを説明してくれてありがとうございます。 ToStringを15以上のSig figを印刷するようにするにはどうしてですか? - 私は元の文字列に戻ることができるようにしたい - その方法は、文字列を解析して精度を失うことなく変換を行うようにDoubleを得ることができる。 – GreyCloud

+0

'doub.ToString(" G17 ")'は同じ文字列を与えるデバッガが生成します。しかし、私はデバッガが何をしているのかは分かりません。 'double'は精度が限られているので、一般的に文字列を解析して元の文字列を返すことはできません。元の文字列を知る必要がある場合は、それを覚えておいてください。 –

4

残念です、と思います。 139,000付近でDecimalの精度はDoubleよりはるかに優れています。しかし、依然としてこの問題のために、とは異なるDoubleと同じDecimalに投影されています。実際には例えば

double doub1 = 138630.7838038626; 
double doub2 = 138630.7838038628; 
Console.WriteLine(doub1 < doub2);     // true, values differ as doubles 
Console.WriteLine((decimal)doub1 < (decimal)doub2); // false, values projected onto same decimal 

そこ異なる表現Doubledoub1間及び上記doub2があるので、それらは同じではありません。ここ

は幾分愚かワークaronudある:

static decimal PreciseConvert(double doub) 
{ 
    // Handle infinities and NaN-s first (throw exception) 
    // Otherwise: 
    return Decimal.Parse(doub.ToString("R"), NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint); 
} 

"R"書式文字列は、十分に余分な数字は(Decimalは、優れた精度を持つドメイン内の)マッピング単射を作るために含まれていることを保証します。一部の範囲で、longInt64)はDoubleのものよりも優れている精度を有すること


注意。そこで、ここでのコンバージョンが同じ方法で行われたかどうかを確認しました(最初は小数点以下15桁まで四捨五入されています)。ではない!だから、:

double doub3 = 1.386307838038626e18; 
double doub4 = 1.386307838038628e18; 

Console.WriteLine(doub3 < doub4);    // true, values differ as doubles 
Console.WriteLine((long)doub3 < (long)doub4); // true, full precision of double used when converting to long 

ターゲットがdecimalあるときに別の「ルール」を使用して一貫性のないようです。

(decimal)(long)doub3は、(decimal)doub3よりも正確な結果を生成することに注意してください。

+0

問題は、139,000に近い数値ではありません。倍精度の精度は16桁であるため、この数値を減らすと、桁がセパレータの左側または右側にあるかどうかは関係ありません13.86307838038626に同じ問題があります。小数点以下の桁数は32桁ですので、この問題は発生しません。 –

+0

@ GabrielVonlantenC.Lopesこの問題は正しいですか139,000に近い数値に特有のものではありません。私はその番号を例として考えました。なぜなら、それは元の質問の数字だったからです。実際、(非常におおよそ) '1e-12'と' 1e + 29'の間の数字はまったく同じ問題を抱えています。この範囲外では、 'decimal'は定義されていないか、' double'よりも精度が高くありません。 (ただし、 'decimal'の精度は28-29桁です)。 –