Що в Java означає що означає NaN?


107

У мене є програма, яка намагається зменшити doubleкількість до потрібної кількості. Вихід, який я отримую, - це NaN.

Що NaNозначає Java?


Є хороший опис NaN та загальних підводних каменів при використанні NaN на Java: ppkwok.blogspot.co.uk/2012/11/…
Phil

Якщо ви запитуєте: "що за NaN?" в Java (або будь-якій іншій мові) я можу надати вам випадок використання, коли це дуже зручно: коли у мене є двовимірний масив плавців, але мій обчислення не має значущого значення для деякої частини цього двовимірного масиву, Я заповню це значення "NaN". Це може використовуватися для подачі сигналу користувачам мого розрахунку (наприклад, коли він перетворюється на растрове зображення) "не звертайте уваги на значення в цій точці". Дуже корисний!
Дан Х

До речі, що саме - це означає "зменшити" подвійну? Цікаво ...
Dan H

Відповіді:


153

З цієї сторінки :

"NaN" означає "не число". "Nan" виробляється, якщо операція з плаваючою точкою має деякі вхідні параметри, які призводять до того, що операція дає певний невизначений результат. Наприклад, 0,0, поділене на 0,0, є арифметично невизначеним. Беручи квадратний корінь від’ємного числа, також не визначено.


16
Крім того, NaN визначається стандартом IEEE для арифметики з плаваючою комою (IEEE 754), який явно слідує Java. Читання стандарту відкриває вам очі на багато речей, причому численні значення нуля є однією з речей.
Есько

37
Також NaNмає цікаву властивість бути єдиним «числом», яке не є таким самим, як у порівнянні. Тому загальне (і в багатьох мовах тільки) тест , якщо число xє NaNполягає в наступному:boolean isNaN(x){return x != x;}
quazgar

3
Посилання у відповідь мертва?
Панг

3
... "Взяття квадратного кореня від'ємного числа не визначене (в арифметиці)" ... Його немає! його на самому справі , iі деякі мови , як пітон справа дуже добре з ним ... Це може бути не так в javaти
Рафаель T

5
@RafaelT Я б сказав, що це не визначено в не складній арифметиці. Немає способу призначити складне число float або double у Java. Python динамічно набирається, тому в цьому випадку можливо просто повернути складне число.
sstn

19

NaNозначає "Не число" і є в основному поданням спеціального значення з плаваючою точкою в стандарті IEE 754 з плаваючою точкою . NaN загалом означає, що значення - це те, що неможливо виразити дійсним числом плаваючої точки.

Перетворення призведе до цього значення, коли значення, яке перетворюється, є чимось іншим, наприклад, при перетворенні рядка, який не представляє числа.


Як перетворити? З parseFloat()або parseDouble? Або щось інше?
Алонсо дель Арте

14

NaNозначає "Не число" і є результатом невизначених операцій над числами з плаваючою комою, як, наприклад, ділення нуля на нуль. (Зауважимо, що хоча ділення ненульового числа на нуль також зазвичай не визначене в математиці, це не призводить до NaN, а до позитивної чи негативної нескінченності).


5

NaNозначає "Не число". Це спеціальне значення з плаваючою комою, що означає, що результат операції не був визначений або не відображався як дійсне число.

Дивіться тут для отримання додаткового пояснення цього значення


5

NaN означає Не Число. Він використовується для позначення будь-якого значення, яке математично не визначене. Як і ділення 0,0 на 0,0. Ви можете подивитися тут для отримання додаткової інформації: https://web.archive.org/web/20120819091816/http://www.concentric.net/~ttwang/tech/javafloat.htm

Опублікуйте свою програму тут, якщо вам потрібна додаткова допомога.



4

Значить не число. Це загальне уявлення про неможливе числове значення у багатьох мовах програмування.


4

Приклад мінімальної експлуатації

Перше, що вам потрібно знати, - це те, що концепція NaN реалізована безпосередньо на апаратному забезпеченні процесора.

Усі основні сучасні процесори, схоже, дотримуються IEEE 754, який визначає формати з плаваючою комою, а NaN, які є лише спеціальними значеннями поплавця, є частиною цього стандарту.

Тому концепція буде дуже схожою на будь-якій мові, включаючи Java, яка просто випромінює код з плаваючою комою безпосередньо в процесор.

Перш ніж продовжувати, ви можете спершу прочитати такі відповіді, які я написав:

Тепер для деяких дій Java. Більшість функцій, що представляють інтерес, не є основними мовами, живуть всередині 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 вище за течією .

Виконати з:

javac Nan.java && java -ea Nan

Вихід:

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

Отже, з цього ми дізнаємось кілька речей:

  • дивні плаваючі операції, які не мають жодного розумного результату, дають NaN:

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

    генерувати a NaN.

    В C, насправді, можна попросити підняти сигнали для таких операцій, feenableexceptщоб виявити їх, але я не думаю, що це піддається впливу в Java: Чому ціле ділення на нуль 1/0 дає помилку, але плаваюча точка 1 / 0,0 повертає "Інф"?

  • дивні операції, які знаходяться на межі плюс або мінус нескінченності, однак дають + - нескінченність замість NaN

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

    0.0 майже належить до цієї категорії, але, ймовірно, проблема полягає в тому, що вона може перейти до плюс-мінус нескінченності, тому вона залишилася як NaN.

  • якщо NaN є входом плаваючої операції, вихід також має тенденцію бути NaN

  • Є кілька можливих значень для NaN 0x7fc00000, 0x7fc00001, 0x7fc00002, хоча x86_64 здається генерувати тільки 0x7fc00000.

  • NaN і нескінченність мають подібне бінарне представлення.

    Розбимо декілька з них:

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

    З цього ми підтверджуємо, що IEEE754 вказує:

    • і NaN, і нескінченність мають показник == 255 (усі)
    • нескінченності мають мантісу == 0. Тому існує лише дві можливі нескінченності: + і -, диференційовані знаком біта
    • NaN має мантісу! = 0. Тому існує кілька можливостей, крім мантіси == 0, що є нескінченним
  • NaN можуть бути як позитивними, так і негативними (верхній біт), хоча це не впливає на звичайні операції

Тестовано в Ubuntu 18.10 amd64, OpenJDK 1.8.0_191.


3

Це не хлопець на Java, але в JS та інших мовах я використовую це "Не число", тобто деяка операція призвела до того, що він не став дійсним числом.



3

Недійсне значення з плаваючою комою (наприклад, результат ділення на нуль)

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


Я посперечаюсь з цією відповіддю. По-перше: "NaN" - це дійсне значення для плавця IEEE! (Зрештою, він визначений у специфікації ... тому його "дійсний", правда?). По-друге: "поділ на нуль" може бути представлений IEEE "Позитивна нескінченність" або "Негативна нескінченність"; кращим прикладом "NaN" є "нуль, поділений на нуль", як правильно вказали деякі інші відповіді.
Дан Х

"Дійсні значення" та "визначені в специфікації" - це не те саме. Погоджено на 0/0.
Володимир Дюжев
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.