web-dev-qa-db-ja.com

10進数の代わりにdoubleを使用する必要があるのはいつですか?

doubleの代わりにfloat(またはdecimal)を使用する3つの利点を挙げることができます。

  1. より少ないメモリを使用します。
  2. プロセッサが浮動小数点演算をネイティブでサポートしているため、高速です。
  3. より広い範囲の数値を表すことができます。

しかし、これらの利点は、モデリングソフトウェアに見られるような計算集約的な操作にのみ適用されるようです。もちろん、財務計算などの精度が必要な場合は、doubleを使用しないでください。 「通常の」アプリケーションでdoubleの代わりにfloat(またはdecimal)を選択する実際的な理由はありますか?

追加して編集:すばらしい回答をありがとう、私は彼らから学んだ。

もう1つの質問:数人は、doubleが実数をより正確に表すことができると主張しました。宣言されたとき、私は彼らが通常より正確にそれらを表すと思うでしょう。しかし、浮動小数点演算を実行すると、精度が(場合によっては大幅に)低下する可能性があるというのは本当ですか?

255
Jamie Ide

利点を非常によくまとめたと思います。ただし、1つのポイントが欠落しています。 decimal タイプは、基数10の数値(通貨/財務計算で使用される数値など)の表現においてのみより正確です。一般的に、 double タイプは、少なくとも同等の精度(私が間違っていれば誰かが私を修正します)と、任意の実数に対して間違いなく高速を提供します。簡単な結論は、どちらを使用するかを検討するときは、doubleが提供するbase 10精度が必要でない限り、常にdecimalを使用してください。

編集:

演算後の浮動小数点数の精度の低下に関する追加の質問については、これはわずかに微妙な問題です。実際、各操作が実行されると、精度(ここでは正確さを表す用語として同じ意味で使用します)は着実に低下します。これには2つの理由があります。

  1. 特定の数(最も明らかに10進数)を浮動小数点形式で真に表現できないという事実
  2. 手で計算を行っているかのように、丸め誤差が発生します。ただし、これらのエラーが多くの思考を正当化するほど重要であるかどうかは、コンテキスト(実行する操作の数)に大きく依存します。

いずれの場合も、理論上同等である(ただし異なる計算を使用して到達した)2つの浮動小数点数を比較する場合は、ある程度の許容差(許容範囲は異なりますが、通常は非常に小さい)を許可する必要があります。

精度のエラーが発生する可能性がある特定のケースのより詳細な概要については、 Wikipediaの記事 の「精度」セクションを参照してください。最後に、マシンレベルでの浮動小数点数/操作の詳細な(および数学的な)議論が必要な場合は、よく引用される記事を読んでみてください すべてのコンピューター科学者が知っておくべきこと浮動小数点演算について

298
Noldorin

あなたは、浮動小数点型を使用する利点にスポットを当てているようです。私はすべての場合に小数用に設計する傾向があり、プロファイラーを使用して、小数に対する操作がボトルネックまたはスローダウンを引き起こしているかどうかを知らせてくれます。これらの場合、私はdoubleまたはfloatに「ダウンキャスト」しますが、内部でのみ行い、実行される数学演算の有効桁数を制限することで精度の損失を慎重に管理しようとします。

