БлогNot. О двоичном представлении вещественных чисел и как его вычислить

О двоичном представлении вещественных чисел и как его вычислить

Хороший вопрос задал студент: если вычислить на калькуляторе 21024 получим 1,7976931348623×10308, что, в общем, соответствует значению константы DBL_MAX, вздумай мы таковое напечатать:

#include <iostream>
#include <cfloat>

int main() {
 std::cout.precision (18);
 std::cout << DBL_MAX; //1.79769313486231571e+308
 return 0;
}

Нет ли здесь влияния иноагентов связи и как вообще такое возможно, если восемью байтами или 64 битами по любимой формуле можно представить всего 264 или примерно 1,845×1019 различных значений?

Связь действительно есть, но не прямая.

Представление двоичных вещественных чисел описано стандартом IEEE 754.

Все мы видели популярную табличку, показывающую, как распределены биты вещественного числа (здесь показано 8-байтовое значение, соответствующее типу числовых значений double на 64-разрядной платформе):

Знак
(11 бит)
Порядок
(52 бита)
Мантисса
63 56 55 48 47 40 39 32 31 24 23 16 15 8 7 0

и знаем, что вычисляется вещественное число по формуле вида (-1)знак * 2порядок * мантисса, чем обычно и ограничиваемся, а как отсюда получается конкретное значение, остаётся не слишком ясным.

Попробуем расписать немного подробней.

Знаковый бит определяет знак числа (в том числе, для значения "ноль", которое в компьютере является знаковым), нулевой бит - это знак числа "+", единичный - знак "-".

Поле порядка представляет собой 11-битное целое число без знака с возможными значениями от 0 до 211-1 = 2047 в смещённой форме: значение порядка 1023 представляет собой ноль. Показатель степени варьируется от -1022 до +1023, поскольку показатели степени -1023 (все нули) и +1024 (все единицы) зарезервированы для специальных чисел.

  • Порядок 00116 = 110 - наименьший возможный, так как 21-1023 = 2-1022;
  • порядок 3ff16 = 102310 - это 21023-1023 = 20, нулевой порядок;
  • например, 40516 = 102910 соответствует порядку числа 21029-1023 = 26;
  • 7fe16 = 204610 соответствует 22046-1023 = 21023, наибольший возможный порядок;
  • порядок 00016 = 010 используется для представления нуля (если F = 0) и для денормализованных чисел (если F≠0);
  • порядок 7ff16 = 010 используется для представления бесконечности (если F = 0) и значения NaN ("не число", если F≠0).

Здесь F - дробная часть мантиссы (без учёта старшего бита мантиссы, всегда равного единице).

53-битная мантисса (из которой явно сохраняется 52 бита) дает точность от 15 до 17 значащих десятичных цифр (2−53 ≈ 1,11 × 10−16). Если десятичная строка, содержащая не более 15 значащих цифр, преобразуется в формат двойной точности с получением обычного числа, а затем преобразуется обратно в десятичную строку с тем же количеством цифр, конечный результат должен соответствовать исходной строке. Если число двойной точности преобразуется в десятичную строку, содержащую не менее 17 значащих цифр, а затем преобразуется обратно в представление двойной точности, окончательный результат должен совпадать с исходным числом.

В теории всё так, а на практике проблемы с точностью у double могут возникнуть уже после сложения двух чисел... Например, если их порядки отличаются на 13 и более.

Реальное значение, принимаемое 64-битным числом двойной точности с заданным смещенным показателем порядка и 52-битной мантиссой, равно (-1)знак × (1.b51b50...b0)2 × 2порядок - 1023 или (-1)знак × (1+∑i=152 {b52-i × 2-i)} × 2порядок - 1023 .

