Di Jawa, apa arti NaN?


107

Saya memiliki program yang mencoba menyusutkan doubleke angka yang diinginkan. Output yang saya dapatkan adalah NaN.

Apa NaNartinya di jawa?


Ada penjelasan yang baik tentang NaN dan kesalahan
Phil

Jika Anda bertanya "apa gunanya NaN?" di Java (atau bahasa lain), saya dapat memberi Anda kasus penggunaan yang sangat berguna: ketika saya memiliki array 2-D float, tetapi perhitungan saya tidak memiliki nilai yang berarti untuk beberapa bagian dari array 2-D itu, Saya akan mengisi nilai itu dengan "NaN". Ini dapat digunakan untuk memberi sinyal kepada pengguna hilir tentang penghitungan saya (seperti saat diubah menjadi gambar raster) "jangan perhatikan nilai saat ini". Sangat berguna!
Dan H

BTW, apa - tepatnya - artinya "mengecilkan" ganda? Penasaran ...
Dan H

Jawaban:


153

Diambil dari halaman ini :

"NaN" adalah singkatan dari "bukan angka". "Nan" dihasilkan jika operasi floating point memiliki beberapa parameter input yang menyebabkan operasi tersebut menghasilkan beberapa hasil yang tidak ditentukan. Misalnya, 0,0 dibagi 0,0 tidak ditentukan secara aritmatika. Mengambil akar kuadrat dari bilangan negatif juga tidak ditentukan.


16
Selain itu, NaN didefinisikan oleh The IEEE Standard for Floating-Point Arithmetic (IEEE 754) secara eksplisit yang diikuti oleh Java secara membabi buta. Membaca standar membuka mata Anda pada banyak hal, beberapa nilai nol adalah salah satunya.
Esko

37
Juga, NaNmemiliki sifat yang menarik sebagai satu-satunya "bilangan" yang tidak sama dengan dirinya sendiri jika dibandingkan. Oleh karena itu umum (dan dalam banyak bahasa-satunya) tes jika nomor xadalah NaNadalah sebagai berikut:boolean isNaN(x){return x != x;}
quazgar

3
Link jawaban sudah mati?
Pang

3
... "Mengambil akar kuadrat dari bilangan negatif tidak terdefinisi (dalam aritmatika)" ... Bukan! sebenarnya idan beberapa bahasa seperti python sangat cocok dengannya ... Mungkin tidak demikian halnya pada javaAnda
Rafael T

5
@RafaelT Saya akan mengatakan itu tidak ditentukan dalam aritmatika non-kompleks. Tidak ada cara untuk menetapkan bilangan kompleks ke float atau double di Java. Python diketik secara dinamis, oleh karena itu mungkin saja mengembalikan bilangan kompleks dalam kasus ini.
sstn

19

NaNberarti "Bukan Angka" dan pada dasarnya merupakan representasi dari nilai titik mengambang khusus dalam standar titik mengambang IEE 754 . NaN secara umum berarti bahwa nilai adalah sesuatu yang tidak dapat diekspresikan dengan bilangan floating point yang valid.

Konversi akan menghasilkan nilai ini, jika nilai yang dikonversi adalah nilai lain, misalnya saat mengonversi string yang tidak mewakili angka.


Bagaimana mengkonversi? Dengan parseFloat()atau parseDouble? Atau sesuatu yang lain?
Alonso del Arte

14

NaNberarti "Bukan Angka" dan merupakan hasil dari operasi yang tidak ditentukan pada bilangan floating point seperti misalnya membagi nol dengan nol. (Perhatikan bahwa sementara membagi bilangan bukan nol dengan nol juga biasanya tidak ditentukan dalam matematika, ini tidak menghasilkan NaN tetapi dalam tak terhingga positif atau negatif).


5

NaNberarti "Bukan angka." Ini adalah nilai floating point khusus yang berarti bahwa hasil operasi tidak ditentukan atau tidak dapat direpresentasikan sebagai bilangan real.

Lihat di sini untuk penjelasan lebih lanjut tentang nilai ini.




4

Berarti Bukan Angka. Ini adalah representasi umum untuk nilai numerik yang tidak mungkin dalam banyak bahasa pemrograman.


4

Contoh minimal runnable

Hal pertama yang harus Anda ketahui, adalah bahwa konsep NaN diterapkan langsung pada perangkat keras CPU.

Semua CPU modern utama tampaknya mengikuti IEEE 754 yang menentukan format floating point, dan NaN, yang hanya nilai float khusus, adalah bagian dari standar itu.

Oleh karena itu, konsepnya akan sangat mirip di semua bahasa, termasuk Java yang hanya memancarkan kode floating point langsung ke CPU.

