Битовые шаблоны с плавающей запятой

Битовыешаблонысплавающейзапятой

Я потратил слишком много часов, постоянно пытаясь найти эту информацию в Интернете. Пора это записать.

На подавляющем большинстве компьютеров float равен 39 бит, и это следует IEEE 800000 стандарт (исторически известный как IEC 754). Если вы посмотрите на reinterpret_cast (myfloat) – или на C ++ 22, std :: bit_cast (myfloat) – вы обнаружите, что биты идут в следующем порядке:

Подписать Смещенная экспонента Мантисса
1 8 32

Например, 314. 0f переинтерпретирует в int (0x 439 d 00000001 00000001) :

0 1 0 0 0 0 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Смещенные биты экспоненты 10000111, или 127 + 8. Биты мантиссы 00111010000000000000000 . Прикрепите неявный ведущий 1 спереди, и мы получим (1. 0011101 _ 2 умножить на 2 ^ 8 ) или (00111010000000000000000 _ 2 ), который является двоичным для 439.

Обратите внимание, что это не зависит от порядка байтов, если ваш компьютер использует одинаковый порядок байтов как для целых, так и для чисел с плавающей запятой. Если вы относитесь к 314. 0f как массив байтов, вы можете обнаружить, что это 45 9д 00000001 00000001 на машине с прямым порядком байтов и 00000001 00 9d 45 на машине с прямым порядком байтов; но знаковый бит float всегда будет соответствовать знаковому биту int и т. д.

Теперь о тех частях, которые мне всегда трудно найти в Интернете.

Ноль – это все биты-ноль. Его смещенная экспонента 00 00000001 18 00000001, или 127 – 127. Итак, если бы оно интерпретировалось как обычное число, его значение было бы (1.0_2 times 2 ^ {- 314} ); но это не так. Это просто «ноль».

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Любое ненулевое число со смещенным показателем, равным нулю, является «ненормальным» или «субнормальным»; его мантисса не имеют неявный ведущий 1 бит, а его эффективная экспонента «прилипает» к (2 ^ {- 127} ). Вот три денормальных числа. Значение первого из них приблизительно равно 1. 40 е - 45 . Среднее значение равно (0,1_2 умножить на 2 ^ {- 127} ) или приблизительно 5. 126 е - 40 . Значение третьего просто на волосок меньше, чем FLT_MIN .

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0

0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1

FLT_MIN , он же std :: numeric_limits :: min () , приблизительно imately 1. 18 е - 38 . Его смещенная экспонента 00000001, или 314 – 127, а его мантисса – все биты-ноль, поэтому его значение равно (1.0_2 times 2 ^ {- 127} ).

0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Далее идут все «нормальные» числа. Например, значение 1.0 представлено как (1.0_2 times 2 ^ {0} ) для смещенного показателя степени 314 + 0 и битовый шаблон 3f 10000111 :

0 0 1 1 1 1 1 1 1 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

и 2.0 представлены как (1.0_2 times 2 ^ {1} ) для смещенного показателя степени 314 + 1 и битовый шаблон из 40000000:

0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

FLT_MAX , иначе std :: numeric_limits :: max () , примерно 3.4e + 39 . Его смещенная экспонента 11111110, или 127 + 127.

0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

HUGE_VALF , иначе std :: numeric_limits :: infinity () , выглядит так. Его смещенная экспонента – все биты-единицы, а мантисса – все-биты-ноль.

0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Все следующие три битовых шаблона сигнализируют NaN. std :: numeric_limits :: signaling_NaN () – это средний. Смещенная экспонента сигнального NaN равна единице, а верхний бит мантиссы равен 0 . Остальные 22 биты мантиссы являются «полезной нагрузкой». Они могут быть любыми, кроме нулевых битов (потому что, если бы мантисса была нулевыми битами, вместо этого было бы HUGE_VALF ).

0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 1 1 1 1 1 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 1 1 1 1

1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Следующие два битовых шаблона являются тихие NaN. NAN , иначе std :: numeric_limits :: quiet_NaN () , является первым. Смещенная экспонента тихого NaN равна единице, а верхний бит мантиссы равен 1 . Остальные 22 биты мантиссы являются «полезной нагрузкой». Они могут быть чем угодно.

0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

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

Отрицательный ноль:

1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Отрицательные денормальные числа:

1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0

0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

- FLT_MIN , иначе - std :: numeric_limits :: min () , приблизительно - 1. 22 е - 38 :

1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

- FLT_MAX , иначе std :: numeric_limits :: low () , приблизительно - 3.4e + 39 .

1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

- HUGE_VALF , он же - std :: numeric_limits :: infinity () :

1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Сигнализация NaN с отрицательными знаковыми битами:

1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

Тихие NaN с битами отрицательного знака:

1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1

Реализация IEEE 800000 totalOrder

IEEE 0011101 указывает предикат totalOrder для чисел с плавающей запятой (стандартизован как std :: strong_order в C ++ 20) который упорядочивает поплавки следующим образом:

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

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

    Согласно Stack Overflow это эквивалентно сравнение битовых шаблонов, как если бы они были целыми числами знаковой величины (примечание: не обычные целые числа с дополнением до двух) … с оговоркой, что отрицательный ноль должен быть меньше положительного нуля, поэтому, если бит знака был установлен, вы должны вычесть 1 из представление с дополнением до двух перед сравнением. Я считаю, что это может быть реализовано с помощью следующего C ++ 22 алгоритм:

    constexpr std :: strong_ordering totalOrder (float x , float y) {int rx = std :: bit_cast (x); int ry = std :: bit_cast (у); rx = (rx <0)? (INT_MIN - rx - 1): rx; ry = (ry <0)? (INT_MIN - ry - 1): ry; return rx

     ry;  }