質問

これは、のコメントを参照したものです この質問:

Java のこのコードは 12.100000000000001 を生成しますが、これは 12.1 を正確に表現できる 64 ビット double を使用しています。– 熱分解

これは本当ですか?浮動小数点数は2のべき乗の和で表現されるので、いくらビットがあっても12.1を正確に表現することはできないと感じました。ただし、両方のアルゴリズムを実装し、(12.1, 3) を有効数字の多い値で呼び出した結果を出力すると、彼と私のアルゴリズムではそれぞれ次のようになります。

12.10000000000000000000000000000000000000000000000000000000000000000000000000 12.10000000000000100000000000000000000000000000000000000000000000000000000000

これを使用して印刷しました String.format("%76f"). 。必要以上にゼロが多いことはわかっていますが、 12.1 には丸めが見られません。

役に立ちましたか?

解決

いいえ。彼のコメントのフォローアップで他の人が指摘したように、2 の累乗 (有限数) の合計がちょうど 12.1 になることはありません。小数点以下の桁数に関係なく、1/3 を 10 進数で正確に表すことができないのと同じです。

他のヒント

バイナリでは、12.1 は次のようになります。

1100.000110011001100110011...

これは終了しないため、double またはその他の有限幅の 2 進浮動小数点型の仮数部 53 ビットで正確に表すことはできません。

0.1 を 2 進数で表現してみます。
0.5は大きすぎます
0.25は大きすぎます
0.125は大きすぎます
0.0625 が適合し、残りは 0.0375 になります。
0.03125 が適合し、残りは 0.00625 になります。
0.015625は大きすぎます
0.0078125は大きすぎます
0.00390625 が適合し、残りは 0.00234375 になります。
0.001953125 が適合し、残りは 0.000390625 になります。

これは無限に繰り返され、基数 2 の値 0.00011001100 が作成されます...

いいえ、正確に double で表現することはできません。Java が BCD (固定小数点 10 進数) をサポートしている場合、それは正確に機能します。

バイナリではありません。空想を許していただければ、「浮動小数点 2 進化 10 進数」を使用できます (私の知る限り、これはまだ実装されていません)。

12.1 = 0000 . 0001 0010 0001 * (10^2)

バイナリでは、ゼロ以外の値はすべて次の形式になります。 1.xyz * m, 、IEEE 形式はこれを利用して先頭の 1 を省略します。FP-BCD に相当するものが何かわからないので、次の形式の値を探しました。 0.xyz * m その代わり。

読むことをお勧めします すべてのコンピュータ科学者が浮動小数点演算について知っておくべきこと. 。そうすれば確実に分かります。:)

double が何であるかを正確に確認する方法は、それを BigDecimal に変換することです。

// prints 12.0999999999999996447286321199499070644378662109375
System.out.println(new BigDecimal(12.1));

はい、12.1 を浮動小数点で正確に表現できます。必要なのは 2 進数表現ではなく、10 進数浮動小数点表現だけです。

BigDecimal 型を使用すると、それを正確に表現できます。

いいえ、10進数です 12.1 有限 (終端) 2 進浮動小数点数として表すことはできません。

覚えておいてください 12.1 は有理数です 121/10. 。この分数は最低の項であることに注意してください (分子と分母の共通因数を削除しても減らすことはできません)。

(矛盾に到達するために)次のように仮定します。 121/10 次のようにも書くことができます n / (2**k) どこ n そして k いくつかの正の整数であり、 2**k を示します k2の乗。次のような反例があります。 独自の因数分解. 。特に

10 * n == 2**k * 121

ここで、左辺は 5 で割り切れますが、右辺は割り切れません。

使用できるオプションの 1 つは、v=0.1 を保存せず、代わりに v10=1 を保存することです。必要に応じて 10 で除算するだけです (除算により結果に切り捨てエラーが発生しますが、v は問題ありません)。

この場合、基本的には固定小数点ハックを行っていますが、数値は浮動小数点のままです。しかし、本当に必要な場合を除いて、通常はこれを行う価値はありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top