Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Tekhnologia_programmirovania.pdf
Скачиваний:
182
Добавлен:
08.04.2015
Размер:
1.76 Mб
Скачать

166 13

cout << p;

выводит изображение символа.

Для перехода к следующей строке экрана выводится манипулятор endl, определенный в iostream.h.

Программа выдает:

Работа с беззнаковыми p = 100 = 01100100

q = 200 = 11001000

p + q = 44, p - q = 156 q >> 2 = 50 = 00110010 Работа со знаковыми

z = 127 = 01111111, z + 1 = -128 = 10000000

x= -59 = 11000101

x| 017 = -49 = 11001111

x& 017 = 5 = 00000101

x^ 017 = -54 = 11001010 ~x = 58 = 00111010

x<< 2 = 20 = 00010100

x>> 2 = -15 = 11110001

13.6. Дробные числа в двоичной системе

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

585 = 4 +1+ 48+1 = 22 + 20 + 12 + 18 = 1× 22 + 0× 21 +1× 20 +1× 2−1 + 0× 2−2 +1× 2−3 = 101.101.

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

Заметим, что при умножении числа на 2 точка, отделяющая целую и дробную части, переместится вправо и старший разряд дробной части превратится в младший разряд целой части. Используя это наблюдение, приходим к следующему алгоритму получения двоичного представления числа, меньшего 1. Нужно умножать число, меньшее 1 на 2. Очередная двоичная цифра дробной части равна цифре целой части после очередного умножения числа на 2. Найдем, например, двоичное представление для числа 5/8 = 0.625, табл.54.

Внутреннее представление чисел

167

Таблица 55. Двоичные цифры числа 5/8

Число

Число *2

Двоичная цифра

0.625

1.25

1

0.25

0.5

0

0.5

1.0

1

0.0

 

 

В данном примере число представляется в виде двоичной дроби с конечным числом цифр, процесс преобразования прекращается, когда число обращается в 0.

Рассмотрим теперь число 0.3, табл.56

Таблица 57. Двоичные цифры числа 0.3

Число

Число*2

Двоичная цифра

0.3

0.6

0

0.6

1.2

1

0.2

0.4

0

0.4

0.8

0

0.8

1.6

1

0.6

1.2

1

Видно, что получение цифр является бесконечным периодическим процессом. Таким образом,

0.3 = 0.010011001100110011001100...

13.7. Внутреннее представление плавающих типов

Числа с плавающей точкой хранятся в памяти в экспоненциальной форме в двоичной системе счисления. Формула такого представления имеет вид

x = ±1.M2 2± p2 .

Здесь 1. M2 – мантисса числа в двоичной системе, p2 – порядок числа

в двоичной системе.

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

16813

5.3= 5 + 0.3 = 101.01001100110011001100110...2 =

=1.01010011001100110011001100...2 *2102

Итак, для числа 5.3 мантисса имеет вид:

M2 = 01010011001100110011001100...2,

порядок равен:

p2 = 102.

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

В памяти хранятся знак числа, часть мантиссы M2 и порядок p2 .

Самая старшая единица мантиссы не хранится, но учитывается в вычислениях.

Рассмотрим для примера тип float, под который отводится 4 байта памяти с подряд идущими адресами. Из 32 бит, выделяемых для размещения float, старший 31-й разряд используется для хранения знака числа (0 – положительное число, 1 – отрицательное), в 8 разрядах (с 23го по 30-й) хранится порядок и в 23-х разрядах (с 0-го по 22-й) размещается мантисса. Порядок хранится в увеличенном на шестнадцатеричное число 7F виде, то есть используется двоичная нотация с избытком 127. Это позволяет обойтись без специального разряда для хранения знака порядка.

Пусть для размещения числа типа float выделены байты с адресами a, a+1, a+2, a+3.

Возможны различные способы размещения в этих байтах разрядов двоичного представления числа. В процессорах фирмы Intel принят способ

1234,

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

 

 

 

Внутреннее представление чисел

169

 

Таблица 59. Двоичный код для чисел с типа float

 

Число

 

 

Двоичный код

16

– ричный

 

 

порядок

Мантисса

код

 

1.0

0

011 1111 1

000 0000 0000 0000 0000 0000

3f 80 00 00

2.0

0

100 0000 0

000 0000 0000 0000 0000 0000

40

00 00

00

10.0

0

100 0001 0

010 0000 0000 0000 0000 0000

41

20 00

00

5.30

0

100 0000 1

010 1001 1001 1001 1001 1010

40 A9 99 9A

13.8. Преобразование типов

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

f + i,

где f – число с плавающей точкой, i – целое.

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

Если возможна потеря информации, например, при присваивании целой переменной значения с плавающей точкой, компилятор может выдать предупреждение (warning), но такие выражения допустимы.

Тип char

Значения типа char – это просто малые целые, потому они свободно используются в арифметических выражениях. При вычислениях char предварительно преобразуется к целому типу. В качестве примера приведем функцию atoi, преобразующую строку цифр в ее числовой эквивалент.

// atoi: преобразование s в целое int atoi(char s[])

{

int i, n = 0;

for(i = 0; s[i] >= ’0’ && s[i] <= ’9’; i++) n = n*10 + s[i] – ’0’;

return n;

}

