Letysite.ru

IT Новости с интернет пространства
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Ieee 754 double precision floating point

Изучение компьютерной арифметики

Рубрика:&nbsp Арифметика с плавающей запятой → IEEE-754 → Основы

Показаны типы данных, которые поддерживает Стандарт. Подробно рассмотрен тип binary32.

Формат IEEE-754 предоставляет возможность уместить число с плавающей запятой с определённой точностью в полях размером от 16 до 128 бит. Опишем эти типы данных:

  • binary16 (половинная точность, half precision),
  • binary32 (одинарная точность, single precision),
  • binary64 (двойная точность, double precision) и
  • binary128 (учетверённая точность, quadruple precision).

Есть также упоминание о формате вроде binary256 (увосмерённая точность, octuple precision) и краткие рекомендации по форматам с расширенной точностью (extended precision formats). Например, формат с расширенной точностью размером 80 бит используется в FPU (x87), но в настоящее время задействуется крайне редко. Ряд компиляторов (например, Visual C++ последних версий) даже не поддерживает подобный тип данных, который обычно называется «long double». Его использование крайне не рекомендуется. Ниже представлена таблица значений $p$, $E$, $e_$ и $e_$ для указанных форматов.

Цифры в названии формата показывают число бит, используемое для двоичного кодирования чисел, в нём представленных.

Binary32

Давайте начнём изучение IEEE-754 с чисел одинарной точности binary32. Этот тип данных поддерживается многими языками, в том числе Си и Си++ (тип данных «float»), так что мы сможем сразу проверить наши знания на практике. В формате binary32 под экспоненту выделено 8 бит (E=8), а под дробную часть мантиссы — 23 (p=24), ещё один бит остаётся для знака.

Итак, пронумеруем биты числа от 0 до 31, а всё пространство из 32 битов разделим на три секции так, как указано на картинке:

Первое поле, синего цвета, занимающее один бит с номером 31, отвечает за знак числа. Второе, зелёное, поле, занимающее биты с 23-го по 30-й, относится к экспоненте. Как мы помним из логики Стандарта IEEE-754, в этом поле сохраняется смещённая экспонента $e_b=e+mathrm$, а смещение $mathrm$ равно $127$. Последнее поле, красное, занимающее 23 бита от 0-го до 22-го отвечает за мантиссу, точнее, за её дробную часть, потому как старший значащий бит (бит целой части) мы не храним явно.

Рассмотрим пример. Число 3,14 запишется в виде $1<,>100,100,011,110,101,110,000,11_<(2)>×2^1$ (мы взяли только 23 цифры после запятой, правильно округлив значение, больше цифр нам не нужно). Наши 23 цифры дробной части — это 10010001111010111000011. Значение смещённой экспоненты будет равно $e_b=1+127=128=10000000_<(2)>$. Таким образом, в двоичном коде с плавающей запятой число 3,14 примет вид:

0 10000000 10010001111010111000011

И здесь начинается то, с чем в действительности столкнётся каждый, кто будет работать с плавающей арифметикой. Смотрите внимательно! Давайте попробуем перевести наше число обратно в десятичный формат:

Если вы не вполне понимаете, откуда в знаменателях эти степени двойки, то поглядите на те позиции мантиссы, на которых стоят единицы (слева направо, начиная отсчёт от единицы). Единицы стоят в первой позиции, затем в четвёртой, затем в восьмой и так далее до позиций 22 и 23. Неявная единица — это как будто 1/2 0 .

Итак, наше число 3,14 не может быть точно представлено с использованием 23 битов после десятичной запятой, поэтому оно округляется до ближайшего числа, представимого в таком формате. Эта особенность плавающей арифметики должна совершенно жёстко закрепиться в вашей памяти. В прикладных расчётах вообще редко встречаются числа, точно представимые в двоичной арифметике с плавающей точкой, всегда есть некоторая погрешность. В нашем примере точность составляет не меньше 10 —6 (разница между исходным и приближённым числами не превышает одной миллионной).

Давайте потренируемся. Возьмём число 25. В двоичном коде оно будет иметь вид 11001. В нормализованной научной нотации: 1,1001×2 4 . Таким образом, смещённая экспонента равна $e_b=4+127=131=10000011_<(2)>$, мантисса (когда мы уберём старший бит и дополним последовательность нулями до 23-х бит) равна 10010000000000000000000. Таким образом, число 25 в формате binary32 примет вид:

0 10000011 10010000000000000000000

