Представление целых чисел. Типы данных. Формы представления чисел. Булевы типы

Возможности 22.06.2019
Возможности

В далекие времена, для IT-индустрии это 70-е годы прошлого века, ученые-математики (так раньше назывались программисты) сражались как Дон-Кихоты в неравном бою с компьютерами, которые тогда были размером с маленькие ветряные мельницы. Задачи ставились серьезные: поиск вражеских подлодок в океане по снимкам с орбиты, расчет баллистики ракет дальнего действия, и прочее. Для их решения компьютер должен оперировать действительными числами, которых, как известно, континуум, тогда как память конечна. Поэтому приходится отображать этот континуум на конечное множество нулей и единиц. В поисках компромисса между скоростью, размером и точностью представления ученые предложили числа с плавающей запятой (или плавающей точкой, если по-буржуйски).

Арифметика с плавающей запятой почему-то считается экзотической областью компьютерных наук, учитывая, что соответствующие типы данных присутствуют в каждом языке программирования. Я сам, если честно, никогда не придавал особого значения компьютерной арифметике, пока решая одну и ту же задачу на CPU и GPU получил разный результат. Оказалось, что в потайных углах этой области скрываются очень любопытные и странные явления: некоммутативность и неассоциативность арифметических операций, ноль со знаком, разность неравных чисел дает ноль, и прочее. Корни этого айсберга уходят глубоко в математику, а я под катом постараюсь обрисовать лишь то, что лежит на поверхности.

1. Основы

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

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

Математически это записывается так:

(-1) s × M × B E , где s - знак, B-основание, E - порядок, а M - мантисса.

Основание определяет систему счисления разрядов. Математически доказано, что числа с плавающей запятой с базой B=2 (двоичное представление) наиболее устойчивы к ошибкам округления, поэтому на практике встречаются только базы 2 и, реже, 10. Для дальнейшего изложения будем всегда полагать B=2, и формула числа с плавающей запятой будет иметь вид:

(-1) s × M × 2 E

Что такое мантисса и порядок? Мантисса – это целое число фиксированной длины, которое представляет старшие разряды действительного числа. Допустим наша мантисса состоит из трех бит (|M|=3). Возьмем, например, число «5», которое в двоичной системе будет равно 101 2 . Старший бит соответствует 2 2 =4, средний (который у нас равен нулю) 2 1 =2, а младший 2 0 =1. Порядок – это степень базы (двойки) старшего разряда. В нашем случае E=2. Такие числа удобно записывать в так называемом «научном» стандартном виде, например «1.01e+2». Сразу видно, что мантисса состоит из трех знаков, а порядок равен двум.

Допустим мы хотим получить дробное число, используя те же 3 бита мантиссы. Мы можем это сделать, если возьмем, скажем, E=1. Тогда наше число будет равно

1,01e+1 = 1×2 1 +0×2 0 +1×2 -1 =2+0,5=2,5

Здесь, поскольку E=1, степень двойки первого разряда (который идет перед запятой), равна «1». Два других разряда, расположенных правее (после запятой), обеспечивают вклад 2 E-1 и 2 E-2 (2 0 и 2 -1 соответственно). Очевидно, что регулируя E одно и то же число можно представить по-разному. Рассмотрим пример с длиной мантиссы |M|=4. Число «2» можно представить в следующем виде:

2 = 10 (в двоичной системе) = 1.000e+1 = 0.100e+2 = 0.010e+3. (E=1, E=2, E=3 соответственно)

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

Это экономит один бит, так как неявную единицу не нужно хранить в памяти, и обеспечивает уникальность представления числа. В нашем примере «2» имеет единственное нормализованное представление («1.000e+1»), а мантисса хранится в памяти как «000», т.к. старшая единица подразумевается неявно. Но в нормализованном представлении чисел возникает новая проблема - в такой форме невозможно представить ноль.

Строго говоря, нормализованное число имеет следующий вид:

(-1) s × 1.M × 2 E .

Качество решения задач во многом зависит от выбора представления чисел с плавающей запятой. Мы плавно подошли к проблеме стандартизации такого представления.

2. Немного истории

В 60-е и 70-е годы не было единого стандарта представления чисел с плавающей запятой, способов округления, арифметических операций. В результате программы были крайне не портабельны. Но еще большей проблемой было то, что у разных компьютеров были свои «странности» и их нужно было знать и учитывать в программе. Например, разница двух не равных чисел возвращала ноль. В результате выражения «X=Y» и «X-Y=0» вступали в противоречие. Умельцы обходили эту проблему очень хитрыми трюками, например, делали присваивание «X=(X-X)+X» перед операциями умножения и деления, чтобы избежать проблем.

Инициатива создать единый стандарт для представления чисел с плавающей запятой подозрительно совпала с попытками в 1976 году компанией Intel разработать «лучшую» арифметику для новых сопроцессоров к 8086 и i432. За разработку взялись ученые киты в этой области, проф. Джон Палмер и Уильям Кэхэн. Последний в своем интервью высказал мнение, что серьезность, с которой Intel разрабатывала свою арифметику, заставила другие компании объединиться и начать процесс стандартизации.

