3

Joshua Bloch のJava puzzlersを読んでいます。パズル 28 で、次の段落が理解できません。

これが機能するのは、浮動小数点値が大きいほど、値と後続の値の間の距離が大きくなるからです。浮動小数点値のこの分布は、固定数の有効ビットによる表現の結果です。十分に大きい浮動小数点値に 1 を追加しても、値は変更されません。これは、後続の値に「ギャップを埋める」わけではないためです。

  1. 浮動小数点値が大きいほど、その値と後続の値の間の距離が大きくなるのはなぜですか?
  2. の場合はInteger1 を加算して次の を取得しますIntegerが、 の場合は次の値floatを取得するにはどうすればよいでしょうか。floatIEEE-754 形式の float 値がある場合、仮数部に 1 を追加して次の float を取得しますか?
4

4 に答える 4

6

最初の 5 つの値のみを設定できる 10 進数ベースの形式を想像してみてください (つまり、仮数の長さが 5 です)。小さい数値の場合は問題ありません: 1.0000、12.000、125.00

しかし、より大きな数の場合は、eg1113500 を切り詰める必要があります。次に表現可能な数値は、100 大きい 1113600 になります。中間の値は、この形式では表すことができません。この範囲の値を読み取っていた場合は、それを切り捨てる必要があります。正確でなくても、一致する最も近い表現を見つけてください。

数値が大きくなるほど問題が大きくなります。34567800000 に到達すると、次に表現可能な数値は 34567900000 になり、1000000 または 100 万のギャップになります。このように、表現の違いはサイズによって異なることがわかります。

反対に、小さい値 0.0001 の場合、次に表現可能な値は 0.0002 であるため、ギャップはわずか 0.0001 です。

浮動小数点値の原理は同じですが、バイナリ エンコーディング (10 の累乗ではなく 2 の累乗) を使用します。

于 2013-08-07T17:12:40.213 に答える
5

浮動小数点は、基数 2 の科学表記法と考えることができます。浮動小数点では、仮数 (別名仮数) と指数の固定ビット数に制限されます。float(24 ビット) またはdouble(53 ビット)のどちらを使用しているかによって、その数は異なります。

基数 10 の科学的表記法を考えると、もう少し馴染みがあります。仮数が整数に制限され、常に有効数字 3 桁で表されると想像してください。次に、この表現で連続した数の次の 2 つのペアを考えてみましょう。

  • 100 x 10 0および 101 x 10 0 (100 および 101)
  • 100×10 1および 101×10 1 (1000 および 1010)

最初のペアの数値間の距離 (別名差) は 1 であるのに対し、2 番目のペアでは 10 であることに注意してください。両方のペアで、仮数は 1 だけ異なります。これは、整数間で可能な最小の差ですが、差は指数でスケーリングされます。そのため、数値が大きいほど、浮動小数点でそれらの間のステップが大きくなります (最初の質問)。

2 番目の質問については、1000 (100 x 10 1 )に 1 (100 x 10 -2 ) を加算する場合を見てみましょう。

  • 100×10 1 + 100×10 -2 = 1001×10 0

ただし、仮数部の有効数字は 3 桁に制限されているため、最後の数値は (丸め後に) 次のように正規化されます。

  • 100×10 1

1000 に戻ります。浮動小数点値を変更するには、その数値と次の数値の差の少なくとも半分を追加する必要があります。この最小差は、数値のスケールによって異なります。

2 進浮動小数点でもまったく同じことが起こっています。詳細 (例: 正規化、ガード ディジット、暗黙の基数ポイント、暗黙のビット) があり、優れた記事What Every Computer Scientist Should Know About Floating-Point Arithmeticで読むことができます。

于 2013-08-07T17:19:23.430 に答える
4
  1. 浮動小数点数は、仮数と指数の組み合わせとして表されます。ここで、数値の値はmantissa * 2^(exponent)、仮数が 2 桁に制限されていると仮定すると (物事を簡単にするために)、1.1 * 2^100非常に大きな数値がある場合、"次の」値は1.2 * 2^100. したがって、混合スケールの計算を行っている場合は、正確な結果を保持するのに十分なスペースが仮数にないため、 に1.1*2^100 + 1丸められます。1.1*2^100
  2. Java 6 以降では、可能なすべての double/float 値を「反復」できるようにするユーティリティ メソッドMath.nextUp()およびMath.nextAfter()があります。その前に、仮数に +1 を追加し、オーバーフローを処理して次/前の値を取得する必要があります。
于 2013-08-07T17:11:55.017 に答える
2

理由は説明していませんが、このサンプル コードは、float と次に使用可能な float の間の距離を計算する方法を示し、多数の例を示します。離れているはずですが、同じfですgInteger.MAX_VALUEそして次の値はhで、これは1099511627776大きいです。

float f = Long.MAX_VALUE;
System.out.println("f = " + new BigDecimal(f));
System.out.println("f bits = " + Float.floatToIntBits(f));
float g = f - Integer.MAX_VALUE;
System.out.println("g = f - Integer.MAX_VALUE = " + new BigDecimal(g));
System.out.println("g bits = " + Float.floatToIntBits(g));
System.out.println("f == g? " + (f == g));
float h = Float.intBitsToFloat(Float.floatToIntBits(f) + 1);
System.out.println("h = " + new BigDecimal(h));
System.out.println("h bits = " + Float.floatToIntBits(h));
System.out.println("h - f = " + new BigDecimal(h).subtract(new BigDecimal(f)));

出力:

f = 9223372036854775808
f bits = 1593835520
g = f - Integer.MAX_VALUE = 9223372036854775808
g bits = 1593835520
f == g? true
h = 9223373136366403584
h bits = 1593835521
h - f = 1099511627776
于 2013-08-07T17:14:41.547 に答える