No Image

Что такое мантисса и экспонента

0 просмотров
22 января 2020

Введение или зачем этот топик

Еще раз о мантиссе и экспоненте

В вычислительной математике дробные значения представляют в виде пары целых чисел (n, e): мантиссы и экспоненты (по-русски более верно «показателя степени», но для краткости и по привычке буду в дальнейшем употреблять именно слово «экспонента»). Пара представляет дробное число в виде n * 2 -e .
Экспоненту можно рассматривать как количество цифр перед запятой, отделяющей дробную часть числа.
Если экспонента переменная, записываемая в регистр и неизвестная при компиляции, (n, e) называют числом с плавающей запятой. Если экспонента известна заранее, (n, e) называют числом с фиксированной точкой. Числа с фиксированной точкой могут записываться в обыкновенные целочисленные переменные (регистры) путем сохранения только мантиссы. Экспоненту обычно обозначают буквой q. Так что, встретив в комментарии к переменной что-нибудь в духе "q15 multiplier", следует рассматривать эту переменную как число с фиксированной точкой и экспонентой, равной 15. Впрочем, я еще вернусь к вопросу нотации, встречающейся в различных исходниках и статьях.

Вычисления

Итак, мы разобрались с тем, что при работе с фиксированной точкой экспонента нигде не записывается и держится «в уме».
Как же производить расчеты? Вычислительная арифметика — целая наука со своими формулами, аксиомами и теоремами. Целью данной статьи не было давать введение в эту науку. Подходы, приведенные ниже, в первую очередь ориентированы на программистов, решающих инженерные и прикладные задачи, т.е. такие, где диапазоны допустимых значений и необходимые точности вычислений известны и ограничены.
Еще одно ограничение статьи — здесь не приводятся алгоритмы тригонометрических и прочих сложных операций. Сделать их полный обзор в одной статье нереально (и вряд ли необходимо). В статье дан базис, необходимый для понимания таких алгоритмов (и разработки собственных), — правила выполнения базовых операций (сложение/вычитание, умножение, деление) и общая методика вычислений с фиксированной точкой.

Сложение и вычитание

Сложение выполняется просто, если представить в уме, что мы должны сложить две десятичные дроби «в столбик» на листе бумаги. При выполнении данной операции числа записываются в столбик так, чтобы запятые, отделяющие дробную часть, располагались одна под другой. В двоичной арифметике подобная операция называется приведением экспонент.
Если перейти от «бумажки» к математической записи, получится следующее:
Пусть имеется два числа a = n1 * 2 -q1 и b = n2 * 2 -q2 .
Тогда:
a + b = n1 * 2 -q1 + n2 * 2 -q2 = (n1 + n2 * 2 (q1 — q2) )*2 -q1 .
Множитель 2 (q1 — q2) при втором слагаемом по сути означает арифметический сдвиг для приведения чисел к одной экспоненте.
Стоит отметить, что результат вычисления также может сдвигаться для приведения к требуемому значению экспоненты.
Фрагмент кода на С:

Из примера может быть понятно, что в реальных вычислениях даже в такой простой операции как сложение, есть простор для раздумий. Всегда стоит держать в уме вопросы:

  • жертвовать точностью или нет? Можно ведь привести слагаемые к меньшей экспоненте сдвигом вправо и отбросить младшие разряды.
  • ограничены ли значения переменных? Сдвиг вправо в данном случае, например, не приводит к потере точности.
  • есть ли возможность расширить разрядность?

Это далеко не полный список, но уже показывает, что не все так просто, как может показаться на первый взгляд. В большинстве практических применений для каждой предметной области известны или могут быть получены диапазоны допустимых значений, так что при работе с фиксированной точкой требуется некоторый опыт или проведение исследований. Зачастую предварительно код пишется с плавающей запятой, после чего исследуются диапазоны значений, и малыми значениями пренебрегают.

Умножение

Умножение с фиксированной точкой может выполняться без хитрых выравниваний и приведения к единой экспоненте. Тем не менее умножение — достаточно опасная операция, которая чаще всего в итоге приводит к потере точности и требует особой аккуратности в обращении.
Начнем с математического описания умножения:
Пусть имеется два числа a = n1 * 2 -q1 и b = n2 * 2 -q2 .
Тогда:
a * b = n1 * 2 -q1 * n2 * 2 -q2 = n1 * n2 * 2 -(q2 + q1) .
Из выражения видно, что экспоненты чисел при умножении складываются: 2 -(q2 + q1) . Разрядность данных в этой статье не рассматривается, пока достаточно лишь запомнить, что для безопасного умножения без переполнения и потери точности разрядность результата должна быть не меньше суммарной разрядности сомножителей.
Из-за сложения экспонент результат умножения приходится корректировать для выполнения дальнейших вычислений. При уменьшении экспоненты младшие разряды результата отбрасываются. То есть происходит потеря точности. Можно уменьшить потери точности (и иногда приходится), но способы борьбы с потерями всегда связаны с накладными расходами.
Фрагмент кода на С:

