Apabila bekerja dengan nombor titik terapung di Java, anda mungkin perasan bahawa dua kali ganda kadangkala menghasilkan hasil yang tidak dijangka atau tidak tepat. Tingkah laku ini boleh membawa kepada ralat, terutamanya dalam aplikasi kewangan atau senario yang memerlukan ketepatan yang tinggi.
Dalam artikel ini, kami akan menyelidiki punca masalah ini, menerangkan cara mengelakkannya, memberikan contoh yang berkesan dan meneroka sama ada versi Java yang lebih baharu menyediakan alternatif yang lebih baik.
Jenis data berganda dalam Java mengikut standard operasi nombor titik terapung IEEE 754. Ia mewakili nombor dalam format binari menggunakan:
Perwakilan binari ini memperkenalkan had:
Sebagai contoh, dalam binari:
Operasi yang melibatkan dua kali ganda mungkin mengumpul ralat:
Tingkah laku ini wujud dalam aritmetik titik terapung dan bukan unik kepada Java.
Berikut ialah contoh yang menunjukkan masalah:
<code class="language-java">public class DoublePrecisionLoss { public static void main(String[] args) { double num1 = 0.1; double num2 = 0.2; double sum = num1 + num2; System.out.println("预期和:0.3"); System.out.println("实际和:" + sum); // 比较 if (sum == 0.3) { System.out.println("和等于0.3"); } else { System.out.println("和不等于0.3"); } } }</code>
Output:
<code>预期和:0.3 实际和:0.30000000000000004 和不等于0.3</code>
Hasil 0.30000000000000004 menyerlahkan ralat pembundaran yang disebabkan oleh perwakilan binari. Malah perbezaan yang remeh boleh menyebabkan masalah besar dalam sistem kritikal.
Kelas BigDecimal di Java menyediakan aritmetik ketepatan arbitrari, menjadikannya sesuai untuk senario yang memerlukan ketepatan tinggi (seperti pengiraan kewangan).
<code class="language-java">import java.math.BigDecimal; public class BigDecimalExample { public static void main(String[] args) { BigDecimal num1 = new BigDecimal("0.1"); BigDecimal num2 = new BigDecimal("0.2"); BigDecimal sum = num1.add(num2); System.out.println("预期和:0.3"); System.out.println("实际和:" + sum); // 比较 if (sum.compareTo(new BigDecimal("0.3")) == 0) { System.out.println("和等于0.3"); } else { System.out.println("和不等于0.3"); } } }</code>
Output:
<code>预期和:0.3 实际和:0.3 和等于0.3</code>
Dengan menggunakan BigDecimal, isu ketepatan dihapuskan dan perbandingan menghasilkan keputusan yang betul.
Cara lain untuk menangani kehilangan ketepatan ialah membandingkan nombor titik terapung dengan toleransi (epsilon). Kaedah ini menyemak sama ada nombor adalah "cukup dekat" dan bukannya bergantung pada kesaksamaan yang tepat.
<code class="language-java">public class EpsilonComparison { public static void main(String[] args) { double num1 = 0.1; double num2 = 0.2; double sum = num1 + num2; double epsilon = 1e-9; // 定义一个小的容差值 System.out.println("预期和:0.3"); System.out.println("实际和:" + sum); // 使用epsilon进行比较 if (Math.abs(sum - 0.3) < epsilon) { System.out.println("和大约等于0.3"); } else { System.out.println("和不等于0.3"); } } }</code>
Output:
<code class="language-java">public class DoublePrecisionLoss { public static void main(String[] args) { double num1 = 0.1; double num2 = 0.2; double sum = num1 + num2; System.out.println("预期和:0.3"); System.out.println("实际和:" + sum); // 比较 if (sum == 0.3) { System.out.println("和等于0.3"); } else { System.out.println("和不等于0.3"); } } }</code>
Contoh: Gunakan precision.equals untuk membandingkan
<code>预期和:0.3 实际和:0.30000000000000004 和不等于0.3</code>
Mengapa menggunakan matematik Apache Commons?
<code class="language-java">import java.math.BigDecimal; public class BigDecimalExample { public static void main(String[] args) { BigDecimal num1 = new BigDecimal("0.1"); BigDecimal num2 = new BigDecimal("0.2"); BigDecimal sum = num1.add(num2); System.out.println("预期和:0.3"); System.out.println("实际和:" + sum); // 比较 if (sum.compareTo(new BigDecimal("0.3")) == 0) { System.out.println("和等于0.3"); } else { System.out.println("和不等于0.3"); } } }</code>
Atas ialah kandungan terperinci Mengapa berganda Kehilangan Ketepatan dan Cara Mengelaknya di Jawa. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!