1.0f + 0.0000000171785715f が 1f を返すのはなぜですか?
-
22-08-2019 - |
質問
コード内のバグを見つけようとして 1 時間努力した後、ついにその理由が見つかりました。1fに非常に小さなフロートを追加しようとしましたが、何も起こりませんでした。理由を理解しようとしていたところ、その小さな float を 0f に追加すると完璧に機能することがわかりました。
なぜこうなった?これは「桁違い」と関係があるのでしょうか?この問題に対する回避策はありますか?
前もって感謝します。
編集:
現時点では、倍精度または 10 進数への変更はオプションではありません。
解決
単精度 (32 ビット) 浮動小数点値の精度は小数点以下約 7 桁であるためです。つまり、追加する値は、少なくとも次の値に追加した場合、実質的にゼロになります。 1
. 。ただし、この場合は指数が小さいため、値自体は簡単に float に格納できます。しかし、それを正常に追加するには 1
大きい方の数値の指数を使用する必要があります...そしてゼロ以降の数字は四捨五入で消えます。
使用できます double
より正確な精度が必要な場合。パフォーマンスの点では、今日のハードウェアではこれに違いはありませんし、メモリもすべての変数について考慮する必要があるほど制約されていないことがよくあります。
編集: あなたが使用すると述べたように、 double
使用できるオプションではありません カハンの合計, 、 として アクーン コメントで指摘されました。
別のオプションとして、中間計算を倍精度で実行し、その後にキャストすることもできます。 float
また。ただし、これは、大きな数値に非常に小さな数値を加算するだけではなく、さらにいくつかの演算がある場合にのみ役立ちます。
他のヒント
フロート精度の桁数が一定であるので、これはおそらく起こるが、指数は明らかに変化することができる。
これは、あなたが0にあなたの小さな数を追加することができますが、あなただけの精密左の十分な数字がないので、0から異なる指数を持っている数にそれを追加することを期待できないことを意味します。
あなたはすべてのコンピュータ科学者は、浮動小数点演算<について知っておくべきことをお読みください/>。
に見えます。私があなただったら、私はdecimal
のように、異なるタイプを使用すると思います。それは、高精度のエラーを修正する必要があります。
float
で、あなただけの約7桁ののの精度を得ることができます。だからあなたのnumber'llは1Fに丸めること。あなたは、このような番号を保存したい場合は、代わりにdouble
を使用する
受け入れられた回答に加えて、次のようになります。 多数の小さな数値といくつかの大きな数値を合計する必要がある場合は、次を使用する必要があります。 カハンの合計.
double
を使用することができないため)は、パフォーマンスが問題である場合は、バイナリスケーリング/固定小数点ポイントにはオプションかもしれません。 float
sは整数として格納されているが、多数(例えば、2 ^ 16)によってスケーリングされます。中間演算は(比較的速い)整数演算を用いて行われます。最終的な答えは、スケーリング係数で割ることによって、端部で浮動小数点に変換することができる。
これはしばしば行われます。
あなたは代わりにdoubleのこれらの山車を行いますあなたのリテラル、上のFサフィックスを使用しています。だからあなたの非常に小さなフロートは大きなフロートに消えます。