ここでの問題は、浮動小数点数が基数 2 で格納されることです。基数 10 の 10 進数を基数 2 の浮動小数点数で正確に表すことはできません。
少し戻りましょう。.1 とはどういう意味ですか? それとも.7?1x10 -1と 7x10 -1を意味します。通常の 10 進数ではなく2 進数を使用している場合、.1 は 1x2 -1または 1/2 を意味します。.11 は、1x2 -1 + 1x2 -2、または 1/2+1/4、または 3/4 を意味します。
このシステムでは、分母が常に 2 のべき乗であることに注意してください。2 のべき乗である分母がなければ、有限の桁数で数値を表すことはできません。たとえば、.1 (10 進数) は 1/10 を意味しますが、無限に繰り返される分数である 2 進数では、0.000110011... (0011 パターンが永遠に繰り返されます)。これは、基数 10 で 1/3 が無限分数 (0.3333....) であるのと似ています。基数 10 は、分母が 2 と 5 の累乗の倍数である数値のみを正確に表すことができます。 60 は 2、3、4、および 5 で割り切れますが、何らかの理由で 10 進数を使用し、コンピューターでは 2 進数を使用します)。
浮動小数点数 (または固定小数点数) の桁数は常に有限であるため、これらの無限に繰り返される小数を正確に表現することはできません。そのため、実際の値にできるだけ近づけるために値を切り捨てるか丸めますが、実際の値と正確には等しくありません。これらの丸められた値を合計し始めると、より多くのエラーが発生し始めます。10 進数では、1/3 の表現が .333 の場合、その 3 つのコピーを合計すると、1 ではなく .999 になります。
考えられる解決策は 4 つあります。.1 や .7 のような小数を正確に表すことだけが重要な場合 (たとえば、1/3 に言及したのと同じ問題が発生することは気にしません)、数値を小数として表すことができます。バイナリコード化された 10 進数、およびそれらを操作します。これは、多くの演算が 10 進数で定義される金融では一般的なソリューションです。これには、コンピュータの FPU の利点を利用せずに独自の算術演算をすべて自分で実装するか、10 進算術ライブラリを見つける必要があるという欠点があります。これも、前述のように、10 進数で正確に表すことができない分数には役立ちません。
別の解決策は、分数を使用して数値を表すことです。分数を使用し、分子と分母に bignum (任意に大きな数) を使用すると、コンピューターのメモリに収まる任意の有理数を表すことができます。繰り返しになりますが、マイナス面は算術が遅くなることです。自分で算術を実装するか、既存のライブラリを使用する必要があります。これはすべての有理数の問題を解決しますが、π または √2 に基づいて計算された確率で終わった場合でも、それらを正確に表すことができないという同じ問題があり、1 つも使用する必要があります。後のソリューションの。
3番目の解決策は、数値を正確に1に加算することだけが重要な場合、n個の可能性があるイベントに対して、それらの確率のn -1の値のみを保存し、最後の確率を次のように計算することです。 1 から残りの確率の合計を引いたもの。
そして 4 番目の解決策は、浮動小数点数 (または無理数を表すために使用される分数などの不正確な数) を扱うときに常に覚えておく必要があることを行い、2 つの数値が等しいかどうかを決して比較しないことです。再び基数 10 で、1/3 の 3 つのコピーを合計すると、.999 になります。その数を 1 と比較したい場合は、代わりに比較して 1 に十分近いかどうかを確認する必要があります。差の絶対値 1 ~ .999 が .01 などのしきい値未満であることを確認します。