В вычислительной технике NaN ( / n æ n / ) , что означает Not a Number (не число ) , представляет собой конкретное значение числового типа данных (часто число с плавающей точкой ), которое не определено как число, например, результат 0/0 . Систематическое использование NaN было введено стандартом IEEE 754 с плавающей точкой в 1985 году, наряду с представлением других неконечных величин, таких как бесконечности .
В математике результат 0/0 обычно не определяется как число [a] и поэтому может быть представлен как NaN в вычислительных системах.
Квадратный корень отрицательного числа не является действительным числом , и поэтому также представлен как NaN в совместимых вычислительных системах. NaN также могут использоваться для представления отсутствующих значений в вычислениях. [1] [2]
Предоставляются два отдельных типа NaN, называемые тихими NaN и сигнальными NaN . Тихие NaN используются для распространения ошибок, возникающих из-за недопустимых операций или значений. Сигнальные NaN могут поддерживать расширенные функции, такие как смешивание числовых и символьных вычислений или другие расширения базовой арифметики с плавающей точкой.
В вычислениях с плавающей точкой NaN не то же самое, что бесконечность , хотя оба обычно обрабатываются как особые случаи в представлениях вещественных чисел с плавающей точкой, а также в операциях с плавающей точкой. Недопустимая операция также не то же самое, что арифметическое переполнение (которое вернуло бы бесконечность или наибольшее конечное число по величине) или арифметическое подзаряд (которое вернуло бы наименьшее нормальное число по величине, субнормальное число или ноль ).
Значения NaN в формате IEEE 754 кодируются с помощью поля экспоненты, заполненного единицами (как значения бесконечности), и некоторого ненулевого числа в поле мантиссы (чтобы отличать их от значений бесконечности); это позволяет определять несколько различных значений NaN в зависимости от того, какие биты установлены в поле мантиссы, а также от значения ведущего бита знака (но приложения не обязаны предоставлять различную семантику для этих различных значений NaN).
Например, NaN одинарной точности (32 бита) IEEE 754 будет закодирован как
s111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
где s — знак (чаще всего игнорируется в приложениях), а последовательность x представляет собой ненулевое число (значение ноль кодирует бесконечности). На практике старший бит из x используется для определения типа NaN: «тихий NaN» или «сигнальный NaN» (подробнее см. в разделе Кодирование). Остальные биты кодируют полезную нагрузку (чаще всего игнорируется в приложениях).
Операции с плавающей точкой, отличные от упорядоченных сравнений, обычно распространяют тихий NaN ( qNaN ). Большинство операций с плавающей точкой на сигнальном NaN ( sNaN ) сигнализируют об исключении недопустимой операции ; действие исключения по умолчанию тогда такое же, как для операндов qNaN, и они производят qNaN, если производят результат с плавающей точкой.
Распространение тихих NaN через арифметические операции позволяет обнаруживать ошибки в конце последовательности операций без обширного тестирования на промежуточных этапах. Например, если начать с NaN и добавить 1 пять раз подряд, каждое добавление приведет к NaN, но нет необходимости проверять каждое вычисление, поскольку можно просто отметить, что конечный результат — NaN. Однако, в зависимости от языка и функции, NaN могут быть тихо удалены из цепочки вычислений, где одно вычисление в цепочке даст постоянный результат для всех других значений с плавающей точкой. Например, вычисление x 0 может дать результат 1, даже если x — NaN, поэтому проверка только конечного результата скроет тот факт, что вычисление до x 0 привело к NaN. В общем случае, затем, для обнаружения всех случаев, когда вводятся NaN, необходим более поздний тест на установленный недопустимый флаг [3] (см. Определение функции ниже для получения дополнительных сведений).
В разделе 6.2 старого стандарта IEEE 754-2008 есть две аномальные функции ( функции maxNum
и minNum
, которые возвращают максимум и минимум соответственно двух операндов, которые, как ожидается, будут числами), которые отдают предпочтение числам — если хотя бы один из операндов является NaN, то возвращается значение другого операнда. Пересмотр IEEE 754-2019 заменил эти функции, поскольку они не являются ассоциативными (когда в операнде появляется сигнальный NaN). [4] [5]
Сравнения определены стандартом IEEE 754 для учета возможных операндов NaN. [6] При сравнении двух действительных чисел или расширенных действительных чисел (как в форматах с плавающей точкой IEEE 754) первое число может быть либо меньше, либо равно, либо больше второго числа. Это дает три возможных отношения. Но когда хотя бы один операнд сравнения — NaN, эта трихотомия не применяется, и необходимо четвертое отношение: неупорядоченное . В частности, два значения NaN сравниваются как неупорядоченные, а не как равные.
Как указано, предикаты, связанные с математическими символами <, ≤, =, ≥, > (или эквивалентными обозначениями в языках программирования), возвращают false для неупорядоченного отношения. Так, например, NOT ( x < y ) логически не эквивалентно x ≥ y : для неупорядоченного, т. е. когда x или y равно NaN, первый возвращает true, а последний возвращает false. Однако ≠ определяется как отрицание =, поэтому он возвращает true для неупорядоченного.
Согласно этим правилам, сравнение x с самим собой, x ≠ x или x = x , можно использовать для проверки того, является ли x NaN или не NaN.
Предикаты сравнения являются либо сигнальными, либо несигнальными для тихих операндов NaN; сигнальные версии сигнализируют об исключении недопустимой операции для таких сравнений (т. е. по умолчанию это просто устанавливает соответствующий флаг статуса в дополнение к поведению несигнальных версий). Предикаты равенства и неравенства являются несигнальными. Все другие стандартные предикаты сравнения, связанные с указанными выше математическими символами, являются сигнальными, если они получают операнд NaN. Стандарт также предоставляет несигнальные версии этих других предикатов. Предикат определяет, является ли значение NaN, и никогда не сигнализирует об исключении, даже если x является сигнальным NaN.isNaN(x)
Стандарт IEEE для чисел с плавающей точкой требует, чтобы соблюдалось условие NaN ≠ NaN . Напротив, частный стандарт арифметики posit 2022 года имеет схожую концепцию, NaR (Not a Real), где соблюдается условие NaR = NaR . [7]
Существует три вида операций, которые могут возвращать NaN: [8]
pow
функция и целочисленная экспоненциальная pown
функция определяют 0 0 , 1 ∞ и ∞ 0 как 1 .powr
определяет все три неопределенные формы как недопустимые операции и поэтому возвращает NaN.NaN также могут быть явно назначены переменным, как правило, как представление отсутствующих значений. До стандарта IEEE программисты часто использовали специальное значение (например, −99999999) для представления неопределенных или отсутствующих значений, но не было никакой гарантии, что они будут обработаны последовательно или правильно. [1]
NaN не обязательно генерируются во всех вышеперечисленных случаях. Если операция может создать условие исключения, а ловушки не замаскированы, то операция вместо этого вызовет ловушку. [9] Если операнд является тихим NaN, и также нет сигнализирующего операнда NaN, то условия исключения нет, и результатом является тихий NaN. Явные назначения не вызовут исключения даже для сигнализирующих NaN.
В общем, тихие NaN или qNaN не вызывают никаких дополнительных исключений, поскольку они распространяются через большинство операций. Но исключение недопустимой операции сигнализируется некоторыми операциями, которые не возвращают значение с плавающей точкой, такими как преобразования формата или определенные операции сравнения.
Сигнальные NaN, или sNaN, являются особыми формами NaN, которые при использовании большинством операций должны вызывать исключение недопустимой операции, а затем, если это уместно, "успокаиваться" в qNaN, который затем может распространяться. Они были введены в IEEE 754. Было несколько идей относительно того, как их можно использовать:
При обнаружении обработчик ловушек может декодировать sNaN и вернуть индекс к вычисленному результату. На практике этот подход сталкивается со многими осложнениями. Обработка знакового бита NaN для некоторых простых операций (таких как абсолютное значение ) отличается от обработки для арифметических операций. Ловушки не требуются стандартом. [ необходима цитата ]
IEEE 754-2019 рекомендует реализовать операции getPayload , setPayload и setPayloadSignaling , [10] стандартизируя доступ к полезным нагрузкам для упрощения использования приложений. [11] Согласно справочному документу IEEE 754-2019, эту рекомендацию следует интерпретировать как «требуемую для новых реализаций с оговоркой для обратной совместимости». [12]
В форматах обмена IEEE 754 NaN идентифицируются определенными, предопределенными битовыми шаблонами, уникальными для NaN. Знаковый бит не имеет значения. Двоичный формат NaN представлен экспоненциальным полем, заполненным единицами (как значения бесконечности), и некоторым ненулевым числом в поле значащей части (чтобы отличать их от значений бесконечности). Исходный стандарт IEEE 754 от 1985 года ( IEEE 754-1985 ) описывал только двоичные форматы с плавающей точкой и не указывал, как следует помечать состояние сигнализации/спокойствия. На практике старший значащий бит поля значащей части определял, является ли NaN сигнальным или тихим. В результате были получены две различные реализации с обратными значениями:
is_quiet
is_signaling
.Первый вариант был предпочтительнее, поскольку он позволяет реализации заглушить сигнальный NaN, просто установив бит сигнализации/заглушения в 1. Обратное невозможно при последнем варианте, поскольку установка бита сигнализации/заглушения в 0 может привести к бесконечности. [13]
В редакциях стандарта IEEE 754 2008 и 2019 годов содержатся формальные требования и рекомендации по кодированию состояния сигнализации/спокойствия.
is_quiet
. [15] То есть этот бит не равен нулю, если NaN тихий, и нулю, если NaN сигнальный.is_signaling
. То есть этот бит равен нулю, если NaN не активен, и не равен нулю, если NaN сигнализирует. [16]Для соответствия IEEE 754-2008 значение бита сигнализации/тишины в последних процессорах MIPS теперь можно настроить через поле NAN2008 регистра FCSR. Эта поддержка является необязательной в MIPS Release 3 и обязательной в Release 5. [17]
Состояние/значение остальных битов поля значимости не определены стандартом. Это значение называется «полезной нагрузкой» NaN. Если операция имеет один вход NaN и распространяет его на выход, полезная нагрузка результирующего NaN должна быть такой же, как у входного NaN (это не всегда возможно для двоичных форматов, когда сигнальное/тихое состояние кодируется флагом is_signaling
, как объяснено выше). Если есть несколько входов NaN, полезная нагрузка результирующего NaN должна быть из одного из входных NaN; стандарт не указывает, какой именно.
В ряде систем есть концепция «канонического NaN», где одно конкретное значение NaN выбирается как единственное возможное значение qNaN, сгенерированное операциями с плавающей точкой, не имеющими входного значения NaN. Значение обычно выбирается как тихое NaN с нулевой полезной нагрузкой и произвольно определенным битом знака.
Использование ограниченного количества представлений NaN позволяет системе использовать другие возможные значения NaN для неарифметических целей, наиболее важным из которых является «NaN-boxing», т. е. использование полезной нагрузки для произвольных данных. [23] (Эта концепция «канонического NaN» не совпадает с концепцией «канонического кодирования» в IEEE 754.)
Существуют разные мнения о правильном определении результата числовой функции , которая получает тихий NaN в качестве входных данных. Одна точка зрения заключается в том, что NaN должен распространяться на выход функции во всех случаях, чтобы распространить указание на ошибку. Другая точка зрения, принятая стандартами ISO C99 и IEEE 754-2008 в целом, заключается в том, что если функция имеет несколько аргументов и выход однозначно определяется всеми не-NaN входными данными (включая бесконечность), то это значение должно быть результатом. Так, например, значение, возвращаемое hypot(±∞, qNaN)
и, hypot(qNaN, ±∞)
равно +∞.
Проблема особенно остра для функции возведения в степень = x y . Выражения 0 0 , ∞ 0 и 1 ∞ считаются неопределенными формами , когда они встречаются как пределы (как и ∞ × 0), и вопрос о том, следует ли определять ноль в нулевой степени как 1, имеет разделившиеся мнения.pow(x, y)
Если вывод считается неопределенным, когда параметр не определен, то pow(1, qNaN)
должен выдавать qNaN. Однако математические библиотеки обычно возвращают 1 для любого действительного числа y , и даже когда y является бесконечностью . Аналогично они выдают 1 для даже когда x равен 0 или бесконечности. Обоснованием возврата значения 1 для неопределенных форм было то, что значение функций в особых точках может быть принято как определенное значение, если это значение находится в пределе значение [ необходимо пояснение ] для всех, кроме исчезающе малой части шара вокруг предельного значения параметров. [ необходима цитата ] Версия стандарта IEEE 754 2008 года гласит, что и должны возвращать 1, поскольку они возвращают 1, что бы ни использовалось, вместо тихого NaN. Более того, ISO C99, а позднее IEEE 754-2008, решили указать = 1 вместо qNaN; Причина такого выбора указана в обосновании C: [24] «Как правило, C99 избегает результата NaN там, где полезно числовое значение. ... Результат равен +∞, поскольку все большие положительные значения с плавающей точкой являются четными целыми числами».pow(1, y)
pow(x, 0)
pow(1, qNaN)
pow(qNaN, 0)
pow(−1, ±∞)
pow(−2, ∞)
Чтобы удовлетворить тех, кто желает более строгой интерпретации того, как должна действовать степенная функция, стандарт 2008 года определяет две дополнительные степенные функции: , где показатель степени должен быть целым числом, и , которая возвращает NaN всякий раз, когда параметр является NaN или возведение в степень даст неопределенную форму .pown(x, n)
powr(x, y)
Большинство форматов целых чисел фиксированного размера не могут явно указывать на недопустимые данные. В таком случае при преобразовании NaN в целочисленный тип стандарт IEEE 754 требует, чтобы исключение недопустимой операции было сигнализировано. Например, в Java такие операции выдают экземпляры java.lang.ArithmeticException
. [25] В C они приводят к неопределенному поведению , но если поддерживается приложение F, операция выдает «недопустимое» исключение с плавающей точкой (как того требует стандарт IEEE) и неуказанное значение.
Пакет Perl используетMath::BigInt
«NaN» для результата строк, которые не представляют допустимые целые числа. [26]
> perl -mMath::BigInt -e "print Math::BigInt->new('foo')" NaN
Разные операционные системы и языки программирования могут иметь разные строковые представления NaN.
нан (C, C++, Python)NaN (ECMAScript, Rust, C#, Julia). Julia может отображать альтернативные значения NaN, в зависимости от точности, NaN32 и NaN16; NaN — для типа Float64.NaN%НАН (C, C++, Rust)NaNQ (IBM XL и AIX: Fortran, C++ предложение n2290)NaNS (то же самое)qNaNsNaN1.#SNAN (Excel)1.#QNAN (Excel)-1.#ИНД (Excel)+nan.0 (Схема)
Поскольку на практике закодированные NaN имеют знак, тихий/сигнальный бит и необязательную «диагностическую информацию» (иногда называемую полезной нагрузкой ), они иногда будут встречаться и в строковых представлениях NaN. Вот несколько примеров:
-nan
), если он присутствует. Стандартного отображения полезной нагрузки или статуса сигнализации не существует, но тихое значение NaN определенной полезной нагрузки может быть создано либо путем предоставления строки функции разбора чисел (например, ), либо путем предоставления строки последовательности символов (или для sNaN), оба интерпретируются способом, определяемым реализацией.nan(char-sequence)
strtod
nan()
nans()
nan()
и nans()
. Они анализируют последовательность символов как целое число strtoull
(или эквивалент другого размера) с его обнаружением целочисленных оснований.nan()
синтаксический анализ, но strtod()
принимает шестнадцатеричный формат без префикса.Не все языки допускают существование нескольких NaN. Например, ECMAScript использует только одно значение NaN.
По большей части платформа Java SE обрабатывает значения NaN заданного типа так, как будто они свернуты в одно каноническое значение, и поэтому эта спецификация обычно относится к произвольному NaN как к каноническому значению.
Если указаны
символы…
, они используются каким-то неопределенным образом для выбора конкретного представления NaN (их может быть несколько).