一般に、値が一時的な(再利用されない)場合、浮動小数点型を使用しても安全です。浮動小数点型の実際の問題は、次の3つのシナリオです。

  1. 浮動小数点値を集計しています(この場合、精度エラーは悪化します)
  2. 浮動小数点値に基づいて値を構築します(たとえば、再帰アルゴリズムで)
  3. 非常に多くの有効数字を使用して数学を実行しています(たとえば、123456789.1 * .000000000000000987654321

編集

C#10進数のリファレンスドキュメント によると:

decimalキーワードは、128ビットのデータ型を示します。浮動小数点型と比較して、decimal型は精度が高く範囲が狭いため、財務計算および通貨計算に適しています。

私の上記の声明を明確にするために:

私はすべての場合に小数用に設計する傾向があり、プロファイラーを使用して、小数に対する操作がボトルネックまたはスローダウンを引き起こしているかどうかを知らせてくれます。

小数が有利な業界でしか働いたことがない。物理学やグラフィックエンジンで作業している場合は、おそらく浮動小数点型(floatまたはdouble)用に設計する方がはるかに有益です。

10進数は無限に正確ではありません(プリミティブデータ型の非整数に対して無限の精度を表すことは不可能です)が、2倍よりはるかに正確です。

  • 10進数= 28-29有効数字
  • double =有効桁数15-16
  • float = 7有効数字

EDIT 2

Konrad Rudolph のコメントに対して、アイテム#1(上記)は間違いなく正しいです。不正確さの集約は確かに複雑になります。例については、以下のコードを参照してください。

private const float THREE_FIFTHS = 3f / 5f;
private const int ONE_MILLION = 1000000;

public static void Main(string[] args)
{
    Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"));
    float asSingle = 0f;
    double asDouble = 0d;
    decimal asDecimal = 0M;

    for (int i = 0; i < ONE_MILLION; i++)
    {
        asSingle += THREE_FIFTHS;
        asDouble += THREE_FIFTHS;
        asDecimal += (decimal) THREE_FIFTHS;
    }
    Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION);
    Console.WriteLine("Single: {0}", asSingle.ToString("F10"));
    Console.WriteLine("Double: {0}", asDouble.ToString("F10"));
    Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"));
    Console.ReadLine();
}

これにより、次が出力されます。

Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 599999.9999886850
Decimal: 600000.0000000000

ご覧のとおり、同じソース定数から加算しているにもかかわらず、doubleの結果は精度が低く(おそらく正しく丸められますが)、floatの精度ははるかに低く、それだけに減少します。有効数字2桁。

56
Michael Meadows

