float データ型が近似と見なされ、decimal データ型が正確と見なされる理由がわかりません。良い説明を探しています、ありがとう。
4 に答える
まあ、それはあなたの見方次第です。float
とdecimal
(C# のような型を意味すると仮定すると) は両方とも、正確な値を表します。ただし、どちらの場合も、変換(および算術演算) は、保存された値が「理論上の正確な値に最も近い値」にすぎない近似値になる可能性があります。
特に、そして重要なことに、「float
おおよその」アイデアの通常の原因は、コード内のリテラル値の変換です。
float f = 0.1f;
decimal d = 0.1m;
これらのリテラルは10 進数で表されます。また、0.1 は 2 進浮動小数点数として正確に表すことはできません。ただし、10 進浮動小数点数として正確に表すことができます。
リテラルにバイナリを使用した場合、たとえば
// Imaginary syntax - doesn't work in C#!
float f = 0b0.11f;
その場合、ここには近似値はありません。その値は、10 進数値 0.75 とまったく同じになります。
基本的に、基数 10 の数字を考えるのは人間の偏見に関するものです。片手に 3 本の指を持ち、基数 3 の値を自然に表すエイリアンの観点からは、 と の両方float
がdecimal
「近似値」になります。
(有効桁数と値の範囲に関して、C# と の間には他にも重要な違いがありますが、それは別の問題ですfloat
。)decimal
その通りです。そのような包括的な声明を出すのは誤解を招きます。完全に理解するには、2 つのことを把握する必要があります。
まず、decimal は、小数点以下の桁数が固定された (正確な) 10 進数値を格納することを目的としています。通常はお金です (たとえば、小数点以下はセントです)。これは非常に特殊な使用例です。任意の値の正確なストアではありません。これは小数点以下の桁数が固定された 10 進数値専用であり、実装はそれを正しく行うように調整されています。
第 2 に、float はより一般的なデータ型であることを意図しており、「任意の」値を格納するために使用されます。実装はそれを反映しています (したがって、たとえば、実装は幅広いスケールをカバーし、操作を可能な限り効率的にサポートすることを目的としています)。 )。特に、すべての 10 進数値を正確に表すことができない 2 進数表現を使用します。たとえば、正確に 0.5 を格納できますが、正確に 0.1 を格納することはできません。これは、使用されている 2 進数 - 基数 2 - 表現の単なる事実ですが、これは、お金に関しては、浮動小数点数は良い考えではないことを意味します: 0.10 を浮動小数点数として正確に格納できない場合、10 セントを含む計算は予想外に蓄積される可能性があります。エラー。
つまり、どちらにも制限があります。decimal が float よりも「より正確」である唯一の方法は、理解しやすいということです。それが正確に機能する値は、明確に定義され、有用であり、使用する「自然な」基数 10 表現と一致します。対照的に、基になる基数 2 の表現に依存するため、どの値が float によって正確に格納され、どの値が格納されないかを理解するのははるかに困難です。
ここですべての厄介な詳細を取得できますが、基本的にIEEE浮動小数点は、整数の仮数に2を整数乗したものとして数値を格納します。3分の1のような一部の分数は、繰り返しのない基数10の10進数として正確に表現できないのと同様に、多くの分数は2進分数として正確に表現できません。これはしばしば驚くべきことです。なぜなら、循環小数として1/3に使用されていたのに対し、直感的には1/5は0.2として簡単に表現できると期待しているのですが、2進数では、循環小数(2進数?)であり、有限数で正確に表現することはできません。ビットの。
値は、その文字列表現のdecimal
値と正確に等しく (編集: 10 進数で、Skeet が指摘しているように)、decimal
限られた桁数で 10 進数を正確に表現することもできます。一方、float
値はその文字列表現とは異なることが多く、. として正確に表現できない 10 進数 (0.1 など) が多数ありますfloat
。