Как внедряются Inf и NaN?
Как математические понятия, я хорошо знаю, что inf
а также nan
на самом деле Но что меня действительно интересует, так это то, как они реализованы на языках программирования.
В питоне я могу использовать inf
а также nan
в арифметических и условных выражениях, например:
>>> nan = float('nan')
>>> inf = float('inf')
>>> 1 + inf
inf
>>> inf + inf
inf
>>> inf - inf
nan
Это привело бы меня к мысли, что внутри python есть специальная зарезервированная битовая последовательность для этих двух математических величин, и никакое другое число не может занять эти позиции. Правильно ли мое предположение? Можете ли вы просветить меня в этом отношении?
Если мое предположение верно, то это легко объяснить:
>>> inf == inf
True
Однако это не так:
>>> nan == nan
False
Очевидно, в математике это правильный ответ. Но как Python знает, что он должен выплюнуть False
в этом случае?
Кроме того, как реализация Python отличается от реализации Java или C++?
2 ответа
Как правило, арифметика с плавающей запятой реализуется непосредственно аппаратно. Действительно, существуют специальные битовые комбинации для бесконечности и NaN, которые распознаются аппаратным модулем с плавающей точкой.
64-битные числа с плавающей точкой IEEE, используемые в CPython в типичных системах, имеют 1 бит для знака, 11 бит для показателя степени и 52 бита для мантиссы. Смотрите https://en.wikipedia.org/wiki/Double-precision_floating-point_format
Если показатель степени содержит 0b11111111111 (все единицы), то число равно либо inf, либо nan, в зависимости от того, что хранится в мантиссе. Python не должен делать ничего особенного для обработки этих случаев. Вы получите те же результаты, сравниваете ли вы числа в Python, C, Java или на ассемблере.
Это не специфичное для Python поведение, это скорее стандартное использование Python с плавающей точкой (и, возможно, все распространенные языки?).
nan
а также inf
являются специальным значением стандарта IEEE_754 с плавающей запятой. Конечно, они имеют внутренние представления (битовую последовательность, которую вы упоминаете), но их поведение не является обычным. Поведение не является обычным для других значений с плавающей запятой, но оно хорошо определено IEEE_754. Реализация осуществляется на уровне инструкций. (Процессор обрабатывает это в своей схеме с плавающей запятой)
Одно уточненное и нетривиальное поведение, NaN!= Все, включая себя.
Зная это, вы можете написать что-то вроде:
def isNaN(f): return f != f