Как различить разные типы NaN-плавающих в Python

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

Очевидно, TestStand различает значения «IND» и «NAN» с плавающей запятой. В соответствии сСправка по TestStand:

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

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

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

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

 Craig McQueen08 окт. 2010 г., 03:12
Я хочу установить переменную вNAN (скорее, чемIND) в TestStand, через COM с использованием Python. Конечному пользователю будет проще документировать, если мы сможем последовательно использоватьNAN по всей нашей системе.
 JoshD08 окт. 2010 г., 03:02
Почему именно вы хотите это сделать? Вы можете быть слишком усложняющим вещи. Вы можете использовать NoneType, возможно ...

Ответы на вопрос(4)

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

IEEE арифметика с плавающей точкой в ​​Python

Обновить: не будет ли это работать?

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
 Craig McQueen08 окт. 2010 г., 07:19
Это полезный справочник для изучения NAN и INF в Python. К сожалению, это не так далеко, как ответить на мой вопрос.
 ars12 окт. 2010 г., 02:26
Я на Windows Vista с python 2.5, scipy 0.8. Не уверен, если это имеет значение, но это 64-битный.
 ars08 окт. 2010 г., 04:47
@ Стигма: Д'Ох! Ссылка исправлена, спасибо.
 Stigma08 окт. 2010 г., 04:44
Вы, вероятно, намеревались связатьВот.
 Craig McQueen12 окт. 2010 г., 01:23
scipy.nan звучит интересно. Обратите внимание, что в Windows он печатается просто какnan, Так что если вы получите1.#QNAN Я предполагаю, что вы на Linux. К сожалению, я сегодня дома болею, и у меня есть ноутбук с Windows, но на нем нет TestStand, чтобы попробовать это.

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

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

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

Чтение Python и Pywin32 Исходный код

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

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

Так что похоже, что я проследилNaN из интерфейса COM обратно в простой Cdouble тип, содержащийPy_NANчто бы это ни было на платформе Windows.

Значение TestStand 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. Оказывается, что TestStand'sNAN имеет значениеFFFF000000000001, В соответствии сСводные таблицы Кевина этоотрицательный тихий НАН. TestStand-х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)
 ars11 окт. 2010 г., 09:21
разве не работали scipy NaN при прохождении через COM?
 Craig McQueen13 окт. 2010 г., 01:57
@ars, как я показал в своем обновленном ответе, дажеscipy.nan не сработает. «Тихий отрицательный NaN» сделал свое дело.
 Craig McQueen12 окт. 2010 г., 05:31
Я еще не пробовалаscipy.nan на моем компьютере, который запускает TestStand.
 ars13 окт. 2010 г., 02:01
Полезно знать, спасибо за обновление!

Из того, что я могу сделать вывод, кажется, что есть некоторая путаница в том, чтобы думать, что знакNaN определяет, тихо или нет. Напротив, соглашение состоит в том, что наиболее значимая часть мантиссы определяет это. ОтВикипедия (выделение добавлено):

В форматах хранения с плавающей запятой, соответствующих стандарту IEEE 754, NaN идентифицируются с помощью определенных заранее определенных битовых комбинаций, уникальных для NaN.Знаковый бит не имеет значения, NaN в двоичном формате представлены экспоненциальным полем, заполненным единицами (например, значениями бесконечности), и некоторым ненулевым числом в поле значимостей (чтобы отличать их от значений бесконечности). Исходный стандарт IEEE 754 от 1985 года (IEEE 754-1985) только описывал двоичные форматы с плавающей запятой и не определял, как должно маркироваться состояние сигнализации / тишины. На практике самый значимый бит поля значимости и поля определяет, сигнализирует ли NaN или тихий ... В пересмотре 2008 года стандарта IEEE 754 (IEEE 754-2008) даются официальные рекомендации по кодированию состояния сигнализации / спокойного состояния.Для двоичных форматов наиболее значимым битом поля значимости должен быть флаг 'is_quiet'. То есть этот бит ненулевой, если NaN тихий, и нулевой, если NaN сигнализирует.

Поскольку большинство реализаций соответствуют стандарту IEEE 754-2008, вам следует следовать этому соглашению. В общем случае вы не можете планировать согласованность бита знака для NaN, даже для разных NaN на одной платформе. В соответствии с этим соглашением,float('nan') а такжеscipy.nan оба кажутся тихими NaN, по крайней мере, в случаях, описанных выше.

 Craig McQueen08 окт. 2018 г., 05:59
Кажется, что NI TestStand имеет нетрадиционную интерпретацию различных типов NaN. По крайней мере, так было, когда я задавал этот вопрос. Я не использовал TestStand в течение последних 7 лет.
Решение Вопроса

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

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

>>> 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.

Давайте попробуем создать Сигнальный 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.

 Henry Schreiner07 сент. 2018 г., 12:28
Я не уверен, еслиfloat('nan') всегда один или другой, когда вы меняете системы, но вы можете получить другую нан, запустив-float('nan'), Кроме того, в Python 3.5+, ваш код для просмотра шестнадцатеричной записи должен бытьstruct.pack(">d", float('nan')).hex().
 Craig McQueen12 окт. 2010 г., 04:31
Спасибо за ответ, Стигма. Я позволил себе отредактировать его, чтобы добавить примеры кода. Очень признателен.
 Stigma12 окт. 2010 г., 05:02
Я рад, что вы получили из этого то, что вам нужно, и спасибо за добавление примеров кода для других, как я, чтобы учиться. :)

Ваш ответ на вопрос