Все были настроены серьезно, ведь очень выгодно продвинуть свою архитектуру и сделать ее стандартной. Свои предложения представили компании DEC, National Superconductor, Zilog, Motorola. Производители мейнфреймов Cray и IBM наблюдали со стороны. Компания Intel, разумеется, тоже представила свою новую арифметику. Авторами предложенной спецификации стали Уильям Кэхэн, Джероми Кунен и Гарольд Стоун и их предложение сразу прозвали «K-C-S».

Практически сразу же были отброшены все предложения, кроме двух: VAX от DEC и «K-C-S» от Intel. Спецификация VAX была значительно проще, уже была реализована в компьютерах PDP-11, и было понятно, как на ней получить максимальную производительность. С другой стороны в «K-C-S» содержалось много полезной функциональности, такой как «специальные» и «денормализованные» числа (подробности ниже).

В «K-C-S» все арифметические алгоритмы заданы строго и требуется, чтобы в реализации результат с ними совпадал. Это позволяет выводить строгие выкладки в рамках этой спецификации. Если раньше математик решал задачу численными методами и доказывал свойства решения, не было никакой гарантии, что эти свойства сохранятся в программе. Строгость арифметики «K-C-S» сделала возможным доказательство теорем, опираясь на арифметику с плавающей запятой.

Компания DEC сделала все, чтобы ее спецификацию сделали стандартом. Она даже заручилась поддержкой некоторых авторитетных ученых в том, что арифметика «K-C-S» в принципе не может достигнуть такой же производительности, как у DEC. Ирония в том, что Intel знала, как сделать свою спецификацию такой же производительной, но эти хитрости были коммерческой тайной. Если бы Intel не уступила и не открыла часть секретов, она бы не смогла сдержать натиск DEC.

Подробнее о баталиях при стандартизации смотрите в интервью профессора Кэхэна , а мы рассмотрим, как выглядит представление чисел с плавающей запятой сейчас.

3. Представление чисел с плавающей запятой сегодня

Разработчики «K-C-S» победили и теперь их детище воплотилось в стандарт IEEE754. Числа с плавающей запятой в нем представлены в виде знака (s), мантиссы (M) и порядка (E) следующим образом:

(-1) s × 1.M × 2 E

Замечание. В новом стандарте IEE754-2008 кроме чисел с основанием 2 присутствуют числа с основанием 10, так называемые десятичные (decimal) числа с плавающей запятой.

Чтобы не загромождать читателя чрезмерной информацией, которую можно найти в Википедии , рассмотрим только один тип данных, с одинарной точностью (float). Числа с половинной, двойной и расширенной точностью обладают теми же особенностями, но имеют другой диапазон порядка и мантиссы. В числах одинарной точности (float/single) порядок состоит из 8 бит, а мантисса – из 23. Эффективный порядок определяется как E-127. Например, число 0,15625 будет записано в памяти как

Рисунок взят из Википедии

В этом примере:

  • Знак s=0 (положительное число)
  • Порядок E=01111100 2 -127 10 = -3
  • Мантисса M = 1.01 2 (первая единица не явная)
  • В результате наше число F = 1.01 2 e-3 = 2 -3 +2 -5 = 0,125 + 0,03125 = 0,15625

Чуть более подробное объяснение

Здесь мы имеем дело с двоичным представлением числа «101» со сдвигом запятой на несколько разрядов влево. 1,01 - это двоичное представление, означающее 1×2 0 + 0×2 -1 + 1×2 -2 . Сдвинув запятую на три позиции влево получим 1,01e-3 = 1×2 -3 + 0×2 -4 + 1×2 -5 = 1×0,125 + 0×0,0625 + 1×0,03125 = 0,125 + 0,03125 = 0,15625.

3.1 Специальные числа: ноль, бесконечность и неопределенность
В IEEE754 число «0» представляется значением с порядком, равным E=E min -1 (для single это -127) и нулевой мантиссой. Введение нуля как самостоятельного числа (т.к. в нормализованном представлении нельзя представить ноль) позволило избежать многих странностей в арифметике. И хоть операции с нулем нужно обрабатывать отдельно, обычно они выполняются быстрее, чем с обычными числами.

Также в IEEE754 предусмотрено представление для специальных чисел, работа с которыми вызывает исключение. К таким числам относится бесконечность (±∞) и неопределенность (NaN). Эти числа позволяет вернуть адекватное значение при переполнении. Бесконечности представлены как числа с порядком E=E max +1 и нулевой мантиссой. Получить бесконечность можно при переполнении и при делении ненулевого числа на ноль. Бесконечность при делении разработчики определили исходя из существования пределов, когда делимое и делитель стремиться к какому-то числу. Соответственно, c/0==±∞ (например, 3/0=+∞, а -3/0=-∞), так как если делимое стремиться к константе, а делитель к нулю, предел равен бесконечности. При 0/0 предел не существует, поэтому результатом будет неопределенность.

Неопределенность или NaN (от not a number) – это представление, придуманное для того, чтобы арифметическая операция могла всегда вернуть какое-то не бессмысленное значение. В IEEE754 NaN представлен как число, в котором E=E max +1, а мантисса не нулевая. Любая операция с NaN возвращает NaN. При желании в мантиссу можно записывать информацию, которую программа сможет интерпретировать. Стандартом это не оговорено и мантисса чаще всего игнорируется.

Как можно получить NaN? Одним из следующих способов:

  • ∞+(- ∞)
  • 0 × ∞
  • 0/0, ∞/∞
  • sqrt(x), где x<0
