私が知っているように、倍数はメモリに64ビットを予約します。浮動小数点数は 32 ビットを予約します。
私は次のことを試しました:
double result=0.1f+0.3f;
System.out.println(result);
その結果、印刷され0.4000000059604645
ます。次のメモリ ブロックからのデータですか (最初の 32 ビットと次の 32 ビット)?
それは何か他のものですか?
私が知っているように、倍数はメモリに64ビットを予約します。浮動小数点数は 32 ビットを予約します。
私は次のことを試しました:
double result=0.1f+0.3f;
System.out.println(result);
その結果、印刷され0.4000000059604645
ます。次のメモリ ブロックからのデータですか (最初の 32 ビットと次の 32 ビット)?
それは何か他のものですか?
この行:
double result=0.1f+0.3f;
最初に文字列 "0.1" と "0.3" を値に変換し、次にの規則を使用しfloat
て 2 つの値を加算し、最後に結果を a に変換して代入を行います。float リテラルを値に変換すると、丸め誤差が発生します。(ちょうど 1/3 が基数 10 で無限に繰り返される展開を持つように、1/10 と 3/10 は基数 2 で無限に繰り返される展開を持ち、どちらでも正確に表すことはできません。(しゃれた意図)。からへの拡大拡張は正確ですが、システムは拡張された解像度に意味のあるデータが含まれていると想定します。float
float
double
float
float
double
float
float
double
の規則を使用して加算を実行する場合は、キャストまたはリテラルを使用してdouble
、少なくとも 1 つのオペランドを最初に変換する必要があります。double
double
double result=0.1f+0.3d;
上記では、0.3 はdouble
完全なdouble
精度に変換されます。0.1 は に変換されてからfloat
に拡張されるためdouble
、double
よりも丸め誤差が大きい値になり0.1d
ます。ほとんどのコンパイラは、コンパイル時にこれを行います。
このコードを Oracle の javac コンパイラ (バージョン 1.7.0_11、デフォルト設定) でコンパイルします。
public class Foo1 {
public static void main(String[] args) {
double dff = 0.1f + 0.3f;
double dfd = 0.1f + 0.3d;
double ddd = 0.1d + 0.3d;
System.out.println("dff=" + dff);
System.out.println("dfd=" + dfd);
System.out.println("ddd=" + ddd);
System.out.println("dff==dfd: " + (dff == dfd));
System.out.println("dff==ddd: " + (dff == ddd));
System.out.println("dfd==ddd: " + (dfd == ddd));
System.out.println("ddd==0.4: " + (10*ddd == 4));
}
}
次のように始まるバイトコードを生成します (javap -c を使用して逆アセンブルします):
ldc2_w #2 // double 0.4000000059604645d
dstore_1
ldc2_w #4 // double 0.4000000014901161d
dstore_3
ldc2_w #6 // double 0.4d
dstore 5
次の出力が生成されます。
dff=0.4000000059604645
dfd=0.4000000014901161
ddd=0.4
dff==dfd: false
dff==ddd: false
dfd==ddd: false
ddd==0.4: true
0.1d と 0.3d の表現誤差と加算の丸め誤差 (存在する場合) が、0.4d の表現誤差と正確に一致する方法で組み合わされるため、最後の行は "true" を示しています。に変更した場合(および に変更0.3
した場合)はあまり良くありません。0.2
10*ddd==4
10*ddd==3
一般に、float
またはを使用するかどうかに関係なく、double
丸め誤差が発生し、結果が正確になる可能性は低くなります。精度を拡張するには、 を使用する必要がありますBigDecimal
。見栄えの良い出力が必要な場合は、書式指定子を使用します (たとえば、System.out.printf()
またはを使用String.format()
)。
What Every Computer Scientist Should Know About Floating-Point Arithmeticもお読みください。