Читайте также:  Смотреть фильмы с компьютера на телевизоре samsung

Отмечу, что 15 младших разрядов результата умножения были отброшены, чтобы привести число к формату слагаемого. Можно было, конечно, увеличить разрядность переменной c, но, как я уже говорил, на практике диапазоны значений обычно ограничены и младшими разрядами умножения зачастую пренебрегают. Кроме того, не учитывается возможность наличия в исходных сомножителях ненулевых старших разрядов.
Но в данной статье обработка переполнений не рассматривается.

Деление

Начнем с математического выражения для деления:
Пусть имеется два числа a = n1 * 2 -q1 и b = n2 * 2 -q2 .
Тогда:
a / b = n1 * 2 -q1 / (n2 * 2 -q2 ) = n1 / n2 * 2 -(q1 — q2) .
Сомножитель 2 -(q1 — q2) означает, что при выполнении деления экспонента автоматически уменьшается. Если не принять меры, часть значащих разрядов отбрасывается автоматически.
Способ коррекции очевиден — необходимо заранее увеличить разрядность делителя настолько, чтобы в результате деления получить желаемое количество значащих бит:
a / b = n1 * 2 -q1 * 2 q3 / (n2 * 2 -q2 ) = n1 / n2 * 2 -(q1 — q2 + q3) .
Таким образом, экспонента частного увеличена на q3 разряда.
Фрагмент кода на С:

Очевидно, что при превышении числом разрядности 32 бита, проблему уже не решить так просто. Тем не менее, для простых инженерных расчетов 32-битных чисел обычно более, чем достаточно.
Есть один простой способ значительно сократить потерю точности при делении — предварительное нормирование делимого. Нормирование — фактически максимальный сдвиг мантиссы влево, при котором не происходит отбрасывания значащих битов. Определить, на сколько можно сдвинуть число, можно путем подсчета ведущих нулей в делимом, для чего существуют специальные алгоритмы (или даже аппаратные инструкции процессора).
После деления частное следует сдвинуть вправо на такое же количество бит для восстановления экспоненты.
Вышеприведенный фрагмент кода при этом может выглядеть таким образом:

Как видим, потери точности в данном случае не произошло и без увеличения разрядности делимого.
Впрочем, так происходит не всегда, и если требуется остаться в рамках определенной разрядности (например, 32 бита), приходится реализовывать деление алгоритмически. В обзорной статье вряд ли стоит погружаться в такие дебри — для понимания процесса деления и связанных с ним сложностей достаточно уже приведенного описания.

Нотация, принятая в литературе и различных исходниках

В последнем разделе статьи я хотел бы еще раз вернуться к общепринятой нотации, используемой при описании алгоритмов с фиксированной точкой.
Это достаточно важный момент, на который приходится обращать внимание при чтении чужих исходников.
Наиболее распространенными являются два варианта обозначения числа с фиксированной точкой:

  1. QM — где M — число разрядов после запятой. Использована в статье
  2. QN.M — где N — число разрядов до запятой без учета знакового бита, а M — после.

Минус первой нотации очевиден: при работе с переменной приходится обращаться к объявлению переменной (вспоминать ее разрядность) и производить в уме некоторые вычисления, чтобы понять, как привести экспоненту к желаемой. Больше того, если вспомнить округление (int32_t)d в примере с умножением, можно отметить, что при комментариях в данной нотации сложно понять, приведет ли сдвиг или отбрасывание значащих битов к ошибке.
При использовании комментариев во второй нотации можно просто записывать точность вычислений, что исключает необходимость вспоминать, как объявлена переменная.
Поясню примером:

