Назад, к оглавлению
Стандарт IEEE754-2008 представления чисел с плавающей запятой (фрагмент учебника ISBN 978-5-97060-304-8 и ISBN 978-5-94074-766-6)

Числа с плавающей точкой/запятой согласно стандарту IEEE754-2008

--

         Смеем предположить, что хранение целых чисел в памяти ЭВМ не является сложным для среднестатистического читателя, большей частью материал, изложенный выше, принимается интуитивно, так как сильно пересекается со школьным курсом, рассматривающим разные системы счисления. Кажущаяся на первый взгляд простота приводит разум к логичному вопросу: зачем подробнее изучать то, что и так понятно, разве можно узнать что-то новое? Как следствие, формат хранения чисел в памяти ЭВМ для многих, в том числе и будущих программистов, представляет собой «чёрный ящик»: создал переменную, присвоил значение, выполнил вычисления, считал результат.
         До тех пор пока не требуются точные вычисления, работа «ящика» оказывается предсказуемой и устраивает большинство из нас. Если язык программирования не типизирован, то можно перестать думать о форматах данных вообще, так как последний будет преобразовывать их «на лету». (Собственно, есть за что любить тот же PHP.) В противном случае вам придётся из какой-нибудь книжки по программированию узнать о существовании различных типов данных и их пограничных значениях. Но и тут если не требуется что-то большее, чем сложение чисел с точностью не более чем двух знаков после запятой (например, рубли, копейки), а цифры в расчётах не более чем семизначные, то мир прекрасен и написанные нами программы работают. Однако, как только мы делаем что-то более специфичное, начинаются «фокусы», в ряде которых мы и попробуем разобраться.
         В предыдущем разделе был рассмотрен более простой вопрос – представление целых чисел, но и там были свои проблемы, например переполнение на пограничных значениях. В этом разделе мы коснёмся вопросов хранения и обработки вещественных чисел, фактически заглянем во внутренности «чёрного ящика» всех современных ЭВМ. Смеем предположить, что «подводных камней» будет намного больше, чем сейчас можно представить.

         Замечание. Плавающая запятая или плавающая точка? В России традиционно целая часть числа от дробной отделяется запятой, также по сей день действует ГОСТ 16325–88 «Машины вычислительные электронные цифровые общего назначения. Общие технические требования», где используется термин «плавающая запятая». Так как на сегодня наша промышленность, электроника и наука «скорее не развивается, чем развивается», наблюдается отставание в мировом масштабе. Информационный вакуум быстро компенсируется зарубежными коллегами выпуском своих стандартов, документаций и прочего, которые после часто переводятся непрофильными переводчиками. Так, у нас появился, если не сказать что был навязан, термин «плавающая точка». В современной литературе эти понятия являются синонимами. Что же касается «запятой» в качестве разделителя целого и дробной части, последняя используется в более чем 60 стран [24].


2.1.4.1. Краткие теоретические сведения
38

         Для представления действительных чисел в компьютерах используется формат с плавающей запятой (точкой) 1. Актуальными являются два стандарта для машинной арифметики с плавающей точкой.

IEEE 754-2008 IEEE Standard for Floating-Point Arithmetic определяет представление и операции для чисел с плавающей точкой в компьютерных системах. Рассматривает форматы хранения, правила арифметики (в том числе и правила округления), стандартные и расширенные функции для типов одинарной (single), двойной (double), расширенной (extended) и расширяемой (extendable) точности, а также рекомендует форматы для обмена данными. В рамках используемых форматов определяет:
  • как представлять нормализованные положительные и отрицательные числа с плавающей запятой;
  • как представлять денормализованные положительные и отрицательные числа с плавающей запятой;
  • как представлять «нулевые» числа;
  • как представлять специальные величины «плюс бесконечность» и «минус бесконечность» (±Infinity, ±∞);
  • как представлять специальные величины «Не число» (NaN, NaNs, not a number).
         IEEE 854-1987 IEEE Standard for Radix-Independent Floating-Point Arithmetic обобщает стандарт ANSI/IEEE Std 754-1985, IEEE Standard for Binary Floating-Point Arithmetic (в 1987 году стандарт IEEE 754-2008 ещё не вышел) с целью убрать из него зависимость от основания системы счисления и длины машинного слова. Он описывает числа с основаниями 2 и 10 («the radix shall be either 2 or 10 and shall be the same for all supported precisions»), но, в отличие от IEEE 754-2008, не описывает точное представление таких чисел по битам в памяти ЭВМ. «Radix-Independent» в названии, похоже, стоит понимать лишь как независимость от одного конкретного основания.

Так как перед нами не стоит задача досконального изучения стандартов, перейдём непосредственно к представлению действительных чисел в памяти компьютера на примере одного из типов данных, проверяя при этом отдельные положения небольшими программами.
Во-первых, определимся с терминологией.
Во-вторых, для приводимых примеров будет использоваться язык С. Рассмотрим имеющиеся в нём типы данных.

2.1.4.2. Типы данных в языке С (для хранения действительных чисел)

Как пишет Бьярне Строуструп: «...типы с плавающей точкой представлены тремя размерами: float (одинарной точности), double (двойной точности) и long double (расширенной точности). Точный смысл каждого типа зависит от реализации. Выбор нужной точности в реальных задачах требует хорошего понимания природы машинных вычислений с плавающей точкой. Если у вас его нет, либо проконсультируйтесь с кем-нибудь, либо изучите проблему сами, либо используйте double и надейтесь на лучшее» [21, стр. 112]. «Целью существования... нескольких чисел с плавающей точкой является представление программисту возможности эффективно использовать аппаратные средства. На многих машинах объём памяти, время доступа и скорость вычисления существенно зависят от выбора типа» [21, стр.113]. Согласно документу draft ISO/IEC JTC1 SC22 WG14 N1312 [29], типы float, double и long double для языка C являются базовыми. Компилятором для них отводится 4, 8 и 16 байт или 32, 64, 128 бит соответственно. В старой литературе вы можете встретить информацию, что тип long double занимал в памяти 10 байт или 80 бит, сейчас это не так. Проверить сколько занимает тот или иной тип можно простой программой:

$ cat types_check.c
#include 
void main(void)
{
  printf("Размеры занимаемые переменными (в байтах).\n");
  printf("float: %d\n",sizeof(float));
  printf("double: %d\n",sizeof(double));
  printf("long double: %d\n",sizeof(long double));
}
$ gcc types_check.c && ./a.out
Размеры занимаемые переменными (в байтах).
float: 4
double: 8
long double: 16

Если у вас на компьютере больше гигабайта оперативной памяти и вы считаете, что для современных ЭВМ вопрос выбора формата хранения данных при программировании неактуален, напомним, что также существует мир микроконтроллеров, по сути тех же ЭВМ, чьи объёмы памяти на 1-2 порядка меньше. Даже SIM-карту телефона (или банковскую карту с чипом) можно в какой-то мере рассматривать как специфическую ЭВМ, не говоря уже о том, что во многих автомобилях управление устройствами происходит по CAN-шине, работа с которой не обходится без ЭВМ.

Какой тип выбрать?

Перед началом использования типов попробуем понять, что для представления действительных чисел также существует несколько «сущностей» (по аналогии с рис. 2.1 сущность – это некоторая модель представления действительных чисел и соответствующий ей формат записи числа на бумаге или в памяти ЭВМ) (см. рис. 2.2). Типичные направления движения мыслей между сущностями

По мнению авторов, направление «движения мыслей» наиболее естественно происходит по стрелкам, хотя ничто не мешает вам двигаться и в обратном направлении, даже «перескакивать» через отдельные сущности. Так как за каждой сущностью фактически стоит одна или несколько моделей представления действительных чисел, то высказать однозначно мнение, что какая-то сущность (и как следствие ‒ какой-то формат записи) лучше и что надо использовать только её, нельзя.

«Пробежимся» по графу, изображённому выше на рис. 2.2 от «числа» до его представления в памяти ЭВМ на примере показания термометра (см. табл. 2.6). Типичные направления движения мыслей между сущностями

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

Опираясь на основы моделирования (представление чисел – это модель) и глядя в таблицу легко догадаться, что:

  • каждая модель имеет свои ограничения;
  • достоверность (точность) представления чисел для каждой модели различна;
  • в некоторых сущностях числа могут иметь несколько форм записи;
  • преобразования чисел из одной сущности в другую могут быть неоднозначными.