基数10の値には10進数を使用します(例:他の人が示唆しているように、財務計算。

ただし、doubleは一般に、任意の計算値に対してより正確です。

たとえば、ポートフォリオの各ラインのウェイトを計算する場合は、結果がほぼ100%になるため、doubleを使用します。

次の例では、doubleResultはdecimalResultより1に近いです。

// Add one third + one third + one third with decimal
decimal decimalValue = 1M / 3M;
decimal decimalResult = decimalValue + decimalValue + decimalValue;
// Add one third + one third + one third with double
double doubleValue = 1D / 3D;
double doubleResult = doubleValue + doubleValue + doubleValue;

ポートフォリオの例をもう一度見てみましょう。

  • ポートフォリオの各行の市場価値は金銭的価値であり、おそらく小数で表すのが最適です。

  • ポートフォリオの各行の重み(=市場価値/ SUM(市場価値))は、通常、倍精度で表されます。

24
Joe

精度が必要でない場合は、doubleまたはfloatを使用します。たとえば、私が書いたプラットフォーマーゲームでは、プレーヤーの速度を格納するためにfloatを使用しました。明らかに、画面に描画するために最終的にIntに丸めるため、ここでは超精密を必要としません。

6
FlySwat

一部のアカウンティングでは、代わりにまたは組み合わせて整数型を使用する可能性を考慮してください。たとえば、操作対象のルールでは、すべての計算結果が少なくとも小数点以下6桁で繰り越され、最終結果は最も近いペニーに丸められることを要求するとします。

$ 100の1/6の計算では$ 16.66666666666666 ...が得られるため、ワークシートで実行される値は$ 16.666667になります。 doubleとdecimalの両方で、結果を小数点以下6桁まで正確に生成する必要があります。ただし、整数16666667として結果を繰り越すことにより、累積エラーを回避できます。後続の各計算は同じ精度で行い、同様に繰り越すことができます。例を続けて、その金額に対してテキサス州の消費税を計算します(16666667 * .0825 = 1375000)。 2つを追加する(短いワークシート)1666667 + 1375000 =18041667。小数点を戻すと18.041667、つまり$ 18.04になります。

この短い例では、doubleまたはdecimalを使用した累積エラーは発生しませんが、単にdoubleまたはdecimalを計算して繰り越すだけで重大なエラーが累積する場合を示すのは非常に簡単です。あなたが操作する規則が限られた小数点以下の桁数を必要とする場合、10 ^(小数点以下の桁数が必要)を掛けて整数として各値を保存し、10 ^(小数点以下の桁数が必要)を除して実際の値を取得します値は累積エラーを回避します。

ペニーの端数が発生しない状況(自動販売機など)では、非整数型を使用する理由はまったくありません。単にドルではなくペニーを数えると考えてください。私はすべての計算がペニー全体のみを含むコードを見てきましたが、ダブルの使用はエラーにつながりました!整数のみの計算で問題が解決しました。したがって、私の型にはまらない答えは、可能であれば、2進数と10進数の両方を控えることです。

4
G DeMasters

他の言語またはプラットフォームとバイナリインターロップする必要がある場合は、標準化されているfloatまたはdoubleを使用する必要があります。

3
Will Dean

注:この投稿は、 http://csharpindepth.com/Articles/General/Decimal.aspx からのdecimal型の機能に関する情報と、それが何を意味するかについての私自身の解釈に基づいています。 Doubleは通常のIEEE倍精度であると仮定します。

注2:この投稿の最小値と最大値は、数値の大きさを示しています。

「10進数」の長所。

  • 「10進数」は、(十分に短い)10進数の小数として書くことができる正確な数を表すことができますが、2倍はできません。これは、財務元帳で重要であり、計算を行う人間の結果が正確に一致することが重要な場合も同様です。
  • 「10進数」には、「二重」よりもはるかに大きい仮数があります。つまり、正規化された範囲内の値の場合、「10進数」の精度は2倍よりもはるかに高くなります。

小数の短所

  • それははるかに遅くなります(ベンチマークはありませんが、少なくとも1桁以上かもしれません)、10進数はハードウェアアクセラレーションの恩恵を受けず、その計算は10の累乗による比較的高価な乗算/除算を必要とします(これは、2の累乗による乗算および除算よりもはるかに高価であり、加算/減算前に指数を一致させ、乗算/除算後に指数を範囲内に戻すためです。
  • 10進数は、2桁より早くオーバーフローします。小数は最大±2までの数しか表現できません96-1比較により、doubleは最大±2近くの数値を表すことができます1024
  • 小数はより早くアンダーフローします。 10進数で表現できる最小の数値は±10です-28 。比較により、doubleは2までの値を表すことができます-149 (約10-45)subnromal番号がサポートされ、2-126 (約10-38)そうでない場合。
  • decimalはdoubleの2倍のメモリを占有します。

私の意見では、お金の仕事や人間の計算を正確に一致させることが重要な他の場合には「10進数」をデフォルトで使用し、残りはデフォルトの選択肢としてdoubleを使用する必要があります。

2
plugwash

アプリケーションの機能のタイプを選択します。財務分析のように精度が必要な場合は、質問に答えています。ただし、アプリケーションが見積りで解決できる場合は、ダブルで大丈夫です。

あなたのアプリケーションは高速な計算を必要としていますか、それとも彼はあなたに答えを与えるために世界中で常に時間を費やすでしょうか?本当にアプリケーションの種類に依存します。

空腹のグラフィック? floatまたはdoubleで十分です。金融データ分析、流星は惑星のような精度を打ちますか?それらには少し精度が必要です:)

0
Khan

Double値は、その表記法が10進表示より短い場合、デフォルトで科学表記法にシリアル化されます。 (たとえば、.00000003は3e-8になります)10進値は科学表記法にシリアル化されることはありません。外部パーティが消費するためにシリアル化する場合、これは考慮事項です。

0
chris klassen

Decimalのバイト数は広く、doubleはCPUによってネイティブにサポートされています。 10進数は10進数ですので、10進数の計算中に10進数から2倍への変換が行われます。

For accounting - decimal
For finance - double
For heavy computation - double

.NET CLRはMath.Pow(double、double)のみをサポートすることに注意してください。 10進数はサポートされていません。

.NET Framework 4

[SecuritySafeCritical]
public static extern double Pow(double x, double y);
0
Jeson Martajaya

必要なものに依存します。

Floatとdoubleはバイナリデータ型であるため 一部 ラウンド数の点で困難とエラーがあるため、たとえば、doubleは0.1から0.100000001490116に丸められ、doubleは1/3から0.33333334326441に丸められます。単純に、すべての実数がdouble型で正確に表現されるわけではありません

幸いなことに、C#は、いわゆる10進浮動小数点演算もサポートしています。ここでは、数値はバイナリシステムではなく10進数システムで表されます。したがって、10進浮動小数点演算 精度を失わない 浮動小数点数を保存および処理するとき。これにより、高レベルの精度が必要な計算に非常に適しています。

0
Neil Meyer

正確さよりもパフォーマンスを重視する場合は、浮動小数点を使用してください。

0
Mark Brackett