Другой пример, число −0,3515625. В нормализованной научной нотации примет вид −1,01101×2 −2 . Смещённая экспонента $e_b=-2+127=125=01111101_<(2)>$. Мантисса равна 01101000000000000000000, а поскольку число отрицательное, знаковый бит будет единичным. В итоге, получим запись:

1 01111101 01101000000000000000000

Интересен также пример конвертирования числа 1. Его экспонента равна , поэтому смещённая экспонента примет вид $e_b=127=01111111_<(2)>$, а мантисса будет состоять из одних нулей:

0 01111111 00000000000000000000000

Очень полезно владеть навыком чтения шестнадцатеричных записей чисел с плавающей запятой. Поэтому прошу читателя самостоятельно перевести три предыдущих примера в шестнадцатеричный код:

  • 0 10000011 10010000000000000000000 = 0x41C80000 = 25,0
  • 1 01111101 01101000000000000000000 = 0xBEB40000 = −0,3515625
  • 0 01111111 00000000000000000000000 = 0x3F800000 = 1.0

В будущем мы весьма часто будем иметь дело именно с такой записью, как с наиболее экономной из удобных для человека.

Попробуем выполнить обратную операцию. Пусть в формате binary32 нам дано число 0x449A4000, требуется перевести его в привычную нам десятичную запись. Разбиваем его на три битовых поля:

0 10001001 00110100100000000000000 = 0x449A4000

Смещённая экспонента равна $e_b=137$, то есть порядок числа e=10. Таким образом, всё число имеет значение $$ bigl( 1+2^<-3>+2^<-4>+2^<-6>+2^ <-9>bigr) times 2^ <10>= 1,234. $$

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

Как уже было сказано, стандарт IEEE-754 предоставляет 4 способа округления: к нулю (towards zero), к минус бесконечности (towards minus infinity), к плюс бесконечности (towards plus infinity) и к ближайшему целому, либо к чётному (half to even).

Рассмотрим число 1+2 −23 . В научной нотации оно будет записано как $1<,>000,000,000,000,000,000,000,01 times 2^0$. Это число точно представимо в указанном формате, поэтому не требует округлений. Размера мантиссы хватает как раз на то, чтобы уместить в себя 23-й единичный бит дробной части:

0 01111111 00000000000000000000001

Теперь возьмём 1+2 −23 +2 −24 . $$require1<,>000,000,000,000,000,000,000,01colorbox <1>times 2^0.$$

Нам не хватает одного бита в поле мантиссы, чтобы уместить последний 24-й бит дробной части. Следовательно, требуется округление. Но в какую сторону? Правило half to even требует в случае неоднозначности округлять в сторону чётной мантиссы. То есть получаем 1+2 −23 +2 −24 ≈1+2 −22 :

0 01111111 00000000000000000000010

Теперь возьмём 1+2 −23 +2 −25 : $$require1<,>000,000,000,000,000,000,000,01colorbox<0>1 times 2^0.$$ Здесь мы не видим спорного случая, поэтому однозначно округляется книзу 1+2 −23 +2 −25 ≈1+2 −23 .

0 01111111 00000000000000000000001

Самое маленькое число, которое можно представить в нормализованной научной нотации, это число $1<,>000,000,000,000,000,000,000,00 times 2^ <-126>= 2^<-126>approx1<,>18times 10^<-38>$. У него минимально возможная экспонента −126 и в двоичном коде оно записывается как

0 00000001 00000000000000000000000 = 0x00800000

Максимальное число имеет максимально возможную экспоненту 127 и имеет вид $1<,>111,111,111,111,111,111,111,11 times 2^ <127>= (2-2^<-23>)times 2^<127>approx3<,>4times 10^<38>$.

В двоичном коде это будет выглядеть как

0 11111110 11111111111111111111111 = 0x7F7FFFFF

Если значение смещённой экспоненты равно нулю, то мы имеем дело с денормализованными числами. Значение экспоненты полагается равным e=-126. То есть денормализованные числа имеют вид 0,xxx…×2 −126 . Получается, что самое маленькое число, представимое в формате binary32 имеет вид $$0<,>000,000,000,000,000,000,000,01 times 2^ <-126>= 2^<-126-23>=2^<-149>approx1<,>4times10^<-45>.$$

В двоичном коде:

0 00000000 00000000000000000000001 = 0x00000001

