Rumah > Java > javaTutorial > Mengapa berganda Kehilangan Ketepatan dan Cara Mengelaknya di Jawa

Mengapa berganda Kehilangan Ketepatan dan Cara Mengelaknya di Jawa

Patricia Arquette
Lepaskan: 2025-01-27 18:09:10
asal
924 orang telah melayarinya

Why double Loses Precision and How to Avoid It in Java

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.

Mengapa dua kali ganda kehilangan ketepatan?

1. Standard titik terapung IEEE 754

Jenis data berganda dalam Java mengikut standard operasi nombor titik terapung IEEE 754. Ia mewakili nombor dalam format binari menggunakan:

  • 1 bit digunakan untuk simbol,
  • 11 bit untuk eksponen,
  • 52 bit digunakan untuk pecahan (mantissa).

Perwakilan binari ini memperkenalkan had:

  • Ketepatan terhad: dua kali ganda hanya boleh mewakili sehingga 15-17 digit perpuluhan dengan tepat.
  • Ralat Pembundaran: Banyak pecahan perpuluhan (cth., 0.1) tidak boleh diwakili tepat sebagai nombor perduaan, mengakibatkan ralat pembundaran.

Sebagai contoh, dalam binari:

  • 0.1 menjadi perpuluhan berulang tak terhingga yang dipotong untuk penyimpanan, sekali gus memperkenalkan sedikit ketidaktepatan.

2. Ralat kumulatif dalam operasi aritmetik

Operasi yang melibatkan dua kali ganda mungkin mengumpul ralat:

  • Penambahan/penolakan berulang menguatkan ralat pembundaran.
  • Pendaraban/pembahagian mungkin kehilangan ketepatan kerana pemotongan.

Tingkah laku ini wujud dalam aritmetik titik terapung dan bukan unik kepada Java.


Contoh yang boleh digunakan: kehilangan ketepatan yang disebabkan oleh penggunaan berganda

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>
Salin selepas log masuk
Salin selepas log masuk

Output:

<code>预期和:0.3
实际和:0.30000000000000004
和不等于0.3</code>
Salin selepas log masuk
Salin selepas log masuk

Hasil 0.30000000000000004 menyerlahkan ralat pembundaran yang disebabkan oleh perwakilan binari. Malah perbezaan yang remeh boleh menyebabkan masalah besar dalam sistem kritikal.


Bagaimana untuk mengelakkan kehilangan ketepatan

1. Gunakan BigDecimal untuk pengiraan yang tepat

Kelas BigDecimal di Java menyediakan aritmetik ketepatan arbitrari, menjadikannya sesuai untuk senario yang memerlukan ketepatan tinggi (seperti pengiraan kewangan).

Contoh menggunakan BigDecimal:

<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>
Salin selepas log masuk
Salin selepas log masuk

Output:

<code>预期和:0.3
实际和:0.3
和等于0.3</code>
Salin selepas log masuk

Dengan menggunakan BigDecimal, isu ketepatan dihapuskan dan perbandingan menghasilkan keputusan yang betul.

2. Gunakan nilai Epsilon untuk perbandingan

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.

Contoh menggunakan perbandingan Epsilon:

<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>
Salin selepas log masuk

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>
Salin selepas log masuk
Salin selepas log masuk

Mengapa menggunakan Epsilon untuk membandingkan?

  • fleksibiliti : Ia membolehkan perbezaan kecil yang disebabkan oleh ralat penggabungan.
  • mudah
  • : Kaedah ini tidak memerlukan perpustakaan luaran dan kecekapan adalah tinggi.
Gunakan Apache Commons Math untuk meningkatkan ketepatan

Apache Commons Math adalah perpustakaan yang direka untuk pengkomputeran matematik yang kompleks. Walaupun ia tidak memberikan aritmetik ketepatan sewenang -wenang seperti BigDecimal, ia menyediakan prosedur praktikal yang memudahkan operasi berangka dan meminimumkan kesilapan terapung dalam beberapa kes.

Contoh: Gunakan precision.equals untuk membandingkan

output:
<code>预期和:0.3
实际和:0.30000000000000004
和不等于0.3</code>
Salin selepas log masuk
Salin selepas log masuk

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>
Salin selepas log masuk
Salin selepas log masuk

Perbandingan yang dipermudahkan

: Precision.Equals membolehkan penggunaan toleran yang ditentukan untuk dibandingkan dengan toleransi yang ditentukan, supaya mudah mengendalikan ralat penggabungan.
  • ringan : Perpustakaan menyediakan alat yang memberi tumpuan kepada pengiraan berangka tanpa meningkatkan perbelanjaan BigDecimal.
  • Ringkasan
  • Memahami batasan
: Double sendiri tidak cacat, tetapi kerana perwakilan titik terapung binari, ia tidak sesuai untuk tugas -tugas yang tinggi.

BigDecimal

: BigDecimal dapat memastikan ketepatan, tetapi mungkin mempengaruhi prestasi untuk pengiraan kewangan atau kritikal.
  • Menggunakan Perpustakaan : Apache Commons Math menyediakan program praktikal seperti Precision.Equals, yang secara berkesan dapat mengendalikan perbandingan terapung.
  • Dengan memahami double dan alternatifnya, anda boleh menulis lebih banyak aplikasi Java yang lebih mantap dan lebih tepat.
  • Jika anda menghadapi ketepatan double dan bagaimana menyelesaikan masalah ini, sila beritahu saya dalam komen! ?

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!

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan