1626435587-51311eae4652e8ad616b5bdef025cbb3 (844239), страница 7
Текст из файла (страница 7)
д.Для двоичных чисел указанное ограничение означает, что записьмантиссы любого нормализованного числа начинается с 1, так что любое такое число может быть представлено в виде = ±1, · 2 , где — дробная часть мантиссы числа , — двоичный порядок числа(exponent). Поскольку целая часть мантиссы всегда равна 1, в целяхоптимизации её не сохраняют в памяти ЭВМ.Например, число 1 в нормализованном двоичном виде записывается как +1,000 · 20 , десятичное число 1610 = +1,000 · 24 , аналогично−0,7510 = −1,12 · 2−1 (обратите внимание на мантиссу −1,12 —). Как будет записываться число ≈ 3,141610в нормализованном виде с использованием четырёхразрядной мантиссы? Ближайшая к степень 2 есть 21 , так что ≈ 1,570810 × 21 .Если бы мантисса была десятичной, она бы кодировала десятитысячные доли.
Аналогично, в двоичной записи четырёхразрядная мантиссасоответствует числителю дроби со знаменателем 24 = 16. Посколькус плавающей точкой плавающей запятоймантиссы порядка числачиселнормализованнойминусодна целая одна вторая319/2 ≈ 1,5708 ≈ 1 16, а 910 = 10012 , имеем окончательно ≈ +1,10012 ·21 .В памяти ЭВМ числа записываются в виде последовательности битов (двоичных цифр): самый первый (старший) бит — знак числа ,далее битов — = − (2−1 − 1), последние бит — дробная часть мантиссы числа, · 2 (рис. 2). Нормализованноечисло с плавающей точкой может быть представлено выражением:смещённый порядок = (−1) · (1 + /2 ) · 2 −(2−1−1).(1)Знак числа может быть равен либо 0 ( > 0), либо −1 ( < 0).Дробная часть мантиссы может принимать любое из 2 значений, смещённый порядок меняется от 1 до 2 − 2 включительно (ещё двавозможных значения = 0 и = 2 − 1 зарезервированы, о чем мыпоговорим чуть позже). Таким образом, порядок машинных чисел меняется от min = −2−1 +2 до max = 2−1 −1.
Для чисел с плавающейточкой с одинарной точностью = 8, смещение (bias) 2−1 − 1 = 127,min = −126, 2−min = 1,175 · 10−38 , max = 127, 2max +1 = 3,403 · 1038 .порядок ES(а)(б)Sмантисса M* * * * * * * * * * * * * * * * * * * * * * *S0 0 0 0 0 0 0 0 * * * * * * * * * * * * * * * * * * * * * * *старший бит0x80 00 00 00младшийбит 0x1Рис. 2. Запись (а) нормализованных и (б) денормализованных чисел одинарной точности в соответствии со стандартом IEEE 754Очевидным ограничением нормализованной формы записи чиселс плавающей точкой является невозможность представления нуля иблизких к нулю чисел. Действительно, самое маленькое по модулю нормализованное число в ЭВМ равно 1 = 1,00 .
. . 002 · 2min , тогда какследующее за ним число 2 будет отличаться от 1 в последнем знакемантиссы 2 = 1,00 . . . 012 · 2min . Таким образом, даже если кодировать число 0 с помощью некоторой специально зарезервированной последовательности битов, вблизи нуля получится огромный «провал» —область чисел, непредставимых в нормализованном виде.
Размер этой«околонулевой ямы», отнесенный к расстоянию между соседними числами, равен 1 /(2 − 1 ) = 2 , где — разрядность мантиссы. Для стандартного типа данных с одинарной точностью = 23, 223 = 8,4 · 106 ,для чисел с двойной точностью = 52, 252 = 4,5 · 1015 . Буквальное32отсутствие 4 · 1015 машинных чисел вблизи нуля означает, в частности,существование 2 машинных чисел вида 1, · 2min , разность любыхдвух из которых будет равна нулю − = 0 ∀, = 1, . .
. , 2 . Это,в свою очередь, будет приводить к «неожиданным» делениям на ноль,дополнительным сложностям в написании и отладке программ (проверка условий = и − ̸= 0 может давать разные результаты!)Согласно приблизительным оценкам [A6], в 70-х годах каждый компьютер попадал в «околонулевую яму» в среднем один раз в месяц —очевидно, указанная частота должна была расти пропорционально производительности ЭВМ.Для решения данной проблемы в начале 1980-х были предложены (и в 1985 г. закреплены стандартом IEEE 754)(subnormal) числа, запись мантиссы которых начинается с нуля целых:±0, · 2min −1 .
Денормализованные числа кодируются в памяти ЭВМдвумя целыми числами: знаком = 0, 1 и дробной частью мантиссы .Смещённый двоичный порядок денормализованных чисел равен нулю, что позволяет процессору отличать их от нормализованных чисел,для которых ≥ 1. При этом фактическое значение двоичного порядка, очевидно, совпадает с наименьшим значением min = −2−1 + 2для нормализованных чисел:денормализованные−1 = (−1) (/2 ) · 2−(2−2).(2)Как видно из выражения (2), денормализованные числа образуют равномерную сетку с шагом 2− · 2min . Наименьшее по модулю денормализованное число равно нулю, наибольшее — (1 − 2− ) · 2min , гдеmin = −2−1 + 2. Машинное число, следующее за наибольшим положительным денормализованным числом (1−2− )·2min , равно 1·2min —наименьшему положительному нормализованному числу.Стандарт IEEE 754 предусматривает целый ряд типов данных дляпредставления чисел с плавающей точкой.
Самый «младший» из двоичных типов, который поддерживается языком Си (тип float) и используется в численных расчётах, кодируется 32-битной последовательностью и называется обычно типом данных с плавающей точкой. Кроме того, стандартом предусмотрены 64битные двоичные числа с плавающей точкой (числа), которые также поддерживаются всеми современными компиляторами языка Си и математическими сопроцессорами (в отличие от128-битных чисел с плавающей точкой, имеющих весьма ограниченнуюподдержку).Заметим, что для многих современных процессоров скорость выполнения операций сложения, вычитания и умножения над числами33одинарной точностистидвойной точно-с двойной точностью может не уступать скорости обработки чисел содинарной точностью17 .
В этой связи компилятор Си может генерировать машинный код, выполняющий вычисления с использованиемдвойной точности даже в случае, если результат будет затем помещёнв переменную типа float. Кроме того, константы с плавающей точкой (напр., 3e10) являются константами двойной точности (double) —соответственно, вычисление выражений, в которые они входят, также выполняется с двойной точностью. При необходимости определения констант типа float следует использовать суффикс f в их записи,например, 1.f, 3e10f и т. п.2.3. За пределами разрядной сеткиЧто будет, если 2max умножить на 2? Наблюдательный читатель,возможно, уже заметил, что max = 127, что соответствует смещённомупорядку = 25410 = 1111 11102 . Значение = 25510 = 1111 11112 неиспользуется для кодирования чисел — оно зарезервировано для сигнализации о выходе за пределы разрядной сетки.
Если в результате вычислений с плавающей точкой получаются значения, бо́льшие(1 − 2− ) · 2max , результатом вычислений является «бесконечность»,кодируемая в соответствии с IEEE 754 как = 11 . . . 12 , = 0. Бесконечность, как и все машинные числа с плавающей точкой (включаяноль), бывает двух разных знаков. Результат сложения и умножениябесконечности на любое конечное число снова даёт бесконечность. Припопытке напечатать «бесконечность» с помощью printf результатомможет быть 1.#INF, inf или что-нибудь подобное в зависимости от используемого компилятора.√Результатом операций 0 · ∞, ∞/∞, ∞ + (−∞), 0/0, при < 0являются «не-числа» (not-a-numbers, NaNs), для обозначения которыхиспользуется комбинации = 11 .
. . 12 , ̸= 0. Не-числа обладаютбольшой избыточностью кода — им соответствуют 2 − 1 комбинациябитов, в то время как в соответствие со стандартом IEEE 754 существует всего два типа NaN — «тихие» (quiet) и «сигнальные» (signaling).Функция printf напечатает не-число как -1.#IND00 или nan в зависимости от используемого компилятора.17 Однако на тех же процессорах быстродействие может отличаться при делении чисел с одинарной и двойной точностью, а также при вычислении квадратногокорня и библиотечных функций. Кроме того, существенное отличие производительности наблюдается на графических процессорах (GPU), однако в последнее времяхорошо заметна тенденция сокращения этого разрыва на новых видеокартах, ориентированных на высокопроизводительные вычисления.34В соответствии со стандартом, сравнение NaN с чем бы то ни было всегда даёт логическую ложь (false) — это позволяет выполнятьпроверку результатов вычислений, сравнивая результат с самим собой.Кроме того, в файле <math.h> описаны функции для определения типов чисел, названия которых говорят сами за себя: isnan, isfinite,isinf, isnormal, fpclassify.