Если $e_b = 255$, то есть поле экспоненты заполняют только единичные биты, мы имеем дело с бесконечностями или NaN’ами Поле знака, соответственно, отвечает за знак бесконечности и не имеет смысла для NaN.

  • 0 11111111 00000000000000000000000 = 0x7F800000 = +oo
  • 1 11111111 00000000000000000000000 = 0xFF800000 = -oo

«Не число» NaN кодируется всеми единичками в поле экспоненты и ненулевой мантиссой:

  • 0 11111111 10000000000000000000000 = 0x7FС00000 = NaN
  • 1 11111111 00000000000000000000010 = 0xFF800002 = NaN

Читатель может скомпилировать и запустить следующую программу, чтобы посмотреть на то, как кодируются некоторые числа в формате binary32. Она выводит на экран некоторые значения и отображает их шестнадцатеричный код.

Читать еще:  Документооборот на sharepoint

Например, на VC++ 2015 вывод этой программы будет таким:

Обратите, пожалуйста, внимание, что некоторые значение отражены не точно. Скажем, число 0,1(10) не может быть точно представлено в двоичной системе счисления. В двоичной научной нотации оно будет выглядеть как 1,(1001)×2 −4 . Таким образом, ближайшее число, точно представимое в формате binary32, будет значиться как (округление произошло вверх) $1<,>100,110,011,001,100,110,011,01 times 2^ <-4>= 0<,>100,000,001,490,116,119,384,765,625$

То есть число 0,1 удалось в этом формате закодировать с точностью не меньше 10 −8 . То же самое можно сказать о числе 1/3. В двоичной научной нотации оно будет записано как 1,(01)×2 −2 , а значит ближайшее точно представимое значение будет (после округления вверх) $1<,>010,101,010,101,010,101,010,11 times 2^ <-2>= 0<,>333,333,343,267,440,795,898,437,5$.

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

Взглянув на таблицу, можно сделать вывод о том, что формат binary32 «держит» около 7 значащих цифр. Однако для денормализованных чисел эта точность может быть ниже. С каждой арифметической операцией точность может падать, причём иногда очень существенно.

Это была заключительная статья данной серии.
Предыдущая: «Компьютерное представление чисел с плавающей запятой»
Содержание Все права защищены © Артём Михайлович Караваев, 2016. При копировании материала прошу указывать ссылку на источник

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

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

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

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

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

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

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

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

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

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

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

Все три варианта в той или иной мере используются.

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

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

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

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

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

Читать еще:  Ошибка синтаксиса в выражении запроса access

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

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

В придуманном нами пятибитовом формате возможно представить 16 чисел со знаком «+» (см. табл. 2.10), размещение которых на числовой оси представлено на рис.2.6.

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

Стандарт IEEE 754

Как известно, существует несколько возможных способов представления в машинной памяти множества вещественных чисел. Более того, вплоть до середины 80-х годов существовало не менее нескольких десятков коммерчески значимых архитектур, каждая из которых имела свою реализацию этих способов. И хотя зачастую эти реализации отличались друг от друга лишь параметрами представления чисел, этот факт превращал процесс разработки стандартных программ для вычислений в сущий кошмар для программистов. Такая ситуация сподвигла разработчиков аппаратного обеспечения на выработку единого стандарта на представление вещественных чисел, окончательно принятого в 1985 году и ныне известного как стандарт IEEE-754.

Стандарт был разработан со следующими целями:

  1. Упростить перенос существующего программного обеспечения на новые платформы, соответствующие данному стандарту.
  2. Предоставить новые возможности, полезные и безопасные, для программистов, которые, не будучи экспертами в численном анализе, могут писать черезвычайно запутанные программы. Впрочем, иногда полезность и безопасность представляются противоречащими друг другу.
  3. Предоставить возможность экспертам писать и распространять устойчивые и эффективные вычислительные программы, которые были бы хорошо переносимыми между машинами, соответствующими данному стандарту. Кроме того, программы, написанные в соответствии со стандартом, должны возвращать идентичные результаты на всех машинах.
  4. Предоставить прямую поддержку диагностики времени исполнения, обработки исключительных ситуаций и интервальной арифметики.
  5. Предоставить возможности для разработки стандартных элементарных функций, высокоточной арифметики и символьных вычислений.

Для этого были определены:

  1. Базовые и расширенные форматы чисел с плавающей точкой
  2. Операции сложения, вычитания, умножения, деления, квадратного корня, остатка и сравнения
  3. Преобразования между целочисленными и плавающими форматами
  4. Преобразования между различными плавающими форматами
  5. Преобразования между базовыми форматами чисел с плавающей точкой и десятичными строками
  6. Исключительные ситуации, возникающие при вычислениях с плавающей точкой, и их обработка, включая вычисления с не-числами

