Javaのfloat型とdouble型の表現範囲と精度


展開
漠然と根本進数は正確にすべての小数を表すことができないので、トラップのサイズを決定するために浮いているようだが、覚えておいてください。時には、説明できないことがある。

Javaのように、  

        0.99999999f == 1f // true 

        0.9f == 1f // false

これらを理解するには、まずメモリ内のfloatとdoubleの構造を理解する必要があります

1.メモリ構造
floatおよびdoubleの範囲は、インデックスの桁数によって決まります。
floatの指数は8桁ですが、doubleの指数は11桁ですが、分布は次のとおりです。

浮く:

        1ビット(符号ビット)8ビット(指数ビット)23ビット(仮数ビット)                            
            


double:1
        ビット(符号ビット)11ビット(指数ビット)52ビット(仮数ビット)
したがって、floatの指数範囲は-128〜+ 127であり、doubleの指数範囲は-1024〜+ 1023であり、指数ビットは補数ですフォームで分割。
負の指数は、浮動小数点数で表現できる絶対値が最小のゼロ以外の数を決定し、正の指数は、浮動小数点数で表現できる最大絶対値の数を決定し、浮動小数点値の範囲も決定します。
floatの範囲は-2 ^ 128〜+ 2 ^ 127、つまり-3.40E + 38〜+ 3.40E + 38、doubleの範囲は-2 ^ 1024〜+ 2 ^ 1023、つまり-1.79E + 308〜 + 1.79E + 308。


2.精度
floatとdouble の精度は、仮数の桁数によって決まります。浮動小数点数は科学表記法に従ってメモリに格納されます。整数部分は常に暗黙の「1」です。変更されないため、精度に影響を与えることはできません。
float:2 ^ 23 = 8388608、左端の数字が省略されているため、合計7桁、つまり最大8桁を表すことができる:2 * 8388608 = 16777216。有効桁数は8桁ですが、絶対的な保証は7桁です。つまり、floatの精度は7桁から8桁の有効桁です
。double:2 ^ 52 = 4503599627370496、合計16桁で、同じ、倍精度は16から17です。ビット。
f1 == f2を使用して2つの数値が等しいと判断できない理由は、f1とf2は2つの異なる数値である可能性がありますが、浮動小数点数の精度の制限により、2つの数値が等しいと判断することが間違っている可能性があるためです!

次のコードを使用して確認できます。

        float f1 = 16777215f;
        for(int i = 0; i <10; i ++){
            System.out.println(f1);
            f1 ++;
        }

小数の場合、精度があるため、間違いを犯しやすくなります。

        float f = 2.2f;
        double d =(double)f;
        System.out.println(d); 
        f = 2.25f;
        d =(double)f;
        System.out.println(d); 

出力は
        2.200000047683716
        2.25です。

この単純な数値の出力は次のようになります。

実際、上記の2つの保存された結果の導入を通じて、おそらく答えを見つけました。まず、2桁に変換すると10.01である2.25の単精度の格納方法を見てみましょう。1.001* 2にソートするのは非常に簡単です。 

したがって、2.25のメモリ分布を書き出すことができます。 
        符号ビットは次のとおりです。0
        指数は1、0000 0001は補数で表され、シフトコードは1000 0001です。
        仮数は0010 0000 0000 0000 0000 000

2.25の倍精度は次のように表されます:0 100 0000 0001 0010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 00000000。これにより、強制変換中に2.25の値が変更されないようにします。もう一度2.2を見てみましょう。 2.2科学表記法で表現する必要があります。10進数の10進数を2進数の10進数に変換する方法は、10進数* 2を整数部分に変換することなので、0.282 = 0.4なので、2進数の10進数の最初の桁は、0.4の整数部分0.4、0.4× 2 = 0.8、2桁目は0、0.8 * 2 = 1.6、3桁目は1、0.6×2 = 1.2、4桁目は1、0.2 * 2 = 0.4、5桁目は0なので、決して= 1.0を掛けることができ、結果のバイナリは無限に循環する配置になります00110011001100110011 ...単精度データの場合、仮数は24ビットの精度しか表現できないため、2.2の浮動小数点数は次のように格納されます。

ただし、10進値に変換されたこの格納方法は2.2にはなりません。これは、2.2などの2進数に変換すると10進数が不正確になる可能性があり、doubleタイプのデータにも同じ問題があるため、浮動小数点数で表されるためです。プロセスでいくつかのエラーが発生します。単精度を倍精度に変換すると、エラーも発生します。たとえば、次のコードは異なる結果を出力します。

        float f = 2.2f;
        double d =(double)f;
        System.out.println(f);
        System.out.println(d);
2.25などのバイナリで表現できる10進データの場合、このエラーは発生しません、したがって、上記の奇妙な出力が表示されます。
 

19件の元の記事を公開 賞賛4 170,000回+

おすすめ

転載: blog.csdn.net/u011250186/article/details/105678048