- •Представление вещественных чисел в памяти компьютера.
- •Преобразование типов.
- •История развития технологий программирования
- •1. Программирование в машинных кодах и на языках символического кодирования
- •2. Языки высокого уровня. Структурное и модульное программирование
- •3. Интегрированные системы программирования.
- •4. История и идеи объектно-ориентированного программирования.
- •5. Программирование для Windows. Визуальное программирование
Представление вещественных чисел в памяти компьютера.
Вещественное число (число с плавающей запятой) состоит из двух частей: мантиссы и порядка. Например, число в десятичной системе счисления 0,000123 можно записать одним из следующих способов: 0.0000123*10; 0,123*10-3; 1,23*10-4 и т. д. Аналогично: 78900=0,789*105=78,9*103 и т.д. Термин “число с плавающей запятой” и связан с тем, что десятичная запятая перемещается (плывёт) по числу. Из такого рода различных записей в десятичной системе счисления нас будет интересовать нормализованное число, соответственно 0,123*10-3 и 0,789*105. Первая его часть называется мантиссой (0,123 и 0,789), а числа -3 и 5 – порядком.
Аналогично различные варианты записи (на бумаге, а не в памяти компьютера) вещественного числа имеют место и в двоичной системе счисления. Например, рассмотрим десятичное число 12,375. Для его перевода в двоичную систему счисления отдельно переводим целую часть (см. первый семестр) и отдельно — дробную часть. В качестве вспомогательной можно использовать шестнадцатеричную систему счисления. Для перевода дробной части из десятичной в шестнадцатеричную систему счисления выполняем следующее:
дробную часть числа умножаем на 16;
полученную целую часть результата (число от 0 до 15) переводим в шестнадцатеричную систему счисления и берём в качестве первой после запятой шестнадцатеричной цифры результата;
дробную часть результата, если она не равна нулю, повторно умножаем на 16;
полученную целую часть переводим в шестнадцатеричную систему счисления и берём в качестве следующей шестнадцатеричной цифры;
дробную часть результата снова умножаем на 16;
это продолжаем, пока не наступит одна из следующих ситуаций:
на некотором шаге, не обязательно в самом начале, получим в дробной части нуль. В этом случае перевод выполнили точно. Это имеет место в нашем примере: 0,375*16=6.0;
получим в дробной части число, которое было раньше. Например, 0,15*16=2,4; 0,4*16=6,4. Если продолжать умножение 0,4*16, будем получать одно и то же, т. е 6,4. В таком случае получаем следующий результат: 0,1510= 0,2666…16=0,2(6)16. Круглые скобки означают, что записанные в них одно или несколько разных чисел будут повторяться бесконечное число раз. Говорят, что это число в периоде, т. е. 6 в периоде;
сли не получаем ни нуль, ни повторяющиеся числа, то ограничиваемся заданным предварительно количеством двоичных или шестнадцатеричных цифр. Для числа типа float необходимо получить 24 двоичные цифры, считая от первой значащей, или не менее 7 шестнадцатеричных цифр, не считая первые шестнадцатеричные нули.
Для перевода дробной части из шестнадцатеричной в двоичную систему счисления записываем каждую шестнадцатеричную (но не десятичную!) цифру в виде тетрады, т. е. четырёх двоичных цифр. Получим 12.37510=С.616=1100,0110. При этом последнюю цифру ‘0’ можем не писать. Как и в 10-й с.с., этот нуль незначащий. Остальные нули рядом с десятичной запятой обязательны!
Это двоичное число, как и в десятичной системе счисления, записать можно по-разному: 11,00011*22; 1100011*2-3; 1.100011*23 и т. д. Из приведенных вариантов нас будет интересовать последняя нормализованная запись, в которой в целой части записана одна первая значащая единица. Величину m=1.100011 называют нормализованной мантиссой, а p=310=112 — порядком числа в двоичной системе счисления.
Пусть число объявлено как float. Тогда 4 байта (32 бита) распределяются следующим образом:
один самый “левый” бит отводится под знак мантиссы, или, что то же самое, под знак всего числа. Записывается 0, если мантисса, а, значит и само вещественное число, положительное, и 1— в противном случае. Никакого дополнительного кода для отрицательного вещественного числа, как это было для целых чисел, получать не надо;
следующие 8 разрядов (бит) занимает изменённый порядок записи числа в 2-й с.с., который называется характеристикой числа. Обозначим её x. Знак порядка нигде не хранится. Чтобы он всегда был неотрицательным, порядок увеличивается на 12710, т. е.
x=p+12710=p+7F16. (1)
Для нашего примера здесь будет храниться число
x=310+12710= 13010=8216=100000102.
Это же можно вычислить, используя шестнадцатеричную систему счисления, следующим образом:
x=316+7F16=8216 =100000102 ;
последние 23 (32-1-8) разряда занимает мантисса. При этом целая её часть, равная единице, в памяти не хранится, но учитывается при вычислениях. Если дробная часть числа переведена в шестнадцатеричную, а, значит и в двоичную системы счисления не точно, т. е. имели место варианты b) и c) (см. выше перевод), последняя двоичная цифра мантиссы округляется по обычным правилам. Если первая отбрасываемая двоичная цифра равна единице, то к последней цифре прибавляем двоичную единицу, в противном случае оставляем её без изменения.
Таким образом, число 12,375 в формате float будет представлено следующим образом: 01000001010001100000000000000000. Иногда в литературе можно встретить шестнадцатеричную запись этого результата: 4146000016.
Упражнение. Представить число -0.01 как число с плавающей точкой в формате float.
Переводим модуль числа в шестнадцатеричную, а затем в двоичную системы счисления описанным выше способом:
0.01= 0.028F5С28F5C…16 = 0.0(28F5С)16= 0.0000001010001111010111000010100…2.
Так как под мантиссу отводится 23 разряда, то должны получить 25 двоичных цифр, не считая первых после десятичной точки подряд идущих нулей. Почему? По правилу нормализации самая первая значащая единица (в примере в десятичной цифре 2) в память не записывается, а ещё одна дополнительная двоичная цифра нужна для того, чтобы определить, как округлять число. Так как первая отбрасываемая двоичная цифра =0, то получаем
m=0.010001111010111000010102.
Если число “маленькое”, т. е. целая часть =0, а в дробной части после запятой несколько подряд идущих нулей, то получим отрицательный порядок. Так как 0.0000001010001111010111000010102 = 1.01000111101011100001010*2-7,
то p=-710=-716, x= p+7F16=7F16-716=7816=011110002.
В результате получим ответ: 10111100001000111101011100001010.
Рассмотрим обратную задачу. Пусть в ячейке размером 4 байта хранится следующая последовательность нулей и единиц, шестнадцатеричное представление которой такое: С215999A16. Известно, что здесь хранится вещественное число, т. е. в программе записано, например, объявление: float a. Что это за число в десятичной системе счисления?
Для ответа на этот вопрос в обратном порядке выполняем действия, описанные выше.
Запишем двоичное представление числа: 11000010000101011001100110011010.
Единица в старшем бите (самая “левая”) означает, что всё вещественное число отрицательное.
В следующих 8 битах находится характеристика числа, т. е.
x=100001002=8416.
Из формулы (1) получаем двоичный порядок числа:
p=x-7F16=8416-7F16 =516=510.
Из последних 23 разрядов получаем m=0.001010110011001100110102.
Поэтому искомое число
a=1.00101011001100110011010*25 = 100101.0110011001100110102 25.(6)16 37.410. При этом перевод дробной части выполняли следующим образом:
0.(6) 16 = 0.6666616 = 6*16-1+6*16-2+6*16-3+6*16-4+6*16-50.410.
Так как это отрицательное число, получаем ответ: - 37.410.
