1

編集:浮動小数点演算が正確ではないことは知っています。そして、算数は私の問題でさえありません。追加により、私が期待した結果が得られます。8099.99975fしません。


だから私はこの小さなプログラムを持っています:

public class Test {
    public static void main(String[] args) {
        System.out.println(8099.99975f); // 8099.9995
        System.out.println(8099.9995f + 0.00025f); // 8100.0
        System.out.println(8100f == 8099.99975f); // false
        System.out.println(8099.9995f + 0.00025f == 8099.99975f); // false
        // I know comparing floats with == can be troublesome
        // but here they really should be equal in every bit.
    }
}

IEEE 754単精度浮動小数点数として書かれたときに8099.99975が丸められるかどうかを確認するために書きました。8100驚いたことに、Java8099.9995は float リテラル ( 8099.99975f) として記述された場合に変換します。計算と IEEE 規格を再度確認しましたが、間違いは見つかりませんでした。8100は as と同じくらい離れて8099.99975いますが、 is8099.9995の最後のビットは正しい表現にする必要があります。81000

そこで、Java 言語仕様をチェックして、何か見落としがないかどうかを確認しました。簡単に検索したところ、次の2つのことがわかりました。

  • Java プログラミング言語では、すべての浮動小数点演算子が浮動小数点の結果を結果の精度に丸めるかのように、浮動小数点演算が動作する必要があります。不正確な結果は、無限に正確な結果に最も近い表現可能な値に丸めなければなりません。最も近い 2 つの表現可能な値が等しく近い場合は、最下位ビットが 0 の値が選択されます。

  • Java プログラミング言語は、浮動小数点値を整数に変換するときに、ゼロ方向への丸めを使用します [...]。

ここで、float リテラルについて何も言われていないことに気付きました。したがって、float リテラルは、float にキャストすると、float から int へのキャストと同様にゼロに丸められるだけの double である可能性があると考えました。8099.99975fこれにより、がゼロに丸められた理由が説明されます。

上記の小さなプログラムを書いて私の理論を確認したところ、2 つの float リテラルを追加すると8100、正しい float が計算されることがわかりました。(ここで、8099.9995and0.00025は単一の float として正確に表すことができるため、別の結果につながる可能性のある丸めはありません) float リテラルと計算された float の動作が異なることはあまり意味がなかったので、これは私を混乱させました。言語仕様をもう少し調べて、これを見つけました:

浮動小数点リテラルは、ASCII 文字の F または f [...] の接尾辞が付いている場合、float 型です。float [...] 型の要素は、IEEE 754 32 ビット単精度 [...] バイナリ浮動小数点形式を使用して表現できる値です。

これは最終的に、リテラルを IEEE 標準に従って丸める必要があることを示しています。この場合は8100です。では、なぜ8099.9995ですか?

4

2 に答える 2

3

10 進値の8099.99975有効桁数は 9 桁です。これは、float で正確に表現できる量を超えています。CUNY で浮動小数点解析ツールを使用すると、最も近いバイナリ表現が で8099.9995あることがわかります45FD1FFF。追加しようとすると0.00025、「重要性の喪失」に苦しんでいます。大きい数値の有効桁数 (左側) を失わないようにするには、小さい数値の仮数を右にシフトして、大きい数値のスケール (指数) に一致させる必要があります。これが発生すると、レジスタの右端からシフトするため、その値はゼロになります。

Decimal     Exponent        Significand
---------   --------------  -------------------------
8099.9995   10001011 (+12)  1.11111010001111111111111
   0.00025  01110011 (-12)  1.00000110001001001101111

加算のためにこれらを並べるために、2 番目のものは 24 ビット右にシフトする必要がありますが、単精度浮動小数点の仮数部には 23 ビットしかありません。仮数が消えてゼロになるため、加算は効果がありません。

これを機能させたい場合は、倍精度演算に切り替えてください。

于 2013-11-25T01:52:21.000 に答える