За рамками стандарта остались форматы десятичных строк и чисел, интерпретация знака и мантиссы не-чисел, и преобразования между двоичным и десятичным представлением чисел в расширенных форматах.

Основные определения стандарта IEEE-754.

Смещенный порядок (biased exponent) – сумма порядка и константы (смещения), выбранной так, что сумма неотрицательна.
Двоичное число с плавающей точкой (binary floating point number) – битовая строка, характеризующаяся тремя составляющими: знаком (sign), знаковым порядком (signed exponent) и мантиссой (significand). Ее численное значение (если оно существует) равно произведению знака, мантиссы и двойки, возведенной в степень, равную порядку.
Денормализованное число (denormalized number) – ненулевое число с плавающей точкой, порядок которого имеет некоторое зарезервированное значение (обычно это минимальное представимое в данном формате число), и чей ведущий (явный или неявный бит) нулевой.
Место назначения (destination) – то, куда записывается результат бинарной или унарной операции. Может быть явно назначено пользователем или неявно – системой (к примеру, промежуточные результаты вычисления выражений). Некоторые языки не позволяют пользователям распоряжаться промежуточными результатами. Тем не менее, стандарт описывает результат операции в терминах целевого формата (destination’s format) и значений операндов.
Порядок (exponent) – одна из трех составляющих двоичного числа с плавающей точкой, обычно означающая степень двойки при вычислении значения числа. Иногда порядок называется знаковым (signed) или несмещенным (unbiased).
Дробная часть (fraction) – часть мантиссы, лежащая справа от двоичной точки.
Не-число (NaN) — символическое значение, кодируемое в плавающем формате. Существует два типа не-чисел.
Сигнализирующие не-числа (signaling NaN) генерируют возникновение исключительной ситуации INVALID в случае, когда они встречаются в качестве операндов. «Тихие» не-числа (quiet NaN) могут без всяких исключений существовать на протяжении почти всех вычислительных операций.
Результат (result) – битовая строка (обычно представляющая некоторое число), возвращаемая в место назначения.
Мантисса (significand) – компонента двоичного числа с плавающей точкой, состоящая из явного или неявного ведущего бита слева от подразумеваемой двоичной точки и дробной части справа.
Флаг статуса (status flag) – переменная, которая может принимать два значения. Флаг может быть установленным (set), или неустановленным (clear). Пользователь может очистить флаг, копировать его, или восстановить предыдущее состояние. Будучи установленным, флаг может содержать дополнительную информацию, зависящую от платформы, и, возможно, недоступную некоторым пользователям. Операции, определенные стандартом, могут иметь побочным эффектом выставление следующих флагов: неточный результат (inexact result), исчезновение порядка (underflow), перполнение (overflow), деление на ноль (divide by zero) и неверная операция (invalid operation).
Пользователь (user) – человек, аппаратура или программа, чьи действия не определяются стандартом, имеющий доступ к программному окружению и контролирующий выполнение операций, определяемых стандартом.

Стандарт IEEE-754 на вычисления с плавающей точкой определяет четыре плавающих формата, которые делятся на базовые и расширенные. Уровень соответствия может различаться в зависимости от того, какие форматы реализованы.

Численные значения величин определяются с использованием трех целых параметров:

  1. p — число значащих битов (precision)
  2. e_max — максимальное значение порядка
  3. e_min — минимальное значение порядка

Параметры базовых форматов приведены в таблице:

Двойная точность в формате с плавающей точкой — Double-precision floating-point format

Двойная точность в формате с плавающей точкой является форматом номер компьютера , как правило , занимать 64 бита в памяти компьютера; он представляет собой широкий динамический диапазон числовых значений с помощью точки с плавающей базисной.

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

В IEEE 754-2008 стандарт , формат 64-битная база-2 официально называется binary64 ; он был назван дважды в IEEE 754-1985 . IEEE 754 определяет дополнительные форматы с плавающей точкой, в том числе 32-битной базы-2 с одинарной точностью и, в последнее время , база-10 представлений.