По определению NaN ≠ NaN, поэтому, для проверки значения переменной нужно просто сравнить ее с собой.
Зачем нулю знак (или +0 vs -0)
Любознательный читатель вероятно уже замелил заметил, что в описанном представлении чисел с плавающей запятой существует два нуля, которые отличаются только знаком. Так, 3·(+0)=+0, а 3·(-0)=-0. Но при сравнении +0=-0. В стандарте знак сохранили умышленно, чтобы выражения, которые в результате переполнения или потери значимости превращаются в бесконечность или в ноль, при умножении и делении все же могли представить максимально корректный результат. Например, если бы у нуля не было знака, выражение 1/(1/x)=x не выполнялось бы верно при x=±∞, так как 1/∞ и 1/-∞ равны 0.

Еще один пример:
(+∞/0) + ∞ = +∞, тогда как (+∞/-0) +∞ = NaN

Чем бесконечность в данном случае лучше, чем NaN? Тем, что если в арифметическом выражении появился NaN, результатом всего выражения всегда будет NaN. Если же в выражении встретилась бесконечность, то результатом может быть ноль, бесконечность или обычное число с плавающей запятой. Например, 1/∞=0.

3.3 Денормализованные числа
Что такое субнормальные денормализованные (subnormal) числа рассмотрим на простом примере. Пусть имеем нормализованное представление с длиной мантиссы |M|=2 бита (+ один бит нормализации) и диапазоном значений порядка -1≤E≤2. В этом случае получим 16 чисел:

Крупными штрихами показаны числа с мантиссой, равной 1,00. Видно, что расстояние от нуля до ближайшего числа (0 - 0,5) больше, чем от этого числа к следующему (0,5 - 0,625). Это значит, что разница двух любых чисел от 0,5 до 1 даст 0, даже если эти числа не равны. Что еще хуже, в пропасть между 0,5 и 0 попадает разница чисел, больших 1. Например, «1,5-1,25=0» (см. картинку).

В «околонулевую яму» подпадает не каждая программа. Согласно статистике 70-х годов в среднем каждый компьютер сталкивался с такой проблемой один раз в месяц. Учитывая, что компьютеры приобретали массовость, разработчики «K-C-S» посчитали эту проблему достаточно серьезной, чтобы решать ее на аппаратном уровне. Предложенное ими решение состояло в следующем. Мы знаем, что при E=E min -1 (для float это «-127») и нулевой мантиссе число считается равным нулю. Если же мантисса не нулевая, то число считается не нулевым, его порядок полагается E=E min , причем неявный старший бит мантиссы полагается равным нулю. Такие числа называются денормализованными .

Строго говодя, числа с плавающей запятой теперь имеют вид:

(-1) s × 1.M × 2 E , если E min ≤E≤E max (нормализованные числа)

(-1) s × 0.M × 2 Emin , если E=E min -1. (денормализованные числа)

Вернемся к примеру. Наш E min =-1. Введем новое значение порядка, E=-2, при котором числа являются денормализованными. В результате получаем новое представление чисел:

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

Но роскошь использования денормализованного представления чисел в процессоре не дается бесплатно. Из-за того, что такие числа нужно обрабатывать по-другому во всех арифметических операциях, трудно сделать работу в такой арифметике эффективной. Это накладывает дополнительные сложности при реализации АЛУ в процессоре. И хоть денормализованные числа очень полезны, они не являются панацеей и за округлением до нуля все равно нужно следить. Поэтому эта функциональность стала камнем преткновения при разработке стандарта и встретила самое сильное сопротивление.

3.4 Очередность чисел в IEEE754
Одна из удивительных особенностей представления чисел в формате IEEE754 состоит в том, что порядок и мантисса расположены друг за другом таким образом, что вместе образуют последовательность целых чисел {n} для которых выполняется:

N

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

Float a=0.5; int n = *((int*) &a); float b = *((float*) &(++n)); printf("После %e следующее число: %e, разница (%e)\n", a, b, b-a);
Этот код будет работать только на архитектуре с 32-битным int.

4. Подводные камни в арифметике с плавающей запятой

Теперь – к практике. Рассмотрим особенности арифметики с плавающей запятой, к которым нужно проявить особую осторожность при программировании.
4.1 Округление
С ошибками из-за погрешностей округления в современной арифметике с плавающей запятой встретиться сложно, особенно если использовать двойную точность. Правило округления в стандарте IEEE754 говорит о том, что результат любой арифметической операции должен быть таким, как если бы он был выполнен над точными значениями и округлен до ближайшего числа, представимого в этом формате. Это требует от АЛУ дополнительных усилий и некоторые опции компилятора (такие как «-ffast-math» в gcc) могут отключить такое поведение. Особенности округления в IEEE754:
  • Округление до ближайшего в стандарте сделано не так как мы привыкли. Математически показано, что если 0,5 округлять до 1 (в большую сторону), то существует набор операций, при которых ошибка округления будет возрастать до бесконечности. Поэтому в IEEE754 применяется правило округления до четного. Так, 12,5 будет округлено до 12, а 13,5 – до 14.
  • Самая опасная операция с точки зрения округления в арифметике с плавающей запятой - это вычитание. При вычитании близких чисел значимые разряды могут потеряться, что
    может в разы увеличить относительную погрешность.
  • Для многих широко распространенных математических формул математики разработали специальную форму, которая позволяет значительно уменьшить погрешность при округлении. Например, расчет формулы «x 2 -y 2 » лучше вычислять используя формулу «(x-y)(x+y)».
