52
правки
Изменения
Паршуков, тикет 4-3, 2, 3, 13, 14
Вещественные числа обычно представляются в виде чисел с плавающей запятой. Числа с плавающей запятой — один из возможных способов представления действительных чисел, который является компромиссом между точностью и диапазоном принимаемых значений, его можно считать аналогом экспоненциальной записи чисел, но только в памяти компьютера.
Число с плавающей запятой состоит из набора отдельных двоичных разрядов, условно разделенных на так называемые '''знак'''('''sign'''), '''порядок''' ('''exponent''') и '''мантиссу'''('''mantis'''). В наиболее распространённом формате (стандарт IEEE 754) число с плавающей запятой представляется в виде набора битов, часть из которых кодирует собой мантиссу числа, другая часть — показатель степени, и ещё один бит используется для указания знака числа (<tex>0 </tex> - если число положительное, <tex>1 </tex> - если число отрицательное). При этом порядок записывается как целое число в [[Представление целых чисел: прямой код, код со сдвигом, дополнительный код|коде со сдвигом]], а мантисса - в [[#Нормальная и нормализованная форма|нормализованном виде]], своей дробной частью в двоичной системе счисления. Вот пример такого числа из <tex>16 </tex> двоичных разрядов:
{|class="wikitable" style="border-collapse: collapse; border: none"
|-
== Нормальная и нормализованная форма ==
'''Нормальной формой''' (''normal form'') числа с плавающей запятой называется такая форма, в которой мантисса (без учёта знака) в десятичной системе находится на полуинтервале [0; 1). Такая форма записи имеет недостаток: некоторые числа записываются неоднозначно (например, <tex>0,0001 </tex> можно записать в 4 формах — <tex>0,0001×100001</tex>×<tex>10</tex><sup><tex>0</tex></sup>, <tex>0,001×10001</tex>×<tex>10</tex><sup><tex>−1</tex></sup>, <tex>0,01×1001</tex>×<tex>10</tex><sup><tex>−2</tex></sup>, <tex>0,1×101</tex>×<tex>10</tex><sup><tex>−3</tex></sup>), поэтому распространена также другая форма записи — '''нормализованная'''(''normalized''), в которой мантисса десятичного числа принимает значения от <tex>1 </tex> (включительно) до <tex>10 </tex> (не включительно), а мантисса двоичного числа принимает значения от <tex>1 </tex> (включительно) до <tex>2 </tex> (не включительно). То есть в мантиссе слева от запятой до применения порядка находится ровно один знак. В такой форме любое число (кроме <tex>0</tex>) записывается единственным образом. Ноль же представить таким образом невозможно, поэтому стандарт предусматривает специальную последовательность битов для задания числа <tex>0 </tex> (а заодно и некоторых других [[#Особые значения чисел с плавающей точкой|полезных чисел]], таких как <tex>-\infty</tex> и <tex>+\infty</tex>).Так как старший двоичный разряд (целая часть) мантиссы вещественного числа в нормализованном виде всегда равен «1»«<tex>1</tex>», то его можно не записывать, сэкономив таким образом один бит, что и используется в стандарте IEEE 754. В позиционных системах счисления с основанием большим, чем <tex>2 </tex> (в троичной, четверичной и др.), этого замечательного свойства нет (ведь целая часть там может быть не только единицей).
=== Число половинной точности (''Binary16'', ''Half precision'') ===
'''Число́ полови́нной то́чности''' — компьютерный формат представления чисел, занимающий в памяти половину машинного слова (в случае 32-битного компьютера — <tex>16 </tex> бит или <tex>2 </tex> байта). В силу невысокой точности этот формат представления чисел с плавающей запятой обычно используется в видеокартах, где небольшой размер и высокая скорость работы важнее точности вычислений.
{|class="wikitable" style="border-collapse: collapse; border: none"
|colspan=4 style="border: none; border-right: 1px solid gray; text-align: right"|0
|}
Порядок записан [[Представление целых чисел: прямой код, код со сдвигом, дополнительный код|со сдвигом]] '''<tex>-15</tex>'''. То есть чтобы получить актуально значение порядка нужно вычесть из него сдвиг. Сдвиг можно получить по формуле <tex>2^{b-1}-1</tex>, где <tex>b</tex> - число бит, отведенное на хранение порядка (в случае числа половинной точности <tex>b=5</tex>).
'''Ограничения точности'''
* Целые от нуля до <tex>2048 </tex> передаются как есть.* Целые от <tex>2049 </tex> до <tex>4096 </tex> округляются к ближайшему чётному целому.* Целые от <tex>4097 </tex> до <tex>8192 </tex> округляются до ближайшего целого, делящегося нацело на 4четыре.* Целые от <tex>8193 </tex> до <tex>16384 </tex> округляются до ближайшего целого, делящегося на 8восемь.* Целые от <tex>16385 </tex> до <tex>32768 </tex> округляются до ближайшего целого, делящегося на 16шестнадцать.* Целые от <tex>32769 </tex> до <tex>65535 </tex> округляются до ближайшего целого, делящегося на 32тридцать два.
=== Число одинарной точности (''Binary32'', ''Single precision'', ''float'') ===
'''Число́ одина́рной то́чности''' — компьютерный формат представления чисел, занимающий в памяти одно машинное слово (в случае 32-битного компьютера — <tex>32 </tex> бита или <tex>4 </tex> байта). Используется для работы с вещественными числами везде, где не нужна очень высокая точность.
{|class="wikitable" style="background-color: transparent; border-collapse: collapse; border: none"
|colspan=3 style="border: none; border-right: 1px solid gray; text-align: right"|0
|}
Порядок записан со сдвигом '''<tex>-127</tex>'''.
'''Число́ двойно́й то́чности''' —
компьютерный формат представления чисел, занимающий в памяти два машинных слова (в случае 32-битного компьютера — <tex>64 </tex> бита или <tex>8 </tex> байт). Часто используется благодаря своей неплохой точности, даже несмотря на двойной расход памяти и сетевого трафика относительно чисел одинарной точности.
{|class="wikitable" style="border-collapse: collapse; border: none"
|colspan=4 style="border: none; border-right: 1px solid gray; text-align: right"|0
|}
Порядок записан со сдвигом '''<tex>-1023</tex>'''.
=== Число четверной точности (''Binary128'', ''Quadruple precision'') ===
'''Число́ четверно́й то́чности''' —
компьютерный формат представления чисел, занимающий в памяти четыре машинных слова (в случае 32-битного компьютера — <tex>128 </tex> бит или <tex>16 </tex> байт). Используется в случае необходимости крайне высокой точности.
{|class="wikitable" style="border-collapse: collapse; border: none"
|colspan=66 style="border: none; border-right: 1px solid gray; text-align: right"|0
|}
Порядок записан со сдвигом '''<tex>-16383</tex>'''.
Обычно этот формат реализуется программно, случаи аппаратной реализации крайне редки (но присутствует в процессоре Intel). Также не гарантируется поддержка этого типа в языках программирования, хотя кое-где она и реализована (например, компилятор gcc для архитектуры x86 позволяет использовать тип __float128, являющийся программной реализацией числа с четверной точностью).
То есть число с плавающей запятой, при учете вышесказанного, можно задать следующим образом:
<br/>
* <tex>(-1)^s\times1.M\times2^E</tex>, если <tex>E_{min} \le E \le E_{max}</tex> (''нормализованное число'')
* <tex>(-1)^s\times0.M\times2^{E_{min}}</tex>, если <tex>E=E_{min}-1</tex> (''денормализованное число'')
Где <tex>s</tex> - бит знака, <tex>M</tex> - последовательность битов мантиссы, <tex>E</tex> - значение порядка (с учетом сдвига), <tex>E_{min}</tex> - минимальное значение порядка, используемое для записи чисел (1-''сдвиг'') , <tex>E_{min}-1</tex> - минимальное значение порядка, которое он в принципе может принять (все биты нули, 0-''сдвиг'').
Пример:
e=<tex>3</tex>; m=<tex>4.734612 </tex> (порядок и мантисса первого числа) × e=<tex>5</tex>; m=<tex>5.417242 </tex> (порядок и мантисса второго числа)
-----------------------
e=<tex>8</tex>; m=<tex>25.648538980104 </tex> (произведение как оно есть) e=<tex>8</tex>; m=<tex>25.64854 </tex> (мантисса после округления) e=<tex>9</tex>; m=<tex>2.564854 </tex> (нормализованная форма)
-->
Идея метода сложения и вычитания чисел с плавающей точкой заключается в приведении их к одному порядку. Сначала выбирается оптимальный порядок, затем мантиссы обоих чисел представляются в соответствии с новым порядком, затем над ними производится сложение/вычитание, мантисса результата округляется и, если нужно, результат приводится к нормализированной форме. Пример:
Выполним сложение чисел с плавающей точкой и смещенным порядком в 32-х разрядном формате <tex>-269 </tex> <tex>7</tex>/<tex>32 </tex> и <tex>405,875</tex>. Переведем <tex>-269 </tex> <tex>7</tex>/<tex>32 </tex> в машинный вид. Для этого сначала переведем его в двоичную систему счисления. <tex>-269 </tex> <tex>7</tex>/<tex>32 </tex> = <tex>-269,21875</tex> <tex>-269,21875</tex><sub><tex>10</tex></sub> = <tex>-100001101,00111</tex><sub><tex>2</tex></sub>
Нормализуем полученное двоичное число по правилам машинной арифметики.
<tex>-100001101,00111 </tex> = <tex>-1,0000110100111 </tex> × <tex>10</tex><sup><tex>1000</tex></sup>
Найдем смещенный порядок. Так как в условии говорится о 32-разрядном представлении, то смещение порядка равно <tex>127</tex><sub><tex>10</tex></sub>. E = <tex>8</tex><sub><tex>10</tex></sub> + <tex>127</tex><sub><tex>10</tex></sub> = <tex>1000</tex><sub><tex>2</tex></sub> + <tex>1111111</tex><sub><tex>2</tex></sub> = <tex>10000111</tex><sub><tex>2</tex></sub>
Число отрицательное, следовательно, в бите знака будет стоять единица.
Итак, первое число в машинном 32-разрядном представлении с плавающей точкой будет иметь вид:
<tex>1</tex><strong>10000111</strong><tex>00001101001110000000000 </tex> (жирным шрифтом выделен порядок числа, длина мантиссы - 23 бита).
Переведем второе число в машинный вид, совершая те же действия.
<tex>405,87510 </tex> = <tex>110010101</tex>,<tex>111000000000011010</tex>...<sub><tex>2</tex></sub> = <tex>1,10010101111000000000011010</tex>... × <tex>10</tex><sup><tex>1000</tex></sup> В качестве мантиссы будут сохранены первые <tex>23 </tex> бита после запятой т.е. <tex>10010101111000000000011</tex>.
Очевидно, что порядок со смещением у второго числа будет таким же, как и у первого.
Итак в машинном 32-разрядном представлении второе число будет иметь вид:
<tex>0</tex><strong>10000111</strong><tex>10010101111000000000011</tex> Далее в арифметических операциях будет испльзоватся использоваться число <tex>110010101</tex>,<tex>111</tex><sub><tex>2</tex></sub>=<tex>405</tex>.<tex>875</tex><sub><tex>10</tex></sub>, а не <tex>110010101</tex>,<tex>111000000000011</tex><sub><tex>2</tex></sub>=<tex>405</tex>,<tex>87510</tex><sub><tex>10</tex></sub> видимо для упрощения(хотя это не совсем корректно).
Порядки у слагаемых равны, поэтому пропускаем шаг выравнивания порядков и проводим вычитание мантисс по правилам двоичной арифметики. В
компьютере этим занимается арифметический сопроцессор, встроенный в центральный процессор машины.
<tex>1</tex>,<tex>1001010111100</tex><sub><tex>2</tex></sub> - <tex>1</tex>,<tex>0000110100111</tex><sub><tex>2</tex></sub> = <tex>0</tex>,<tex>1000100010101</tex><sub><tex>2</tex></sub>
Приводим полученный результат к машинному виду. Для этого мы должны внести поправку в порядок - уменьшить его на единицу.
Знак результата - положительный, следовательно, бит знака содержит ноль.
<tex>0</tex><strong>10000110</strong><tex>00010001010100000000000</tex>
Проверим правильность наших вычислений. Переведем результат в десятичное представление.
Найдем реальный порядок результата, вычтя из него значение смещения <tex>127</tex><sub><tex>10</tex></sub>.
E = <tex>10000110</tex><sub><tex>2</tex></sub> - <tex>1111111</tex><sub><tex>2</tex></sub> = <tex>134</tex><sub><tex>10</tex></sub> - <tex>127</tex><sub><tex>10</tex></sub> = <tex>7</tex><sub><tex>10</tex></sub> = <tex>111</tex><sub><tex>2</tex></sub>
Следовательно, число результата будет иметь вид:
A = <tex>1</tex>,<tex>000100010101 </tex> × <tex>10</tex><sup><tex>111</tex></sup> = <tex>10001000</tex>,<tex>10101</tex><sub><tex>2</tex></sub> = <tex>136</tex>,<tex>65625</tex><sub><tex>10</tex></sub>
Результат наших вычислений верен, так как <tex>405</tex>,<tex>875 </tex> - <tex>269</tex>,<tex>21875 </tex> = <tex>136</tex>,<tex>65625</tex>.
=== Алгоритм получения представления вещественного числа в памяти ЭВМ ===
памяти ЭВМ на примере величины типа Double.</P>
<P>Как видно из таблицы, величина это типа занимает в памяти <tex>8 </tex> байт. На
рисунке ниже показано, как здесь представлены поля мантиссы и порядка (нумерация битов осуществляется справа налево):</P>
<P>Можно заметить, что старший бит, отведенный под мантиссу, имеет номер
<tex>51</tex>, т.е. мантисса занимает младшие <tex>52 </tex> бита. Черта указывает здесь на
положение двоичной запятой. Перед запятой должен стоять бит целой части
мантиссы, но поскольку она всегда равна <tex>1</tex>, здесь данный бит не требуется и
соответствующий разряд отсутствует в памяти (но он подразумевается).
смещение. Смещение выбирается так, чтобы минимальному значению порядка
соответствовал нуль. Например, для типа Double порядок занимает <tex>11 </tex> бит и
имеет диапазон от <tex>2</tex><sup><tex>-1023</tex></sup> до <tex>2</tex><sup><tex>1023</tex></sup>, поэтому смещение равно <tex>1023</tex><sub>(<tex>10</tex>)</sub> =
<tex>1111111111</tex><sub>(<tex>2</tex>)</sub>. Наконец, бит с номером <tex>63 </tex> указывает на знак числа.</P>
<P>Таким образом, из вышесказанного вытекает следующий <strong>алгоритм</strong> для
<LI>нормализовать двоичное число, т.е. записать в виде <I>M</I> × 2<I><sup>p</sup></I>, где <I>M</I> —
мантисса (ее целая часть равна <tex>1</tex><sub>(<tex>2</tex>)</sub>) и <I>p</I> — порядок, записанный в
десятичной системе счисления;</LI>
</OL>
<P><B>Пример.</B> Запишем код числа <tex>-312</tex>,<tex>3125</tex>.</P>
<OL>
<LI>Двоичная запись модуля этого числа имеет вид <tex>100111000</tex>,<tex>0101</tex>.</LI>
<LI>Имеем <tex>100111000</tex>,<tex>0101 </tex> =
<tex>1</tex>,<tex>001110000101</tex> × <tex>2</tex><sup><tex>8</tex></sup>.</LI>
<LI>Получаем смещенный порядок <tex>8 </tex> + <tex>1023 </tex> = <tex>1031</tex>. Далее имеем
<tex>1031</tex><sub>(<tex>10</tex>)</sub> = <tex>10000000111</tex><sub>(<tex>2</tex>)</sub>.</LI>
<LI>Окончательно
</LI>
<P><B>Пример.</B> Пусть дан код 3FEC600000000000<sub>(16)</sub> или
<centerOL>
</tableLI>Прежде всего замечаем, что это код положительного числа, поскольку в
разряде с номером <tex>63</centertex>записан нуль. Получим порядок этого числа:
<OLtex>01111111110</tex><sub>(<tex>2</tex>)</sub> = <tex>1022</tex><sub>(<tex>10</tex>)</sub>; <tex>1022</tex> - <tex>1023</tex> = <tex>-1</tex>.</LI>
<LI>Прежде всего замечаемЧисло имеет вид <tex>1</tex>, что это код положительного числа, поскольку в <tex>1100011</tex> × <tex>2</tex><sup><tex>-1</tex></sup> или
== Ссылки ==