В начале 90-х создание трёхмерного игрового движка означало, что вы заставите машину выполнять почти не свойственные ей задачи. Персональные компьютеры того времени предназначались для запуска текстовых процессоров и электронных таблиц, а не для 3D-вычислений с частотой 70 кадров в секунду. Серьёзным препятствием стало то, что, несмотря на свою мощь, ЦП не имел аппаратного устройства для вычислений с плавающей запятой. У программистов было только АЛУ, перемалывающее целые числа.
При написании книги Game Engine Black Book: Wolfenstein 3D я хотел наглядно показать, насколько велики были проблемы при работе без плавающей запятой. Мои попытки разобраться в числах с плавающей запятой при помощи каноничных статей мозг воспринимал в штыки. Я начал искать другой способ. Что-нибудь, далёкое от и их загадочных экспонент с мантиссами. Может быть, в виде рисунка, потому что их мой мозг воспринимает проще.
В результате я написал эту статью и решил добавить её в книгу. Не буду утверждать, что это моё изобретение, но пока мне не приходилось видеть такого объяснения чисел с плавающей запятой. Надеюсь, статья поможет тем, у кого, как и у меня, аллергия на математические обозначения.
Цитирую Дэвида Голдберта (David Goldbert):
Для многих людей арифметика с плавающей запятой кажется каким-то тайным знанием.
Полностью с ним согласен. Однако важно понимать принципы её работы, чтобы полностью осознать её полезность при программировании 3D-движка. В языке C значения с плавающей запятой — это 32-битные контейнеры, соответствующие стандарту IEEE 754. Они предназначены для хранения и выполнения операций над аппроксимациями вещественных чисел. Пока я видел только такое их объяснение. 32 бита разделены на три части:
Внутренности числа с плавающей запятой.
Три части числа с плавающей запятой.
Пока всё нормально. Пойдём дальше. Способ интерпретации чисел обычно объясняется с помощью такой формулы:
Именно это объяснение чисел с плавающей запятой все ненавидят.
И здесь я обычно начинаю терять терпение. Возможно, у меня аллергия на математическую нотацию, но когда я это читаю, в моём мозгу ничего не «щёлкает». Такое объяснение похоже на способ рисования совы:
Хоть это изложение и верно, такой способ объяснения чисел с плавающей запятой обычно не даёт нам никакого понимания. Я виню эту ужасную запись в том, что она разочаровала тысячи программистов, испугала их до такой степени, что они больше никогда не пытались понять, как же на самом деле работают вычисления с плавающей запятой. К счастью, их можно объяснить иначе. Воспринимайте экспоненту как окно (Window) или интервал между двумя соседними целыми степенями двойки.
Три части числа с плавающей запятой.
Окно сообщает нам, между какими двумя последовательными степенями двойки будет число: [0,1], [1,2], [2,4], [4,8] и так далее (вплоть до [,]. Смещение разделяет окно на сегментов. С помощью окна и смещения можно аппроксимировать число. Окно — это отличный механизм защиты от выхода за границы. Достигнув максимума в окне (например, в [2,4]), можно «переплыть» вправо и представить число в пределах следующего окна (например, [4,8]). Ценой этого будет только небольшое снижение точности, потому что окно становится в два раза больше.
Викторина: сколько точности теряется, когда окно закрывает больший интервал? Давайте возьмём пример с окном [0,1], в котором 8388608 смещений накладываются на интервал размером 1, что даёт нам точность . В окне [2048,4096] 8388608 смещений накладываются на интервал , что даёт нам точность .
На рисунке ниже показано, как кодируется число 6,1. Окно должно начинаться с 4 и заканчиваться следующей степенью двойки, т.е. 8. Смещение находится примерно посередине окна.
Значение 6,1 аппроксимированное с помощью числа с плавающей запятой.
Давайте возьмём ещё один пример с подробным вычислением представлением в виде числа с плавающей точкой хорошо известного всем нам значения: 3,14.
В двоичном виде это преобразуется в следующее:
Двоичное представление с плавающей точкой числа 3,14.
То есть значение 3,14 аппроксимируется как 3,1400001049041748046875.
Соответствующее значение в непонятной формуле:
И, наконец, графическое представление с окном и смещением:
Окно и смещение числа 3,14.
Интересный факт: если модули операций с плавающей запятой были такими медленными, почему в языке C в результате использовали типы float и double? Ведь в машине, на которой изобретался язык (PDP-11), не было модуля операций с плавающей запятой! Дело в том, что производитель (DEC) пообещал Деннису Ритчи и Кену Томпсону, что в следующей модели он будет. Они были любителями астрономии и решили добавить в язык эти два типа.
Интересный факт: те, кому в 1991 году действительно нужен был аппаратный модуль операций с плавающей запятой, могли его купить. Единственными, кому он мог понадобиться в то время, были учёные (по крайней мере, так Intel понимала потребности рынка). На рынке они позиционировались как «математические сопроцессоры». Их производительность была средней, а цена огромной (200 долларов 1993 года — это 350 долларов в 2016 году.). В результате уровень продаж оказался посредственным.
Надеюсь, статья была вам полезна!
Аннотация: Цель лекции: определить структуру числа с плавающей запятой, особенности его представления в соответствии с ГОСТ IEEE 754, порядок выполнения умножения, деления сложения и вычитания чисел с плавающей запятой, особые ситуации, возникающие при выполнении этих операций и способы обработки этих ситуаций. Ключевые слова: число с плавающей запятой, ГОСТ IEEE 754, особые ситуации при обработке чисел с плавающей запятой.
Число с плавающей запятой представляется в виде мантиссы (М) и порядка (П).
Например, число А = 123 может быть представлено в виде числа с мантиссой 12,3 и порядком +1, то есть 12,3 *10+1.
Другие представления этого самого же числа могут выглядеть так: 123 = 123*100 = 1230 10-1 = 0,123*10+3 = 0, 0123 * 10+4 = …Для того чтобы число с плавающей запятой представлялось единственным образом, его мантисса должна быть нормализована, то есть на нее накладывается следующее ограничение.
Нормализованная мантисса должна удовлетворять условию:
( 10.1) |
где р – основание системы счисления, то есть мантисса представляет собой правильную дробь, у модуля которой старшая цифра отлична от нуля.
Из приведенного выше примера этому условию удовлетворяет лишь запись
intuit.ru/2010/edi»>А = 0,123*10+3Как мантисса, так и порядок могут быть как положительными, так и отрицательными числами. Поэтому в общем виде число с плавающей запятой имеет следующий формат (Рис. 10.1). В дальнейшем мы рассмотрим, как форма кодирования чисел в ЭВМ сказывается на этом формате. В этой лекции будем исходить именно из такой формы представления числа с плавающей запятой, так как она позволяет выявить все особенности обработки таких чисел.
Рис. 10.1. Структура числа с плавающей запятой
Порядок представляет собой число с фиксированной точкой, мантисса – число с фиксированной запятой. Поэтому:Ммакс = 0,1 … 1 = 1-2-n
Ммин = 2-1 (напомним, что мантисса должна быть нормализована).
Пмакс = 0,1 … 1 = 2m-1
-Пмакс = -(2m-1)
Мы пока ведем речь только о естественном, а не машинном представлении числа, где, например, в так называемом дополнительном коде можно представить на одну комбинацию отрицательных чисел больше, чем положительных.
В данном случае достаточно просто определить диапазон представляемых чисел
Абсолютная погрешность представления числа с плавающей запятой ЭВМ составит:
Относительная погрешность представления в ЭВМ числа с плавающей запятой будет равна:
Таким образом, мы видим, что для чисел с плавающей запятой диапазон их представления весьма широк и определяется в основном, количеством разрядов, отводимых под порядок числа, а относительная погрешность меняется гораздо меньше, чем для чисел с фиксированной точкой (всего в 2 раза) и определяется количеством разрядов, отводимых под запись мантиссы числа.
Сначала рассмотрим случай перемножения двух чисел с плавающей запятой в десятичной системе счисления.
(0,3*103) * (0,2*102) = (0,3 * 0,2) *103+2 = 0,06 * 105 = 0,6* 104
Последний шаг выполнен для нормализации мантиссы результата.
Таким образом, если представить операнды в двоичной системе счисления как
а произведение мы хотим тоже получить в виде числа с плавающей запятой, то есть
то умножение сводится к двум простейшим действиям, рассмотренным ранее: сложению порядков сомножителей как целых чисел и перемножению мантисс как операндов с фиксированной запятой. При необходимости к ним добавляется еще нормализация мантиссы результата:
intuit.ru/2010/edi»>Пz = Пx + ПyMz = Mx * My
Интерес здесь представляют особые случаи, которые могут возникнуть на различных этапах обработки числа. Так при сложении чисел с фиксированной точкой (речь идёт о порядках) может возникнуть переполнение, которое сделает невозможным дальнейшую работу с этим числом, либо при перемножении мантисс сомножителей мы получим денормализованную мантиссу результата, что потребует ее коррекции с одновременной коррекцией полученного ранее порядка произведения. Все эти и некоторые другие обстоятельства необходимо учитывать при проведении данной операции.
Ряд этих случаев будем рассмотрен нами при обсуждении ГОСТа IEEE 754 на представление чисел с плавающей запятой [ …]. В то же время иногда подобные ситуации возникают в процессе выполнения самой операции, а окончательный результат оказывается допустимым числом. Рассмотрим все эти случаи.
Главное обстоятельство, на которое следует обратить внимание при умножении чисел с плавающей запятой, это диапазон мантисс, которые получаются при выполнении операции.
Так как мы исходим из того, что мантиссы обоих операндов нормализованы, то есть удовлетворяют условию
1 > |Mx,y| ≥ 2-1,
то 1 > |Mz| = |Mx| * |My| ≥ 2-2.
Таким образом, нормализация мантиссы если и потребуется, то только путем сдвига на один разряд влево. При этом порядок, естественно, следует уменьшить на 1. Отсюда вытекает следующая последовательность действий.
Т.к. |Mx| ≥ 2-1, |My| ≥ 2-1, то |Mz| ≥ 2-2
Возможная область ненормализованной мантиссы:
2-1 > |Mz| ≥ 2-2
Если |Mz| < 2-1, то выполнить нормализацию мантиссы с одновременной коррекцией порядка:
|Mz| = |Mz| * 2+1
Пz = Пz -1
intuit.ru/2010/edi»>Если в результате получим Пz = — ∞, то Z=0.Если в ходе перемножения мантисс получим |Mz| ≥ 2-1 , но ранее при обработке порядков получили Пz = + ∞ (см п.1.2), то Z = ∞
При Z=0 выполнение программы в ЭВМ продолжается.
При Z = ∞ устанавливается флаг прерывания, и ЭВМ приостанавливает обработку данных чисел.
Страница, которую вы пытались открыть по этому адресу, похоже, не существует. Обычно это результат плохой или устаревшей ссылки. Мы извиняемся за любые неудобства.
Если вы впервые посещаете TechTarget, добро пожаловать! Извините за обстоятельства, при которых мы встречаемся. Вот куда вы можете пойти отсюда:
ПоискСеть
Основная полоса при передаче сигналов связи означает, что для отправки и приема цифровых сигналов доступен только один путь …
Широкополосный доступ относится к телекоммуникациям, в которых для передачи информации доступна широкая полоса частот.
Оптоволокно до дома (FTTH), также называемое оптоволокном до помещения (FTTP), представляет собой установку и использование оптического волокна от центрального …
Безопасность
Общая система оценки уязвимостей (CVSS) — это общедоступная платформа для оценки серьезности уязвимостей безопасности в . ..
WPA3, также известный как Wi-Fi Protected Access 3, является третьей итерацией стандарта сертификации безопасности, разработанного Wi-Fi …
Брандмауэр — это устройство сетевой безопасности, предотвращающее несанкционированный доступ к сети. Проверяет входящий и исходящий трафик…
ИТ-директор
The Agile Manifesto — это документ, определяющий четыре ключевые ценности и 12 принципов, в которые его авторы верят разработчикам программного обеспечения…
Total Quality Management (TQM) — это система управления, основанная на вере в то, что организация может добиться долгосрочного успеха, …
Системное мышление — это целостный подход к анализу, который фокусируется на том, как взаимодействуют составные части системы и как. ..
HRSoftware
Непрерывное управление эффективностью в контексте управления человеческими ресурсами (HR) представляет собой надзор за работой сотрудника …
Вовлеченность сотрудников — это эмоциональная и профессиональная связь, которую сотрудник испытывает к своей организации, коллегам и работе.
Кадровый резерв — это база данных кандидатов на работу, которые могут удовлетворить немедленные и долгосрочные потребности организации.
Обслуживание клиентов
Бесконтактный платеж — это беспроводная финансовая транзакция, при которой покупатель совершает покупку, перемещая токен безопасности в …
Исходящий вызов — это вызов, инициированный оператором центра обработки вызовов клиенту от имени центра обработки вызовов или клиента.
Social CRM, или социальное управление взаимоотношениями с клиентами, — это управление взаимоотношениями с клиентами и взаимодействие с ними, поддерживаемое …
Мэри Пэт Кэмпбелл
У вас открыт Excel? Поместите это в A1:
=1*(.5-.4-.1)
Что вы получили? Если вы получили ноль, попробуйте попросить Excel показать вам больше цифр после запятой. Однако, как правило, Excel по умолчанию возвращается к следующей нотации с плавающей запятой:
-2.78E-17
Конечно, это мало, но не ноль.
Отдельно, если вы посмотрите мою таблицу из январского выпуска журнала CompAct за 2014 год, сопровождающую статью под названием «Вариации приближения — исследование в расчетах», вы увидите, что на некоторых вкладках кумулятивная сумма вероятностей для аппроксимированное биномиальное распределение меньше 1 (примерно на 10 ^ -14). Это может вызвать у нас проблемы с некоторыми приложениями дистрибутива. Вычисленные числа должны в сумме давать единицу, по крайней мере, для вкладок, не использующих приближения, если бы мы использовали точную арифметику, карандаш и бумагу. Но в Excel этого не будет.
Хотя приведенные выше примеры относятся к Excel, это не уникально для Excel. В частности, существуют аспекты того, как Excel обрабатывает числа с плавающей запятой, но я хочу начать с общих проблем и не вдаваться в мучительные подробности. Просто раздражающая деталь.
Во-первых, что такое представление вещественного числа с плавающей запятой? Это выглядит так:
(+/-) Значимая* основа Показатель степени
Стандартные формы обычно заставляют эту «значащую» часть быть между 0,0 и 9.999999 (до уровня точности станка). База будет указана (обычно две для компьютеров). Каждая система будет иметь ограничения на количество значащих цифр (называемых точностью) и будут ограничения на показатель степени (положительный и отрицательный). Между положительными и отрицательными числами может быть некоторая асимметрия, так что наименьшее отрицательное число может не совпадать по абсолютной величине с наибольшим положительным числом в системе (аналогично для диапазона показателей).
Для преувеличения эффекта арифметических операций с плавающей запятой я буду использовать довольно низкие ограничения. Я позволю до четырех значащих цифр (будет содержать -9от 0,999 до 9,999), я допущу степени от минус трех до четырех и буду использовать основание 10 для облегчения ручной проверки операций.
Давайте рассмотрим некоторые проблемы, связанные с арифметикой с плавающей запятой:
Мы постоянно сталкиваемся с этой потерей точности в наших вычислениях, потому что наши числа преобразуются из десятичных в двоичные числа с плавающей запятой. Многие вещи, которые хорошо выглядят в десятичном виде, например 0,1 или 0,4, в двоичном виде повторяются. В двоичном формате 0,5 имеет прекрасное представление: 0,1. Поэтому, когда мы конвертируем 0,1 и 0,4 в двоичные числа, теряя при этом точность, а затем пытаемся вычесть их из 0,5, мы не получаем 0. накладывает потолок на количество сигфигов, которое вам разрешено иметь. Это дает вам представление о том, как теряется точность при операциях с плавающей запятой. 9-1? То есть мы пытаемся прибавить 777,7 к .9555.
В точной арифметике ответ равен 778,6555. Но это слишком много значащих цифр для нашей системы с плавающей запятой. Мы должны округлить это число до 778,7, чтобы оно соответствовало нашей системе. Разница между округленным ответом и нашим точным ответом составляет 0,0445. В относительном выражении это незначительная ошибка, так что, возможно, это нас не беспокоит.
Но что должно беспокоить нас, так это когда мы делаем что-то вроде сложения набора чисел, которые в конечном итоге должны давать одно, но каждое из которых очень мало. -3 к 9.-1. В нашей системе это получается так: 0,9999 + 0,00001 = 0,99991 = 0,9999. Теперь предположим, что мы пытаемся добавить этот столбец чисел:
.9999 |
.00001 |
.00001 |
.00001 |
.00001 |
.00001 |
.00001 |
.00001 |
.00001 |
.00001 |