Как я могу вручную установить битовое значение числа с плавающей запятой, равное NaN?

Я пытаюсь запустить некоторые тесты с преобразованиями и приведением поплавков к другим типам, и я хочу установить для своей переменной с плавающей запятой разные значения nan.

"побитовый пример стандарта IEEE с плавающей запятой одинарной точности (32-битного) NaN будет следующим: s111 1111 1axx xxxx xxxx xxxx xxxx xxxx, где s - знак (чаще всего игнорируется в приложениях), a определяет тип NaN, а x — дополнительная полезная нагрузка (чаще всего игнорируется в приложениях). Если a = 1, это тихий NaN; если a равен нулю и полезная нагрузка не равна нулю, то это сигнальный NaN».

В основном я хочу найти способ установить полезную нагрузку или xxxx представления. Есть ли способ сделать это в c?


person Chris    schedule 28.04.2012    source источник


Ответы (3)


Вы можете управлять битами «полезной нагрузки», передавая соответствующие строки в C99 nan, nanf, nanl, но они будут генерировать только тихие значения NaN, а интерпретация строки остается неопределенной (в большинстве реализаций она обрабатывается как шестнадцатеричное число).

В качестве альтернативы используйте союз:

#ifndef __STDC_IEC_559__
#error "This program requires IEEE floating point arithmetic"
#endif

#include <stdint.h>
#include <assert.h>

static_assert(sizeof(float) == sizeof(uint32_t),
    "This program requires float to be 32 bits exactly");

float nanf_with_payload_bits(uint32_t payload)
{
   if (payload & 0x7FA00000) abort();

   union ieee_single {
       float f;
       uint32_t i;
   } nan;

   nan.i = 0x7FA00000 | payload;
   return nan.f;
}

Запись в один член объединения и последующее чтение из другого, когда оба типа имеют одинаковый размер, НЕ вызывает неопределенное поведение в C99+errata. (Это было неопределенное поведение в C89, но большинство компиляторов определили его для того, чтобы делать то, что вы ожидаете. Это может быть неопределенное поведение в C++, я не уверен; однако, опять же, большинство компиляторов определяют его сделать то, что вы ожидаете.)

Если вы используете эту функцию для создания сигнальных NaN, имейте в виду, что их поведение явно оставлено неопределенным в C99/C11, Приложение F.

НЕ пытайтесь разбить компонент i объединения на структуру с битовыми полями. Расположение битовых полей в памяти внутри структуры частично определяется реализацией и частично не указано, и, в частности, последовательность битовых полей не обязательно упаковывается в слово в том же порядке, что и ЦП. (или, действительно, должным образом упакованы вообще).


Ссылки на стандарты (все C99):

  • такое использование объединения является только неуказанным поведением: 6.2.6.1p7; J.1
  • расположение битовых полей в структуре непредсказуемо: 6.2.6.1p1,2; 6.7.2.1п10,11,13; J.3.9
  • поведение сигнализации NaN не определено: F.2.1
person zwol    schedule 28.04.2012
comment
Что именно вы имели в виду под безумием порядка байтов? У меня может быть проблема, связанная с этим. - person Chris; 28.04.2012
comment
Если коротко, то порядок битовых полей в struct не обязательно согласуется с чем-либо еще. Однако порядок битов в uint32_t будет таким же, как порядок битов в float во всех современных системах (раньше были компьютеры, где они не были одинаковыми, но AFAIK ни один из них не производился в течение довольно долгого времени). Длинная версия слишком длинная для этой коробки. Мне нужно увидеть код, который вызывает у вас проблемы, чтобы сказать что-нибудь еще. Предлагаем вам задать новый вопрос об этом и связать его здесь. - person zwol; 28.04.2012
comment
Просто связал это: stackoverflow.com/questions/ 10366485/ Спасибо! - person Chris; 28.04.2012

Используйте 1_:

int32_t i = 0x7FC00000;
float f;
memcpy(&f, &i, sizeof(f));

Вы также можете утверждать, что sizeof(f) == sizeof(i), но если вы знаете, что числа с плавающей запятой соответствуют стандарту IEEE, то, по-видимому, вы также знаете, каковы размеры основных типов.

person Steve Jessop    schedule 28.04.2012

Существует поддерживаемый способ записи полезной нагрузки тихого NaN на C.

Функции nan, nanf и nanl (заголовок math.h, раздел 7.12.11.2 спецификации C 1999 г.) принимают строки в качестве аргументов. Функции strtof, strtod и strtold (заголовок stdlib.h, раздел 7.20.1.3) принимают строки вида «NAN (последовательность символов)». Функции fscanf и sscanf следуют за strtod. Однако последовательность символов интерпретируется способом, определяемым реализацией. (Это означает, что ваш компилятор должен предоставить вам документацию, определяющую интерпретацию. Некоторые компиляторы не будут подчиняться этому требованию стандарта.)

Функция fprintf (stdio.h, раздел 7.19.6.1) может выводить строку вида "NAN(последовательность символов)" в формате с плавающей запятой (a, e, f, g), как и printf и sprintf. Стандарт разрешает вывод «NAN» без последовательности символов, поэтому это не будет работать со многими компиляторами.

Поскольку интерпретации определяются реализацией, не следует ожидать, что они будут переносимыми. Обычно они предназначены для специальных целей, таких как отладка.

person Eric Postpischil    schedule 01.05.2012