Комментарии во второй нотации очевидно удобнее.
Не буду рассуждать тут о пользе комментариев (далеко не везде они вообще есть), скажу только, что для себя я всегда расписываю при вычислениях типы переменных, чтобы не ошибиться и не запутаться с приведением экспонент.
Если комментарии отсутствуют в принципе, чтение и понимание кода конечно же усложняется, но, запутавшись, всегда можно добавить подобные расшифровки в Q-нотации, чтобы понять, откуда взялся «этот сдвиг влево на 4, а потом сдвиг вправо на 10».
Отмечу, что в недавно выложенных Google исходниках VoIP движка GIPS (webrtc) в комментариях чаще всего просто пишут Q, подразумевая что все биты числа отводятся под дробную часть. Меня лично это весьма путает, т.к. приходится рыться в определениях, чтобы уточнить, как работает код.
Для себя я использую еще одну нотацию, которая отличается от вышеприведенных и близка к нотации MATLAB тулбокса для работы с фиксированной точкой. Она привязывает математику к разрядности переменных и упрощает жизнь, когда надо оценить результат операции (разрядность и экспоненту).
Числа с фиксированной точкой в своих комментариях я отмечаю как QN.M, где N — разрядность числа, M — количество разрядов после запятой.
Поясню, почему я нашел такую схему удобной для себя:

  1. Зная разрядность числа всегда можно предсказать разрядность результата, т.е. выбрать тип переменной, достаточный для его представления.
  2. Мне лично неудобна для чтения запись вида Q(-N).M, которая появляется во второй нотации после выполнения сдвига вправо и нехватке разрядов для дробной части. Например, запись для 16-битного числа, в котором экспонента равна 18 (n*2 -18 ), у меня выглядит q16.18, а по второй нотации q(-3).18. Запись в первой нотации, как уже было сказано, в любом случае заставляет обращаться к определению для понимания точности вычислений, но в данном случае без определения еще и непонятно: были уже отброшены ведущие значащие биты или нет.
  3. Произведя вычисления по своей нотации, мне проще увидеть, в переменную какой разрядности поместится результат, и как выравнивать экспоненты. Например, q32.15 * q16.4 = q48.19. Сразу видно, что для полного представления результата надо 48-бит. Во второй нотации запись выглядит как q16.15 * q11.4 = q27.19, и приходится подсчитывать, что 27 + 19 = 47 + 1 знаковый от первого сомножителя + 1 знаковый от второго = 48 бит. Мелочь, а приятно. Особенно, когда исходников много.
Читайте также:  Читать тексты на русском языке

О плюсах и минусах использования фиксированной точки

Столь подробное описание даже для базовых операций способно отпугнуть инженеров и программистов от использования фиксированной точки в вычислениях, особенно, если уже выработана привычка к плавающей запятой без слежения за результатом. Тем не менее, в использовании фиксированной точки есть свои плюсы, некоторые из которых неочевидны.
Для того, чтобы окончательно определиться, надо ли оно вам, можно использовать следующую сводку по вычислениям с фиксированной точкой.
Плюсы:

  • Необходимость думать.
  • Предсказуемость результата. При правильном подходе к кодированию результат вычислений будет одинаков на любой платформе (процессор + компилятор) с точностью до разряда. Для данного явления существует специальный термин «битэкзактность» (от англ., bit-exactness). Правильно закодированный алгоритм всегда битэкзактен и, следовательно, может исследоваться на нецелевой платформе. Особенно это полезно, когда отладка на целевой платформе затруднена или невозможна и можно снять только входные данные.
  • Полный контроль за поведением кода. Фиксированная точка исключает появление «неожиданностей», связанных с особенностями реализации плавающей запятой на используемой платформе.
  • Автоматическая «фильтрация» пренебрежимо малых значений. В плавающей запятой ошибки вычислений могут накапливаться, в фиксированной точке этого не происходит (за счет отбрасывания малых значений) или процесс накопления ошибок можно контролировать алгоритмически.
  • Алгоритмически контролируемый диапазон значений переменных. Плавающая запятая дает больше свободы в вычислениях, но результат может выходить за пределы допустимых, что приводит к необходимости его контролировать отдельно. В фиксированной точке эта проблема решается автоматически на этапе разработки и отладки алгоритма.
  • Переносимость алгоритмов. Данный плюс изрядно коррелирует с первым, но стоит отметить, что целочисленные вычисления гораздо лучше поддержаны множеством не-х86 процессоров, чем вычисления с плавающей запятой. Так что, разработав один раз алгоритм в фиксированной точке, портировать его на различные «слабые» платформы становится гораздо проще. Иногда целочисленные вычисления вообще единственное, что доступно на целевой платформе.
  • Возможность контролировать сложность вычислений путем понижения точности при разработке алгоритма.
  • Иногда это интересно.
Читайте также:  Устройство штекера для прикуривателя