4.2 Неассоциативность арифметических операций
В арифметике с плавающей запятой правило (a*b)*c = a*(b*c) не выполняется для любых арифметических операций. Например,

(10 20 +1)-10 20 =0 ≠ (10 20 -10 20)+1=1

Допустим у нас есть программа суммирования чисел.

Double s = 0.0; for (int i=0; i Некоторые компиляторы по умолчанию могут переписать код для использования нескольких АЛУ одновременно (будем считать, что n делится на 2):

Double sa, s; sa=sa=0.0; for (int i=0; i Так как операции суммирования не ассоциативны, эти две программы могут выдать различный результат.

4.3 Числовые константы
Помните, что не все десятичные числа имеют двоичное представление с плавающей запятой. Например, число «0,2» будет представлено как «0,200000003» в одинарной точности. Соответственно, «0,2 + 0,2 ≈ 0,4». Абсолютная погрешность в отдельном
случае может и не высока, но если использовать такую константу в цикле, можем получить накопленную погрешность.
4.4 Выбор минимума из двух значений
Допустим из двух значений нам нужно выбрать минимальное. В Си это можно сделать одним из следующих способов:
  1. x < y? x: y
  2. x <= y? x: y
  3. x > y? y: x
  4. x >= y? y: x
Часто компилятор считает их эквивалентными и всегда использует первый вариант, так как он выполняется за одну инструкцию процессора. Но если мы учтем ±0 и NaN, эти операции никак не эквивалентны:
x y x < y? x: y x <= y? x: y x > y? y: x x >= y? y: x
+0 -0 -0 +0 +0 -0
NaN 1 1 1 NaN NaN
4.5 Сравнение чисел
Очень распространенная ошибка при работе с float-ами возникает при проверке на равенство. Например,

Float fValue = 0.2; if (fValue == 0.2) DoStuff();
Ошибка здесь, во-первых, в том, что 0,2 не имеет точного двоичного представления, а во-вторых 0,2 – это константа двойной точности, а переменная fValue – одинарной, и никакой гарантии о поведении этого сравнения нет.

Лучший, но все равно ошибочный способ, это сравнивать разницу с допустимой абсолютной погрешностью:

If (fabs(fValue – fExpected) < 0.0001) DoStuff(); // fValue=fExpected?

Недостаток такого подхода в том, что погрешность представления числа увеличивается с ростом самого этого числа. Так, если программа ожидает «10000», то приведенное равенство не будет выполняться для ближайшего соседнего числа (10000,000977). Это особенно актуально, если в программе имеется преобразование из одинарной точности в двойную.

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

Bool AlmostEqual2sComplement(float A, float B, int maxUlps) { // maxUlps не должен быть отрицательным и не слишком большим, чтобы // NaN не был равен ни одному числу assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); int aInt = *(int*)&A; // Уберем знак в aInt, если есть, чтобы получить правильно упорядоченную последовательность if (aInt < 0) aInt = 0x80000000 - aInt; //aInt &= 0x7fffffff; //(см. комментарий пользователя Vayun) // Аналогично для bInt int bInt = *(int*)&B; if (bInt < 0) bInt = 0x80000000 - bInt; /*aInt &= 0x7fffffff;*/ unsigned int intDiff = abs(aInt - bInt); /*(см. комментарий пользователя Vayun)*/ if (intDiff <= maxUlps) return true; return false; }

В этой программе maxUlps (от Units-In-Last-Place) – это максимальное количество чисел с плавающей запятой, которое может лежать между проверяемым и ожидаемым значением. Другой смысл этой переменной – это количество двоичных разрядов (начиная с младшего) в сравниваемых числах разрешается упустить. Например, maxUlps=16, означает, что младшие 4 бита (log 2 16) могут не совпадать, а числа все равно будут считаться равными. При этом, при сравнении с числом 10000 абсолютная погрешность будет равна 0,0146, а при сравнении с 0.001, погрешность будет менее 0.00000001 (10 -8).

5. Проверка полноты поддержки IEE754

Думаете, что если процессоры полностью соответствуют стандарту IEEE754, то любая программа, использующая стандартные типы данных (такие как float/double в Си), будет выдавать один и тот же результат на разных компьютерах? Ошибаетесь. На портабельность и соответствие стандарту влияет компилятор и опции оптимизации. Уильям Кэхэн написал программу на Си (есть версия и для Фортрана), которая позволяет проверить удовлетворяет ли связка «архитектура+компилятор+опции» IEEE754. Называется она «Floating point paranoia» и ее исходные тексты доступны для скачивания . Аналогичная программа доступна для GPU . Так, например, компилятор Intel (icc) по умолчанию использует «расслабленную» модель IEEE754, и в результате не все тесты выполняются. Опция «-fp-model precise» позволяет компилировать программу с точным соответствием стандарту. В компиляторе GCC есть опция «-ffast-math», использование которой приводит к несоответствию IEEE754.

Заключение

Напоследок поучительная история. Когда я работал над тестовым проектом на GPU, у меня была последовательная и параллельная версия одной программы. Сравнив время выполнения, я был очень обрадован, так как получил ускорение в 300 раз. Но позже оказалось, что вычисления на GPU «разваливались» и обращались в NaN, а работа с ними в GPU была быстрее, чем с обычными числами. Интересно было другое - одна и та же программа на эмуляторе GPU (на CPU) выдавала корректный результат, а на самом GPU – нет. Позже оказалось, что проблема была в том, что этот GPU не поддерживал полностью стандарт IEEE754 и прямой подход не сработал.

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

| Планирование уроков на учебный год (ФГОС) | § 1.2. Представление чисел в компьютере

Уроки 6 - 7
§ 1.2. Представление чисел в компьютере

Ключевые слова:

Разряд
беззнаковое представление целых чисел
представление целых чисел со знаком
представление вещественных чисел

1.2.1. Представление целых чисел

Оперативная память компьютера состоит из ячеек, каждая из которых представляет собой физическую систему, состоящую из некоторого числа однородных элементов. Эти элементы обладают двумя устойчивыми состояниями, одно из которых соответствует нулю, а другое - единице. Каждый такой элемент служит для хранения одного из битов - разряда двоичного числа. Именно поэтому каждый элемент ячейки называют битом или разрядом (рис. 1.2).

Рис. 1.2. Ячейка памяти

Для компьютерного представления целых чисел используется несколько различных способов, отличающихся друг от друга количеством разрядов (под целые числа обычно отводится 8, 16, 32 или 64 разряда) и наличием или отсутствием знакового разряда. Беззнаковое представление можно использовать только для неотрицательных целых чисел, отрицательные числа представляются только в знаковом виде.

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

Максимальное значение целого неотрицательного числа достигается в случае, когда во всех разрядах ячейки хранятся единицы. Для n-разрядного представления оно будет равно 2 n -1. Минимальное число соответствует п нулям, хранящимся в n разрядах памяти, и равно нулю.

Ниже приведены максимальные значения для беззнаковых целых n-разрядных чисел:

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

Пример 1 . Число 53 10 = 110101 2 в восьмиразрядном представлении имеет вид:

Это же число 53 в шестнадцати разрядах будет записано следующим образом:

При представлении со знаком самый старший (левый) разряд отводится под знак числа, остальные разряды - под само число. Если число положительное, то в знаковый разряд помещается 0, если число отрицательное - 1. Такое представление чисел называется прямым кодом.

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

На сайте Федерального центра информационно-образовательных ресурсов (http://fcior.edu.ru/) размещён информационный модуль «Число и его компьютерный код». С помощью этого ресурса вы можете получить дополнительную информацию по изучаемой теме.

Для выполнения операций с отрицательными числами используется дополнительный код, позволяющий заменить операцию вычитания сложением. Узнать алгоритм образования дополнительного кода вы можете с помощью информационного модуля «Дополнительный код», размещённого на сайте Федерального центра информационно-образовательных ресурсов (http://fcior.edu.ru/).

1.2.2. Представление вещественных чисел

Любое вещественное число А может быть записано в экспоненциальной форме:

где:

m - мантисса числа;

p - порядок числа.

Например, число 472 ООО ООО может быть представлено так: 4,72 10 8 , 47,2 10 7 , 472,0 10 6 и т. д.

С экспоненциальной формой записи чисел вы могли встречаться при выполнении вычислений с помощью калькулятора, когда в качестве ответа получали записи следующего вида: 4.72Е+8.

Здесь знак «Е» обозначает основание десятичной системы счисления и читается как «умножить на десять в степени».

Из приведённого выше примера видно, что положение запятой в записи числа может изменяться.

Для единообразия мантиссу обычно записывают как правильную дробь, имеющую после запятой цифру, отличную от нуля. В этом случае число 472 ООО ООО будет представлено как 0,472 10 9 .

Вещественное число может занимать в памяти компьютера 32 или 64 разряда. При этом выделяются разряды для хранения знака мантиссы, знака порядка, порядка и мантиссы.

Пример:

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

Максимальное значение порядка числа для приведённого выше примера составляет 1111111 2 = 127 10 , и, следовательно, максимальное значение числа:

0,11111111111111111111111 10 1111111

Попытайтесь самостоятельно выяснить, каков десятичный эквивалент этой величины.

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

САМОЕ ГЛАВНОЕ

Для компьютерного представления целых чисел используются несколько различных способов, отличающихся друг от друга количеством разрядов (8, 16, 32 или 64) и наличием или отсутствием знакового разряда.

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

При представлении со знаком самый старший разряд отводится под знак числа, остальные разряды - под само число. Бели число положительное, то в знаковый разряд помещается 0, если число отрицательное, то 1. Положительные числа хранятся в компьютере в прямом коде, отрицательные - в дополнительном.

При хранении в компьютере вещественных чисел выделяются разряды на хранение знака порядка числа, самого порядка, знака мантиссы и мантиссы. При этом любое число записывается так:

где:

m - мантисса числа;
q - основание системы счисления;
p - порядок числа.

Вопросы и задания

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

2. Как в памяти компьютера представляются целые положительные и отрицательные числа?

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

4. Представьте число 63 10 в беззнаковом 8-разрядном формате.

5. Найдите десятичные эквиваленты чисел по их прямым кодам, записанным в 8-разрядном формате со знаком:

а) 01001100;
б) 00010101.

6. Какие из чисел 443 8 , 101010 2 , 256 10 можно сохранить в 8-разрядном формате?

7. Запишите следующие числа в естественной форме:

а) 0,3800456 10 2 ;
б) 0,245 10 -3 ;
в) 1,256900Е+5;
г) 9,569120Е-3.