170 13

Выражение s[i] – ’0’ дает числовое значение цифры, размещенной в s[i], так как значения ’0’, ’1’,…, ’9’ образуют непрерывную возрастающую последовательность (’0’ = 48, ’1’ = 49,…, ’9’ = 57).

Предложенный вариант функции atoi несовершенен, например, не предусмотрена возможность записи числа в виде последовательности цифр, начинающейся знаком + или -. Заголовочный файл stdlib.h содержит описания ряда библиотечных функций для преобразования строк в числовые значения.

Функция

int atoi(const char *s)

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

Функция

long atol(const char *s)

переводит s в long. Функция

double atof(const char *s)

переводит s в double, игнорируя начальные пробелы.

Следующая функция lower преобразует заглавную латинскую букву в строчную. Если же символ не является заглавной буквой, он не изменяется.

int lower(int c)

{

if(c >= ’A’ && c <= ’Z’) return c + ’a’ – ’A’;

else return c;

}

Для латинских букв эта функция будет работать правильно, так как между одноименными буквами верхнего и нижнего регистров одинаковая разность, кроме того, латинский алфавит плотный, то есть между ’A’ и ’Z’ и между ’a’ и ’z’ расположены только буквы. Для русских букв в кодовой таблице 866, которая используется в DOS-программах, это не так. Заглавные русские буквы ’А’, ’Б’, …, ’Я’ идут плотно, а у строчных русских букв есть разрыв между ’п’ и ’р’, в котором расположены символы псевдографики. В кодовой таблице 1251, используемой в Windows, русские заглавные и строчные буквы расположены непрерывно в алфавитном порядке.

Имеются библиотечные функции для преобразования символов и проверки их типа, объявленные в заголовочном файле ctype.h.

Внутреннее представление чисел

171

Функция

int tolower(int c);

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

Функция

int toupper(int c)

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

Функция

int isalpha(int c)

возвращает 1, если c – латинская буква, иначе 0. Функция

int isdigit(int c)

возвращает 1, если c – цифра, иначе 0. Функция

int isalnum(int c)

возвращает 1, если c – латинская буква или цифра, иначе 0. Функция

int isspace(int c)

возвращает 1, если c – пробел, табуляция, новая строка, возврат каретки, новая страница, вертикальная табуляция, а иначе 0.

Функция

int isupper(int c)

возвращает 1, если c – заглавная латинская буква, иначе 0. Перечисленные функции не обрабатывают правильно русские

буквы.

Проверку

s[i] >= ’0’ && s[i] <= ’9’, использованную в функции atoi, можно заметить на

isdigit(s[i]).

Язык не определяет, является тип char знаковым или нет, поэтому это зависит от реализации. Например, в C++Builder тип char считается

172 13

знаковым. В Visual C++ тип char – беззнаковый. В Turbo C++ характеристика char определяется настройками компилятора. Для установки спецификации unsigned для char нужно выполнить команду меню Options, Compiler, Code generation и установить

соответствующий флажок, рис.57.

Рис.58. Настройки компилятора Turbo C++

В выражениях char преобразуется в int. Для знакового char преобразование производится посредством «распространения знака» и получится отрицательное число, если старший разряд был единичным. Для беззнакового char преобразование производится путем заполнения старших разрядов слева нулями, поэтому получаемое значение будет всегда положительным.

Значения логических выражений

Отношения типа i > j и логические выражения, содержащие операторы &&, ||, ! определяют выражение, которое имеет значение 1, если оно истинно и 0, если ложно. После присваивания

d = c>= ’0’ && c <= ’9’;

d будет иметь значение 1, если c – цифра и 0 в противном случае. Однако функции, подобные isdigit, могут выдавать в качестве истины любое ненулевое значение.

Внутреннее представление чисел

173

Арифметические преобразования

Перед выполнением оператора вроде + или * с операндами разных типов «низший тип» повышается до «высшего». Высшим считается тип с большим размером памяти. Для целых типов одного размера высшим считается беззнаковый тип по отношению к типу со знаком. Результат выражения будет иметь высший тип.

Правила преобразования следующие:

Если один из операндов имеет тип long double, другой тоже преобразуется к long double.

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

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

В противном случае типы char, unsigned char, signed char

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

Затем, если один из операндов имеет тип unsigned long, другой тоже преобразуется к unsigned long.

В противном случае, если один из операндов имеет тип long int, другой unsigned int, то если long int может представить все значения типа unsigned int, то unsigned int преобразуется в long int, иначе оба операнда преобразуются к типу unsigned long int.

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

В противном случае, если один из операндов имеет тип unsigned int, другой тоже преобразуется в unsigned int.

В противном случае оба операнда имеют тип int.

Пусть на конкретной машине int занимает 16 битов, а long – 32. В этом случает long содержит все возможные значения unsigned int, и выражение

–1L < 1U

будет истинным, так как 1U преобразуется в long и после преобразования будет иметь значение 1.

Но

–1L > 1LU,

так как –1L имеет внутреннее представление из одних единиц и, после повышения до типа unsigned long, воспринимается как большое положительное число, в то время, как 1LU имеет единичку в младшем разряде, а остальные разряды – нули.