Sebelum melanjutkan, Anda mungkin ingin membaca terlebih dahulu jawaban yang saya tulis berikut ini:

Sekarang untuk beberapa tindakan Java. Sebagian besar fungsi minat yang tidak ada dalam bahasa inti ada di dalamnya java.lang.Float.

Nan.java

import java.lang.Float;
import java.lang.Math;

public class Nan {
    public static void main(String[] args) {
        // Generate some NaNs.
        float nan            = Float.NaN;
        float zero_div_zero  = 0.0f / 0.0f;
        float sqrt_negative  = (float)Math.sqrt(-1.0);
        float log_negative   = (float)Math.log(-1.0);
        float inf_minus_inf  = Float.POSITIVE_INFINITY - Float.POSITIVE_INFINITY;
        float inf_times_zero = Float.POSITIVE_INFINITY * 0.0f;
        float quiet_nan1     = Float.intBitsToFloat(0x7fc00001);
        float quiet_nan2     = Float.intBitsToFloat(0x7fc00002);
        float signaling_nan1 = Float.intBitsToFloat(0x7fa00001);
        float signaling_nan2 = Float.intBitsToFloat(0x7fa00002);
        float nan_minus      = -nan;

        // Generate some infinities.
        float positive_inf   = Float.POSITIVE_INFINITY;
        float negative_inf   = Float.NEGATIVE_INFINITY;
        float one_div_zero   = 1.0f / 0.0f;
        float log_zero       = (float)Math.log(0.0);

        // Double check that they are actually NaNs.
        assert  Float.isNaN(nan);
        assert  Float.isNaN(zero_div_zero);
        assert  Float.isNaN(sqrt_negative);
        assert  Float.isNaN(inf_minus_inf);
        assert  Float.isNaN(inf_times_zero);
        assert  Float.isNaN(quiet_nan1);
        assert  Float.isNaN(quiet_nan2);
        assert  Float.isNaN(signaling_nan1);
        assert  Float.isNaN(signaling_nan2);
        assert  Float.isNaN(nan_minus);
        assert  Float.isNaN(log_negative);

        // Double check that they are infinities.
        assert  Float.isInfinite(positive_inf);
        assert  Float.isInfinite(negative_inf);
        assert !Float.isNaN(positive_inf);
        assert !Float.isNaN(negative_inf);
        assert one_div_zero == positive_inf;
        assert log_zero == negative_inf;
            // Double check infinities.

        // See what they look like.
        System.out.printf("nan            0x%08x %f\n", Float.floatToRawIntBits(nan           ), nan           );
        System.out.printf("zero_div_zero  0x%08x %f\n", Float.floatToRawIntBits(zero_div_zero ), zero_div_zero );
        System.out.printf("sqrt_negative  0x%08x %f\n", Float.floatToRawIntBits(sqrt_negative ), sqrt_negative );
        System.out.printf("log_negative   0x%08x %f\n", Float.floatToRawIntBits(log_negative  ), log_negative  );
        System.out.printf("inf_minus_inf  0x%08x %f\n", Float.floatToRawIntBits(inf_minus_inf ), inf_minus_inf );
        System.out.printf("inf_times_zero 0x%08x %f\n", Float.floatToRawIntBits(inf_times_zero), inf_times_zero);
        System.out.printf("quiet_nan1     0x%08x %f\n", Float.floatToRawIntBits(quiet_nan1    ), quiet_nan1    );
        System.out.printf("quiet_nan2     0x%08x %f\n", Float.floatToRawIntBits(quiet_nan2    ), quiet_nan2    );
        System.out.printf("signaling_nan1 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan1), signaling_nan1);
        System.out.printf("signaling_nan2 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan2), signaling_nan2);
        System.out.printf("nan_minus      0x%08x %f\n", Float.floatToRawIntBits(nan_minus     ), nan_minus     );
        System.out.printf("positive_inf   0x%08x %f\n", Float.floatToRawIntBits(positive_inf  ), positive_inf  );
        System.out.printf("negative_inf   0x%08x %f\n", Float.floatToRawIntBits(negative_inf  ), negative_inf  );
        System.out.printf("one_div_zero   0x%08x %f\n", Float.floatToRawIntBits(one_div_zero  ), one_div_zero  );
        System.out.printf("log_zero       0x%08x %f\n", Float.floatToRawIntBits(log_zero      ), log_zero      );

        // NaN comparisons always fail.
        // Therefore, all tests that we will do afterwards will be just isNaN.
        assert !(1.0f < nan);
        assert !(1.0f == nan);
        assert !(1.0f > nan);
        assert !(nan == nan);

        // NaN propagate through most operations.
        assert Float.isNaN(nan + 1.0f);
        assert Float.isNaN(1.0f + nan);
        assert Float.isNaN(nan + nan);
        assert Float.isNaN(nan / 1.0f);
        assert Float.isNaN(1.0f / nan);
        assert Float.isNaN((float)Math.sqrt((double)nan));
    }
}

GitHub upstream .

Jalankan dengan:

javac Nan.java && java -ea Nan

Keluaran:

nan            0x7fc00000 NaN
zero_div_zero  0x7fc00000 NaN
sqrt_negative  0xffc00000 NaN
log_negative   0xffc00000 NaN
inf_minus_inf  0x7fc00000 NaN
inf_times_zero 0x7fc00000 NaN
quiet_nan1     0x7fc00001 NaN
quiet_nan2     0x7fc00002 NaN
signaling_nan1 0x7fa00001 NaN
signaling_nan2 0x7fa00002 NaN
nan_minus      0xffc00000 NaN
positive_inf   0x7f800000 Infinity
negative_inf   0xff800000 -Infinity
one_div_zero   0x7f800000 Infinity
log_zero       0xff800000 -Infinity

Jadi dari sini kita belajar beberapa hal:

  • operasi mengambang aneh yang tidak memiliki hasil yang masuk akal memberi NaN:

    • 0.0f / 0.0f
    • sqrt(-1.0f)
    • log(-1.0f)

    menghasilkan NaN.

    Di C, sebenarnya mungkin untuk meminta sinyal untuk dimunculkan pada operasi semacam itu dengan feenableexceptuntuk mendeteksinya, tetapi saya tidak berpikir itu terekspos di Jawa: Mengapa pembagian integer dengan nol 1/0 memberikan kesalahan tetapi floating point 1 / 0.0 mengembalikan "Inf"?

  • operasi aneh yang berada di batas baik plus atau minus tak terhingga namun memberikan + - tak terhingga, bukan NaN

    • 1.0f / 0.0f
    • log(0.0f)

    0.0 hampir termasuk dalam kategori ini, tetapi kemungkinan masalahnya adalah bahwa itu bisa menjadi plus atau minus infinity, jadi itu dibiarkan sebagai NaN.

  • jika NaN adalah masukan dari operasi mengambang, keluarannya juga cenderung menjadi NaN

  • ada beberapa nilai yang mungkin untuk NaN 0x7fc00000, 0x7fc00001, 0x7fc00002, meskipun x86_64 tampaknya hanya menghasilkan 0x7fc00000.

  • NaN dan infinity memiliki representasi biner yang serupa.

    Mari kita uraikan beberapa di antaranya:

    nan          = 0x7fc00000 = 0 11111111 10000000000000000000000
    positive_inf = 0x7f800000 = 0 11111111 00000000000000000000000
    negative_inf = 0xff800000 = 1 11111111 00000000000000000000000
                                | |        |
                                | |        mantissa
                                | exponent
                                |
                                sign

    Dari sini kami mengkonfirmasi apa yang ditentukan IEEE754:

    • baik NaN dan infinitas memiliki eksponen == 255 (semua satu)
    • infinitas memiliki mantissa == 0. Oleh karena itu hanya ada dua kemungkinan infinitas: + dan -, dibedakan oleh bit tanda
    • NaN memiliki mantissa! = 0. Oleh karena itu ada beberapa kemungkinan, kecuali mantissa == 0 yang tak terhingga
  • NaN dapat berupa positif atau negatif (bit atas), meskipun hal ini tidak berpengaruh pada operasi normal

Diuji di Ubuntu 18.10 amd64, OpenJDK 1.8.0_191.


3

Bukan orang Java, tetapi dalam JS dan bahasa lain saya menggunakan "Bukan Nomor", yang berarti beberapa operasi menyebabkannya menjadi bukan nomor yang valid.



3

Bukan nilai floating-point yang valid (misalnya hasil pembagian dengan nol)

http://en.wikipedia.org/wiki/NaN


Saya berdalih dengan jawaban ini. Pertama: "NaN" ADALAH nilai yang valid untuk float IEEE! (Lagi pula, itu didefinisikan dalam spesifikasi ... jadi "valid", kan?). Kedua: "pembagian dengan nol" dapat diwakili oleh IEEE "Infinity Positif" atau "Infinity Negatif"; contoh yang lebih baik dari "NaN" adalah "nol dibagi nol", seperti yang ditunjukkan oleh beberapa jawaban lain dengan benar.
Dan H

"Nilai valid" dan "ditentukan dalam spesifikasi" bukanlah hal yang sama. Setuju dengan 0/0.
Vladimir Dyuzhev
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.