8. Запишите число 2010,0102 10 пятью различными способами в экспоненциальной форме.

9. Запишите следующие числа в экспоненциальной форме с нормализованной мантиссой - правильной дробью, имеющей после запятой цифру, отличную от нуля:

а) 217,934 10 ;
б) 75321 10 ;
в) 0,00101 10 .

10. Изобразите схему, связывающую основные понятия, рассмотренные в данном параграфе.

Представление чисел в компьютере

Целые числа являются простейшими числовыми данными, с которыми оперирует ЭВМ. Целые числа в компьютере хранятся в формате с фиксированной запятой . В этом случае каждому разряду ячейки памяти соответствует всегда один и тот же разряд числа, а «запятая» находится справа после младшего разряда.

Для хранения целого неотрицательного числа отводится одна ячейка памяти 1 байт (8 бит), т.е диапазон чисел, которые могут храниться в оперативной памяти в формате целых неотрицательных чисел, от 0 до 255 (всего 256). Минимальное число 0 соответствует восьми нулям, а максимальное 255 соответствует восьми единицам (255 10 = 11111111 2).

Для представления целого числа со знаком самый старший (левый) бит отводится под знак числа, остальные разряды - под само число. Если число положительное, то в знаковый разряд помещается 0, если отрицательное - 1. Например, в байте можно представить знаковые числа от -128 до 127.

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

