Внутреннее представление плавающих типов
Числа с плавающей точкой хранятся в памяти в экспоненциальной форме в двоичной системе счисления. Формула такого представления имеет вид
.
Здесь 1. – мантисса числа в двоичной системе, – порядок числа в двоичной системе.
Чтобы получить двоичные цифры мантиссы, нужно представить число в виде суммы степеней двойки. Например,
Итак, для числа 5.3 мантиссаимеет вид:
= 01010011001100110011001100...2,
порядокравен:
= 102.
Видно, что мантисса числа 5.3 есть бесконечная периодическая дробь. Разряды мантиссы, не умещающиеся в пределы разрядной сетки, отбрасываются. Если старший отбрасываемый разряд равен единице, то происходит округление путем прибавления единицы к младшему разряду мантиссы.
В памяти хранятся знак числа, часть мантиссы и порядок . Самая старшая единица мантиссы не хранится, но учитывается в вычислениях.
Рассмотрим для примера тип 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,
то есть младшие разряды двоичного представления числа размещаются в байтах с меньшими адресами. В табл.27. приведены примеры внутреннего представления чисел типа float.
Таблица 27. Двоичный код для чисел с типа float
Число | Двоичный код | 16 – ричный код | ||
порядок | Мантисса | |||
1.0 | 011 1111 1 | 000 0000 0000 0000 0000 0000 | 3f 80 00 00 | |
2.0 | 100 0000 0 | 000 0000 0000 0000 0000 0000 | 40 00 00 00 | |
10.0 | 100 0001 0 | 010 0000 0000 0000 0000 0000 | 41 20 00 00 | |
5.30 | 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;
}
Выражение 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.
Функция
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 считается знаковым. В Visual C++ тип char – беззнаковый. В Turbo C++ характеристика char определяется настройками компилятора. Для установки спецификации unsigned для char нужно выполнить команду меню Options, Compiler, Code generation и установить соответствующий флажок, рис.33.
Рис.33. Настройки компилятора Turbo C++
В выражениях char преобразуется в int. Для знакового char преобразование производится посредством «распространения знака» и получится отрицательное число, если старший разряд был единичным. Для беззнакового char преобразование производится путем заполнения старших разрядов слева нулями, поэтому получаемое значение будет всегда положительным.