あなたは、浮動小数点数に固有の不正確さが存在すると主張します。これは最初に少し検討する価値があると思います。
数字システム を決定する場合 数字を表すために(紙、コンピューター回路、またはその他の場所で)、2つの別々の 考慮すべき問題:
-
その基本;および
-
そのフォーマット 。
ベースを選んでください、任意のベース…
有限のスペースによって制限されるため、無限集合
の任意のメンバーを表すことはできません。 。 例:購入する紙の量や手書きの小ささに関係なく、指定されたスペースに収まらない整数を見つけることは常に可能です(紙がなくなるまで余分な数字を追加し続けることができます)。つまり、整数 、通常、有限空間を特定の間隔内にあるものだけを表すように制限します。正/負の符号と3桁のスペースがある場合は、[-999,+999]
の間隔に制限することができます。 。
すべて 空でない[-999,+999]
、[0,1]
、[0.000001,0.000002]
または他の何か—その間隔内にはまだ無限の実数のセットがあります(1つは(ゼロ以外の)小数桁を追加し続ける必要があるだけです)!したがって、任意の実数は常に できるものに「丸める」 有限の空間で表現されます。
有限空間で表すことができる実数のセットは、使用される記数法によって異なります。 私たちの(おなじみの)位置
base-10
システムでは、半分は有限のスペースで十分です( 0.510
)ただし、3分の1ではありません( 0.33333…10
);対照的に、(あまり馴染みのない)位置では base-9
システムの場合は逆です(これらの同じ番号はそれぞれ0.44444…9
および0.39
)。これらすべての結果として、10進数の位置にわずかなスペースを使用して表すことができる(したがって表示される)いくつかの数値があります。 私たち人間にとって非常に「丸い」こと)、例えば10分の1は、実際には無限のバイナリ回路を正確に格納する必要があります(したがって、デジタルの友人にはあまり「丸い」ようには見えません)。特に、2は10の因数であるため、逆の場合は同じではありません。有限の2進数で表すことができる数値は、有限の10進数でも表すことができます。
継続的な量に対してこれ以上のことはできません。 最終的に、そのような量は一部で有限表現を使用する必要があります 記数法:そのシステムがコンピュータ回路、人間の指、他の何か、またはまったく何もない状態で簡単に使用できるかどうかは任意です。どのシステムを使用する場合でも、値は必須 丸められるため、常に 「表現エラー」が発生します。
言い換えれば、完全に正確な測定器を持っていても(物理的に不可能です)、それが報告する測定値はすべて、すでに丸められています。 たまたまそのディスプレイに収まる数になります(使用する基数が何であれ、明白な理由から、通常は10進数です)。したがって、「86.2オンス」が実際に「86.2オンス」になることはありません。 "ではなく、" 86.1500000...ozと86.2499999...ozの間の何かの表現 "。(実際には、楽器は不完全であるため、実際に言えることは、信頼度 実際の値はその間隔内にありますが、それは間違いなくここのポイントから何らかの方法で逸脱しています。
しかし、個別の量に対してはもっとうまくいくことができます 。このような値は「任意の実数」ではないため、上記のいずれにも当てはまりません。正確に表すことができます。 それらが定義された記数法では、実際、は (別の記数法に変換して有限の長さに切り捨てると、不正確な数値に丸められるため)。コンピュータは、数値を文字列として表すことにより、(非効率的に)そのような状況を処理できます。 ASCII
を検討してください または
フォーマットを適用する…
これは記数法の(やや恣意的な)基準の特性であるため、値が「丸い」ように見えるかどうかは、その精度とは関係ありません。 。これは本当に重要な観察です 、これは多くの人々の直感に反します(そしてそれが私が上記の数値的根拠を説明するのに多くの時間を費やした理由です)。
代わりに、精度は 有効数字
の数によって決まります。 表現には 。値を少なくとも記録できるストレージ形式が必要です 正しいと思われる数の有効数字 。 86.2
と記載されている場合に、正しいと見なされる値を例として取り上げます。 および0.0000862
、最も一般的な2つのオプションは次のとおりです。
-
固定小数点 、有効数字の数は大きさに依存します :例:固定の5進数表現では、値は
86.20000
として格納されます。 および0.00009
(したがって、それぞれ有効数字7桁と1桁があります)。この例では、精度が失われています 後者の値では(実際、何かを完全に表現できなくなったとしてもそれほど時間はかかりません。 重要な);以前の値は偽の精度 に保存されていました 、これは私たちの有限のスペースの無駄です(実際、値が大きくなりすぎてストレージ容量がオーバーフローするのにそれほど時間はかかりません)。この形式が適切な場合の一般的な例は、会計システムの場合です。通常、金額はペニーまで追跡する必要があります それらの大きさに関係なく(したがって、小さい値には低い精度が必要であり、大きい値には高い精度が必要です)。たまたま、通貨も通常は離散的であると見なされます(ペニーは分割できません)。したがって、これは、上記の表現エラーを回避するために特定の基準(ほとんどの最新の通貨では10進数)が望ましい状況の良い例でもあります。
-
浮動小数点 、有効数字の数は大きさに関係なく一定 :例: 5有効数字の小数表現では、値は
86.200
として格納されます。 および0.000086200
(そして、定義上、両方の時間で5つの有効数字の精度があります)。この例では、両方の値が精度を失うことなく保存されています。;どちらも同じ量です 誤った精度であり、無駄が少なくなります(したがって、有限空間を使用して、大小両方のはるかに広い範囲の値を表すことができます)。この形式が適切な場合の一般的な例は、実際の測定値を記録する場合です。 :測定器の精度(すべてsystematic の両方に悩まされています および
ランダム エラー)はスケールに関係なくかなり一定であるため、十分な有効数字(通常は約3桁または4桁)があれば、底の変更によって別の数値に丸められたとしても、精度が失われることはありません。 。 ただし、浮動小数点ストレージ形式の精度 私たちのコンピューターで使用されていますか?
-
IEEE754 単精度(binary32)浮動小数点 数値は24ビット、つまり
log10(2)
(7を超える)重要な数字-つまり許容誤差は±0.000006%
未満です。 。つまり、「86.20000
」と言うよりも正確です。 "。 -
IEEE754 倍精度(binary64)浮動小数点 数値は53ビット、つまり
log10(2)
(ほぼ16)桁、重要-つまり±0.00000000000001%
をわずかに超える許容誤差があります 。つまり、「86.2000000000000
」と言うよりも正確です。 "。
理解しておくべき最も重要なことは、これらの形式はそれぞれ1万を超えるということです。 および1兆 倍より正確 「86.2」と言うよりも、2進数から10進数への正確な変換には、誤った誤った精度が含まれている場合でも(無視する必要があります。これについては後ほど詳しく説明します)。
-
両方にも注意してください およびを修正 浮動小数点形式では、形式がサポートするよりも正確に値がわかっていると、精度が低下します。 このような⁄3 × 3000
5桁の固定小数点では、999.99000
が生成されます 1000.00000
ではなく;および⁄7 − ⁄50
5-有効数字の浮動小数点は0.0028600
になります 0.0028571
ではなく 。
数値解析 の分野 はこれらの影響を理解することに専念していますが、任意 終了が保証されている計算方法では無限の精度を提供できないため、使用可能なシステム(頭の中で計算を実行する場合でも)はこのような問題に対して脆弱です。 :たとえば、円の面積を計算する方法を検討してください。πに使用される値の精度が必然的に失われ、結果に伝播します。
結論
-
実際の測定では、バイナリ浮動小数点を使用する必要があります :高速、コンパクト、非常に正確で、他の何よりも悪くはありません(開始した10進数バージョンを含む)。 MySQLの浮動小数点データ型 以降 IEEE754であり、これはまさに彼らが提供するものです。
-
通貨アプリケーションでは、小数の固定小数点を使用する必要があります :速度が遅く、メモリを浪費しますが、値が不正確な量に丸められないことと、多額の金額でペニーが失われないことの両方を保証します。 MySQLの固定小数点データ型 以降 BCDでエンコードされた文字列であり、これはまさに彼らが提供するものです。
最後に、プログラミング言語は通常、バイナリ浮動小数点を使用して小数値を表すことを覚えておいてください。 タイプ:したがって、データベースに値が別の形式で格納されている場合は、それらがアプリケーションにどのように取り込まれるかに注意する必要があります。そうしないと、インターフェイスで値が変換される可能性があります(それに伴うすべての問題が発生する可能性があります)。
この場合、どのオプションが最適ですか?
うまくいけば、私はあなたの価値観が安全にできることをあなたに確信させました(そしてすべきです )「不正確さ」をあまり気にせずに浮動小数点型に格納されますか?覚えておいてください、彼らはもっと 薄っぺらな3桁の有効数字の小数表現よりも正確です。誤った精度を無視する必要があります(ただし、常に とにかく、固定小数点形式を使用している場合でも、それを実行してください。
質問については、オプション3よりもオプション1または2のいずれかを選択してください。比較が簡単になります(たとえば、最大質量を見つけるには、MAX(mass)
を使用するだけです。 、一方、2つの列にわたって効率的に行うには、いくつかのネストが必要になります。
これら2つの間で、どちらを選択するかは重要ではありません。浮動小数点数は、スケールに関係なく、一定数の有効ビットとともに格納されます。 。
さらに、一般的なケースでは、一部の値がオプション1を使用して元の小数表現に近い2進数に丸められ、同時に他の値がオプション2を使用して元の10進数表現に近い2進数に丸められる場合があります。このような表現エラーは、常に無視されるべき誤った精度の範囲内でのみ現れることがすぐにわかります。
ただし、これ この場合、16オンスから1ポンド(16は2の累乗)であるため、2つのアプローチを使用した元の10進数値と保存された2進数の相対的な違いは同一 :
-
5.387510
(5.3367187510
質問で述べたように)は、binary32floatに101.0110001100110011001102
(これは5.3874998092651367187510
):これは0.0000036%
元の値から(ただし、前述のように、「元の値」は、それが表す物理量のかなりお粗末な表現でした)。binary32 floatは小数点以下7桁の精度しか格納しないことを知っているので、コンパイラは特定のを知っています。 8桁目以降はすべて間違いなく 精度が誤っているため、必須 すべてで無視されます ケース-したがって、入力値がそれ以上の精度を必要としない場合 (もしそうなら、binary32は明らかにフォーマットの間違った選択でした)、この保証 開始時と同じように丸く見える10進値への戻り:
5.38750010
。ただし、実際にはドメイン知識 を適用する必要があります。 この時点で(他のストレージ形式の場合と同様に)、後続の2つのゼロなど、存在する可能性のある誤った精度を破棄します。 -
86.210
1010110.001100110011001102
(これは86.199996948242187510
):これも0.0000036%
元の値から。以前と同様に、誤った精度を無視して元の入力に戻します。
基数ポイント の配置を除いて、数値のバイナリ表現がどのように同一であるかに注意してください。 (4ビット離れています):
101.0110 00110011001100110 101 0110.00110011001100110
これは、5.3875×2=86.2であるためです。