Одним из первых языков программирования , чтобы обеспечить типы данных одинарной и двойной точности с плавающей точкой была Fortran . До широкого принятия IEEE 754-1985, представление и свойство типов данных с плавающей точкой зависят от производителя компьютера и компьютерной модели, и на решениях , принятых языках программирования реализаторов. Например, GW-BASIC типа данных «с двойной точностью был 64-битный МБФ формата с плавающей точкой.

  • 16-битный : Половина (binary16)
  • 32-битный : Одно (binary32), decimal32
  • 64-битный : Двойной (binary64), decimal64
  • 128-битное : Четырехместный (binary128), decimal128
  • 256-битный : восьмикратный (binary256)
  • Продлен точности форматов (40-разрядная или 80-разрядная версия )

содержание

IEEE 754 с двойной точностью в двоичном формате с плавающей точкой: binary64

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

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

Поле показатель можно интерпретировать либо как 11-разрядное целое число от -1024 до 1023 ( 2 с дополнением ) или 11-битового целого числа без знака от 0 до 2047, который является общепринятым предвзятым формой в определении стандарта IEEE 754 binary64. Если беззнаковое формат целого числа используются, значение показателя , используемое в арифметическом показателе степени сдвинут уклоном — для IEEE 754 binary64 случае, значение показателя 1023 представляет фактический нуль (то есть в течение 2 е — 1023 , чтобы быть одним, е должно быть 1023). Экспоненты в диапазоне от -1022 до +1023 , поскольку показатели -1023 (все 0s) и +1024 (все 1s) зарезервированы для специальных номеров.

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

Читать еще:  Что такое acl в folder access

Формат записываются с мантиссой , имеющей неявные целое числом бит со значением 1 (для специальных данных , за исключением того , см кодировки экспоненту ниже). С 52 бит мантиссы фракции , появляющегося в формате памяти, общая точность 53 бита , следовательно , (приблизительно 16 десятичных цифр, 53 журнала 10 (2) ≈ 15,955). Биты изложены следующим образом :

Реальное значение предполагается по заданному 64-битной двойной точности опорной точки с заданной необъективной экспоненты и 52-битная дробь является е < Displaystyle е>

( — 1 ) знак ( 1. б 51 б 50 , , , б 0 ) 2 × 2 е — +1023 < Displaystyle (-1) ^ < текст <знак>> (1.b_ <51>B_ <50>. b_ <0>) _ <2> раз 2 ^ <е-1023>>

( — 1 ) знак ( 1 + Σ я знак равно 1 52 б 52 — я 2 — я ) × 2 е — +1023 < Displaystyle (-1) ^ < текст <знак>> влево (1+ сумма _ <я = 1>^ <52> <52 b_-I>2 ^ <- I> справа) 2 раз ^ <е-1023>>

Между 2 52 = 4,503,599,627,370,496 и 2 53 = 9,007,199,254,740,992 представляемое числа точно целые числа. Для следующего диапазона, от 2 53 до 2 54 , все умножается на 2, так что представимые числа четные и т.п. С другой стороны , для предыдущего диапазоне от 2 51 до 2 52 , интервал 0,5, и т.д.

Расстояние между в виде дроби чисел в диапазоне от 2 л до 2 л + 1 равно 2 п -52 . Максимальная относительная погрешность округления при округлении числа до ближайшего представимому один ( машина эпсилона ), следовательно , 2 -53 .

Ширина 11 бит экспоненты допускает представление чисел в диапазоне от 10 -308 и 10 308 , с полной точностью 15-17 десятичных цифр. При ущербе точности, то субнормально представление позволяет даже меньшие значения до примерно 5 × 10 -324 .

Экспонент кодирование

С двойной точностью двоичной плавающей точкой показатель кодируется с использованием в смещение-двоичного представления, с нулевым смещением быть 1023; также известный как смещение показателя в стандарте IEEE 754. Примеры таких представлений были бы:

Как преобразовать число с плавающей точкой в ​​двойное (оба хранятся в представлении IEEE-754) без потери точности?

Я имею в виду, например, что у меня есть следующее число, закодированное в IEEE-754 одинарной точности:

Двоичное число выше хранится в буквальной строке.

Вопрос в том, как я могу преобразовать эту строку в представление двойной точности IEEE-754 (что-то вроде следующего, но значение не совпадает), БЕЗ потери точности?

который тот же номер закодирован в IEEE-754 двойной точности.

Я попытался использовать следующий алгоритм для преобразования первой строки обратно в десятичное число первым, но он теряет точность.

Я использую Qt C ++ Framework на платформе Windows.

РЕДАКТИРОВАТЬ: я должен извиниться, может быть, я не получил четко выраженный вопрос.
Я имею в виду, что я не знаю истинного значения 23,85, я получил только первую строку и хочу преобразовать ее в представление с двойной точностью без потери точности.