Представление числа в привычной форме "знак"-"величина", при которой старший разряд ячейки отводится под знак, а остальные - под запись числа в двоичной системе, называется прямым кодом двоичного числа.

Например, прямой код двоичных чисел 1001 и -1001 для 8-разрядной ячейки равен 0 0001001 и 1 0001001 соответственно.

Положительные числа в ЭВМ всегда представляются с помощью прямого кода. Прямой код числа полностью совпадает с записью самого числа в ячейке машины.

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

Дополнительный код положительного числа равен прямому коду этого числа.

Дополнительный код отрицательного числа m равен 2 n -|m|, где n - количество разрядов в ячейке.

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

Алгоритм получения дополнительного кода отрицательного числа.

Для получения дополнительного k-разрядного кода отрицательного числа необходимо:

    модуль отрицательного числа представить прямым кодом в k- двоичных разрядах;

    значение всех бит инвертировать: все нули заменить на единицы, а единицы на нули, таким образом, получается k-разрядный обратный код исходного числа);

    к полученному обратному коду прибавить единицу.

Пример:

Получим 8-разрядный дополнительный код числа -52:
00110100 - число |-52|=52 в прямом коде
11001011 - число -52 в обратном коде
11001100 - число -52 в дополнительном коде

Представление вещественных чисел в компьютере.

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

Этот способ представления опирается на нормализованную (экспоненциальную) запись действительных чисел.
Нормализованная запись отличного от нуля действительного числа A - это запись вида:
А= m* q n ,
где
m - мантисса числа (правильная дробь, у которой первая цифра после запятой не равна нулю),
q - основание системы,
n - порядок числа.

Примеры:
1. 3,1415926 = 0, 31415926 * 101;
2. 1000=0,1 * 104;
3. 0,123456789 = 0,123456789 * 100;
4. 0,00001078 = 0,1078 * 8-4; (порядок записан в 10-й системе)
5. 1000,00012 = 0, 100000012 * 24.

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

Инструкция

Если в виде дроби надо представить целое число , то используйте в качестве знаменателя единицу, а исходное значение ставьте в числитель. Такая форма записи называться неправильной обыкновенной дробью, так как модуль ее числителя больше модуля знаменателя. Например, число 74 можно записать, как 74/1, а число -12 - как -12/1. При необходимости вы можете числитель и знаменатель в одинаковое количество раз - значение дроби в этом случае по-прежнему будет соответствовать исходному числу. Например, 74=74/1=222/3 или -12=-12/1=-84/7.

Если исходное число представлено в формате десятичной дроби , то его целую часть оставьте без изменений, а разделительную запятую замените пробелом. Дробную часть поставьте в числитель, а в качестве знаменателя используйте десятку, возведенную в степень с показателем, равным количеству знаков в дробной исходного числа. Полученную в результате дробную часть можно сократить, разделив числитель и знаменатель на одинаковое число . Например, десятичной дроби 7,625 будет соответствовать обыкновенная дробь 7 625/1000, которая после сокращения примет значение 7 5/8. Такая форма записи обыкновенной дроби смешанной. При необходимости ее можно привести к неправильному обыкновенному виду, умножив целую часть на знаменатель и прибавив результат к числителю: 7,625 = 7 625/1000 = 7 5/8 = 61/8.

Если исходная десятичная дробь является и периодической, то используйте, например, систему уравнений для вычисления ее эквивалента в формате дроби обыкновенной. Скажем, если исходная дробь равна 3,5(3), то можно тождество: 100*x-10*x=100*3,5(3)-10*3,5(3). Из него можно вывести равенство 90*x=318, а , что искомая дробь будет равна 318/90, что после сокращения даст обыкновенную дробь 3 24/45.

