Pull to refresh

Comments 29

Все эти странности идут из стандарта IEE 754. Собрались люди и сделали стандарт так, что какую бы чушь ты не считал, чтобы получил адекватный результат. (Чушь — адекватный результат, хм, ладно....)
Глядя на это все иногда возникает чувство, что тут немного перемудрили…

Там, насколько я помню, не комитет по стандартизации придумывал, а Intel продавила свою реализацию.

Заведомо там вначале условие, что если 1, то и возвращается 1 неглядя на остальные аргументы.
Может не надо было называть число «not a number», если это все-таки число, хоть и не определенное.

Но это в самом деле не число. Оно не обладает свойствами действительных чисел.

Да. Но как я понимаю, здесь ставится вопрос «Что предпочтительнее в данных обстоятельствах?»

Это зависит от задачи. Скажем, при определении кривой Безье соглашение о том, что 0**0=1 упрощает формулу.


Где-то тут на Хабре была статья о том, что в некоторых языках программирования определено три разных функции возведения в степень, отличающиеся только поведением в точке 0**0.

Спасибо, очень понравилось ваше мнемоническое правило, что NaN — это на самом деле число, просто неизвестное. Могу добавить, что, поскольку log(-1) = NaN, это число ещё и необязательно вещественное (в данном случае комплексное).

Еще один прикол NaN — он не равен ничему, даже самому себе


>>> nan != nan
True
Ну это-то логично. Если под NaN может быть любое число, то вероятность совпадения исчезающе мала. А вот если-бы вы результат функции конторая выдала вам nan сравнивали сам с собой-тогда уже другой вопрос.
Только вот это не всегда так. Например, GLSL не на любых GPU вернёт true при проверке NaN != NaN. Только isnan() вернёт правильный результат.

В большинстве реализаций это так, но существуют исключения, которые отходят отходят от стандарта. В PostgreSQL NaN == NaN, и NaN больше чем любое число (больше, чем Infinity)

Это было введено в стандарт для того, чтобы не пришлось добавлять в языки операцию проверки на NaN.
В ранних языках стандартным способом проверки x на NaN было условие x != x.

Я нашел ответ на SO от бывшего члена комитета IEEE754.


More importantly, there was no isnan( ) predicate at the time that NaN was formalized in the 8087 arithmetic; it was necessary to provide programmers with a convenient and efficient means of detecting NaN values that didn’t depend on programming languages providing something like isnan( ) which could take many years.
https://stackoverflow.com/questions/1565164/what-is-the-rationale-for-all-comparisons-returning-false-for-ieee754-nan-values/1573715#1573715
Если функция возводится в степень и при этом стремится к 0, то в результате получится 1, вне зависимости от того, какое значение имеет функция.

Кто-то не знаком с определением числа e, например. lim_{x -> inf} (1 + 1/x) ^ (1/x) = e != 1.

Поправочка. В написанном вами пределе всё-таки получится 1^0 = 1. Чтобы e получить, надо считать 1^∞, т.е. (1 + 1/x)^x при x→∞. Но если степень стремится к нулю, то не единица может получаться в особенностях вида 0^0 и ∞^0. Например, x^{1 / ln x} → e при x→0.

Да, ошибся. Забыл, как выглядит замечательный предел.

Я подумал и угадал верный результат. При этом я даже едва знаком с питоном. По-моему, всё предельно логично.

Я подумал и угадал верный результат.

С учетом всех ваших статей на Хабре — вам можно верить на слово.
По-моему, всё предельно логично.

Верно. Возможно раньше я бы тоже ответил правильно, но уже пол года активно использую Pandas, а там NaN начинает восприниматься буквально, как пропущенные (или отсутствующие) данные. Перестаешь воспринимать NaN как число.

Интересно, а это поведение тоже выглядит предельно логично?


>>> 0*nan
nan

Да, потому что за NaN в предложенной логике может скрываться Inf.

Ну кстати, если так рассуждать, ломается логика случая, с которого мы начали. Единица в степени бесконечность — это неопределённость.
Да. Ноль в положительной степени — ноль, в отрицательной — бесконечность.

Я угадал верный результат только потому что раз есть вопрос (и целая статья на эту тему), значит не очень очевидное поведение. Логическо только 2 подошла. Но, стоит признаться, я думал что приоритет у вычислительного рака NaN выше и все функции, которые на него натыкаются, так же должны возвращать NaN без исключений.


Более того, в некоторых языках (не будем тыкать в js пальцем) за NaN может скрываться не какое-то число, которое не влезло в дабл или что-то в этом духе, а строка или вообще объект. В нем выражение Math.pow(1, "give me a power!") или даже с смайликом в качестве степени — возможно. Единица в степени эмоджи, равная единице, выглядит странно.


Справедливости ради, в JS все наоборот, как обычно:


1 ** NaN // NaN

"Give me a power" ** 0 // 1
new Object() ** 0 // 1
А я ее как-то читал :)

Прежде чем писать статью, вбил «NaN» в поиск Хабра, был уверен, что про это уже кто-нибудь писал. Надо сказать, в результате поиска очень много классных статей.
Имеет ли смысл использовать такое на практике? Думаю, что лучше не стоит.

Правильно думаете. NaN — это семейство значений с плавающей точкой, у которых экспонента состоит полностью из 1, а мантисса не состоит полностью из нулей. Поэтому nan как литерал не обязан быть по хэшу равен nan, полученному в ходе вычислений.


По теме статьи — вопрос дискуссионный, что считать наиболее правильным подходом. Как по мне, надо бы различать два случая:


  • 1.0**nan должно быть nan, т.к. 1.0 обозначает лишь некоторое число между 1-eps/2 и 1+eps. В частности, (1 + 10**(-10))**nannan, но (float32(1 + 10**(-10)))**nan == 1 выглядит несколько абсурдно
  • 1**nan (1 — целое число) вполне можно взять равным 1.0, т.к. целочисленный литерал тут обозначает точную единицу без какой-либо погрешности
Во многих процессорах операция с nan может приводить к программному исключению. Правда эта функция может быть и выключена. Так что программное исключение тоже может быть результатом вычисления приведенного примера:)
Sign up to leave a comment.

Articles