Как различать различные типы NaN float в Python

я пишу код Python 2.6, который взаимодействует с Ni TestStand 4.2 через COM в Windows. Я хочу сделать значение" NAN " для переменной, но если я передам его float('nan'), TestStand отображает его как IND.

по-видимому, TestStand различает значения с плавающей запятой "IND" и "NAN". Согласно испытательном комплексе помочь:

  • IND соответствует Сигнализация NaN в Visual C++, в то время как
  • NAN соответствует QuietNaN

это означает, что Python float('nan') эффективно Сигнализация NaN при прохождении через COM. Однако из того, что я читал о Сигнализация NaN кажется, что Сигнализация NaN немного "экзотический" и Тихий НАНА ваша "обычная" Нэн. Поэтому у меня есть сомнения, что Python будет проходить Сигнализация NaN через COM. как я мог узнать, если питон float('nan') передается через COM как Сигнализация NaN или Тихий НАНА, а может неопределено?

есть ли способ сделать Сигнализация NaN и QuietNaN или неопределено в Python, при взаимодействии с другими языками? (Используя ctypes возможно?) Я предполагаю, что это будет решение для конкретной платформы, и я бы принял это в этом случай.

обновление: в Редакторе последовательности TestStand я попытался сделать две переменные, одну из которыхNAN и другой набор в IND. Затем я сохранил его в файле. Затем я открыл файл и прочитал каждую переменную с помощью Python. В обоих случаях, Python читает их как nan поплавок.

3 ответов


Я немного покопал для вас, и я думаю, что вы могли бы использовать struct модуль в сочетании с информацией на сводные диаграммы Кевина. Они объясняют точные битовые шаблоны, используемые для различных типов чисел с плавающей запятой IEEE 754.

единственное, что вам, вероятно, придется быть осторожным, если я читаю темы на этом IND-eterminate значение, является то, что это значение имеет тенденцию вызывать какой-то прерывания с плавающей запятой при назначении непосредственно в коде C, заставляя его превращаться в простой NaN. Что, в свою очередь, означало, что этим людям советовали делать такие вещи в ASM, а не C, так как C абстрагировал этот материал.. Поскольку это не моя область, и я не уверен, в какой степени такая ценность будет связываться с Python, я решил упомянуть об этом, чтобы вы могли, по крайней мере, следить за любым таким странным поведением. (См. принятый ответ для этот вопрос).

>>> import struct

>>> struct.pack(">d", float('nan')).encode("hex_codec")
'fff8000000000000'

>>> import scipy
>>> struct.pack(">d", scipy.nan).encode("hex_codec")
'7ff8000000000000'

со ссылкой на Кевин Сводные Диаграммы, это показывает, что float('nan') на самом деле технически неопределенное значение, в то время как scipy.nan тихая Нэн.

давайте попробуем сделать сигнальный NaN, а затем проверить его.

>>> try_signaling_nan = struct.unpack(">d", "\x7f\xf0\x00\x00\x00\x00\x00\x01")[0]
>>> struct.pack(">d", try_signaling_nan).encode("hex_codec")
'7ff8000000000001'

нет, сигнальный NaN преобразуется в Тихий NaN.

теперь давайте попробуем сделать тихий NaN непосредственно, а затем проверить его.

>>> try_quiet_nan = struct.unpack(">d", "\x7f\xf8\x00\x00\x00\x00\x00\x00")[0]
>>> struct.pack(">d", try_quiet_nan).encode("hex_codec")
'7ff8000000000000'

так вот как сделать правильный Тихий NaN с помощью struct.unpack()--по крайней мере, на платформе Windows.


CPython определение nan

когда Python сообщает nan, откуда оно взялось?

  • результат расчета (конкретные значения платформы?)
  • Py_NAN в исходном коде CPython C
    • определяется как (Py_HUGE_VAL * 0.)
      • значение зависит от платформы
      • Py_HUGE_VAL, вероятно, определяется как HUGE_VAL--у него есть записка, чтобы сказать, что это должно быть HUGE_VAL за исключением платформ, где это сломанный.
  • float('nan') которая определяется из Py_NAN в исходном коде C CPython.

чтение исходного кода Python и pywin32

я взглянул на исходный код C для pywin32, в частности win32com, который формирует слой перевода Python COM COM. Этот код:

  • принимает входной объект
  • звонки PyNumber_Float() чтобы преобразовать его в Python float (если это еще не)
  • звонки PyFloat_AsDouble() чтобы преобразовать его в простой C double значение.
    • это просто возвращает C double непосредственно содержится в PyFloatObject .

таким образом, похоже, что я проследил NaN от com-интерфейса обратно к простому C double тип содержащей Py_NAN, что бы это ни оказалось на платформе Windows.

испытательный стенд NAN Значение

теперь я пробовал это с Ni TestStand. Сначала я попробовал:

quiet_nan = struct.unpack(">d", "\x7f\xf8\x00\x00\x00\x00\x00\x01")[0]
# Set the variable's value in TestStand
locals_prop_object.SetValNumber(var_name, 0, quiet_nan)

но что еще появилось в TestStand как IND. Итак, я создал файл TestStand с переменными, установленными в IND и NAN, и прочитайте значения из Python. Получается, что в испытательном комплексе NAN имеет значение FFFF000000000001. Согласно сводные диаграммы Кевина что это отрицательный спокойной НЭН. Испытательном комплексе по IND имеет ожидаемое значение неопределено, FFF8000000000000.

успехов

Итак, после всего этого мне удалось установить NAN в TestStand, от Python:

# Make a NAN suitable for TestStand
teststand_nan = struct.unpack(">d", "\xff\xff\x00\x00\x00\x00\x00\x01")[0]
# Set the variable's value in TestStand
locals_prop_object.SetValNumber(var_name, 0, teststand_nan)

У Джона Кука был хороший пост на этом, который может быть полезен:

обновление: разве это не сработает?

In [144]: import scipy

In [145]: scipy.nan
Out[145]: 1.#QNAN

In [146]: scipy.inf
Out[146]: 1.#INF

In [147]: scipy.inf * 0
Out[147]: -1.#IND