7

doubleJava型がJavaのメモリにその値を格納する方法を理解したいと思います。次のコードを実行すると、予期しない出力が表示されます。

public static void main(String[] args)  {

    float a = 1.5f;
    float b= 0.5f;
    double c= 1.5;
    double d = 0.5;

    float a1 = 1.4f;
    float b1= 0.5f;
    double c1= 1.4;
    double d1 = 0.5;

    System.out.println(" a- b is " + (a-b));
    System.out.println(" c- d is " + (c-d));
    System.out.println("a1-b1 is " + (a1-b1));
    System.out.println("c1-d1 is " + (c1-d1));

}

出力:

a-bは1.0です
 c-dは1.0です
a1-b1は0.9です
c1-d1は0.8999999999999999です

なぜc1-d1等しくないの0.9ですか?

他の異なる値も試しましたが、期待どおりの結果が返される場合と返されない場合があります。

4

2 に答える 2

3

丸め誤差について聞いたことがあるかもしれませんが、なぜここで丸め誤差があるのか​​疑問に思われるかもしれません。

float a1 = 1.4f;
float b1 = 0.5f;
double c1 = 1.4;
double d1 = 0.5;

System.out.println(new BigDecimal(a1) + " - " + new BigDecimal(b1) + " is " +
        new BigDecimal(a1).subtract(new BigDecimal(b1)) + " or as a float is " + (a1 - b1));
System.out.println(new BigDecimal(c1) + " - " + new BigDecimal(d1) + " is " +
        new BigDecimal(c1).subtract(new BigDecimal(d1)) + " or as a double is " + (c1 - d1));

プリント

1.39999997615814208984375 - 0.5 is 0.89999997615814208984375 or as a float is 0.9
1.399999999999999911182158029987476766109466552734375 - 0.5 is
     0.899999999999999911182158029987476766109466552734375 
     or as a double is 0.8999999999999999

ご覧のとおり、これらの値を正確に表すことも、表すことfloatdoubleできません。floatまたはdoubleを出力すると、これを隠すために丸めが発生します。このfloatの場合、小数点以下7桁に丸めると、期待した数になります。16桁の精度を持つdoubleの場合、丸め誤差が表示されます。

@Eric Postpischilのように、floatordouble演算に丸め誤差があるかどうかは、使用される値に完全に依存することに注意してください。この状況では、表された値が2倍の値よりも0.9から離れていても、より正確であるように見えたのはフロートでした。

つまり、使用する場合、floatまたはdouble賢明な丸め戦略を使用する必要がある場合です。これができない場合は、BigDecimalを使用してください。

System.out.printf("a1 - b1 is %.2f%n", (a1 - b1));
System.out.printf("c1 - d1 is %.2f%n", (c1 - d1));

プリント

a1 - b1 is 0.90
c1 - d1 is 0.90

floatまたはdoubleを印刷する場合、最も近い10進数の短い値が本当に必要な値であると想定されます。つまり、0.5ulp以内です。

例えば

double d = 1.4 - 0.5;
float f = d;
System.out.println("d = " + d + " f = " + f);

プリント

d = 0.8999999999999999 f = 0.9
于 2012-10-26T14:51:33.633 に答える
2

のJavaドキュメントprintlnは、(いくつかのリンクを介して)のドキュメントを参照していますtoString。のドキュメントにtoStringfloatは、またはに印刷される桁数はdouble、同じタイプの隣接する表現可能な値から値を一意に区別するために必要な数であると記載されています。

「1.4f」をfloatに変換すると、結果は1.39999997615814208984375(16進浮動小数点では0x1.666666p + 0)になります。.5を引くと、結果は0.89999997615814208984375(0x1.ccccccp-1)になります。たまたま、このフロートは.9に最も近いフロートでもあります。したがって、印刷すると「.9」が印刷されます。

「1.4」をdoubleに変換すると、結果は1.399999999999999911182158029987476766109466552734375(0x1.6666666666666p + 0)になります。.5を引くと、結果は0.899999999999999911182158029987476766109466552734375(0x1.cccccccccccccp-1)になります。0.90000000000000002220446049250313080847263336181640625(0x1.ccccccccccccdp-1)が近いため、これは.9に最も近いdoubleではありません。したがって、Java仕様では、値を.9と区別して、より細かく印刷する必要があります。結果「0.8999999999999999」は、実際の値を正確に表しています。

于 2012-10-26T14:32:44.517 に答える