Минусы:

  • Необходимость думать.
  • Пониженный (в простейшем случае) диапазон значений переменных по сравнению с плавающей запятой.
  • Необходимость алгоритмически контролировать диапазон значений переменных. Значительная часть времени при разработке уходит на правильное масштабирование и выбор диапазонов.
  • Необходимость следить за разрядностью на каждом этапе вычислений.
  • Необходимость писать собственный фреймворк базовых функций (тригонометрических, логарифмических и т.п.) или модифицировать существующий.
  • Необходимость погружаться в прикладную область при разработке алгоритма.
  • Необходимость повышать культуру написания и поддержки кода — без использования собственных наработок в фиксированной точке не обойтись. В плавающей точке чаще всего можно, не задумываясь, переписать математику «в лоб», с использованием готовых функций.

Онлайн калькулятор для перевода чисел в экспоненциальный вид и обратно, другим языком для вычисления чисел с буквой E.
На компьютере (в частности в тексте компьютерных программ) экспоненциальную запись записывают в виде MEp (пример 1e-10), где:

M — мантисса,
E (exponent) — буква E в числе, означающая «*10^» («…умножить на десять в степени…»),
p — порядок.
Это необходимо для представлении очень больших и очень малых чисел, а также для унификации их написания.

Многие пользователи калькуляторов столкнулись с вопросом: Что означает буква "E" в цифровом калькуляторе?
Это Экспоненциа́льная за́пись— представление действительных чисел в виде мантиссы и порядка. Удобна для записи очень больших и очень малых чисел.

Например, расшифруем эти числа:
Е — это 10, цифры после Е — показатель степени, в который возводится 10.
0.66E004 = 0,66 * 10^4 = 0.66*10000 = 6600
0.66E-007 = 0.66 * 10^(-7) = 0.66 * 0.0000001 = 0.000000066
0.66E11 = 0.66 * 10^11 = 0.66 * 100000000000 = 66000000000

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

Вычислим числа с буквой "е":
1e-10 = 0.0000000001 — ноль целых одна десятимиллиардная
6e+17 = -600000000000000000000
Есть число 2.6E3. Что означает буква Е = 2 600 — две тысячи шестьсот
1Е+6 = равен миллиону 1 000 000

Экспоненциальная форма представления чисел обычно используется для записи очень больших или очень малых чисел, кот в естественной форме содержат большое количество незначащих нулей (1 000 000 = 1·10 6 ). Вещественные числа (конечные и бесконечные десятич. дроби) записываются в формате с плавающей запятой, т.е. положение запятой в числе может меняться.

Формат чисел с плавающей запятой: A = m · q n

m – мантисса числа q – основание системы счисления n – порядок числа

Естественная форма Экспоненциальная форма
десятичная система счисления 16000000000000000 = 1,6 ·10 16 0,00000000000000016 = 1,6 ·10 -16
двоичная система счисления 11000000000000000 = 1,1 ·2 16 0,00000000000000011 = 1,1 ·2 -16

Диапазон изменения чисел определяется количеством разрядов, отведенный для хранения порядка числа, точностьопределяется количеством разрядов, отведенных для хранения мантиссы.

Нормализованная мантисса.

Прежде чем сохранить двоичное значение с плавающей запятой, необходимо нормализовать мантиссу.Этот процесс похож на нормализацию десятичного значения с плавающей запятой. Например, значение 1234.567 будет нормализовано, как 1.234567 x 10 3 путем перемещения десятичной точки до одной цифры.Аналогично, значение 1101.101 нормализуется в 1.101101 x 2 3 путем перемещения десятичной точки и домножения. Вот несколько примеров:

Двоичное значение Нормализуется Экспонента
1101.101 1.101101 3
.00101 1.01 -3
1.0001 1.0001
10000011.0 1.0000011

Вы наверное заметили, что в нормализованной мантиссе цифра 1 всегда слева от десятичной точки.
При хранении значений, в мантиссе единица не прописывается, а подразумевается.

Экспоненты коротких реальных значений хранятся как 8-разрядные целые числа без знака, с уклоном 127.

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: Студент — человек, постоянно откладывающий неизбежность. 10826 — | 7386 — или читать все.

91.146.8.87 © studopedia.ru Не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования. Есть нарушение авторского права? Напишите нам | Обратная связь.

Отключите adBlock!
и обновите страницу (F5)

очень нужно

Комментировать
0 просмотров
Комментариев нет, будьте первым кто его оставит

Это интересно
No Image Компьютеры
0 комментариев
No Image Компьютеры
0 комментариев
No Image Компьютеры
0 комментариев
No Image Компьютеры
0 комментариев
Adblock detector