2.1.4.3. Пример «36,6»


         Все мы когда-либо измеряли температуру и знаем, что такое градусник. Смеем предположить, что если дома в руках не держали, то уж в поликлинике ртутный градусник видели. Допустим, что последний показал какое-то значение, например 36,6 градуса по шкале Цельсия. Мы опустим из рассмотрения философские вопросы, выходящие за рамки статьи: «что и как измерил градусник?» и «каковы относительная и абсолютные погрешности измерения?», разрешив на них ответить специалистам по физике и метрологии. Фактически мы рассмотрели модель, что-то измерили и записали на бумаге в десятичной системе показания измерительного прибора – термометра, в нашем случае как 36,6. На самом деле то, что мы реально измерили, мы не знаем, ведь мы могли измерить и 36,5999999999999.... или другое значение, то есть мы неизбежно столкнулись с точностью – новой проблемой, которой при записи целых чисел [20] не возникало. В нашей модели мы интуитивно выбрали точность до одного знака после запятой. Выбери мы больше знаков для представления результатов измерения (факт, что нет физического смысла записывать число точнее, чем погрешность измерения, опустим) – столкнулись бы с ограничением в записи числа на листочке бумаги... например, листочек шириной в 33 клетки, а запись по одному знаку в клетке – вот вам и ограничение.

