- •Часть I. Работа в среде
- •Глава 1. Интегрированная среда
- •1.1. Окно просмотра результатов Output
- •1.2. Окно просмотра переменных Watch
- •1.3. Структура меню
- •1.3.1. Пункт File (работа с файлами)
- •1.3.2. Пункт Edit (работа с редактором)
- •1.3.3. Пункт Run (запуск на выполнение)
- •1.3.4. Пункт Compile (компиляция)
- •1.3.5. Пункт Options (установка параметров системы)
- •1.3.6. Пункт Debug (установки отладчика)
- •1.3.7. Пункт Break/Watch (точки останова/обзор)
- •1.4. Интерактивная справка
- •Глава 2. Настройка системы
- •2.1. Система настройки среды программирования
- •2.2. Принятые в системе расширения имен файлов
- •Часть II. Язык турбо паскаль
- •Глава 3. Построение программ
- •3.1. Алфавит языка и зарезервированные слова
- •3.2. Общая структура программ
- •3.3. Комментарии и ключи компиляции
- •3.4. Условная компиляция программ
- •Глава 4. Введение в систему типов языка
- •4.1. Простые типы языка
- •4.1.1. Целочисленные типы
- •4.1.2. Вещественные числа
- •4.1.3. Логический тип
- •4.1.4. Символьный тип
- •4.1.5. Строковый тип
- •4.1.6. Адресный тип
- •4.1.7. Перечислимые типы
- •4.1.8. Ограниченные типы (диапазоны)
- •4.2. Сложные типы языка
- •Глава 5. Константы и переменные
- •5.1. Простые константы
- •5.2. Переменные
- •5.2.1. Совмещение адресов директивой absolute
- •5.2.2. Переменные со стартовым значением или типизированные константы
- •5.3. Операция присваивания и совместимость типов и значений
- •5.4.Изменение (приведение) типов и значений
- •Глава 6. Управляющие структуры языка
- •6.1. Простой и составной операторы
- •6.2. Условный оператор (if...Then...Else)
- •If Условие then Оператор1 else Оператор2;
- •6.3. Оператор варианта (case)
- •6.4. Оператор цикла с предусловием (while)
- •6.6. Оператор цикла с параметром (for...Do)
- •6.7. Оператор безусловного перехода Goto
- •6.8. Операторы Exit и Halt
- •6.9. Процедуры и функции
- •6.9.1. Параметры. Глобальные и локальные описания
- •6.9.2. Опережающее описание процедур и функций
- •6.9.3. Объявление внешних процедур
- •6.9.4. Процедуры и функции как параметры
- •6.9.5. Переменные-процедуры и функции
- •6.9.6. Специальные приемы программирования
- •6.10. Модули. Структура модулей
- •6.11. Особенности работы с модулями
- •6.12. Система библиотечных модулей языка
- •Часть III. Средства языка турбо паскаль
- •Глава 7. Массивы, записи и множества в деталях
- •7.1. Массивы (Array) и работа с ними
- •7.2. Тип «запись» (Record) и оператор присоединения With
- •7.3. Тип «множество» (Set). Операции с множествами
- •Глава 8. Обработка символов и строк
- •8.1. Символьный и строковый типы (Char и String)
- •8.2. Операции над символами
- •8.3. Операции над строками
- •8.3.1. Редактирование строк
- •8.3.2. Преобразование строк
- •8.3.2.1. Процедура Str( X [: Width [: dec ] ]; var s : String)
- •Глава 9. Математические возможности Турбо Паскаля
- •9.1. Базовые операции
- •9.2. Битовая арифметика
- •9.3. Логические вычисления и операции отношения
- •9.4. Математические процедуры и функции
- •9.4.1. Обсуждение математических функций языка
- •9.4.2. Генераторы случайных чисел
- •9.4.3. Оптимизация сложения и вычитания
- •9.5. Использование математического сопроцессора 80x87
- •Глава 10. Код программы, данные, адреса
- •10.2. Распределение памяти при выполнении программ
- •10.3. Анализ расположения кода и областей данных программы
- •10.5. Средства для работы с адресами
- •10.5.1. Определение адреса переменных
- •10.5.2. Создание адреса функцией Ptr
- •10.5.3. Определение размеров типов и переменных
- •Глава 11. Ссылки, динамические переменные и структуры
- •11.1. Ссылочные переменные
- •11.2. Операция разыменования
- •11.3. Организация памяти области кучи
- •11.4. Управление размерами области кучи и стека
- •11.5. Процедуры управления кучей
- •11.5.1. Размещение динамических переменных.
- •11.5.2. Освобождение динамических переменных.
- •11.5.3. Управление состоянием кучи.
- •11.5.4. Анализ состояния кучи.
- •11.5.5. Более детальный анализ состояния кучи
- •11.6. Ссылки, работающие не с кучей
- •11.5.6. Обработка ошибок распределения памяти
- •11.7. Как организовать структуры, большие чем 64к?
- •11.8. Практический пример построения стека
- •Глава 12. Ввод-вывод данных и файловая система
- •12.1. Понятие логического файла
- •12.2. Физические файлы в ms-dos
- •12.3. Понятие буфера ввода-вывода
- •12.4. Файловые типы Турбо Паскаля
- •12.5. Общие процедуры для работы с файлами
- •12.5.1. Связывание файлов
- •12.5.2. Открытие файлов
- •12.5.3. Закрытие файлов
- •12.5.4. Переименование файлов
- •12.5.5. Удаление файлов
- •12.5.6. Анализ состояния файлов
- •12.6. Текстовые файлы
- •12.6.1. Текст-ориентированные процедуры и функции
- •12.6.2. Операции ввода-вывода в текстовые файлы
- •123 1.23 [Клавиша ввода]
- •123 [Клавиша ввода] 1.23 [Клавиша ввода]
- •12.7. Типизированные файлы и операции ввода-вывода
- •12.8. Бестиповые файлы и операции ввода-вывода
- •12.9. Последовательный и прямой доступ к файлам
- •12.9.1. Опрос размеров файлов и позиции в них
- •12.9.2. Позиционирование в файлах
- •12.9.3. Усечение файлов
- •12.10. Процедуры для работы с каталогами
- •12.11. Обработка ошибок ввода-вывода
- •12.11.1. Функция ioResult
- •12.11.2. Примеры обработки ошибок ввода-вывода
- •12.11.3. Сводка номеров ошибок ввода-вывода
- •Глава 13. Объектно-ориентированное программирование
- •13.1. Определения объектов
- •13.2. Область действия полей объекта и параметр Self
- •13.3. Наследование
- •13.4. Присваивание объектов
- •13.5. Полиморфизм
- •13.5.1. Статические методы
- •13.5.2. Виртуальные методы
- •13.5.3. Выбор вида метода
- •13.6. Динамические объекты
- •13.6.1. Создание динамических объектов
- •13.6.2. Освобождение объектов. Деструкторы
- •13.6.3. Обработка ошибок при работе с динамическими объектами
- •13.7. Функции TypeOf и SizeOf
- •13.8. Задание стартовых значений объектам
- •13.9. Модули, экспортирующие объекты
- •Глава 14. Специальные средства языка
- •14.1. Работа с командной строкой. Функции ParamCount и ParamStr
- •14.2. Доступ к памяти пэвм. Массивы Mem, MemW, MemL
- •14.3. Доступ к портам ввода-вывода. Массивы Port и PortW
- •14.4. Процедура заполнения FillChar
- •14.5. Процедура перемещения данных Move
- •14.6. Функции обработки машинных слов Lo, Hi и Swap
- •14.7. Вставки машинного кода в программе
- •14.7.1. Оператор inline
- •14.7.2. Процедуры с директивой inline
- •14.8. Процедура завершения и обработка ошибок программ
- •14.8.1. Оператор RunError
- •14.8.2. Сводка номеров фатальных ошибок
- •Часть IV. Специальные библиотеки языка
- •Глава 15. Модуль crt
- •15.1. Вывод специальных символов
- •15.2. Модификация операторов Read, ReadLn
- •15.3. Системные переменные модуля crt
- •15.3.1. Переменные управления выводом на дисплей
- •15.3.2. Переменные управления работой клавиатуры
- •15.3.3. Переменная TextAttr
- •15.4. Процедуры и функции модуля crt
- •15.4.1. Работа с экраном в целом
- •15.4.2. Позиционирование курсора
- •15.4.3. Работа со строками
- •15.4.4. Настройка цвета
- •15.4.5. Подача звуковых сигналов
- •15.4.6. Использование встроенного таймера
- •15.4.7. Опрос клавиатуры
- •If KeyPressed then Действие ;
- •15.4.8. Переназначение стандартных файлов
- •Глава 16. Модуль dos
- •16.1. Опрос и установка параметров ms-dos
- •16.1.1. Управление параметрами break и verify 16.1.1.1.
- •16.1.2. Опрос системных переменных ms-dos
- •16.2. Работа с часами и календарем
- •16.2.1. Опрос и назначение даты
- •16.2.3. Работа с датой создания файлов
- •16.3. Анализ ресурсов дисков
- •16.4. Работа с каталогами и файлами
- •16.4.1. Типы и константы модуля dos для работы с файлами
- •16.4.2. Переменная DosError
- •16.4.3. Процедуры поиска файлов на диске
- •16.4.4. Работа с атрибутами файлов
- •16.4.5. Анализ имен файлов
- •16.5. Работа с прерываниями ms-dos
- •16.5.1. Чтение и перестановка адресов подпрограмм прерываний
- •16.5.2. Вызов прерывания процедурой Intr
- •16.5.3. Процедура MsDos
- •6.6. Организация субпроцессов и резидентных программ
- •16.6.1. Программирование субпроцессов
- •Глава 17. Модуль Printer
- •7.1. Содержимое модуля Printer
- •17.2. Низкоуровневые средства работы с принтером
- •17.3. Работа с двумя принтерами одновременно
- •Глава 18. Модуль Overlay
- •18.1. Оверлейное построение программ
- •18.2. Правила оформления оверлейных программ
- •18.3. Инициализация работы оверлеев
- •18.3.1. Включение администратора оверлеев
- •18.3.2. Анализ результата инициализации
- •18.3.3. Размещение оверлейного файла в ems-памяти
- •18.4. Управление оверлейным буфером
- •18.4.1. Опрос размера буфера
- •18.4.2. Установка размера буфера
- •18.4.3. Принудительная очистка буфера
- •18.5. Оптимизация работы оверлеев
- •18.5.1. Установка размера области испытаний
- •18.5.2. Подсчет вызовов оверлеев
- •18.6. Предопределенные переменные для работы с оверлеями
- •18.7. Включение оверлеев в ехе-файлы
- •Глава 19. Модуль Graph
- •19.1. Файлы bgi и содержимое модуля Graph
- •19.2. Управление графическими режимами
- •19.2.1. Инициализация и закрытие графического режима
- •19.2.2. Обработка ошибок инициализации
- •19.2.3. Классификация и анализ графических режимов
- •19.2.4. Очистка экрана и переключение режимов
- •19.2.5. Управление режимом вывода отрезков на экран
- •19.3. Системы координат и «текущий указатель»
- •19.3.1. Координаты устройства и мировые координаты
- •19.3.2. Управление «текущим указателем»
- •19.4. Рисование графических примитивов и фигур
- •19.4.1. Линии и их стили
- •1100110011001100 — Всего 16 разрядов.
- •19.4.2. Коэффициент сжатия изображения
- •19.4.3. Окружности, эллипсы и дуги
- •19.4.4. Построение прямоугольников и ломаных
- •19.5. Управление цветами и шаблонами заливки (заполнения)
- •19.5.1. Немного о цветах
- •19.5.2. Задание типа заливки
- •19.5.3. Заливка областей изображения
- •19.5.4. Опрос и установка цветов пера и фона
- •19.5.5. Управление палитрой
- •19.6. Битовые графические операции
- •19.6.1. Битовые операции
- •19.6.2. Работа с фрагментами изображений
- •19.7. Управление видеостраницами
- •19.8. Графические окна
- •19.9. Вывод текста
- •19.9.1. Выбор шрифта и стиля
- •19.9.2. Предварительная загрузка и регистрация шрифтов
- •19.9.3. Непосредственный вывод строк
- •19.9.4. Размер букв и его масштабирование
- •19.9.5. Опрос стиля и ориентации шрифтов
- •19.10. Включение шрифтов и драйверов в ехе-файл
- •19.11. Подключение новых драйверов
- •19.12. Один полезный совет
- •Часть V. Практические
- •Глава 20. Профессиональная работа с
- •20.1. Программный опрос режимов текстового дисплея
- •20.2. Организация доступа к видеопамяти
- •20.3. Запоминание окон экрана и их восстановление
- •20.3.1. Общие принципы работы с окном
- •20.3.2. Модуль Win
- •20.4. Работа с образом экрана на диске
- •20.5. Крупные надписи на экране
- •20.6. Управление формой курсора
- •Глава 21. Как осуществить полный доступ к клавиатуре
- •21.1. Как организовать опрос алфавитно-цифровой клавиатуры
- •21.2. Опрос клавиши в регистре Ctrl
- •21.3. Опрос расширенных кодов и функциональных клавиш
- •21.4. Опрос служебных клавиш
- •21.5. Анализ клавиш регистров и их состояния
- •21.6. Скэн-коды клавиатуры и работа с ними
- •21.7. Эффект обратной записи в буфер ввода
- •Глава 22. Работа с оперативной
- •22.1. Многобитовое и многоплоскостное озув
- •22.2. Карта дисплейной памяти
- •22.3. Вывод текста на графический экран
- •22.4. Работа с графическими образами на диске
- •Приложение 2 Ключи и директивы компилятора
- •Ключи режимов компиляции
- •Директивы с параметрами
- •Приложение 3
- •Файл tpc.Cfg
- •Приложение 4 Список утилит пакета Турбо Паскаль (версия 5.5)
- •Программа администрирования библиотек
- •Утилита поиска текстов grep
- •Утилита преобразования двоичных файлов binobj
- •Приложение 5
- •Основные команды перемещения курсора
- •Расширенный набор команд перемещения курсора
- •Команды вставки и удаления
- •Команды работы с блоками
- •Поиск и замена
- •Прочие команды
- •Приложение 6
- •If False then Оператор;
- •Приложение 7
- •Глава 6. Управляющие структуры языка
- •Глава 8. Обработка символов и строк
- •Глава 9. Математические возможности Турбо Паскаля
- •Глава 16. Модуль dos
- •Глава 17. Модуль Printer
- •Глава 18. Модуль Overlay
- •Глава 19. Модуль Graph
- •Глава 20. Профессиональная работа с текстовыми изображениями
- •Глава 21. Как осуществить полный доступ к клавиатуре
- •Глава 22. Работа с оперативной памятью видеоадаптеров
- •Литература
- •Оглавление
- •Часть I. Работа в среде программирования
- •Часть II. Язык турбо паскаль
- •Часть III. Средства языка турбо паскаль
- •Часть IV. Специальные библиотеки языка
- •Часть V. Практические приемы работы с пэвм
9.2. Битовая арифметика
Кроме стандартных для всех языков математических действий над вещественными и целыми числами, Турбо Паскаль вводит дополнительные операции над целыми числами, в том числе и так называемую битовую, или поразрядную, арифметику.
Битовая арифметика хорошо развита в языке Турбо Паскаль. Необходимость в ее применении возникает, когда надо работать не с десятичными значениями чисел, а с их двоичным представлением. В этом случае можно сравнивать отдельные биты двух чисел, выделять двоичные фрагменты, заменять их и т.п. Это часто используется при работе с видеопамятью в текстовом или графическом режимах. Кроме того, есть ряд чисто математических задач, которые удобно решать в двоичном представлении.
Ограничение на битовые операции одно: они должны применяться только над целыми типами — Byte, ShortInt, Word, Integer, LongInt и совместимыми с ними. Именно эти типы кодируют значения в правильные двоичные числа, как в школьном учебнике по информатике. (То, что в памяти некоторые целые типы хранят свои байты значений в обратном порядке, никак не влияет на поразрядные действия и логику работы с ними. Все особенности учитываются самими поразрядными операциями, и мы можем о них даже не вспоминать.) Например, значения 4 и 250 типа Byte представляются как двоичные наборы 00000100 и 11111010, число 65535 типа Word — это уже 16 бит: 11111111 11111111 и т.д.
Общая формула для значений типов Byte и Word имеет вид
Byte : Значение = B7*27 + B6*2б + B5*25 +...+ B1*2* + B0;
Word : Значение = B15*215 + B14*214+...+B7*27 +...+ B0.
Множители B0, B1 и т.п. — это значения соответствующих битов, равные либо 0, либо 1, а числовые множители — это 2 в степени номера бита. {164}
Внутреннее отличие имеют представления целых типов со знаком: ShortInt, Integer и LongInt. По размеру тип ShortInt равен типу Byte, a Integer — типу Word. Но они могут хранить отрицательные целые числа, правда, меньшие по абсолютному значению чем 255 и 65535:
ShortInt : -128 ..127 ( 8 бит ),
Integer : -32768 .. 32767 ( 16 бит ),
LongInt : -2147483648 .. 2147483647 ( 32 бит ).
Самый левый бит в представлении отрицательного числа всегда равен 1, если значение отрицательное, и 0 в противном случае. Формула перевода битов в значение для типов ShortInt, Integer, LongInt такова:
Shortlnt : Знач= -B7*27 + B6*26 + B5*25 +...+ B1*21 + B0;
Integer : Знач=-B15*215 + B14*214+...+B7*27 +...+ B0;
LongInt : Знач=-B31*231 + B30*230+...+B15*215 +...+ B0;
Примеры кодировки отрицательных чисел для типа ShortInt (бит знака числа отделен здесь пробелом) :
-1 :1 1111111 ( -1*128 + 127 )
-2 : 1 1111110 ( -1*128 + 126 )
-3 : 1 1111101 ( -1*128 + 125 )
-125 : 1 0000011 ( -1*128 + 3 )
-128 : 1 0000000 ( -1*128 + 0 )
Если в кодировании положительных значений абсолютное значение числа тем больше, чем больше единиц в его записи, то для отрицательных значений нули и единицы как бы поменяются местами — и абсолютное значение числа тем больше, чем больше будет в записи нулей. Поэтому, например, двоичное представление того же числа -128 в формате Integer (это уже 16 бит) будет 11111111 10000000.
Вещественные типы кодируются каждый раз по-разному, но всегда достаточно сложно: одна группа битов составляет мантиссу числа, вторая — порядок, да еще знак... Битовые операции к вещественным числам (типам) не применяются.
Посмотреть двоичную форму представления целых чисел можно с помощью функции (рис. 9.1). Операции shl и shr из примера на рис. 9.1 будут рассмотрены чуть позже. {165}
{ФУНКЦИЯ ПЕРЕВОДА ЦЕЛОГО ЧИСЛА В ДВОИЧНОЕ ПРЕДСТАВЛЕНИЕ} { X - целое число (можно передавать и другие типы ) } { NumOfBits - число позиций в двоичном представлении } FUNCTION Binary( X:LongInt; NumOfBits : Byte ) : String; VAR bit, i : Byte; { вспомогательные переменные } s : String[32]; BEGIN s: = ' '; { обязательная чистка строки } for i:=0 to 31 do begin { цикл перевода } bit := ( X shl i ) shr ( 31 ); { выделение бита } s := s + Chr( Ord( '0' ) + bit ) { запись в строку } end; {for} { конец цикла } Delete( s, 1, 32-NumOfBits ); { отсечение лишних битов} Binary :- s { возвращаемая строка } END; VAR i : Integer; {=== ПРИМЕР ВЫЗОВА === } BEGIN for i:=-5 to 5 do WriteLn(i:7, '--> ', Binary( i, 8*SizeOf(i))); Readln { пауза до нажатия клавиши ввода } END. |
Рис. 9.1
Итак, какие же действия предоставляет поразрядная арифметика? Первая группа — это логические операции над битами (табл. 9.2).
Таблица 9.2
Операции |
Название |
Форма записи |
Приоритет |
not |
Поразрядное отрицание |
not A |
1 (высший) |
and |
Логическое умножение |
A1 and A2 |
2 |
or |
Логическое сложение |
A1 or A2 |
3 |
xor |
Исключающее 'ИЛИ' |
A1 xor A2 |
4 (низший) |
Not — поразрядное отрицание — «переворачивает» значение каждого бита на противоположное. Так, если A в двоичном виде представляется как 01101100, то not A станет 10010011:
not [1] = 0
not [0] = 1
Квадратные скобки вокруг аргументов обозначают действие над одним битом. {166}
And — так называемое логическое умножение или поразрядная операция 'И':
[0] and [1] = [1] and [0] = [0]
[0] and [0] = [0]
[1] and [1] = [1]
Здесь аргументы специально взяты в скобки — их надо рассматривать как отдельные единичные биты; реальные же примеры не столь очевидны:
(6 and 4) = 4
(6 and 1) = 0
и т.п. Все станет ясно, если 6 и 4 представить как двоичные числа:
0000110 (6) 0000110 (6)
and 0000100 (4) и and 0000001 (1)
______________ ______________
0000100 (4) 0000000 (0)
Впрочем, вовсе не обязательно записывать числа в виде нулей и единиц. Операция and в 99% случаев нужна для двух целей: проверить наличие битов или убрать ( т.е. обнулить) некоторые из них.
Такая проверка нужна, когда число является набором флагов. Например, большое число системных ячеек памяти ПЭВМ содержит сведения о конфигурации машины или ее состоянии. При этом один байт может трактоваться так: бит 6 равен 1 — значит включен режим CapsLock, бит 4 равен 0 — следовательно какой-либо другой режим Lock выключен и т.д. Пусть A содержит этот самый байт с восемью флагами, и надо проверить состояние бита номер 5 (нумерация идет справа налево, от 0 до 7). Единица в бите 5 дает число 25 = 32. Это второй аргумент. Если в A в пятом бите есть единица, то должно выполниться условие
( A and 32 ) = 32
Осталось оформить все это в оператор IF. Можно проверить наличие сразу нескольких «включенных» битов, например, 5-го, 2-го и 0-го. Число с единицами в этих позициях и нулями в остальных равно 2+2 + 1 = 32+4+1 = 37. Если A среди прочих имеет единицы в битах 5, 2 и 0, то в этом случае будет истинным выражение
( A and 37 ) = 37
Исключение или выключение битов достигается следующим образом. Пусть надо исключить бит 3 из переменной A типа Byte (здесь важно знать тип, в который «умещается» текущее значение A). Исключить — значит, задать нулем. Первым делом определяется {167} число, в котором все биты равны 1, кроме бита номер 3. Для типа Byte оно равно (255 – 23) = 247, где 255 — максимальное значение, вписываемое в байт. Если теперь это число логически умножить на A, то единицы в 247 никак не повлияют на состояние битов в переменной A, а ноль в третьем бите заместит любое значение в A на том же месте. Таким образом, можно записать
A := A and (255 – 8);
чтобы получить значение A с отключенным 3-м битом.
Все это верно и для нескольких битов сразу: если надо исключить биты 3 и 7, то просто запишем
A := A and (255 – 8 – 128);
где 8 = 23 и 128 = 27.
Or — логическое сложение; оно же операция 'ИЛИ', определяется следующими действиями над битами:
[1] or [0] = [0] or [1] = [1]
[0] or [0] = [0]
[1] or [1] = [1]
Квадратные скобки обозначают один бит. Эта операция может с успехом применяться при включении (установки в 1) отдельных битов двоичного представления целых чисел. Так, если надо, чтобы бит 4 значения A стал равным единице, а остальные не изменились, то следует записать
A := A or 16;
где 16 = 24 . При этом не имеет значения, что было в 4-м бите значения A. В любом случае там появится единица.
Аналогичным образом можно включать сразу несколько битов, например, 4-й, 1-й и 0-й:
A := A or (16 + 2 + 1);
Кроме перечисленных, введена еще одна операция xor — исключающее 'ИЛИ' (математическое название — «сложение по модулю 2»). Эта операция возвращает 0, если оба ее аргумента равны, и 1 в противном случае:
[1] xor [1] = [0]
[0] xor [0] = [0]
[1] xor [0] = [0] xor [1] = [1]
Операцию xor можно с успехом применять при смене значения бита (или нескольких битов) на противоположные. Пусть необходимо {168} переключить состояние бита 5 числа А. Это будет сделано операцией A xor 32 , где 32 = 25.
Исключающее 'ИЛИ' обладает одной особенностью: примененное дважды к одной и той же переменной, оно восстановит ее исходное значение, т.е. всегда выполняется равенство:
A = ( A xor B ) xor B
Следующая группа поразрядных операций — циклические сдвиги (табл. 9.3).
Таблица 9.3
-
Операция
Название
Форма записи
shl
Циклический сдвиг влево на N позиций
A shl N
shr
Циклический сдвиг вправо на N позиций
A shr N
Приоритет операций shl и shr одинаков и среди всех остальных невысок (см. табл. 9.1). Поэтому, как правило, выражения сдвига должны быть заключены в скобки.
Суть операций shr и shl одинакова: они сдвигают двоичную последовательность значения A на N ячеек (битов) вправо или влево. При этом те биты, которые «уходят» за край разрядности (8, 16 и 32 в зависимости от значения A), теряются, а освободившееся место с другой стороны заполняется нулями (всегда при сдвиге влево и иногда вправо) или единицами (только при сдвиге вправо отрицательных значений типа ShortInt, Integer и LongInt). Например, число с двоичным представлением 11011011 будет трансформироваться при сдвигах влево следующим образом:
( 11011011 shl 0 ) = 11011011
( 11011011 shl 1 ) = 10110110
( 11011011 shl 2 ) = 01101100
( 11011011 shl 3 ) = 11011000
( 11011011 shl 4 ) = 10110000
...
( 11011011 shl 7 ) = 10000000 ( 11011011 shl 8 } = 00000000
Если бы число имело значение типа Word от 256 до 65535, то эффект был бы тем же, только биты «переезжали» бы в поле длиной 16 бит. Для LongInt поле составит 32 бита. При применении операций shl и shr к отрицательным величинам типов ShortInt, Integer, LongInt освобождаемое слева место заполняется единицами.{169}
Конечно, операции сдвига достаточно специфичны и реально нужны только при обработке битовых последовательностей. Пример их использования был дан на рис. 9.1. Там каждый бит последовательно сдвигается к самому левому краю, стирая тем самым все впереди стоящие биты, а затем возвращается в самую правую позицию, стирая тем самым все стоящие правее его биты. В итоге получаем число, равное 0 или 1, в зависимости от содержимого очередного бита.
Операция shl может заменять умножение целых чисел на степени двойки:
J shl 1 = J*2
J shl 2 = J*4
J shl 3 = J*8
Сжатие и кодирование информации. Обычная емкость памяти ПЭВМ (640K) — не так уж велика, как может показаться. Часто вопросы эффективного хранения данных становятся важными для работоспособности программ. Пусть, к примеру, нужно хранить в памяти выборку целых чисел со значениями от 0 до 15, состоящую из 80000 чисел. Так как минимальный тип для каждого числа применительно к Турбо Паскалю — Byte, то всего понадобится 80000 байт. Массив на 80000 байт не пропустит компилятор (максимум, что он сможет «переварить», — это 64K). Кроме того, для представления значения от 0 до 15 достаточно четырех битов, а отводится восемь.
Именно здесь заложена идея и принцип сжатия информации: в одном байте можно уместить два четырехбитовых значения. Тогда понадобится всего 40000 байт, что дает двукратный выигрыш! При этом потери заключаются в необходимости кодирования и декодирования значений. Процедуры преобразования могут иметь вид, показанный на рис. 9.2.
Если бы значения в выборке были целыми и имели диапазон 0..3 (т.е. занимали два бита), то можно было бы в один байт уместить четыре таких значения и т.д. Логика останется той же, изменятся лишь параметры в процедурах преобразования.
К сожалению, подобный подход нельзя применить к вещественным значениям. Единственное, что можно посоветовать — это посмотреть, нужны ли именно вещественные формы хранения данных. Так, если хранится массив вещественных (Real — 6 байт на элемент) значений размеров чего-либо в метрах с точностью до сантиметра, и самое длинное измерение не превосходит 2,55 м, то гораздо эффективнее будет хранить их как массив размеров в сантиметрах. И одно значение будет свободно размещаться в одном байте! Тип Byte занимает 1 байт — экономия шестикратная. {170}
{Процедура кодирования X1 и X2 в один байт (X1, X2<=15) } PROCEDURE Code2to1( X1,X2 : Byte; VAR X1X2 : Byte ); BEGIN X1X2 := X1 + (X2 shl 4 ) END; {Процедура декодирования X1 и X2 из одного байта } PROCEDURE DeCode1to2{ X1X2 : Byte; VAR X1,X2 : Byte ); BEGIN X1 := X1X2 and 15; { X1X2 and $F } X2 := X1X2 shr 4 END; VAR {== ПРИМЕР ВЫЗОВА ==} C, C1, C2 : Byte; BEGIN Code2to1(8,7, C); WriteLn('8 и 7 - кодируются в —> ',C); DeCode1to2(C, C1, C2); WriteLn(C:3, — декодируются в --> ',C1:-3,' и ',C2); ReadLn { пауза до нажатия клавиши ввода } END. |
Рис. 9.2