Между 252 = 4 503 599 627 370 496 и 253 = 9 007 199 254 740 992 представимые числа в точности целые. Для следующего диапазона, от 253 до 254, всё умножается на 2, поэтому представляемые числа — четные и т. д. И наоборот, для предыдущего диапазона от 251 до 252 коэффициент равен 1/2 и т.д. Реально умножать ничего не нужно, так как есть быстрые битовые сдвиги для умножения и деления двоичного числа на два.

Коэффициент для мантиссы чисел в диапазоне от 2n до 2n+1 равен 2n−52. Таким образом, максимальная относительная ошибка округления числа (машинный эпсилон) составляет 2−53.

11-битная разрядность порядка позволяет представить числа от 10–308 до 10308 с точностью до 15–17 десятичных знаков. Компрометируя точность, денормализованное представление допускает даже меньшие значения, примерно до 5 × 10−324.

С учётом описанных выше исключений, попробуем вычислить вещественное число как (-1)знак×2порядок-1023×1.мантисса

  • 0 00000000001 00000000000000000000000000000000000000000000000000002 = 0010 0000 0000 000016 = +2−1022 × 1 ≈ 2.2250738585072014 × 10−308 (минимальное положительное double);
  • 0 11111111110 11111111111111111111111111111111111111111111111111112 = 7FEF FFFF FFFF FFFF16 = +21023 × (1 + (1 − 2−52)) ≈ 1.7976931348623157 × 10308 (максимальное положительное double, или =2^1023*(1+(1-2^(-52))) в виде формулы для Excel);
  • 0 00000000000 00000000000000000000000000000000000000000000000000002 - это плюс ноль, а если самый левый бит заменить на единицу, получим минус 0;
  • 0 11111111111 00000000000000000000000000000000000000000000000000002 - это плюс бесконечность, а если самый левый бит заменить на единицу, получим минус бесконечность;
  • 0 11111111111 00000000000000000000000000000000000000000000000000012 - сигнальное нечисло;
  • 0 11111111111 10000000000000000000000000000000000000000000000000012 - тихое нечисло;
  • 0 11111111111 11111111111111111111111111111111111111111111111111112 - просто нечисло;
  • 0 01111111101 01010101010101010101010101010101010101010101010101012 = 3FD5 5555 5555 555516 = +2−2 × (1 + 2−2 + 2−4 + ... + 2−52) - та самая 1/3, о которой я всегда говорю, что её "невозможно представить в компьютере точно";

Записали вещественную одну треть в файл и посмотрели, что получилось
Записали вещественную одну треть в файл и посмотрели, что получилось

"Обратный" порядок байт в файле связан с тем, что у нас little-endian на компе.

  • 0 10000000000 10010010000111111011010101000100010000101101000110002 = 4009 21FB 5444 2D1816 - число "пи";

Сделали то же самое с числом "пи"
Сделали то же самое с числом "пи"

  • 0 01111111111 00000000000000000000000000000000000000000000000000002 = 3FF0 0000 0000 000016 +20 × 1 = просто вещественная единица;
  • 0 01111111111 00000000000000000000000000000000000000000000000000012 = 3FF0 0000 0000 000116 = +20 × (1 + 2−52) = 1.0000000000000002, число, большее единицы, минимально отличное от неё для нашего представления;
  • 0 10000000000 00000000000000000000000000000000000000000000000000002 = 4000 0000 0000 000016 = +21 × 1 = вещественная двойка;
  • 0 10000000011 01110000000000000000000000000000000000000000000000002 = 4037 0000 0000 000016 = +24 × 1.01112 = 101112 = вещественное 23;
  • ну и так далее.

Что же до значения 21024, то это число как раз соответствует количеству всех возможных чёрно-белых картинок EMS размером 32×32 = 1024 пикселя, которых, к сожалению, наши опсосы в SMS'ках давно не поддерживают. Действительно интересно, что по общевселенскому "закону одной тысячной" примерно такая часть этих изображений показалась бы нам осмысленными.

04.03.2023, 08:44 [332 просмотра]


теги: учебное c++ числа

показать комментарии (1)