Решение

Хорошо: оставьте знаковый бит, переписайте показатель степени (минус старое смещение, плюс новое смещение) и дополните мантиссу нулями справа …

(Как говорит @Mark, некоторые особые случаи нужно рассматривать отдельно, а именно, когда смещенный показатель равен нулю или максимуму.)

Другие решения

IEEE-754 (и с плавающей точкой в ​​целом) не может представлять периодические двоичные десятичные дроби с полной точностью. Даже тогда, когда они на самом деле являются рациональными числами с относительно небольшим целым числом и знаменателем. Некоторые языки предоставляют рациональный тип, который может это делать (это языки, которые также поддерживают неограниченные целые числа точности).

Как следствие, эти два номера, которые вы разместили, НЕ являются тем же номером.

Они на самом деле являются:

где . представляют собой бесконечную последовательность 0 s.

Стивен Кэнон в комментарии выше дает вам соответствующие десятичные значения (не проверял их, но у меня нет оснований сомневаться, что он понял их правильно).

Поэтому преобразование, которое вы хотите сделать, не может быть выполнено, так как число с одинарной точностью не имеет необходимой вам информации (у вас НЕТ СПОСОБА узнать, является ли число на самом деле периодическим или просто выглядит так, как будто оно повторяется) ,

Прежде всего, +1 для идентификации входных данных в двоичном виде.

Во-вторых, это число не соответствует 23,85, но немного меньше. Если вы переверните его последнюю двоичную цифру из 0 в 1 число будет по-прежнему не точно равно 23,85, но немного больше. Эти различия не могут быть адекватно отражены в поплавке, но они могут быть приблизительно зафиксированы в двойном размере.

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

Я рекомендую преобразовать в число с плавающей точкой или округление или добавить очень маленькое значение непосредственно перед отображением (или регистрацией) числа, потому что визуальный вид — это то, что вам нужно действительно потеря при увеличении точности.

Не поддавайтесь искушению округлить сразу после приведения и использовать округленное значение в последующих вычислениях — это особенно рискованно в циклах. Хотя может показаться, что это устраняет проблему в отладчике, накопленные дополнительные неточности могут еще больше исказить конечный результат.

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

Двоичные числа с плавающей запятой, как правило, не могут точно представлять значения десятичной дроби. Преобразование из десятичного дробного значения в двоичную с плавающей запятой (см. «Беллерофон» в «Как точно читать числа с плавающей запятой» Уильяма Д. Клингера) и из двоичной с плавающей запятой обратно в десятичное значение (см. «Dragon4») в книге «Как печатать числа с плавающей запятой точно» Гая Л. Стила-младшего и Джона Л. Уайта) дают ожидаемые результаты, потому что один преобразует десятичное число в ближайшую представимую двоичную плавающую точку, а другой управляет ошибкой, чтобы узнать, какие десятичное значение, из которого оно получено (оба алгоритма улучшены и сделаны более практичными в David Gay’s dtoa.c . Алгоритмы являются основой для восстановления std::numeric_limits ::digits10 десятичные цифры (кроме, возможно, конечных нулей) из значения с плавающей запятой, хранящегося в типе T ,

К сожалению, расширение float к double разрушает значение: попытка отформатировать новое число во многих случаях не даст десятичного оригинала, потому что float дополненный нулями отличается от ближайшего double Bellerophon создаст и, таким образом, ожидает Dragon4. Однако есть два подхода, которые работают достаточно хорошо:

  1. Как кто-то предложил преобразовать float в строку, и эта строка в double , Это не особенно эффективно, но может быть доказано, что оно дает правильные результаты (конечно, при условии правильной реализации не совсем тривиальных алгоритмов).
  2. Предполагая, что ваше значение находится в разумном диапазоне, вы можете умножить его на степень 10 так, чтобы младшая значащая десятичная цифра отличалась от нуля, преобразовать это число в целое число, это целое число в double и, наконец, разделите полученное двойное число на исходную степень 10. У меня нет доказательств того, что это дает правильное число, но для диапазона значений, которые меня интересуют, и которое я хочу точно сохранить в float , это работает.

Один разумный подход, чтобы избежать этой цели, заключается в использовании десятичное число с плавающей точкой значения, как описано для C ++ в Десятичный TR на первом месте. К сожалению, они пока не являются частью стандарта, но я представил предложение в комитет по стандартизации C ++, чтобы это изменить.

Ссылка на основную публикацию
Adblock
detector