Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие часть 1.doc
Скачиваний:
60
Добавлен:
24.09.2019
Размер:
6.98 Mб
Скачать
    1. Типы данных

1.1.1. Понятие типа данных

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

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

Тип данных определяет множество допустимых значений данных и множество операций над этими значениями.

Все типы данных, используемые в языках высокого уровня, можно разделить на две большие группы:

  • скалярные (простые);

  • структурированные (составные, конструируемые).

Скалярные типы, в свою очередь, делятся на несколько групп:

  • базовые (встроенные в язык), т. е. типы, предопределенные в языке программирования;

  • производные от базовых (например, перечисляемый тип или диапазон в языке Pascal);

  • ссылочные типы (указатели) обеспечивают возможность работы с множеством абстрактных адресов памяти.

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

Большинство языков программирования представляет стандартный набор структурированных типов:

  • массивы (в том числе строки — массивы символов);

  • записи (в языке С они называются структурами, аналоги записей с вариантами — объединения);

  • в некоторых языках, например в Pascal, есть множества.

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

Внутреннее представление данных, размер выделяемой памяти и реализация операций предоставляются на усмотрение разработчиков компиляторов. Детали внутренней реализации сильно зависят от архитектуры компьютера и операционной системы, они могут изменяться в различных версиях компилятора, но при этом прикладные программы на языке высокого уровня не потребуют никаких изменений. Единственное, что предоставляется программисту практически всеми языками программирования, — операция sizeof(тип) для определения размера области памяти, отводимой под переменную заданного типа. Если такой подход не устраивает программиста, он может воспользоваться языком ассемблера, но при этом производительность его (программиста) работы резко снизится.

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

1.2.2. Внутреннее представление базовых типов в оперативной памяти

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

В современных компьютерах имеется две основных формы представления данных:

  • с фиксированной точкой (в русском переводе иногда употребляют термин "с фиксированной запятой", т. к. речь идет о разделителе, отделяющем целую часть числа от дробной части);

  • с плавающей точкой (запятой).

Первый способ употребляется для хранения целых чисел, символов и логических значений. По этой причине в языках C/C++ все перечисленные типы данных относятся к целочисленным. Второй способ используется для хранения вещественных чисел либо целых чисел, имеющих очень широкий диапазон значений. Примерно такой набор базовых типов имеется во всех языках.

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

Например:

целое число 19 в двоичной форме с фиксированной точкой будет записано как 10011 (разложение по степеням двойки: 19=1×24+0×23+0×22+1×21+1×20). Один крайний бит отводится под знак числа (для положительного числа 0, для отрицательного 1), остальные незанятые биты заполняются нулями.

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

Например: вещественное число 15,375 в двоичной форме с плавающей запятой можно представить как 1,111011×211, где 1,111011 — мантисса, 11 — порядок (запись в двоичной форме).

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

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

  • Целочисленные типы в языке программирования — это интервал целых чисел. Операции над целыми числами определены лишь тогда, когда исходные данные и результат лежат в этом интервале. Иначе возникает ситуация, называемая переполнением. При целочисленном переполнении, как правило, не возникает ошибка выполнения программы, однако результат становится неверным. За исключением переполнения все операции над аргументами с фиксированной точкой выполняются точно (без погрешности).

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

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

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

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

  • Следует быть осторожным при выполнении операций между числами, порядки которых сильно отличаются, например, между очень большими и очень маленькими числами. Возможны ситуации, когда мантисса не сможет обеспечить требуемую точность. Например, при сложении чисел 10000000 и 0.00000001 типа float языка C разрядности мантиссы не хватит, чтобы представить число 10000000.00000001, и результат останется равным 10000000.

Замечание

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