为什么使用add2
方法的结果是错误的?Double.toString(d1)
为什么能保持double
的精度不丢失?
public static double add(double d1, double d2) {
BigDecimal bd1 = new BigDecimal(Double.toString(d1));
BigDecimal bd2 = new BigDecimal(Double.toString(d2));
return bd1.add(bd2).doubleValue();
}
public static double add2(double d1, double d2) {
BigDecimal bd1 = new BigDecimal(d1);
BigDecimal bd2 = new BigDecimal(d2);
return bd1.add(bd2).doubleValue();
}
public static void main(String[] args) {
double d1 = 1.0000002;
double d2 = 0.0000002;
System.out.println(Double.toString(d1));
System.out.println("d1 + d2 = " + (d1 + d2)); // 1.0000003999999998
System.out.println("d1 + d2 = " + add(d1, d2)); // 1.0000004
System.out.println("d1 + d2 = " + add2(d1, d2)); // 1.0000003999999998
}
PS:引出一个概念问题:
double d = XXXX.XXXXXX;
System.out.println(d); //这里总是不会丢失精度的,为什么?
Apabila BigDecimal menggunakan dua kali ganda sebagai parameter input, perduaan tidak boleh mewakili perpuluhan dengan tepat Selepas pengkompil membaca rentetan "0.0000002" dan "1.0000002", ia mesti menukarnya kepada nilai berganda 8 bait Ia adalah
1.0000001999999998947288304407265968620777130126953125
seperti ini .Jadi, apabila dijalankan, nilai sebenar sebenarnya dihantar kepada pembina BigDecimal ialah
1.0000001999999998947288304407265968620777130126953125
.BigDecimal boleh menukar rentetan dengan betul kepada nombor titik terapung yang benar-benar tepat apabila menggunakan Rentetan sebagai parameter input.
Dalam bahagian System.out.println, jika parameter input ialah rentetan, ia akan dikeluarkan secara langsung Jika parameter input adalah jenis lain, kaedah Object.toString akan dipanggil untuk penukaran dan kemudian output. Double.toString akan menggunakan ketepatan tertentu untuk membundarkan double sebelum mengeluarkannya.
Komen pada pembina BigDecimal menangani isu ini:
Penjelasan tambahan:
Double.toString
Kaedah ini menghasilkanString
dan akan dibundarkan. Parameter inputnew BigDecimal(Double.toString(d1))
ialahString
selepas pemprosesan, dan pembinaBigDecimal(String val)
dipanggil.Kaedah BigDecimal(String val) dalam kod sumber akan memproses val menjadi tatasusunan char[]:
Kemudian panggil
BigDecimal(char[] in)
pembina.Dan panggilan BigDecimal(d1) baharu
BigDecimal(double val)
Perkara pertama selepas kaedah ini masuk ialahTukar parameter input kepada binari, jadi ketepatan akan hilang.
Kehilangan ketepatan yang disebabkan oleh penambahan berganda adalah sama seperti keadaan di atas Ia mula-mula ditukar kepada bit dan kemudian dikira, dan kemudian ketepatan hilang. .