Python3 Infinity/NaN: десятичное число или число с плавающей запятой

Дано (Python3):

>>> float('inf') == Decimal('inf')
True 

>>> float('-inf') <= float('nan') <= float('inf')
False

>>> float('-inf') <= Decimal(1) <= float('inf')
True

Почему следующие недействительны? Я прочитал Особые значения.

Инвалид

>>> Decimal('-inf') <= Decimal('nan') <= Decimal('inf')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

>>> Decimal('-inf') <= float('nan') <= Decimal('inf')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

>>> float('-inf') <= Decimal('nan') <= float('inf')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

person Douglas Denhartog    schedule 06.02.2015    source источник
comment
Вы читали напр. docs.python.org/3/library/decimal.html#special- значения   -  person jonrsharpe    schedule 06.02.2015
comment
Да; но не указанный стандарт IEEE 854 (см. Таблицу 3 в разделе 5.7).   -  person Douglas Denhartog    schedule 06.02.2015


Ответы (1)


Из decimal.py исходного кода:

# Note: The Decimal standard doesn't cover rich comparisons for
# Decimals.  In particular, the specification is silent on the
# subject of what should happen for a comparison involving a NaN.
# We take the following approach:
#
#   == comparisons involving a quiet NaN always return False
#   != comparisons involving a quiet NaN always return True
#   == or != comparisons involving a signaling NaN signal
#      InvalidOperation, and return False or True as above if the
#      InvalidOperation is not trapped.
#   <, >, <= and >= comparisons involving a (quiet or signaling)
#      NaN signal InvalidOperation, and return False if the
#      InvalidOperation is not trapped.
#
# This behavior is designed to conform as closely as possible to
# that specified by IEEE 754.

И из раздела Специальные значения. вы говорите, что читали:

Попытка сравнить два десятичных числа с использованием любого из операторов <, <=, > или >= вызовет сигнал InvalidOperation, если любой из операндов является NaN, и возвратит False, если этот сигнал не перехвачен.

Обратите внимание, что IEEE 754 использует NaN в качестве значения исключения с плавающей запятой; например вы сделали что-то, что не может быть вычислено, и вместо этого вы получили исключение. Это сигнальное значение, и его следует рассматривать как ошибку, а не как нечто, с чем можно сравнивать другие числа с плавающей запятой, поэтому в стандарте IEEE 754 оно не равно ничему другому.

Кроме того, в разделе Особые значения упоминаются:

Обратите внимание, что спецификация General Decimal Arithmetic не определяет поведение прямых сравнений; эти правила для сравнений с использованием NaN были взяты из стандарта IEEE 854 (см. Таблицу 3 в разделе 5.7).

и смотря раздел 5.7 IEEE 854, мы находим:

В дополнение к ответу истина/ложь, исключение недопустимой операции (см. 7.1) должно сигнализироваться, когда, как указано в последнем столбце таблицы 3, «неупорядоченные» операнды сравниваются с использованием одного из предикатов, включающих «‹» или «>». " но нет "?." (Здесь символ «?» означает «неупорядоченный».)

при сравнении с NaN классифицируются как неупорядоченные.

По умолчанию InvalidOperation перехватывается, поэтому при использовании <= и >= против Decimal('NaN') возникает исключение Python. Это логическое расширение; Python имеет фактические исключения, поэтому, если вы сравните значение исключения NaN, вы можете ожидать возникновения исключения.

Вы можете отключить перехват с помощью Decimal.localcontext():

>>> from decimal import localcontext, Decimal, InvalidOperation
>>> with localcontext() as ctx:
...     ctx.traps[InvalidOperation] = 0
...     Decimal('-inf') <= Decimal('nan') <= Decimal('inf')
... 
False
person Martijn Pieters    schedule 06.02.2015
comment
Как в этом случае развязать InvalidOperation? - person Douglas Denhartog; 06.02.2015
comment
@ddenhartog: например, используя локальный контекст. - person Martijn Pieters; 06.02.2015
comment
Спасибо :) Нет причин, по которым я не могу просто использовать float('nan') с обеих сторон; Мне было просто любопытно в учебных целях! - person Douglas Denhartog; 06.02.2015