Источники:

  • Можно Ли Число 450 000 Представить Как Произведение 2 Чисел?

В быту чаще всего встречаются не натуральные числа: 1, 2, 3, 4 и т.д. (5 кг. картофеля), а дробные, нецелые числа (5,4 кг лука). Большинство из них представлены в виде десятичных дробей. Но десятичную дробь представить в виде дроби достаточно просто.

Инструкция

Например, дано число "0,12". Если не эту дробь и представить ее так, как есть, то выглядеть она будет так: 12/100 ("двенадцать "). Чтобы избавиться от сотни в , нужно и числитель, и знаменатель поделить на число, которое делит их числа. Это число 4. Тогда, поделив числитель и знаменатель, получается число: 3/25.

Если рассматривать более бытовую , то часто на ценнике у видно, что вес его составляет, к примеру, 0,478 кг или пр. Такое число тоже легко представить в виде дроби :
478/1000 = 239/500. Дробь эта достаточно некрасивая, и если бы была возможность, то эту десятичную дробь можно было бы сокращать и далее. И все тем же методом: подбора числа, которое делит как числитель, так и знаменатель. Это число наибольшим общим множителем. "Наибольшим" множитель потому, что гораздо удобнее и числитель, и знаменатель сразу поделить на 4 (как в первом примере), чем делить дважды на 2.

Видео по теме

Десятичная дробь - разновидность дроби , у которой в знаменателе есть "круглое" число: 10, 100, 1000 и т.д., Например, дробь 5/10 имеет десятичную запись 0,5. Исходя из этого принципа, дробь можно представить в виде десятичной дроби .

Инструкция

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

Вам понадобится

  • Калькулятор

Инструкция

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

Представление чисел

Числа в математике

Число-важнейшее понятие математики, которое складывалось и развивалось в течение длительного периода истории человечества. Люди начали работать с числами еще с первобытных времен. Первоначально человек оперировал лишь целыми положительными числами, которые называются натуральными числами: 1, 2, 3, 4, … Долго существовало мнение о том, что есть самое большое число, “боле сего несть человеческому уму разумевати” (так писали в старославянских математических трактатах).

Развитие математической науки привело к выводу, что самого большого числа нет. С математической точки зрения ряд натуральных чисел бесконечен, т.е. неограничен. С появлением в математике понятия отрицательного числа (Р.Декарт, XVII век в Европе; в Индии значительно раньше) оказалось, что множество целых чисел неограниченно как “слева”, так и “справа”. Математическое множество целых чисел дискретно и неограниченно (бесконечно).

Понятие вещественного (или действительного) числа в математику ввел Исаак Ньютон в XVIII веке. С математической точки зрения множество вещественных чисел бесконечно и непрерывно . Оно включает в себя множество целых чисел и еще бесконечное множество нецелых чисел. Между двумя любыми точками на числовой оси лежит бесконечное множество вещественных чисел. С понятием вещественного числа связано представление о непрерывной числовой оси, любой точке которой соответствует вещественное число.

Представление целых чисел

В памяти компьютера числа хранятся в двоичной системе счисления (см. “Системы счисления ” 2). Есть две формы представления целых чисел в компьютере: целые без знака и целые со знаком.

Целые без знака - это множество положительных чисел в диапазоне , где k - это разрядность ячейки памяти, выделяемой под число. Например, если под целое число выделяется ячейка памяти размером в 16 разрядов (2 байта), то самое большое число будет таким:

В десятичной системе счисления это соответствует: 2 16 – 1 = 65 535

Если во всех разрядах ячейки нули, то это будет ноль. Таким образом, в 16-разрядной ячейке помещается 2 16 = 65 536 целых чисел.

Целые числа со знаком - это множество положительных и отрицательных чисел в диапазоне [–2 k –1 , 2 k –1 – 1]. Например, при k = 16 диапазон представления целых чисел: [–32 768, 32 767]. Старший разряд ячейки памяти хранит знак числа: 0 - число положительное, 1 - число отрицательное. Самое большое положительное число 32 767 имеет следующее представление:



Например, десятичное число 255 после перевода в двоичную систему счисления и вписывания в 16-разрядную ячейку памяти будет иметь следующее внутреннее представление:

Отрицательные целые числа представляются в дополнительном коде. Дополнительный код положительного числа N - это такое его двоичное представление, которое при сложении с кодом числа N дает значение 2 k . Здесь k - количество разрядов в ячейке памяти. Например, дополнительный код числа 255 будет следующим:

Это и есть представление отрицательного числа –255. Сложим коды чисел 255 и –255:

Единичка в старшем разряде “выпала” из ячейки, поэтому сумма получилась равной нулю. Но так и должно быть: N + (–N ) = 0. Процессор компьютера операцию вычитания выполняет как сложение с дополнительным кодом вычитаемого числа. При этом переполнение ячейки (выход за предельные значения) не вызывает прерывания выполнения программы. Это обстоятельство программист обязан знать и учитывать!

Формат представления вещественных чисел в компьютере называется форматом с плавающей точкой . Вещественное число R представляется в виде произведения мантиссы m на основание системы счисления n в некоторой целой степени p , которую называют порядком: R = m * n p .