Таблица 2.6. Форматы числа в разных сущностях
СущностьОписание, форматыЗначение
Действительное число мера чего-то, зависит от того, в чём и как измеряют (в нашем случае это высота столбика ртути в условных единицах пропорционально измеренной температуре) Градусник. Пример «36,6»
Десятичная система счисления
  • естественная форма записи счисления
  • нормализованный экспоненциальный вид
  • денормализованный экспоненциальный вид
  • 36,6
    3,66∙101
    0,366∙102
    Двоичная система счисления
  • естественная форма записи
  • форма с плавающей запятой в экспоненциальном нормализованном виде
  • форма с плавающей запятой в экспоненциальном денормализованном виде
  • 100100,100110011001100110... 1,00100100110011001100110...∙2101 0,10010010011001100110011...∙2110
    Промежуточный вид IEEE 754 Преобразование двоичного нормализованного числа в binary32 формат стандарта IEEE 754 0 10000100 00100100110011001100110
    Двоичная форма представления в ЭВМ Непосредственное хранение в представления в памяти ЭВМ (для архитектуры LITTLE_ENDIAN байты хранятся в обратном порядке) 01100110 01100110 00010010 01000010
    Шестнадцатеричная форма представления ячеек памяти в ЭВМ Компактная форма записи содержимого памяти 66 66 12 42

             Точная запись числа, полученного в одной системе измерений и записанная в какой-то системе счисления, может не иметь однозначного представления в другой системе счисления, как если бы вас попросили точно записать периодическую дробь 1/3.

             Действительное число может быть записано несколькими способами. Рассмотрим различные виды (формы) записи. Число 36,6 мы можем записать как 0,366∙102. Различие форматов записи в десятичной системе счисления наглядно можно увидеть в продуктовом магазине. Где-то на одной пачке товара может быть написано 1 кг (считай 1∙103 г), а на другой 1000 г, а где-то будет 0,5 кг. А измерь мы вес какого-нибудь товара, например, в тройских унциях, явно придётся округлять значения или отбрасывать разряды, оставляя лишь n знаков после запятой.
             И как же все эти числа записать в памяти ЭВМ, например чтобы после сложить и узнать общую массу всех товаров? Разнообразие форм в записи одного числа может послужить причиной затруднений для работы цифрового устройства. Во избежание этого нужно:
    • либо заранее преобразовывать все числа к единой форме,
    • либо создать специальные алгоритмы распознавания формата числа,
    • либо указывать каждый раз его форму записи.
    Все три варианта в той или иной мере используются.
             В первом случае мы можем все вычисления делать с типом float (либо другим). Во-втором случае рассмотрите фрагмент кода, который PHP-интерпретатор правильно распознает, преобразует форматы, а потом правильно посчитает и выведет сумму.
    <?php
    $a='1';
    $b=0.5;
    $c=4;
    $d=$a+$b+$c;
    echo $d;
    ?>
    
    А для третьего случая приведём код на С с явным указанием типов:
    int a=1;
    float b=0.5;
    
             Из примеров выше может показаться, что интерпретируемые программы удобнее, но за удобство приходится платить – они работают явно медленнее, чем те же алгоритмы в скомпилированном виде.
             Переход от десятичной системы счисления к двоичной рассматривать не будем, так как эти вещи рассматриваются в школьном курсе информатики. Если забыли, см. «Cхема Горнера и перевод из одной позиционной системы в другую» [26, § 14, стр. 37–39].


    2.1.4.3.1. Терминология

             Если не брать в рассмотрение представление нуля, бесконечности и прочих исключений как чисел с плавающей запятой, то можно практически считать синонимами термины «число с плавающей запятой» и «число, записанное в экспоненциальной форме». В связи с чем числа с плавающей запятой в общем случае можно представить в экспоненциальном виде: ν= F =M⋅qp , где M – мантисса, q – основание системы счисления, а p – показатель степени или порядок числа ν (или F).
    ...
    2.1.4.3.2. Алгоритм преобразования


    2.1.4.4. «10 формул!»
    47

    Практическая проверка правильности вычислений показала, что предыдущие преобразования верны. Если проводимые вычисления не показались вам сложными и вы считаете, что уже умеете преобразовывать любые числа по формату IEE754, то спешим вас огорчить, рано радуетесь. Если бы мы говорили о формате хранения целых беззнаковых чисел, то можно было бы «остановиться», так как для них используется всего лишь одна формула преобразований. В случае же с действительными числами забежим вперёд и скажем, что таких формул будет 10! В примере выше мы использовали лишь одну, ниже разберём остальные. В этом, наверное, и кроется основная проблема изучения формата хранения чисел, когда обучаемыми рассматриваются лишь некоторые случаи преобразований, а все остальные уходят из рассмотрения.

    Понять сказанное проще, проведя рассуждения «от обратного», а именно «от памяти к числу». Так как для хранения данных одной переменной типа float у нас задействовано 32 двоичных разряда, то максимальное число вариантов будет 232, начиная 32 «нулями» и заканчивая всеми «единицами». Записывать числа удобнее в более компактной шестнадцатеричной форме, где начало и конец будут 00 00 00 00 и FF FF FF FF. см. табл. 2.8a.

             Если попытаться сопоставить коду хранящемуся в памяти (двоичному значению 4-байтовой переменной) действительное число которое этим кодом кодируется (по стандарту IEEE-754), то удобнее будет получившуюся «таблицу соответствия» поделить на 10 последовательных диапазонов (множеств), по числу формул которыми они могут быть преобразованы в действительные числа. (См. табл. 2.8 б.)
             Далее, если попытаться разместить более-менее адекватно все множества на числовой оси (как мы привыкли слева направо), то получится примерно следующая картинка, взятая из [17]. см. рис. 2.3.



    Рассмотрим подробнее рис. 2.3. Над воображаемой осью координат «x» записаны значения ячеек памяти. Под осью записаны значения чисел, а цветом указаны «форму- лы», по которым можно осуществить преобразования, причём с целью упрощения и исходя из симметрии их число (как и цветов на рис., оттенков при чёрно-белом изда- нии) сокращено до пяти. «Пробежимся» по положительной части оси и разберём их.

    2.1.4.5.1. Ноль (нуль)
    48

    «Ноль – он и в Африке ноль». Для представления нуля в памяти используется комбинация нулей во всех 32 разрядах. Согласитесь, что это тривиально и легко запомнить.

    Фрагмент памяти ЭВМ, содержащий значения 00 00 00 0016 (следует учитывать, что реальная последовательность хранения зависит от архитектуры, см. стр. 36), будучи интерпретирован как число формата binary32 IEEE754-2008, считается числом «+0».

    «+0»

    Следует отметить, что если рассматривать «отрицательную область», то там тоже будет «свой» ноль.

    «−0»

    Из рисунков видно, что при шестнадцатеричной записи в памяти отображение «–0» будет как 80 00 00 00 (следует учитывать, что реальная последовательность хранения зависит от архитектуры и может быть обратной, см. стр. 36).

    При кодировании целых чисел одним байтом от значения «−0» отказались в пользу ещё одного отрицательного числа, вот почему при 256 вариантах мы пользуемся не симметричным диапазоном [−127, +127], а асимметричным [−128, +127], как и [−32768, +32767] и т. д. Смею предположить, что «+0» и «−0», с точки зрения математики, если не рассматривать пределы справа и слева, есть одно и то же – «0», а в чём различие «+» и «−» – философский вопрос. Однако из факта существования двух нулей технически можно сделать интересные выводы, например для операции сравнения. Если ранее, при использовании целых чисел, из равенства «представления чисел в памяти ЭВМ» следовало и равенство самих чисел, то для типов с плавающей запятой одним сравнением уже не обойтись. Например, при сравнении фрагментов памяти 80 00 00 00 и 00 00 00 00, хранящих числа с плавающей запятой, побитно видно, что они различаются, а значит, можно ошибочно предположить, что числа, представленные данными записями, разные, по факту же мы понимаем, что числа равны.

    Замечание, открытый вопрос

    Почему комбинация 80 00 00 0016 не была использована для представления какого-нибудь ещё числа, как это было сделано с целыми типами?

    Смеем предположить, что с целыми типами, при использовании 8 бит, «выигрыш» оказался существен, плюс несложность добавления числа «на край» отрицательных чисел подсказала простое решение, как использовать это значение. Целые типы с большим числом разрядов просто унаследовали данный подход. Что же касается чисел с плавающей запятой, видимо, даже при разработке стандарта IEEE754 сочли вклад 1/216 для формата Binary16 несущественным, не говоря уже о меньшем вкладе 1/232 для формата binary32 и т. д. Следует отметить, что в «блоке NaN», о котором написано ниже, заложено больше неиспользуемых значений.

    Для удобства изложения поменяем порядок изучения формул и рассмотрим сначала нормализованные числа.

    2.1.4.5.2. Нормализованные числа
    49

    Ранее мы рассмотрели пример преобразования температуры t = 36,6 °C и определили как десятичное число 36,6 будет храниться в памяти ЭВМ. Фактически мы для этого использовали «нормализованный» формат хранения числа в памяти. Рассмотрим общую формулу преобразования и какие из неё следуют ограничения. Стандарт IEEE754 по этому поводу предлагает следующее хранение данных в памяти (см. рис. 2.4): Рисунок 2.4. Распределение битов в памяти ЭВМ для хранения чисел с плавающей запятой по стандарту IEEE754 где переменные берутся из таблицы 2.6, в зависимости от желаемой точности. Работа с первоисточниками есть основа знаний, но не всегда они удобны для восприятия рядовыми читателями, в связи с этим предлагаем обратиться к «адаптированным фрагментам» стандарта от Владимира Яшкардина в [17] и от Сергея Холодилова в [25], где указанные вопросы изложены намного лучше (недостаток – отличные обозначения), так как на ряду с наглядными картинками приводятся различные примеры. ISBN 978-5-97060-304-8
    Рисунок 2.5. Распределение битов памяти по формату IEEE754 при точности binary32 (w ≡ b = 8, t ≡ n = 23, k = 32) (верх – общая формула; низ – binary32) На рис. 2.5:
    • S – бит знака;
    • E – смещённый показатель степени двоичного числа;
    • T – остаток мантиссы двоичного нормализованного числа с плавающей запятой (в [17] и [25] обозначается через M, что вносит путаницу).

    Дадим некоторые пояснения. Переход от смещённого показателя к реальному выполняется вычитанием смещения, которое равно (2(b − 1) − 1) ≡ (2(w−1) −1). То есть для расчётов реальная степень числа 2 вычисляется как хранимое значение минус смещение: E−(2(w−1)−1), для binary32 получится E−127.
             Дополнительная сложность для читателей (слушателей) в восприятии материала состоит в том, что через букву T обозначен остаток мантиссы, а не сама мантисса. Почему так оказывается удобнее, будет разъяснено позднее. Нормализация подразумевает, что для мантиссы будет выполняться следующее условие: 1 ≤ | Mреальная | < Z, где Z – основание системы счисления. Так как мы рассматриваем положительные числа, то модуль в условии можно опустить. Для отрицательной мантиссы всё аналогично с точностью до знака, который хранится в первом бите записи числа. Также, так как мы используем двоичную систему счисления, её основание Z = 2 и условие будет выглядеть следующим образом: 110 ≤ Mреальная 10 < 210. Запишем ограничения условий в двоичной системе счисления. Получим 12 ≤ Mреальная 2 < 102. Допишем не значащие (с точки зрения математики) нули для наглядности.
             Получим 1,00000000...2Mреальная 2 < 10,00000000...2, то есть Mреальная 2 есть число вида 1,xxxxxxxx..., где, как уже легко заметить, первая цифра в записи всегда равна 1.
             Если мы хотим записать в память t знаков дробной части числа 1,xxxxxxxx..., придётся вычесть из него единицу (какой смысл её хранить, занимая ячейку памяти, если она всегда равна 1?), после чего мы получим 0,xxxxxxxx..., далее следует «передвинуть» запятую на t разрядов вправо, что для двоичной системы равносильно умножению числа на 2t.
             То есть общая формула преобразования будет T = (Mреальная−1)·2t, выразим из этого выражения Mреальная:
             Сопоставив изложенное выше, получим общую формулу, связывающую представляемое число и хранимые в памяти ЭВМ данные: ISBN 978-5-97060-304-8 , (формула № 1) для формата binary32 из табл. 2.7 подставим следующие значения: w ≡ b = 8, t ≡ n = 23, k = 32, в результате чего получим:
    ISBN 978-5-97060-304-8
             Замечание. В нормализованной форме записи невозможно записать 0. Так как запиши мы в представлении мантиссы нули – получим единицу, а запиши мы в степени число, дающее после вычитания смещения ноль – получим 20, что по определению есть 1, следовательно, формула № 1, где используется произведение этих чисел, даст в результате единицу, а не ноль. Если же мы вспомним, что договорились представлять ноль всеми нулями и запишем их в формулу № 1, то получим 5,87747175411144·10−39 – самое минимальное положительное число, представимое такой формулой. Заметим, что это число не может быть представлено форматом IEEE754 binary32, так как мало (совсем на «чуть-чуть» меньше того, что позволяет представить формат). Аналогично для числа со знаком «минус» −5,87747175411144·10−39. Фактически именно эти числа являются представлением «+0» и «−0» в модели IEEE754. Ну а то, что число 0 есть в памяти 00 00 00 0016, как мы договорились выше, есть красивое совпадение.
    2.1.4.5.3. 2.1.4.4.3. Денормализованные числа
    51

    (англ. denormalized numbers, subnormal numbers)
             Денормализованные числа – это числа, которые нельзя представить в нормализованной форме по формуле № 1. Попытаемся ответить на вопрос: «В чём преимущество денормализованных чисел?» Чтобы ответить на этот вопрос, разберёмся, чем они отличаются от нормализованных, тогда всё и встанет на свои места. Рассуждения ниже по большей части основаны на материале, взятом из [19], который был переработан и дополнен, устранены ошибки. Для упрощения изложения рассмотрим «игрушечный» формат «несуществующий binary5», в котором возможно не только представить, но и перебрать все 25 = 32 вариантов чисел для большей ясности.
    несуществующий игрушечный формат binary5
             Из пяти битов записи «xyyzz» отведём один бит на кодирование знака (поле «S»), два бита на кодирование показателя степени (поле «Е»), два бита для хранения кода мантиссы (поле «T»). Для поля знака S имеем два варианта: «0» и «1». Пусть «0» кодирует знак «+», а «1» – знак «−». Представим параметры формата «несуществующий binary5» в табл. 2.9 на ряду со значениями существующего формата binary32 стандарта IEEE 754-2008.

    Таблица 2.9. Параметры формата «несуществующий binary5»

    Таблица 2.9. Параметры формата «несуществующий binary5» ISBN 978-5-97060-304-8
             Поясним значение «emax» максимального показателя степени. На его кодирование отведено 2 бита, значит возможны варианты: «00», «01», «10», «11». Учитывая необходимость кодирования как положительных, так и отрицательных значений степени, ставим в соответствие этим вариантам: −1, 0, 1, 2 (таким образом, смещение «bias» равно 1). (Если вы не поняли, почему мы выбрали именно эти значения и сместили их таким образом, предложите свой вариант и поищите у него недостатки, нарисовав ось и разместив на ней получившиеся у вас числа.)
             Так как нормализованная мантисса для двоичных чисел всегда имеет вид 1,xxxxxxxx2 (ноль мы не рассматриваем), то первый единичный бит можно в памяти не хранить (то есть он хранится «неявно» и, при необходимости выполнить вычисления, восстанавливается автоматически). Поэтому отведённые под мантиссу 2 бита мы будем использовать для хранения первых двух знаков после запятой, что позволит хранить в памяти ещё один бит дробной части мантиссы. Поэтому точность p в табл. 2.9 записана как три, так как 3 = 2 + 1.
             В придуманном нами пятибитовом формате возможно представить 16 чисел со знаком «+» (см. табл. 2.10), размещение которых на числовой оси представлено на рис.2.6.

    ... подробнее см. в бумажном издании, либо по запросу на почту...

    2.1.4.5.4. Бесконечность (∞)
    57

    Так как по формуле № 1 представить число «+∞» не представляется возможным, впрочем, как и 0, было предложено сделать исключение и ввести данное число в формат IEEE754 дополнительно. Если ноль представлялся всеми нулями, то логично было бы представить бесконечность единицами во всех разрядах (кроме знака). Однако так не поступили, возможно из-за потенциально сложных технических решений, предложив рассматривать числа с максимально возможной степенью отдельно. Так, числа, у которых по представлению рис. 2.6 в смещённом показателе степени окажутся все единицы, следует рассматривать отдельно, а наименьшее из этих чисел, согласно формуле № 1, то есть то, где все биты мантиссы будут равны нулю, следует считать числом «+∞». Для формата binary32 IEEE754 это будет число записанное в памяти как 7F 80 00 00 (следует учитывать, что реальная последовательность байтов зависит от архитектуры, см. стр. 36, аналогично и для −∞). «+∞» Фрагмент памяти, содержащий значения FF 80 00 00, будучи интерпретирован по формату binary32 IEEE754, будет считаться ЭВМ как −∞. «−∞» В рассмотренном примере выше число 410, записанное в памяти как 01100, можно было бы интерпретировать как +∞.
    2.1.4.5.5. Не числа (NaN, Not a Number)
    58

    2.1.4.6. Интересные наблюдения
    59


             Теперь, когда мы поверхностно ознакомились с форматом хранения действительных чисел приведём несколько интересных наблюдений и перейдём к экспериментам с целью проверки на практике полученных знаний.
             было замечено в [19], одна из удивительных особенностей представления чи- сел в формате IEEE754 состоит в том, что порядок и мантисса расположены друг за другом таким образом, что вместе образуют последовательность целых чисел {n}, для которых выполняется: n < n+1 => F(n) < F(n+1), где F(n) – число с плавающей запятой, образованное от целого n разбиением его битов на «смещённый порядок» и «часть битов мантиссы». Поэтому если взять положительное число с плавающей запятой, преобразовать его к целому, прибавить «1», мы получим следующее число, которое представимо в этой арифметике.
             Как было замечено в [19], одна из удивительных особенностей представления чисел в формате IEEE754 состоит в том, что порядок и мантисса расположены друг за другом таким образом, что вместе образуют последовательность целых чисел {n}, для которых выполняется:
             n < n+1 => F(n) < F(n+1),
    где F(n) – число с плавающей запятой, образованное от целого n разбиением его битов на «смещённый порядок» и «часть битов мантиссы». Поэтому если взять положительное число с плавающей запятой, преобразовать его к целому, прибавить «1», мы получим следующее число, которое представимо в этой арифметике.

    ... подробнее см. в бумажном издании, либо по запросу на почту...






    Приобрести учебник по "Информатике" в котором изложен данный материал можно в издательстве "ДМК-Пресс", в торгово-издательском холдинге "Планета Альянс", в интернет-магазине "Альт Линукс", в редакции и интернет-магазине журнала «Системный администратор», в г.Тула, а также в интернет магазинах и книжных магазинах вашего города.