Представление числа в форме с плавающей точкой неоднозначно. Например, для десятичного числа 25,324 справедливы следующие равенства:

25,324 = 2,5324 * 10 1 = 0,0025324 * 10 4 = 2532,4 * 10 –2 и т.п.

Чтобы не было неоднозначности, договорились в ЭВМ использовать нормализованное представление числа в форме с плавающей точкой. Мантисса в нормализованном представлении должна удовлетворять условию: 0,1 n m < 1 n . Иначе говоря, мантисса меньше единицы и первая значащая цифра - не ноль. В некоторых случаях условие нормализации принимают следующим: 1 n m < 10 n .

В памяти компьютера мантисса представляется как целое число, содержащее только значащие цифры (0 целых и запятая не хранятся). Следовательно, внутреннее представление вещественного числа сводится к представлению пары целых чисел: мантиссы и порядка.

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

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

В старшем бите 1-го байта хранится знак числа: 0 обозначает плюс, 1 - минус. Оставшиеся 7 бит первого байта содержат машинный порядок . В следующих трех байтах хранятся значащие цифры мантиссы (24 разряда).

В семи двоичных разрядах помещаются двоичные числа в диапазоне от 0000000 до 1111111. Значит, машинный порядок изменяется в диапазоне от 0 до 127 (в десятичной системе счисления). Всего 128 значений. Порядок, очевидно, может быть как положительным, так и отрицательным. Разумно эти 128 значений разделить поровну между положительными и отрицательными значениями порядка: от –64 до 63.

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

Связь между машинным порядком (Mp) и математическим (p) в рассматриваемом случае выражается формулой: Mp = p + 64.

Полученная формула записана в десятичной системе. В двоичной системе формула имеет вид: Mp 2 = p 2 + 100 0000 2 .

Для записи внутреннего представления вещественного числа необходимо:

1) перевести модуль данного числа в двоичную систему счисления с 24 значащими цифрами,

2) нормализовать двоичное число,

3) найти машинный порядок в двоичной системе счисления,

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

Пример. Записать внутреннее представление числа 250,1875 в форме с плавающей точкой.

Решение

1. Переведем его в двоичную систему счисления с 24 значащими цифрами:

250,1875 10 = 11111010,0011000000000000 2 .

2. Запишем в форме нормализованного двоичного числа с плавающей точкой:

0,111110100011000000000000 Ч 10 2 1000 .

Здесь мантисса, основание системы счисления
(2 10 = 10 2) и порядок (8 10 = 1000 2) записаны в двоичной системе.

3. Вычислим машинный порядок в двоичной системе счисления:

Mp 2 = 1000 + 100 0000 = 100 1000.

4. Запишем представление числа в четырехбайтовой ячейке памяти с учетом знака числа

Шестнадцатеричная форма: 48FA3000.

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

Наименьшее по абсолютной величине число равно нулю. Наибольшее по абсолютной величине число в форме с плавающей точкой - это число с самой большой мантиссой и самым большим порядком.

Для четырехбайтового машинного слова таким числом будет:

0,111111111111111111111111 · 10 2 1111111 .

После перевода в десятичную систему счисления получим:

MAX = (1 – 2 –24) · 2 63 10 19 .

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

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

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

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

Количество вещественных чисел, точно представимых в памяти компьютера, можно вычислить по формуле : N = 2 t · (U L + 1) + 1. Здесь t - количество двоичных разрядов мантиссы; U - максимальное значение математического порядка; L - минимальное значение порядка. Для рассмотренного выше варианта представления (t = 24, U = 63,
L
= –64) получается: N = 2 146 683 548.

Пример 1. Получить внутреннее представление в формате “со знаком” целого числа 1607 в двухбайтовой ячейке памяти.

Решение

1) Перевести число в двоичную систему счисления: 1607 10 = 11001000111 2 .

2) Дописывая слева нули до 16 разрядов, получим внутреннее представление этого числа в ячейке:

Желательно показать, как для сжатой формы записи этого кода используется шестнадцатеричная форма, которая получается заменой каждой четверки двоичных цифр одной шестнадцатеричной цифрой: 0647 (см. “Системы счисления ” 2).

Более сложной является задача получения внутреннего представления отрицательного целого числа (–N ) - дополнительного кода. Нужно показать ученикам алгоритм этой процедуры:

1) получить внутреннее представление положительного числа N ;

2) получить обратный код этого числа заменой 0 на 1 и 1 на 0;

3) к полученному числу прибавить 1.

Пример 2. Получить внутреннее представление целого отрицательного числа –1607 в двухбайтовой ячейке памяти.

Решение

Полезно показать ученикам, как выглядит внутреннее представление самого маленького отрицательного числа. В двухбайтовой ячейке это –32 768.

1) легко перевести число 32 768 в двоичную систему счисления, поскольку 32 768 = 2 15 . Следовательно, в двоичной системе это:

2) запишем обратный код:

3) прибавим единицу к этому двоичному числу, получим

Единичка в первом бите обозначает знак “минус”. Не нужно думать, что полученный код - это минус ноль. Это –32 768 в форме дополнительного кода. Таковы правила машинного представления целых чисел.

Показав этот пример, предложите ученикам самостоятельно доказать, что при сложении кодов чисел 32 767 + (–32 768) получится код числа –1.



Рекомендуем почитать

Наверх