Вы находитесь на странице: 1из 152

21.10.

00 16:42
МИНИСТЕРСТВО ОБРАЗОВАНИЯ РФ

МОСКОВСКИЙ ГОСУДАРСТВЕННЫЙ ИНДУСТРИАЛЬНЫЙ УНИ-


ВЕРСИТЕТ

Н.А. Берков

ПРОГРАММИРОВАНИЕ НА VISUAL BASIC

УЧЕБНОЕ ПОСОБИЕ

Издание третье, переработанное

Москва 2001
УДК 681.3.06
ББК 32.973-01
Б48

Берков Н. А. ПРОГРАММИРОВАНИЕ НА VISUAL BASIC: Учебное


пособие. – М: МГИУ, 2001. –152с.

Данное учебное пособие предназначено для студентов и учеников старших классов


из подшефных школ МГИУ, изучающих информатику. Приводится описание основных
типов данных и операторов популярного алгоритмического языка Visual Basic for Ap-
plication. В работе рассмотрено большое число учебных примеров на различные типы
алгоритмов. Все приведенные в учебном пособии примеры отлаживались в среде паке-
та Microsoft Office 2000 под управлением операционной системы Windows 98. Основ-
ное внимание уделено методам программирования стандартных алгоритмов.

Рецензент Пярнпуу А.А., д.ф.-м.н., профессор каф. "Вычислительная ма-


тематика и программирование" (МГАИ)

Редактор

ЛР № 020407 от 12.02.97
Подписано в печать Сдано в производство
Формат бумаги 60 x 90/16 Бум. множит.
Усл. печ. л. 8,25 Уч.-изд. л. 8,75 Тем. план
Тираж 500 Заказ
РИЦ МГИУ , 109280, Москва, Автозаводская, 16
ISBN 5-276-00002-6 © Н.А.Берков, 2001
© МГИУ, 2001

2
Введение
Алгоритмический язык Basic был разработан в 1964 году как алгорит-
мический язык для начинающих пользователей ЭВМ. С тех пор было на-
писано несколько тысяч версий языка Basic для самых различных типов
ЭВМ. Особой популярности он достиг на этапе появления бытовых и пер-
вых персональных компьютеров. Эти компьютеры имели малый объем
оперативной памяти, в который необходимо было поместить ядро опера-
ционной системы, программу пользователя ЭВМ, данные для программы и
еще программу перевода с алгоритмического языка на машинный язык. В
этих компьютерах Basic служил в качестве операционной системы и про-
граммы переводчика программ пользователя в машинный язык. С появле-
нием современных ПЭВМ язык Basic был существенно модернизирован
под их значительно возросшие возможности. Современная версия алго-
ритмического языка Basic имеет название Visual Basic(VB) и является дос-
таточно мощным инструментом для решения широкого круга задач: от
учебных задач для начинающих пользователей до объектно-
ориентированных программ.
Язык Visual Basic разработан фирмой Microsoft и практически является
стандартом визуального проектирования приложений. Ядро основных
операторов Visual Basic полностью позаимствовано с более ранней версии
Basic – QBasic. Последняя редакция Visual Basic имеет номер 6.0. Во все
приложения всемирно известного пакета программ Microsoft Office (Word,
Excel, Access и др.), который установлен практически на всех ПЭВМ мира,
встроен вариант языка Visual Basic имеющий название Visual Basic for
Application. На Visual Basic for Application пишутся макросы и процедуры
текстового процессора Word, табличного процессора Excel, системы
управления базами данных Access и т.д. Таким образом, почти на каждом
домашнем компьютере, где установлено любое приложение Microsoft
Office, можно изучать Visual Basic.
Основной целью данного учебного пособия является:
помочь читателям научиться достаточно сложному процессу составления
программ для компьютера. Для этой цели трудно найти другой такой про-
стой и удобный язык программирования. Ныне модные алгоритмические
языки C++ и Java не имеют такого удобного визуального интерфейса с
пользователем как Visual Basic. После ввода имени функции в Visual Basic
сразу же появляется подсказка, дающая информацию о количестве и типах
аргументов. При неправильном синтаксисе оператора, метода или другого
программного элемента сразу же возникают информация об ошибке и кно-
почка, нажав на которую можно получить исчерпывающую информацию
об ошибке.
Для обнаружения ошибок этапа выполнения в Visual Basic имеется
мощный и удобный отладчик. Можно в любом месте программы поставить

3
контрольную точку, в которой на этапе выполнения останавливается про-
грамма. Затем, подведя курсор к любой переменной величине в программе,
мы узнаем ее значение на момент остановки программы. Это освобождает
программиста от многочисленных контрольных печатей на этапе отладки
программы и тем самым экономит время этапа отладки программы.
Данное учебное пособие ориентировано, прежде всего, на учащихся
средних общеобразовательных школ и студентов 1го курса высших учеб-
ных заведений. В программу обучения входит изучение табличного про-
цессора Excel. Одним из мощнейших средств этого процессора является
умение его самостоятельно записывать код макроса в виде программы на
Visual Basic. Следующим сильным средством Excel является простота и
удобство построения графиков, диаграмм и гистограмм при помощи мас-
тера диаграмм. Проведя расчеты при помощи программы, написанной на
VB, и записав значения функции в столбец рабочего листа Excel, можно
вызвать подпрограмму автоматического построения графика решения и за-
тем при необходимости средствами Excel, Word или другого приложения
распечатать на принтере. При работе с VB на Excel удобно результаты вы-
водить в ячейки рабочих листов, которые можно затем анализировать и
обрабатывать.
Все программы, приведенные в данной работе, ориентированы на таб-
личный процессор Excel. Кроме того, работа рассчитана на начинающих
программистов, поэтому приведены только основные типы данных, опера-
торов, методов и свойств объектов VB. Основное внимание в работе уде-
лено стандартным алгоритмам программирования. Поэтому такие сложные
элементы объектно-ориентированного программирования, как инкапсуля-
ция, наследование, полиморфизм, классы и т.д., в данной работе опущены.
В момент написания учебного пособия в России используется три ру-
сифицированные версии пакета Microsoft Office: Office 5.0, Office 97 и Of-
fice 2000. Учитывая, что работа будет опубликована в 2000 году, когда ко-
личество копий пакета Office 97 пока что превышает количество копий
других версий, работа ориентирована, в основном, на пакет Microsoft Of-
fice 97.

4
1. Основные элементы языка
1.1. Первая программа
По установившейся традиции большинство учебников по программи-
рованию начинаются с первой простейшей программы, печатающей при-
ветствие на английском языке: Hello World. На английском, потому что
проще. Многие компиляторы необходимо еще научить понимать русский
алфавит. Чтобы запустить первую программу, необходимо провести доста-
точно трудоемкий процесс инсталляции приложения. Мы предполагаем,
что на Вашем компьютере уже установлено приложение Excel с пакета
Microsoft Office 97 или 2000 и в него включен раздел Visual Basic. Также
предполагается, что читатель уже (хотя бы немножко) знаком с работой в
Excel.
Напишем первую программу, которая выводит предложение:
Привет начинающим программистам!
Для этого необходимо войти в Excel 97, Word 97 или Access 97 и одно-
временно нажать комбинацию из двух клавиш Alt и F11 (Alt+F11). Вы
войдете в стандартное окно Microsoft Visual Basic – Книга1. В главном ме-
ню войдите в подменю Вставка и нажмите на пункт Модуль. (Для кратко-
сти в дальнейшем будем обозначать Вставка/Модуль.) Возникнет окно:
Книга1 Модуль1 (Программа). Существует и второй способ войти в мо-
дуль. Для этого необходимо нажать комбинацию клавиш Alt+F8 или
Сервис/Модуль/ Макросы. При этом появляется окно со списком имею-
щихся в открытом файле программ. После чего, необходимо выбрать уже
существующую программу и нажать кнопку иэменить или ввести имя но-
вой программы и нажать на кнопку создать. В качестве первой программы
после команды Alt+F8, введем в поле имя макроса слово Привет и нажмем
мышкой кнопку Создать. Появиться новое окно, в котором записаны три
строки. Первая строка является заглавием программы, вторая строка явля-
ется пустой и третья строка показывает, что текст программы закончен.
Sub Привет()

End Sub
В пустой строке напишите функцию вывода текста MsgBox с парамет-
ром, содержащим выводимый текст.
Sub привет()
MsgBox (“Привет начинающим программистам!”)
End Sub
Находясь внутри программы, нажмите
функциональную клавишу F5 или на
кнопку Run Sub/UserForm (Выполнить
программу/Форму). Эта кнопка находится
на панели инструментов Visual Basic и
имеет форму треугольника. В возникшем

5
окошке Вы получите результат работы программы.
На этапе отладки программы результаты удобно выводить в окно от-
ладки Debug при помощи метода Print. Вывод в окно отладки удобен еще в
том случае, если полученные результаты необходимо выводить на печать
или включать в другой файл.
Sub привет1()
Debug.Print “Привет начинающим программистам!”
End Sub
Для того чтобы посмотреть результаты работы этой программы, необ-
ходимо войти в меню вид/окно отладки или нажать комбинацию из двух
клавиш Ctrl+G. В результате этих действий откроется окно отладки, в ко-
торую будут выводиться результаты метода Print.
Позже мы еще вернемся к функции MsgBox и методу Print для вывода
числовой информации и для управления выводом.
Если Вы все же работаете с версией Excel 5.0 или 7.0, то для выполне-
ния приведенной выше тестовой программа необходимо вставить Модуль.
Для этого переместите курсор мышки на название любого рабочего листа
таблицы Excel и нажмите правую кнопку мышки. В контекстном меню вы-
берите пункт Модуль. В полученном листе Модуль1 можно писать про-
граммы на VB.
Опытные программисты всегда в текст программы вставляют много-
численные комментарии. Они предназначены для того, чтобы другой про-
граммист мог разобраться в программе, а также, чтобы сам программист
по истечении времени мог легко модернизировать свою же программу.
Комментарии можно вставлять в любом месте программы, поставив
символ ‘ (апостроф), после которого пишется текст комментария. Весь
текст от символа ‘ до конца строки при переводе программы в машинный
код компилятор пропускает. Если вся строка является строкой-
комментарием, то вначале строки пишется слово Rem, а затем текст-
комментарий.
Операторы языка Visual Basic пишутся на отдельной строке. В случае,
если оператор не вмещается на одной строке, его можно продолжить на
следующей строке, добавив в конце продолжаемой строки пробел и сим-
вол подчеркивания. Например:
Debug.Print “Привет начинающим программистам”; _
“Московского Государственного Индустриального Университета!”
Для того чтобы на одной строке написать два коротких оператора их
необходимо разделить символом двоеточия. Например:
A=cos(x) : B=sin(x): c=0
Программы, написанные в Visual Basic for Application, хранятся внутри
файла с документом приложения Word, Excel или Access. Для сохранения
написанной программы в пакете Excel, необходимо вернуться в рабочий
лист и в пункте меню Файл выбрать команду Сохранить как …, а затем в
предложенном окне выбрать папку и ввести имя файла.

6
1.2. Типы данных
Как известно, вся информация в компьютере хранится в виде последо-
вательности бит (т.е. двух символов 0 и 1). Для того чтобы считать инфор-
мацию с определенного адреса, необходимо знать не только начало ин-
формации, но и вид информации. Для каждого вида информации есть
стандарт ее хранения. Видеоинформация имеет один стандарт, аудиоин-
формация — другой, текстовая информация — третий, числовая информа-
ция — четвертый и т.д. Причем для хранения числовой информации в
ЭВМ имеется несколько типов данных. Целые и вещественные числа хра-
нятся в памяти ЭВМ различным способом.

1.2.1. Константы
Константы хранят значения, которые нельзя изменять во время вы-
полнения программы. Константы также могут иметь имена. Константы,
имеющие имена, называются поименованными. В VB имеется ряд встро-
енных поименованных констант. Программист также может создавать свои
константы.
Константы бывают арифметические, логические и символьные.
1.2.1.1. Арифметические константы
Арифметические константы в свою очередь разделяются на целые и
вещественные.
Целая константа представляет собой непустую последовательность
десятичных или шестнадцатеричных цифр, возможно с предшествующим
знаком + или -. Знак + необязателен, поэтому его можно опустить. Если
константа представлена в виде восьмеричного или шестнадцатеричного
целого числа, то перед константой ставится два символа &O (в восьмерич-
ной системе) или &H (в шестнадцатеричной системе).
Примеры целых констант:
1998 -125 0 2737 &HAB1 &O5261 .
Последние три целые константы имеют одно и то же значение, но зада-
ны в различных системах счисления: десятичной, шестнадцатеричной и
восьмеричной.
Вещественные константы соответствуют рациональным числам.
Применяются два типа записи вещественных констант. Константа в
форме с фиксированной запятой, которая записывается в виде целой части
числа, десятичной точки и дробной части.
Например: 12.3 -3.14159 0.0001.
Для очень малых (по абсолютной величине) и очень больших чисел ис-
пользуется степенная форма записи вещественных констант: ±α.βE±γ. В
математике это число записывается в виде: ±α,β·10±γ. При записи знаков —
как числа, так и порядка — символ + можно опускать.
Примеры констант в такой форме: 1.6E-20 -3.14e+20

7
1E100 0.314e1 31.4e-1 .
Диапазон представления констант в степенной форме: от -1,79·10308 до
-4,94·10-324 для отрицательных чисел и от 4,94·10-324 до 1,79·10308 для по-
ложительных чисел.
Степенная форма, в которой целая часть α равна 0, а дробная часть β
начинается с цифры большей 0, называется нормализованной формой
числа.
1.2.1.2. Логические константы
Существуют всего две логические константы True и False, что означает
истина и ложь. Логические константы используются в логических
выражениях.
1.2.1.3. Символьные константы
Символьные константы состоят из последовательности символов, за-
ключенных в кавычки. Длиной константы является количество содержа-
щихся в ней символов. Каждый символ, включая пробел, занимает в памя-
ти 1 байт.
Каждый символ, входящий в символьную константу, имеет код яв-
ляющийся целым числом в диапазоне от 0 до 255. Первые 128 символов
(0–127) набора символов соответствуют буквам и символам стандартной
американской клавиатуры. Эти первые 128 символов совпадают с набором
символов ASCII. Следующие 128 символов (128–255) представляют буквы
национальных алфавитов.
Примеры. “Visual Basic” , “ Привет всем программистам”, “Microsoft
Office 2000”, “2000”.

1.2.2. Переменные величины


В программах написанных на VB часто необходимо вводить обозначе-
ния для некоторых величин. Затем эти величины в программе могут изме-
няться в зависимости от результата действий некоторых команд других ве-
личин. Для хранения значений этих величин в памяти ЭВМ автоматически
отводится необходимое количество ячеек памяти. В большинстве языков
программирования для хранения таких величин используются переменные.
Переменная – именованная область памяти, используемая для хране-
ния данных, значения которых можно изменять в ходе выполнения про-
граммы.
1.2.2.1. Основные типы переменных
Каждая переменная имеет имя (идентификатор), которое обязано быть
уникальным в пределах области видимости этой переменной. Кроме того,
переменная имеет тип, определяющий ее длину и способ ее хранения в па-
мяти ЭВМ.
На имя переменной накладываются некоторые ограничения: начинает-
ся с буквы; не должно содержать пробелов и специальных символов; длина
не более 255 символов; не совпадает с ключевыми словами VB.

8
В современных языках программирования все переменные, используе-
мые в программе, необходимо описать, т.е. сообщить компилятору или ин-
терпретатору тип всех используемых переменных. В этом случае уменьша-
ется количество ошибок, связанных с несоответствием типа переменных.
В VB действует следующее соглашение: если в модуль, в котором на-
писана программа, включен оператор Option Explicit, то необходимо в обя-
зательном порядке описывать все встречающиеся в программе перемен-
ные.
В табл. 1.1 приведены основные типы данных. В первом столбце указа-
но наименование типа данных; во втором столбце — размер памяти, необ-
ходимый для переменной соответствующего типа; в третьем столбце —
диапазон изменения переменных и в четвертом столбце — краткое описа-
ние переменной.
Таблица 1.1
Назва- Раз- Диапазон Описание
ние мер изменения
Byte 1 байт От 0 до 255 Байтовая целая переменная
Integer 2 бай- -32768 до 32767 Короткая целая переменная
та
Long 4 бай- От –2 147 483 648 Длинная целая переменная
та до
2 147 483 647
Currency 8 байт Денежный формат. 4 знака по-
сле запятой и 15 знаков для це-
лой части
38
Single 4 бай- ≈-3,4·10 до - Вещественная переменная с
-45
та 1,7·10 одинарной точностью. (Точ-
-45
≈1,7·10 до ность 7 значащих цифр)
38
3,4·10
Double 8 байт ≈-1,7·10308 до - Вещественная переменная с
4,9·10-324 двойной точностью. (Точность
-324
≈4,9·10 до 15 значащих цифр)
308
1,7·10
Decimal· 14 ≈±79·1028 для це- 29-значное целое десятичное
байт лых чисел и ≈±7,9 число или дробное сверхточное
для дробных чи- число с 28 знаками после запя-
сел той
String Кол- До ≈2 млрд. Строковая переменная произ-
ву символов вольной длины
сим-
волов
String*n n байт Не более 65567 Строковая переменная постоян-
символов ной длины n байт

9
Boolean 2 бай- True или False Логическая переменная
та
Date 8 байт От 1 января 100 г Переменная для описания даты
до 31 декабря
9999 г
Object 4 бай- Передает ссылку (адрес) на
та объект произвольного типа
Variant 16 Переменная хамелеон
байт

Кроме основных типов данных представленных в таблице, имеется


множество второстепенных типов данных. Программист может вводить
свои пользовательские типы данных, в других языках программирования
называемые структурами.
1.2.2.2. Описание типов переменных
Описать переменную – значит заранее сообщить программе имя пере-
менной и ее тип. Для объявления переменной используется оператор Dim
(от слова Dimension – размер):
Dim имя_переменной_1 [As тип], имя_переменной_2 [As тип],…
Если при объявлении переменной не указан тип, то автоматически
создается переменная типа Variant. Эта переменная занимает 16 байт и
ведет себя как хамелеон. Она способна хранить все типы данных. Однако
время обработки данных увеличивается и возможны некоторые
нестыковки. Поэтому лучше явно описывать по возможности все типы
переменных, используемых в программе.
В VB можно описывать типы переменных по первой букве имени пе-
ременной. Для этого имеются следующие операторы описания:
DefBool, DefByte, DefInt, DefLng, DefCur, DefSng, DefDbl, DefDate,
DefStr, DefObj и DefVar.
Вторая группа букв указывает на тип описываемых переменных. Эти
операторы включаются в начале модуля.
Общий вид этих операторов такой:
Defтип диапазонБукв[, диапазонБукв] . . .
Например:
DefStr S
означает, что все переменные, начинающиеся на букву s и описанные в
операторе Dim без указания типа, будут переменными типа String .
Другой пример.
DefLng I-K, N, M : DefBool L
Описывает все переменные, начинающиеся на буквы I, J, K, N и M, как
переменные типа Long, а начинающиеся на L – переменные логического
типа. В предыдущем примере на одной строке написаны два оператора. В
этом случае их необходимо разделять двоеточием.

10
1.3. Операции и выражения
Операции в Visual Basic можно разделить на три категории: арифмети-
ческие, логические и текстовые.

1.3.1. Оператор присваивания


Для того чтобы можно было уже начинать писать простейшие про-
граммы, введем наиболее часто используемый выполняемый оператор
присваивания.
Общая форма оператора присваивания:
A=E
где A – идентификатор переменной, элемент массива, подстрока или
объект; E – арифметическое, логическое или текстовое выражение. В про-
стейшем случае в качестве E может быть константа, имя переменной, эле-
мент массива, подстрока или имя объекта.
Выполнение оператора состоит из трех этапов:
1. Вычисляется правая часть (если это необходимо). Т.е. получается зна-
чение одного из типов, представленного в табл. 1.1.
2. Если тип полученного значения отличен от типа идентификатора A, то
производится автоматический перевод в тип идентификатора A.
3. Окончательно полученное значение заносится в ячейки памяти, отве-
денные компилятором или интерпретатором под переменную A.
Теперь рассмотрим основные операции VB.

1.3.2. Арифметические операции и выражения


Арифметические выражения образуются из арифметических операндов
и арифметических операций. Арифметическими операндами являются
константы, поименованные константы, переменные, элементы массивов,
обращения к функциям, а также выражения заключенные в скобки. Суще-
ствует семь основных бинарных (операций над двумя операндами) ариф-
метических операций. Для их обозначения используются следующие сим-
волы:
1)сложение - + ; 2) вычитание - - ; 3) умножение - * ; 4) деление - /; 5)
целочисленное деление - \ ; 6) вычисление остатка от деления - Mod; 7)
возведение в степень - ^.
В термин "арифметическое выражение" в VB вкладывается тот же
смысл, что и при обычной математической записи, но при этом можно ис-
пользовать лишь символы VB и алгебраические выражения записываются
в одну строку. Знак умножения “*” опускать нельзя. Порядок выполнения
операций такой же, как и в математических формулах. Вместо математи-
ческих переменных при этом вводятся идентификаторы переменных VB.
Для первых четырех операций действуют следующие два правила:
2. Тип результата операций совпадает с наиболее точным из двух опе-
рандов.

11
3. Порядок точности (от меньшей к большей точности) следующий:
Byte, Integer, Long, Single, Currency и Double.
Следует избегать переполнения результата при использовании типов
Byte и Integer.
Пример 1.
Sub Пример1 ()
Dim a as Byte, b as Byte, c as Integer
a=100: b=200 : c=a+b
MsgBox ( c )
End Sub
В этой программе на этапе выполнения будет выдана ошибка, т.к.
происходит переполнение. Результат сложения переменных a и b,
имеющих тип Byte, будет иметь также тип Byte. Однако число 300 не
влезает в один байт (1байт от 0 до 255). Поэтому при выполнении
оператора присваивания c=a+b произойдет ошибка переполнения.
Пример 2.
Sub Пример2 ()
Dim a as Integer, b as Integer, c as Long
a=1000: b=2000 : c=a*b
MsgBox ( c )
End Sub
В этом примере также на этапе выполнения происходит переполнение,
т.к. результат умножения переменных a и b будет иметь тип Integer, однако
число 2000000 не влезает в два байта (число типа Integer имеет диапазон от
–32768 до 32767).
В операциях целочисленного деления (\) и вычисления остатка от деле-
ния (Mod) действует следующее правило: если любой из операндов явля-
ется вещественным числом, то перед операцией операнды автоматически
округляются по обычным математическим правилам.
Результат операции целочисленного деления всегда целое число типа
Byte, Integer или Long, причем остаток отбрасывается.
Например: 100 \ 99 =1; 100 \ 101 =0; 1.45 \ 1.51 = 0; 3.51 \ 1.49 =4.
Операция Mod возвращает остаток от деления двух чисел. 19 Mod 6.51
=5; 19 Mod 6.5 =1; 19.4 Mod 6.99=5; 10 Mod 5 =0; 10 Mod 3 =1.
Для операции возведения в степень (^) действуют следующие правила.
При возведении в степень xy показатель степени у может быть числом
либо целого типа, либо вещественного. В первом случае возведение в сте-
пень осуществляется при помощи произведения y сомножителей, равных
числу x.
При показателе вещественного типа вычисление производится по фор-
муле x y = e y ln x , что возможно лишь для положительных значений аргу-
мента x.

12
Когда в арифметическом выражении подряд идут несколько операций
возведения в степень, вычисление производится слева направо. Так,
2^3^4=4096, а 2^(3^4) =2,41785163922926E+24.
Приведем несколько примеров преобразования арифметических
выражений в записи на VB:
ab
1) x + y α − .
cd
Вместо каждой математической переменной введем идентификатор.
Вместо переменных x, y, a, b, c и d в программе на VB введем идентифика-
торы с именами, соответствующими математическим обозначениям. Сим-
вола α на клавиатуре нет, поэтому переменной α поставим в соответствие
идентификатор alpha. Запись на VB данного арифметического выражения
имеет вид:
x+y^alpha-a*b/(c*d);
x 12 + x 2 y
2) ⋅z.
z+ε
После введения вместо математических величин идентификаторов пе-
ременных, запись на VB данного арифметического выражения имеет сле-
дующий вид:
(x1^2+x2*y)/(z+epsilon)*z .

1.3.3. Логические операции и выражения


Логические выражения составляются из логических операндов и логи-
ческих операций. Логическими операндами являются логические констан-
ты, имена логических констант, логические переменные, элементы логиче-
ских массивов, обращения к логическим функциям, логические отноше-
ния, а также логические выражения, заключенные в скобки. Существует
шесть основных логических операций:
Not — логическое отрицание;
And — логическое умножение (конъюнкция);
Or — логическое сложение (дизъюнкция);
Imp — логическая импликация;
Xor — логическое исключение;
Eqv — логическая эквивалентность.
Логическая операция Not ⎯ унарная операция (т.е. операция над одним
операндом), а все остальные бинарные. Результат действия логических
операций (таблица истинности) представлена ниже (табл. 1.2).

13
Таблица 1.2
Значение Значение логического выражения
операнда
A B Not A A And B A Or B A Imp B A Xor B A Eqv B
True True False True True True False True
True False False False True False True False
False True True False True True True False
False False True False False True False True
Рассмотрим более подробно первые три наиболее часто используемые
логические операции результаты, которых представлены в табл. 1.2.
1. Первая унарная операция Not принимает значение True, если един-
ственный операнд равен False, и значение False, если операнд равен
True. Например, логическое выражение Not x>0 будет принимать
значение истина, если в момент вычисления данного логического
выражение переменная x меньше либо равна нулю.
2. Вторая операция And принимает значение True, если оба операнда
A и B равны True, а если хотя бы один из них равен False, то резуль-
тат равен False. Например, логическое выражение x>10 And x>0 бу-
дет принимать значение истина, если в момент вычисления данного
логического выражение переменная x∈(0, 10) и значение ложь в
противном случае.
3. Результат логической операции Or принимает значение True, если
хотя бы один из двух операндов равен значению True. Например,
логическое выражение x^2+y^2<1 Or x^2+y^2>4 будет принимать
значение истина, если в момент вычисления данного логического
выражение точка P, с координатами (x, y), находится внутри круга
радиуса 1, либо вне круга радиуса 2 (центр кругов находится в нача-
ле координат).
Логическим отношением называется выражение, состоящее из двух
простых арифметических выражений, связанных одним из шести символов
<, ≤, >, ≥, =, ≠, определяющих операции отношения. Таким образом, ло-
гическое отношение имеет вид AℜB , где A и B - арифметические операн-
ды, а ℜ - любая из шести операций отношения. В VB для обозначения опе-
раций отношения используются следующие символы:
< ⎯ меньше; <= ⎯ не больше; > ⎯ больше;
>= ⎯ не меньше = ⎯ равно; <> ⎯ не равно.
Приоритет логических операций с учетом скобок:
1) обращение к функциям (высший приоритет); 2) арифметические и
текстовые операции; 3) операции отношения; 4) Not; 5) And ; 6) Or; 7) Xor
8) Eqv; 9) Imp (низший приоритет).

14
Примеры.
В программах на VB довольно часто используются логические выра-
жения, которые принимают значения истина, если математические пере-
менные x, y, z и т.д. заключены в какой-то диапазон:
1. Написать программу, которая выводит значение Истина, если введенное
число x является решение неравенства x 2 − x ≤ 0 и Ложь в противном
случае. Решением данного неравенства является множество действи-
тельных чисел x∈[0,3].
На VB это логическое выражение записывается: x >= 0 And x <=3.
Для проверки данного логического выражения можно предложить сле-
дующую программу.
Sub Пример1()
'Описание используемых в программе переменных
Dim L As Boolean, x As Double
'Ввод значения координаты x
x = 2.5
'Логическое выражение, зависящее от x
L = x >= 0 And x <= 3
'Вывод значения логического выражения
MsgBox L
End Sub
Результатом выполнением данной программы будет значение Истина.
Если изменить значение x=3.5, то программа выведет значение Ложь.
⎧x > 0
⎪y ≤ x − y
2. ⎨
z > x 2 + y2

⎩x + y + z > 1 .
На VB это логическое выражение записывается:
x > 0 And y <= x-y And z > x^2+y^2 And x+y+z > 1
3. x∈(-∞,0] ∪ (1,2] ∪ (10, ∞).
На VB это логическое выражение записывается:
(x <= 0) Or (x > 1 And x <= 2) Or (x > 10)
Скобки в данном логическом выражении необязательны, т.к. приоритет
And выше, чем Or. Здесь скобки используются только для наглядности.
1.3.4. Битовые операции
В случае если в логических выражениях оба операнда являются
числовыми значениями, логические операции выполняют логические
действия над битами. В табл. 1.3 представлены значения всех побитовых
операций.

15
Таблица 1.3
Значение Значение битовой операции
операнда
A B Not A A And B A Or B A Imp B A Xor B A Eqv B
1 1 0 1 1 1 0 1
1 0 0 0 1 0 1 0
0 1 1 0 1 1 1 0
0 0 1 0 0 1 0 1
Примеры побитовых операций удобнее рассматривать для чисел типа
Byte в шестнадцатеричной системе счисления. В шестнадцатеричной сис-
теме каждой цифре соответствует четырехзначное двоичное число. Число
типа Byte находится в диапазоне от 0 до 255. В табл. 1.4 представлены
двоичные коды шестнадцатеричных цифр.
Таблица 1.4
0 1 2 3 4 5 6 7
0000 0001 0010 0011 0100 0101 0110 0111
8 9 A B C D E F
1000 1001 1010 1011 1100 1101 1110 1111

Sub ПримерНаБитовыеОперации()
Dim a As Byte, b As Byte
a = &HC7: b = &H9E
Debug.Print "a= "; a; Tab(20); "b= "; b
Debug.Print "Not a= "; Tab(12); Hex(Not a); Tab(20); Not a
Debug.Print "a And b= "; Tab(12); Hex(a And b); Tab(20); a And b
Debug.Print "a Or b= "; Tab(12); Hex(a Or b); Tab(20); a Or b
Debug.Print "a Imp b= "; Tab(12); Hex(a Imp b); Tab(20); a Imp b
Debug.Print "a Xor b= "; Tab(12); Hex(a Xor b); Tab(20); a Xor b
Debug.Print "a Eqv b= "; Tab(12); Hex(a Eqv b); Tab(20); a Eqv b
End Sub
В приведенной программе результаты работы программы выводятся в
окно отладки Debug. Для просмотра результатов необходимо открыть окно
отладки командой Ctrl+G. В программе используются две незнакомые
функции Tab и Hex. Первая функция подводит начало вывода к указанной
позиции в строке вывода. Вторая функция переводит число в шестнадца-
теричное представление. В программе выводятся значения чисел a и b, а
так же значения различных побитовых операций в шестнадцатеричной и
десятичной системах счисления. Ниже представлены результаты работы
программы, при этом добавлены значения результатов в двоичном пред-
ставлении.
Операция Результат Значения операндов
Hex Dec Bin a b
Not a = 38 56 00111000 11000111

16
a And b 86 134 10000110 11000111 10011110
a Or b DF 223 11011111 11000111 10011110
a Imp b BE 190 10111110 11000111 10011110
a Xor b 59 89 01011001 11000111 10011110
a Eqv b A6 166 10100110 11000111 10011110

1.3.5. Текстовые выражения


Существует всего лишь две текстовые операции: конкатенацией или
сцеплением текстовых строк и операция сравнения строк.
1.3.5.1. Конкатенация строк
Эта операция записывается в виде:
A+B или A & B,
где A и B - текстовые операнды, которые могут быть константой, име-
нем константы, переменной, элементом массива, подстрокой, обращением
к функции или выражением, заключенным в скобки;
+ , &- операция конкатенации или сцепления.
Значением текстового выражения является строка символов, получен-
ная последовательным дописыванием к значению операнда A значения
операнда B. Длина результата равна сумме длин значений операндов.
Пример.
Sub Пример1НаТекстовоеВыражение()
Dim Фамилия As String, Имя As String, Отчество As String
Dim ПолноеИмя As String
Фамилия = "Петров"
Имя = "Иван"
Отчество = "Леонидович"
ПолноеИмя = Фамилия + " " + Имя + " " + Отчество
MsgBox (ПолноеИмя)
End Sub
В приведенной программе, имеющей имя При-
мер1НаТекстовоеВыражение, при помощи операторов присваивания трем
переменным — Фамилия, Имя и Отчество присваиваются соответствую-
щие значения. Затем при помощи операции конкатенации они записыва-
ются в одну переменную с идентификатором ПолноеИмя. Между словами
ставиться пробел. Таким образом, программа напечатает текст Петров
Иван Леонидович.
При конкатенации текстовой и числовой переменных при помощи опе-
рации +, необходимо числовую переменную при помощи функции Str пе-
ревести в текстовую переменную, а затем сделать операцию конкатенации
строк.
Sub Пример2НаТекстовыеВыражения()
Dim s As String
s = "Величина числа e равна " + Str(Exp(1))

17
MsgBox s
End Sub
При использовании операции конкатенации &, компилятор самостоя-
тельно произведет преобразования числовых переменных к строковым пе-
ременным.
Sub Пример3НаТекстовыеВыражения()
Dim s As String: s = "Значение sin(1.5708) = " & Sin(1.57)
Debug.Print s: End Sub

1.3.5.2. Операция сравнения строк

Общий вид этой операции:


A Like B
где A и B текстовые выражения. Если строка совпадает с образцом, то
результатом этой операции будет логическая константа True, а в против-
ном случае – False. При сравнении строк используется типичный порядок
сортировки символов. Коды символов как в латинском, так и в русском
алфавитах расположены по возрастанию. При этом сразу идут все заглав-
ные буквы, а потом прописные. Т.е.
A<B<E<…<Z<a<b<e<…<z<А<Б<В<…<Я< а<б<в<…<я.
Операнды можно задавать в виде шаблонов с использованием следую-
щих обозначений: знак вопроса в шаблоне означает один произвольный
символ; символ * – ноль или более произвольных символов; # – любая
цифра (0 - 9); [список_символов] – любой отдельный символ из списка, за-
ключенного в квадратные скобки; [!список_символов] – любой отдельный
символ, не входящий в список символов, заключенных в квадратные скоб-
ки. В квадратных скобках можно указывать интервалы подряд стоящих
символов через дефис [A-Z] – все заглавные латинские буквы).
Примеры. “a Привет” Like “a*т” – возвращает True. “X” Like “[A-Z]” –
возвращает True. “X” Like “[!A-Z]” – возвращает False. “H3K” Like “H#K”
– возвращает True. “AM5r” Like “A[L-P]#[!a-o]” – возвращает True.
Учитывая, что коды всех букв латинского и русского алфавита распо-
ложены в алфавитном порядке, можно сравнивать две текстовые перемен-
ные, точно так же, как и числовые переменные.
Например, программа, приведенная ниже, выводит результат равный
Истина.
Sub СравнениеТекстовыхПеременных()
MsgBox ("Иванов" < "Петров")
End Sub

18
1.4. Встроенные функции
В VB существует стандартный набор (библиотека) встроенных функ-
ций. Встроенные функции составляют часть языка VB. Компилятор распо-
знает их имена и автоматически вставляет их объектный код в выполняе-
мую программу. Все встроенные функции разобьем на 6 типов: функции
преобразования типов данных, функции округления данных, математиче-
ские функции, символьные функции, битовые функции и встроенные под-
программы. В данной работе приводятся только основные (по мнению ав-
тора) встроенные функции. Полный набор функций можно получить, ис-
пользуя очень удобную и полную справочную информацию. Находясь в
модуле, вызвать помощь по использованию любой функции можно, просто
написав имя интересующей функции и нажав на функциональную клави-
шу F1.
1.4.1. Математические функции
Имя Описание действий функции
функ-
ции
Abs(x) Возвращает значение, тип которого совпадает с типом пе-
реданного аргумента x, равного абсолютному значению
указанного числа
Atn(x) Возвращает значение типа Double, содержащее арктангенс
числа x. Значение, возвращаемое данной функцией, лежит
в диапазоне от -π/2 до π/2 радиан
Cos(x) Возвращает значение типа Double, содержащее косинус,
Sin(x) синус и тангенс угла. Обязательный аргумент x представ-
Tan(x) ляет значение типа Double или любое допустимое числовое
выражение, задающее угол в радианах
Exp(x) Возвращает значение типа Double, содержащее результат
возведения числа e (основание натуральных логарифмов) в
указанную степень. Обязательный аргумент x представляет
значение типа Double или любое допустимое числовое вы-
ражение. Если значение аргумента число превышает 709,
возникает ошибка. Константа e приблизительно равняется
2,718282
Sqr(x) Возвращает значение типа Double, содержащее квадратный
корень указанного числа x. Обязательный аргумент x пред-
ставляет значение типа Double или любое допустимое не-
отрицательное числовое выражение
Log(x) Возвращает значение типа Double, содержащее натураль-
ный логарифм числа x. Обязательный аргумент x пред-
ставляет значение типа Double или любое положительное
допустимое числовое выражение

19
Int(x) Возвращают значение типа, совпадающего с типом аргу-
Fix(x) мента x, которое содержит целую часть числа. Обязатель-
ный аргумент x представляет значение типа Double или
любое допустимое числовое выражение. Обе функции Int и
Fix отбрасывают дробную часть числа и возвращают целое
значение. Различие между функциями Int и Fix состоит в
том, что для отрицательного значения аргумента x функ-
ция Int возвращает отрицательное ближайшее целое число,
меньшее либо равное аргументу, а Fix отрицательное бли-
жайшее целое число, большее либо равное указанному.
Например, функция Int преобразует -8.4 в -9, а функция Fix
преобразует -8,4 в -8
Sgn(x) Возвращает значение типа Variant (Integer), соответствую-
щее знаку указанного числа. Обязательный аргумент x мо-
жет представлять любое допустимое числовое выражение.
Возвращаемые значения:-1, если x <0; 0 при x=0 и 1 при
x>0
Rnd(x) Возвращает значение типа Single, содержащее случайное
число в диапазоне от 0 до 1. Если аргумент x<0, то каждый
раз возвращается одно и то же число, используя аргумент
число в качестве опорного числа. Если аргумент >0 или не
задан, то возвращается следующее случайное число в по-
следовательности. Если аргумент =0, то возвращается слу-
чайное число, совпадающее с числом при предыдущем вы-
зове этой функции. Перед вызовом функции Rnd обычно
используют инструкцию Randomize для инициализации
генератора случайных чисел значением, возвращаемым
системным таймером
Round Round(число, кол-во знаков). Возвращает число, округлен-
ное до указанного количества знаков после запятой
Используя встроенные основные математические функции, можно вы-
числить остальные математические функции по формулам:
Секанс Sec(X) = 1 / Cos(X)
Косеканс Cosec(X) = 1 / Sin(X)
Котангенс Cotan(X) = 1 / Tan(X)
Арксинус Arcsin(X) = Atn(X / Sqr(-X * X + 1))
Арккотангенс Arccotan(X) = Atn(X) + 2 * Atn(1)
Арккосинус Arccos(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)
Логарифм по LogN(X) = Log(X) / Log(N)
основанию N

20
1.4.2. Символьные функции
Символьные функции предназначены для работы с переменными тек-
стового типа. При помощи текстовых функций можно найти определенные
слова в тексте, сделать замену одного слова на другое, поменять местами
буквы или набор букв и т.д.
В табл. 1.5 представлены основные символьные функции. Причем мно-
гие функции могут вызываться с различными количествами аргументов.
При этом некоторые аргументы являются необязательными, т.е. при их от-
сутствии компилятор вызывает функцию без этого параметра. В табл. 1.5
аргументы, которые являются необязательными, заключены в квадратные
скобки.
Таблица 1.5
Имя Краткое описание действий функций и их аргументов
функ-
ции
Mid Mid(string, start[, length]). Возвращается подстрока, содер-
жащая указанное число (length) символов строки string, на-
чиная с символа номер start. При отсутствии последнего ар-
гумента возвращается подстрока от символа start до конца
строки. Mid(“Паровоз”,3,2) – возвращает подстроку ро
Mid(“Паровоз”,5) – возвращает воз
Left Left (string, length). Возвращается левая часть строки длиной
length
Left (“Привет, Маша!”,6) – возвращает слово Привет
Right Right (string, length). Возвращается правая часть строки дли-
ной length
Right(“Привет, Маша!”,5) – возвращает подстроку Маша!
Trim Trim(string). Возвращается строка string без начальных и ко-
нечных пробелов
Ltrim(“ Привет, Маша! ”) –возвращает подстроку Привет
Маша!
Ltrim Возвращается строка string без начальных Ltrim и конечных
RTrim Rtrim пробелов
Trim(“ Привет, Маша! ”) – возвращает подстроку Привет
Маша! .
Ucase Ucase(string). Возвращается строка string, преобразованная к
верхнему регистру. Ucase(“привет”) – возвращает ПРИВЕТ
Lcase Lcase(string). Возвращается строка string, преобразованная к
нижнему регистру. Lcase(“ПРИВЕТ”) – возвращает привет

21
InStr InStr([start,] string, sh [,Comp]). Возвращает целое число,
указывающее позицию первого вхождения строки sh внутри
строки string. Если подстроки sh нет в строке string, то воз-
вращается 0. Необязательный аргумент start показывает на-
чало поиска. Если он опущен, то поиск производится, начи-
ная с первого символа. Аргумент Comp задает способ срав-
нения строк. Он может быть опущен или иметь значение 0
или 1. Если аргумент Comp присутствует, то обязан присут-
ствовать и аргумент start. По умолчанию он равен Comp = 0.
При Comp = 1 буквы на нижнем регистре и верхнем регист-
ре считаются одинаковыми
InStr(“Наша Наташа нашла ”,”на”) – возвращает 13
InStr(1,“Наша Наташа нашла ”,”на”,0) – возвращает 1
InStr(3,“Наша Наташа нашла ”,”на”,0-) – возвращает 6
Space Space(число). Возвращает значение типа String, содержащее
указанное число пробелов. Space(20) – возвращает 20 про-
белов
Len Len(String). Возвращает значение типа Long, содержащее
число символов в строке. Len(“Привет”) – возвращает 5
Chr Chr(Код). Возвращает значение типа String, содержащее
символ, соответствующий указанному коду символа.
Chr(65) – возвращает A. Chr(97) – возвращает a
String String( Число, Символ ). Возвращает значение типа String,
содержащее повторяющуюся строку указанной длины
String(5, "*"); String(5, 42); String(5, "*123"). Все три функ-
ции возвращают строку *****
Str Str(Число). Возвращает значение типа String, являющееся
строковым представлением числа. Str(3.14) – возвращает
строку “3.14”
StrComp StrComp(string1, string2[, Comp]). Возвращает значение типа
Integer, представляющее результат сравнения строк string1 и
string2. Параметр Comp имеет такой же смысл, что и для
функции InStr. Функция возвращает –1,если string1 меньше,
чем string2; 0, если string1 равняется string2; 1, если string1
больше, чем string2
Asc Asc(String). Возвращает значение типа Integer, равное коду
символа для первого символа строки. Asc("A") – возвраща-
ет 65. Asc("a") – возвращает 97. Asc("Apple") – возвращает
65

22
Hex Hex(Число). Возвращает строку, содержащую шестнадцате-
ричное представление аргумента. Hex(2000) – возвращает
шестнадцатеричное число 7D0
Oct Oct(Число). Возвращает строку, содержащую восьмеричное
представление аргумента. Oct(2000) – возвращает
восьмеричное число 3720

1.4.3. Функции преобразования


Все функции преобразования имеют один аргумент. Результатом дей-
ствия функций преобразования является величина, тип которой совпадает
с сокращенным названием функции.
CBool(выражение) – преобразует в логический тип. Если результатом вы-
ражения является ненулевое значение, CBool возвращает True; в против-
ном случае возвращается False.
Dim A, B, C : A = 15: B = 15 : C = CBool(A = B) ' C содержит True.
A = 0 : C = CBool(A) ' C содержит False.
CByte(выражение) – преобразует в байтовый тип.
Dim A As Double , B As Byte : A = 12.78
B = CByte(A) ' A содержит 12.
Ccur(выражение) ) – преобразует в тип Currency.
CDate(выражение) – преобразует в тип Date.
CDbl(выражение) – преобразует в тип Double.
CInt(выражение) – преобразует в тип Integer.
CLng(выражение) – преобразует в тип Long.
CSng(выражение) – преобразует в тип Single.
CVar(выражение) – преобразует в тип Variant.
CStr(выражение) – преобразует в тип String.
Функции преобразования переменных часто используются при вводе
данных с клавиатуры при помощи функции InputBox. Более подробно эта
функция будет рассмотрена в разделе 5.2. Функция InputBox вводит с кла-
виатуры строку текста, введенного в текстовое поле окна ввода данных.
Если вводится не текстовое значение, то его необходимо преобразовать к
определенному типу.
Пример. Ввести с клавиатуры в память переменные различного типа.
Sub ВводСКлавиатурыЗначенийРазличногоТипа()
Dim bol As Boolean, byt As Byte, dat As Date
Dim dou As Double, int1 As Integer, lon As Long
bol = CBool(InputBox("Введитепеременную типа Boolean"))
byt = CByte(InputBox("Введитепеременную типа Byte"))
dat = CDate(InputBox("Введитепеременную типа Date"))
dou = CDbl(InputBox("Введитепеременную типа Double"))
int1 = CInt(InputBox("Введитепеременную типа Integer"))
lon = CLng(InputBox("Введитепеременную типа Long"))

23
Debug.Print "bol= "; bol; " byt="; byt; " dat= "; dat; _
" dou= "; dou; " int="; int1; " lon= "; lon
End Sub

1.4.4. Функции даты и времени


Date – возвращает текущую системную дату.
Now - возвращает текущую дату и время по системному календарю и ча-
сам компьютера.
Month(Дата) – возвращает номер месяца (от 1 до 12).
MonthName(Дата) – возвращает название месяца.
Day(Дата) – возвращает номер дня в месяце (от 1 до 31).
Weekday(Data, ND) – возвращает номер дня в неделе. Первый параметр
задает необходимую дату, а второй параметр указывает, какой день недели
считается первым. В качестве этого параметра можно задать следующие
встроенные константы: vbSunday, vbMonday, vbTuesday, vbWednesday,
vbThursday, vbFriday, vbSaturday.
Year(Дата) – возвращает число типа Integer, соответствующее номеру года
параметра Дата.
Timer – возвращает переменную типа Single, содержащую показание сис-
темных часов текущего времени компьютера в секундах, начиная с начала
суток.
Time – возвращает текущее время на системных часах компьютера.
Hour, Minute и Second(время) – эти три функции возвращают число целых
часов, минут и секунд в параметре время.
Рассмотрим пример демонстрирующий функции даты и время.
Sub ПримерНаФункцииДаты()
Dim d As Date
d = #4/12/1961 10:35:17 PM# 'Время старта
Debug.Print "Сегодня " & Now
Debug.Print "Ю. Гагарина стартовал в космос: "; Chr(10); _
"День - "; Day(d); " Месяц - "; Month(d); MonthName(Month(d)); _
" Год - "; Year(d); Chr(13); "Часы - "; Hour(d); "Минуты - "; _
Minute(d); "Секунды"; Second(d); " День недели - "; _
WeekdayName(Weekday(d, vbMonday)); "."
End Sub
Результаты работы программы:
Ю. Гагарина стартовал в космос:
День - 12 Месяц - 4 Апрель Год - 1961
Часы - 22 Минуты - 35 Секунды 17 День недели – среда.

24
2. Управляющие операторы

Управляющие операторы служат для изменения последовательности


выполнения программы. При помощи таких операторов программируются
разветвляющиеся и циклические алгоритмы.
2.1. Оператор безусловного перехода
Общая форма:
GO TO m
где m - метка оператора данного программного модуля.
В VB любой оператор можно пометить, поставив перед ним метку.
Метка — это произвольная последовательность символов, после которой
ставится символ двоеточие. В первых версиях языка Basic все операторы в
обязательном порядке имели метки в виде числа, поэтому оператор пере-
хода применялся очень часто.
Оператор безусловного перехода является самым простым оператором.
В результате выполнения оператора безусловного перехода происходит
передача управления оператору, помеченному меткой m, который может
быть расположен как выше, так и ниже данного оператора безусловного
перехода.
Примечание. Применение операторов безусловного перехода затруд-
няет чтение программы, а также усложняет процесс оптимизации компи-
лятором объектного кода, поэтому его необходимо применять только в
редких случаях. Существует байка: уровень программиста обратно про-
порционален количеству операторов безусловного перехода. Этот опера-
тор программисты обязаны были использовать при написании программ на
старом Basic. На самом деле во всех программах, написанных на языке
Visual Basic, спокойно можно обойтись без применения этого оператора.
Только в том случае, когда в зависимости от каких-то условий необходимо
перейти в другой участок программы значительно ниже или выше данного
оператора, можно использовать этот оператор. При выходе из внутреннего
цикла также необходимо применять этот оператор. В учебных программах,
приведенных в данной работе, он используется очень редко. Разработчики
нового современного языка Java полностью отказались от этого оператора
как от “вредного”.
2.2. Логические операторы if
Операторы перехода if предназначены для передачи управления опера-
торам программного модуля в зависимости от выполнения некоторого ло-
гического условия.

25
2.2.1. Простой укороченный if
Общая форма:
IF(L) Then S
где L ⎯ логическое выражение; S ⎯ любой выполняемый оператор, от-
личный от блочного оператора if, оператора цикла или другого логическо-
го оператора if.
Примечание. В качестве S могут быть несколько простых операторов, на-
ходящихся на одной строке и разделенных запятой.
Оператор работает следующим образом:
1) вычисляется логическое условие L;
2) если L =True, то выполняется оператор S. Затем выполнение про-
граммы продолжается со следующего оператора, если только оператором S
не является оператор Goto. Если значение выражения L=False, оператор S
не выполняется, а выполняется оператор, следующий за оператором if.
Пример. Вводится номер дня недели. Необходимо напечатать его на-
звание. Если день равен 6 или 7, то напечатать еще и текст (Выходной
день), а если меньше 6, то - (рабочий день).
Sub НазваниеДняНеделиПоНомеру()
Dim nameDay As String, numberDay As Long
numberDay = InputBox(" Введите номер дня недели")
If numberDay = 1 Then nameDay = "Понедельник"
If numberDay = 2 Then nameDay = "Вторник"
If numberDay = 3 Then nameDay = "Среда"
If numberDay = 4 Then nameDay = "Четверг"
If numberDay = 5 Then nameDay = "Пятница"
If numberDay = 6 Then nameDay = "Суббота"
If numberDay = 7 Then nameDay = "Воскресенье"
If numberDay = 6 Or numberDay = 7 Then nameDay = nameDay + _
“(Выходной"
If numberDay<6 Then nameDay = nameDay +"(Рабочий"
MsgBox (nameDay & " день)")
End Sub

Примечание. Данную задачу лучше решать с использованием операто-


ра SELECT, описанного ниже.

2.2.2. Простой полный if


Общая форма:
IF(L) Then S Else S1
где L ⎯ логическое выражение; S и S1 ⎯ любые выполняемые операторы,
отличные от блочного оператора if, оператора цикла или другого логиче-
ского оператора if.
Оператор работает следующим образом:
1) вычисляется логическое условие L;

26
2) если L =True, то выполняется оператор S, а иначе оператор S1. Затем
выполнение программы продолжается со следующего оператора.
Пример. Написать программу, которая введенное с клавиатуры дейст-
вительное число x преобразует в число y по правилу: если x положитель-
ное, то y= lnx, иначе y=0.
Sub ТестПолныйIf()
Dim x As Double, y As Double
x = CDbl(InputBox("Введите число"))
If x > 0 Then y = Log(x) Else y = 0
MsgBox ("x=" & x & " y=" & y)
End Sub

2.2.3. Блочные операторы If


Блочные операторы If предназначены для написания структурирован-
ных программ. При их использовании сокращается количество помечен-
ных операторов и количество операторов Goto, что приводит к более про-
стым программам.
2.2.4. Укороченный блочный If
Общий вид:
IF(L) Then где L - логическое выражение; S - блок операторов. Оператор
S работает следующим образом.
End If Вычисляется логическое выражение L. Если оно истинно, то
выполняется блок операторов S, после чего управление переда-
ется оператору следующему за End If

If(L1) Then Блочные операторы If могут быть вложенными друг в дру-


S1 га. В сложных программах количество вложений может
S2 быть достаточно большим, и бывает трудно разобраться,
If(L2) Then какой оператор End If закрывает данный блок If. В таких
S3 программах следует применять выравнивание всех опера-
If(L3) Then торов, относящихся к одному блоку. А также можно ста-
S4 вить комментарии на некоторые отдаленные End If. При
S5 проверке таких участков программ следует придерживать-
End If ся правил: любой оператор End If относится к ближайше-
S6 му, находящемуся выше незакрытому оператору If. Коли-
End If чество блочных If должно соответствовать количеств End
S7 If. Не допускается пересечение блоков If
End If

Пример. Вводятся три числа a, b и c, являющиеся коэффициентами


квадратного уравнения. Найти его корни. Предусмотреть все возможные
комбинации решений.
Sub РешениеКвадратногоУравнения()

27
' Вводится константа, определяющая машинный нуль.
‘Потеря точности при вычислении дискриминанта
Const Dnull = 1E-20
Dim a As Double, b As Double, c As Double, x1 As Double, _
x2 As Double, d As Double
' Функция CDbl переводит текстовую переменную, возвращаемую
' функцией InputBox, в число
MsgBox ("Введите коэффициент квадратного уравнения a, b и c")
a = CDbl(InputBox("Введите a"))
b = CDbl(InputBox("Введите b"))
c = CDbl(InputBox("Введите c"))
If Abs(a) < Dnull Then GoTo Aeq0 ' Если линейное уравнение
d = b ^ 2 - 4 * a * c ' Дискриминант уравнения
If d > Dnull Then ' Два корня
d = Sqr(d): x1 = (-b + d) / (2 * a): x2 = (-b - d) / (2 * a)
MsgBox (" x1= " & x1 & " x2=" & x2)
Exit Sub 'Выйти из программы
End If
If d < -Dnull Then 'Дискриминант отрицательный
If d < Dnull Then MsgBox ("Дискриминант < 0. Нет решений.")
Exit Sub 'Выйти из программы
End If
'Дискриминант = 0. Уравнение имеет один кратный корень
x1 = -b / (2 * a): MsgBox (" x1= " & x1)
Exit Sub 'Выйти из программы
Aeq0: 'Это пример метки
' Линейное уравнение, т.к. сюда попадаем, если a=0
If Abs(b) > Dnull Then MsgBox ("x=" & -c / b)
If Abs(b) <= Dnull And Abs(c) <= Dnull Then
MsgBox ("Уравнение является тождеством")
Exit Sub
End If
If Abs(b) <= Dnull And Abs(c) > Dnull Then
MsgBox ("Уравнение не имеет решений")
End If
End Sub
3.2.4.1. Блочный полный If

Общий вид:
If(L) Then где L - логическое выражение; S, S1 - блоки операторов.
S Оператор работает следующим образом.
Else Вычисляется логическое выражение L. Если оно истинно,
S1 то выполняется блок операторов S, после чего управление
End If передается оператору следующему за End If. Если L -
ложно, то выполняется блок операторов S1, после чего
управление передается оператору, следующему за End If.

28
3.2.4.2. Составной блочный if

Общий вид:
If(L) Then где L, L1, L2, …,LN - логические выражения; S, S1, S2,
S …,SN, SN+1 - блоки операторов. Оператор работает сле-
ElseIf(L1) THEN дующим образом.
S1 Вычисляется логическое выражение L, если оно истин-
ElseIf (L2) THEN но, то выполняется блок операторов S, после чего управ-
S2 ление передается оператору следующему за End If; ина-
…............................ че вычисляется логическое выражение L1, если оно ис-
ElseIf (LN) THEN тинно, то выполняется блок операторов S1, после чего
SN управление передается оператору, следующему за END
Else If, и т.д. Если все логические выражения L, L1, L2, …,LN
SN+1 ложны, то выполняется блок операторов SN+1. Таким об-
End If разом, выполняется ближайший блок операторов Si, для
которого логическое условие Li принимает значение
"истина", после чего происходит выход из блока. Else и
блок SN+1 необязательны

Пример 1. Решить линейное алгебраическое уравнение a·x=b.


Sub РешениеЛинейногоУравнения()
Dim a As Double, b As Double, x As Double
a = CDbl(InputBox("Введите a"))
b = CDbl(InputBox("Введите b"))
If a <> 0 Then
x = b / a : Debug.Print " x= "; x
ElseIf b <> 0 Then
Debug.Print " Уравнение не имеет решения"
Else
Debug.Print " Любое число является решением уравнения"
End If
End Sub

⎧0, x<−1
Пример 2. Вычислить значение ⎪ cos π x , x ∈[ − 1,0 )
функции: ⎪
y = ⎪⎨ x 2 + 1 , x ∈[ 0 , 2 )
⎪7−x, x ∈[ 2 ,7 )

⎪⎩ 0 , x≥7

Sub ПримерНаСоставнойIf()
Dim x As Double, y As Double

29
x = CDbl(InputBox("Введите аргумент функции"))
If x < -1 Then
y=0
ElseIf x < 0 Then
y = Cos(3.14159 * x)
ElseIf x < 2 Then
y=x^2+1
ElseIf x < 7 Then
y=7-x
Else
y=0
End If
MsgBox ("y= " + Str(y))
End Sub

2.3. Оператор выбора


В разветвляющихся алгоритмах достаточно часто применяется опера-
тор выбора. В зависимости от значения управляющего параметра key
управление программой передается в определенный блок:

Select Case key где key - любое числовое или строковое выражение.
Case Lkey1 Lkey1, Lkey2, … , LkeyN - список значений, которые
S1 могут быть константными выражениями;
Case Lkey2 S1, S2, … , SN, SN+1 - блоки операторов.
S2 Case Else является необязательным.
Список значений Lkeyi можно задавать либо одним
….....................
Case LkeyN значением, либо списком отдельных значений, раз-
SN деленных запятыми, либо диапазоном значений. Case
[Case Else Else ─ необязателен.
SN+1 ] Например: Case 5,12,19 - блок выполняется, если
End Select управляющий параметр равен либо 5, либо 12, либо
19.
Case 2 To 10 - блок выполняется, если управляющий
параметр заключен в диапазоне от 2 до 10.
Case “A“ To ”z“ - блок выполняется, если управляю-
щий параметр символьного типа является латинской
буквой.
Case 5To 10,15, Is > 20 блок выполняется, если
управляющий параметр заключен в диапазоне от 5 до
10 или =15 или >20.
Оператор Select работает следующим образом:
Проверяется, есть ли среди списка Lkey1 значение равное значению пе-
ременной key. Если есть, то выполняется блок операторов S, а после вы-
полнения этих операторов происходит выход из оператора Select. Если нет,
то проверяется следующий список Lkey2. И так далее. Если переменная

30
key не принимает ни одно из перечисленных в Case значений, то если при-
сутствует Case Else, выполняется блок операторов SN+1, а если отсутству-
ет, то происходит выход из оператора Select и выполняется оператор сле-
дующий за End Select.
Пример. Программа должна вывести количество дней в текущем меся-
це и выводит текущее число.
Sub ВывестиКоличествоДнейВТекущемМесяце()
Dim n_day As Long
Select Case Month(Now)
Case 1, 3, 5, 7, 8, 10, 12 ' В эти месяцы 31 день
n_day = 31
Case 4, 6, 9, 11 ' В эти месяцы 30 день
n_day = 30
Case 2
' Если текущий год високосный и месяц февраль
If (Year(Now) Mod 4) = 0 Then n_day = 29 Else n_day = 28
End Select
MsgBox ("В текущем месяце " & Str(n_day) & " дней " & " Сегодня " _
& day(Now) & "." & Month(Now) & "." & Year(Now))
End Sub

2.4. Операторы цикла


Для выполнения циклических процессов используются операторы цик-
ла. В VB существуют несколько операторов цикла. Операторы цикла по-
зволяют многократно повторять вычисления некоторого участка програм-
мы, называемого областью цикла, при разных значениях некоторых пара-
метров.
2.4.1. Оператор цикла For …Next
Общий вид оператора:
For ForPar = begin To end [step inc]
Операторы, составляющие тело цикла:
[Exit For]
Next ForPar
ForPar - переменная целого или действительного типа, называемая па-
раметром цикла;
begin, end – выражения, задающие начальное и конечное значения па-
раметра цикла;
inc - необязательное выражение, задающее приращение параметра цик-
ла, называемое шагом параметра цикла. Если шаг не указывается, то он
(по умолчанию) принимается равным 1.
Оператор работает следующим образом:
1. Параметру цикла ForPar присваивается начальное значение begin.
2. Проверяется выполнение условие sgn(inc)* ForPar ≤ end *sgn(inc), где
sgn - функция определяющая знак аргумента.

31
3. Если это логическое условие принимает значение «истина», то вы-
полняются операторы тела цикла и происходит переход на шаг 4. Если ло-
гическое условие шага 2 принимает значение «ложь», то происходит выход
из цикла, т.е. переход на шаг 5.
4. Параметр цикла получает приращение на величину inc (т.е. выполня-
ется оператор присваивания ForPar = ForPar +inc), и происходит переход на
шаг 2.
5. Выполняется следующий за Next For оператор.
6. Если в теле цикла встречается оператор Exit For – происходит выход
из текущего цикла.
Примечание. При использовании вложенных циклов закрывается вна-
чале ближайший к текущему оператору Next For незакрытый цикл.
Примеры. 100 1
Пример 1. Найти сумму первых 1000 членов ряда Дирихле: ∑
2
.
n =1 n
Sub СуммаРядаДирихле ()
Dim s As Double, n As Long
s = 0 ‘ Обнуление переменной, в которой накапливается сумма
For n = 1 To 100 ‘ Цикл выполняется 100 раз
s = s + 1 / n^2 ‘ Накопление суммы в переменной s
Next n ‘ Увеличение параметра цикла на 1
MsgBox (“Сумма= ” & s) ‘ Вывод результата в стандартное окно
End Sub

Пример 2. Написать программу, которая табулирует функцию y=sin2x


в диапазоне [0,π].
Sub ТабуляцияФункции()
Dim pi As Double, x As Double, h As Double, i As Long
Sheets("Лист1").Select ‘ Выбрать объект рабочий лист “Лист1”
pi = 3.1415926535897: h = pi / 20: Row = 0
For x = 0 To pi + h / 100 Step h
Row = Row + 1 ‘ Номер строки для вывода результатов
Cells(Row, 1) = x ‘ В первый столбец абсциссы функции
Cells(Row, 2) = Sin(x) ^ 2 ‘ Во второй столбец ординаты
Next x
End Sub

Результатом работы данной программы является таблица, состоящая из


двух столбцов по 21 значению в каждом. Для вывода результатов исполь-
зуется рабочий лист Excel c именем Лист1. После завершения работы про-
граммы можно при помощи мастера диаграмм построить график получен-
ной функции. В первый столбец рабочего листа выводятся абсциссы, а во
второй - ординаты точек функции. Для того чтобы организовать вывод ре-
зультатов в рабочий лист, необходимо при помощи метода Select активи-
зировать объект Sheets (рабочий лист) с именем Лист1. Вместо имени

32
Лист1 можно написать имя любого существующего в книге рабочего лис-
та.
При использовании в качестве параметра цикла переменной действи-
тельного типа приращение параметра цикла вычисляется приближенно.
Поэтому конечное значение параметра цикла необходимо немного увели-
чить, чтобы цикл выполнился для конечного значения параметра цикла. В
данном примере конечное значение параметра цикла равно не pi, а чуть
больше pi+h/100.
Пример 3. Найти двухмерную сумму ∑ ∑ 2j + i 3 .
80 50

i +j
i =1 j = 1

Sub ДвухмернаяСумма()
Dim s As Double, i As Long, j As Long
s=0
For i = 1 To 80
For j = 1 To 50
s = s + (i + j) / (i ^ 2 + j ^ 3)
Next j, i ‘ Если оба цикла заканчиваются одновременно
MsgBox ("Сумма= " + Str(s))
End Sub

2.4.2. Оператор цикла While


Общий вид оператора:
While L
Операторы, составляющие тело цикла:
Wend
где L - логическое выражение.
Оператор работает следующим образом.
1. Вычисляется логическое условие L.
2. Если L принимает значение “Истина”, то выполняются операторы,
составляющие тело цикла, а затем происходит переход на пункт 1.
3. Если L=”Ложь”, то происходит переход на оператор стоящий за
оператором Wend.
Более коротко: тело цикла выполняется до тех пор пока L=”Истина”.
Пример. Написать игровую программу. Машина загадывает натураль-
ное случайное трехзначное число. Человек должен за меньшее число по-
пыток угадать его.
Sub УгадайЧисло()
Dim Number As Long, NumberRand As Long, ic As Long
' Генерировать произвольный ряд псевдослучайных чисел
Randomize Timer
ic=0 ‘ В этой переменной накапливаем количество
‘совершенных попыток
' Получение натурального случайного трехзначного числа
NumberRand = 899 * Rnd + 100
' Выполнять пока не угадали полученное случайное число

33
‘NumberRand
While Number <> NumberRand
Number = Val(InputBox("Введите трехзначное число"))
ic = ic + 1
If Number > NumberRand Then MsgBox ("Много") _
Elseif Number < NumberRand Then MsgBox ("Мало")
Wend
Dim S as String : S=” Угадал за " & ic & " попыток."
Select Case ic ' Оценка результата игры
Case Is < 10
S=S+"Гений!”
Case 10 To 15
S=S+"Молодец!"
Case 16 To 20
S=S+"Неплохо!"
Case Else
S=S+" Плохо!”
End Select
MsgBox(S)
End Sub

2.4.3. Операторы цикла Do


Таких операторов пять. Операторы, заключенные между строками с
ключевыми словами Do и Loop, называются телом оператора цикла.

Общий вид Описание работы оператора


Do While L 1. Вычисляется логическое выражение L.
S1 2. Если L — истина, то выполняется тело цикла, иначе
[Exit Do] происходит выход из цикла, т.е. переход на пункт 5.
S2 3. Если среди операторов тела цикла встречается опе-
Loop ратор Exit Do, то происходит переход на пункт 5.
4. Переход на пункт 1.
5. Оператор, следующий за оператором Loop.
Do Until L 1. Вычисляется логическое выражение L.
S1 2. Если L — ложь, то выполняется тело цикла, иначе
[Exit Do] происходит выход из цикла (пункт 5).
S2 3. Если среди операторов тела цикла встречается опе-
Loop ратор Exit Do, то происходит выход из цикла (пункт 5).
4. Переход на пункт 1.
5. Оператор, следующий за оператором Loop.
Do 1. Выполняется тело цикла.
S1 2. Если встречается оператор Exit Do, то происходит
[Exit Do] выход из цикла (пункт 5).
S2 3. Вычисляется логическое выражение L.

34
Loop While L 4. Если L — истина, то выполняется переход на 1,
иначе — выход из цикла (5).
5. Оператор, следующий за оператором Loop.
Do 1. Выполняется тело цикла.
S1 2. Если встречается оператор Exit Do, то происходит
[Exit Do] выход из цикла (пункт 5).
S2 3. Вычисляется логическое выражение L.
Loop Until L 4. Если L — ложь, то происходит переход на 1, иначе
— выход из цикла.
5. Оператор, следующий за оператором Loop.
Do Бесконечный цикл. Выполнять тело цикла до тех пор,
S1 пока не встретится оператор Exit Do.
[Exit Do]
S2
Loop
В таблице S1 , S2 – пустой или непустой блок операторов VB.
Пример. Вычислить значение функции для любого значения аргумента
x, введенного с клавиатуры.

xn
S(x) = ∑ .
n =1 n!
Необходимо найти сумму бесконечного ряда. В развернутом виде эта
сумма имеет вид:
x2 x3 x4
S ( x) = x + + + +… .
1⋅ 2 1⋅ 2 ⋅ 3 1⋅ 2 ⋅ 3 ⋅ 4
Слагаемые данного ряда являются индуктивными. Чтобы получить
очередное слагаемое необходимо предыдущее слагаемое умножить на x и
разделить на число равное номеру очередного слагаемого. Сумму вычис-
ляем до тех пор, пока очередное слагаемое не станет по абсолютной вели-
чине меньше некоторого малого значения.
Sub БесконечнаяСумма()
Dim x As Double, s As Double, a As Double, n As Long
x = CDbl(InputBox("Введите аргумент функции"))
a = x: s = a: n = 1
Do Until Abs(a) < 0.00000001 ‘ До тех пока условие=”Ложь”
n=n+1: a=a*x/n: s=s+a
Loop
MsgBox ("Значение функции=" + Str(s))
End Sub

35
3. Массивы и пользовательские типы данных
3.1. Массивы переменных

Массив - это упорядоченная последовательность однотипных данных,


занимающих непрерывную область памяти, к которой можно обратиться
по имени. Элемент этой последовательности называется элементом масси-
ва.
3.1.1. Описание массива
При описании массива необходимо указать его тип, размерность и диа-
пазон изменения индексов. Размерность массива ⎯ это количество изме-
рений. Бывают одномерные (векторы), двухмерные (матрицы или табли-
цы) и многомерные массивы. Обычно массивы описывают в операторах
описания переменных. Описание массива имеет вид:
Dim name1(d1,d2,...,dn) as тип, name2(d1,d2,...,dk) as тип,…
где name1 - имя массива; d1,d2,...,dn - диапазон изменения индексов; n - раз-
мерность массива. При этом di имеют вид (n1 to n2) (n1 - нижняя, а n2 -
верхняя граница изменения индексов). Размерность массива n не может
превышать 60. Нижняя граница массива n1 — необязательна. Значение
этой границы устанавливается оператором Option Base, который можно
вставлять в начале модуля. По умолчанию Option Base 0, т.е., если n1 опу-
щено, то n1 = 0. Если закодировать Option Base 1 - то по умолчанию n1 =1.
Примеры.
Option base 1
Dim a(10 to 100) As Double, b(3,3) As Long, c(-2 to 4) As Integer
Описываются три действительных массива a, b и c. В массиве a 91
элемент: a10,a11, ..., a100. Массив b является матрицей состоящей из 9 эле-
ментов: b1,1, b2,1, b3,1, b1,2 ,b2,2 , b3,2 , b1,3 , b2,3 , b3,3. В памяти двухмерные
массивы хранятся по столбцам, т.е. массив b хранится, как в приведенной
выше последовательности. Массив c состоит из семи элементов: c-2, c-1, c0,
c1, c2, c3, c4.
Обращение к элементу массива производится по имени массива, за ко-
торым следуют в круглых скобках индексы разделенные запятыми.
Например, чтобы обратиться к элементу матрицы b, стоящему в треть-
ей строке и втором столбце, необходимо написать b(3,2).
Нижнюю и верхнюю размерности массива Name можно узнать при по-
мощи двух функций LBound(Name) и UBound(Name).
Пример. Вводится 100 случайных целых чисел в диапазоне от -100 до
1000. Найти минимальное, среднее арифметическое и максимальное зна-
чения этих чисел. Получить и вывести новый массив, разделив элементы
первого массива на среднее арифметическое первого массива.
Sub МассивСлучайныхЧисел()
Const N = 100 ' Удобно описывать размерности массивов

36
Dim a(N) As Integer, b(N) As Double, s As Double
Dim min As Integer, max As Integer, i As Integer
' это самое большое и самое малое числа типа integer
min = 32767: max = -32768 ‘ или min=&H7FFF: max=&H8000
s = 0 ' Очистить переменную, в которой будем накапливать сумму
Randomize Timer ' Настройка ряда случайных чисел
For i = 1 To N
a(i) = Rnd * 1100 - 100 ' Получение случайного числа [-100,1000]
If a(i) < min Then min = a(i) ' Поиск наименьшего
If a(i) > max Then max = a(i) ' Поиск наибольшего
s = s + a(i) ' Накопление суммы
Next i
s=s/N ' Среднее значение
MsgBox ("Минимальное =" & min & "Среднее =" & s & _
"Максимальное = " & max)
' Массивы a и b лучше выводить в ячейки рабочего листа
Sheets("Лист1").Select ' Перейти на рабочий лист с именем Лист1
For i = 1 To N
b(i) = a(i) / s
Cells(i, 1) = a(i) ' В 1-ый столбец
Cells(i, 2) = b(i) ' Во 2-ой столбец
Next i
End Sub

3.1.2. Задание начальных значений элементам массива


При описании статического массива оператором Dim всем элементам
массива присваиваются начальные значения по умолчанию в зависимости
от типа массива:
0 – для числовых массивов;
“” – пустая строка для символьных массивов;
false – для логических массивов;
0:00:00 – для переменных типа Date.
Часто необходимо присвоить элементам массива начальные данные,
отличные от значений по умолчанию. Для решения этой задачи существует
много методов. Приведем шесть наиболее часто встречающихся:
1. При помощи оператора присваивания задать всем элементам массива
начальные значения.
2. В цикле прочитать значения элементов с рабочего листа или с файла и
присвоить элементам массива.
3. Вычислить по формулам.
4. Задать при помощи функции Array.
5. Задать при помощи датчика случайных чисел.
6. При помощи функции InputBox.
Пример. Ввести 10 действительных чисел и подсчитать количество чи-
сел меньших среднеарифметического значения этих чисел.

37
Рассмотрим все 6 вариантов задания исходных данных массиву. Пусть
для первых четырех вариантов начальными значениями элементов массива
будут члены арифметической последовательности 1,5; 11,5; 21,5 ; …Для
пятого варианта начальные условия зададим в виде ряда случайных чисел
в диапазоне от 1,5 до 91,5. Для шестого варианта на этапе выполнения про-
граммы пользователь вводит в массив произвольные числа.
Для вычисления количества элементов больше среднеарифметического
значения используется функция NumberEl, которая затем вызывается во
всех пяти основных программах. Оператор Option Base, который надо
вставлять в начале модуля, сообщает, что нумерация элементов массива по
умолчанию начинается с первого, а не с нулевого элемента. Оператор
Option Explicit запрещает использовать неописанные переменные величины.
Option Explicit ' Не разрешать использование неописанные
‘ переменные
Option Base 1 ' Нумерация элементов массивов (по умолчанию) с 1
‘ Функция, возвращающая число элементов массива Mas больших
‘среднеарифметического значения
Function NumberEl(Mas As Variant, N As Long) As Long
Dim s As Double, numb As Long, i As Long
For i = 1 To N ‘ Подсчитать сумму элементов массива Mas
s = s + Mas(i)
Next i
s = s / N ‘ Это среднеарифметическое значение элементов
MsgBox (s) ‘ Вывести его в стандартное окно
‘ Подсчитать количество элементов > среднеарифметического
For i = 1 To N
If Mas(i) > s Then numb = numb + 1
Next i
NumberEl = numb
End Function
Sub ЗаданиеНачальныхЗначенийЭлементовМассива1()
Const N = 10
Dim Mas(N) As Double
‘ Первый вариант задания начальных значений
Mas(1) = 1.5: Mas(2) = 11.5: Mas(3) = 21.5: Mas(4) = 31.5: Mas(5) = 41.5
Mas(6) = 51.5: Mas(7) = 61.5: Mas(8) = 71.5: Mas(9) = 81.5
Mas(10) = 91.5
MsgBox (NumberEl(Mas, N))
End Sub
Sub ЗаданиеНачальныхЗначенийЭлементовМассива2()
Const N = 10
Dim Mas(N) As Double, i As Long
‘ Второй вариант задания начальных значений
Sheets("Лист1").Select
' В момент выполнения программы, N ячеек 1-го столбца должны
' быть заполнены необходимыми значениями

38
For i = 1 To N
Mas(i) = Cells(i, 1)
Next i
MsgBox (NumberEl(Mas, N))
End Sub
Sub ЗаданиеНачальныхЗначенийЭлементовМассива3()
Const N = 10
Dim Mas(N) As Double, i As Long
‘ Третий вариант задания начальных значений
For i = 1 To N
Mas(i) = 1.5 + (i - 1) * 10
Next i
MsgBox (NumberEl(Mas, N))
End Sub
Sub ЗаданиеНачальныхЗначенийЭлементовМассива4()
Const N = 10
Dim Mas As Variant, i As Long, s As Double, numb As Long
‘ Четвертый вариант задания начальных значений
Mas = Array(1.5, 11.5, 21.5, 31.5, 41.5, 51.5, 61.5, 71.5, 81.5, 91.5)
MsgBox (NumberEl(Mas, N))
End Sub
Sub ЗаданиеНачальныхЗначенийЭлементовМассива5()
Const N = 10
Dim Mas(N) As Double, i As Long, s As Double, numb As Long
‘ Пятый вариант задания начальных значений
For i = 1 To N
Mas(i) = Rnd * 90 + 1.5
Next i
MsgBox (NumberEl(Mas, N))
End Sub
Sub ЗаданиеНачальныхЗначенийЭлементовМассива6()
Const N = 10
Dim Mas(N) As Double, i As Long
‘ Шестой вариант задания начальных значений
For i = 1 To N
Mas(i) = CDbl(InputBox("Введите " & i & " -тый элемент массива"))
Next i
MsgBox (NumberEl(Mas, N))
End Sub

39
3.2. Динамические массивы
Довольно часто при написании программы программист не знает коли-
чества элементов в массиве, который будет использоваться в программе на
этапе выполнения. Для выхода из этой ситуации возможны несколько пу-
тей.
Первый путь - описать массив с максимально возможной размерностью
и предусмотреть останов программы и сообщение о причинах останова в
случае превышения размерности массива. Для сложных программ, тре-
бующих большого объема памяти, этот путь неприемлем. При этом на эта-
пе компиляции для каждого такого массива (такие массивы называются
статические) отводится оперативная память, соответствующая размеру
массива.
Второй более оптимальный путь - использование динамических масси-
вов.
Массивы, для которых память отводится на этапе выполнения про-
граммы, называются динамическими. Для динамических массивов размер
каждого измерения может устанавливаться на этапе исполнения, а не во
время компиляции программы. При необходимости размер динамических
массивов можно изменять.
Для любого динамического массива необходимо в начале программы
описать его оператором описания типов переменных с пустым значением
размерности: Dim Name() as тип. Затем перед использованием при помо-
щи оператора ReDim задать фактическое количество значений по всем
размерностям.
Пример. Ввести N случайных целых трехзначных чисел и подсчитать
среднее значение их, а также количество чисел больших среднего.
Sub ПримерНаДинамическиеМассивы()
Dim Dm() As Long, s As Double, N As Long, Numb As Long, i As Long
N = Val(InputBox("Введите количество чисел"))
' Создание динамического массива из N элементов
ReDim Dm(1 To N)
s=0
Randomize Timer ' Построить ряд псевдослучайных чисел
For i = 1 To N
Dm(i) = Rnd * 899 + 100 ' Получить целые случайное
‘трехзначное число
s = s + Dm(i)
Next i
s = s / N: Numb = 0
For i = 1 To N
If Dm(i) > s Then Numb = Numb + 1
Next i
MsgBox ("Количество чисел больших среднего значения = " _
+ Str(Numb) + " Среднее значение =" + Str(s))
End Sub

40
В процессе работы программы можно менять размеры динамического
массива оператором ReDim. При этом предыдущие данные теряются. Час-
то возникает необходимость либо увеличить, либо уменьшить размерность
массива, не теряя значения. Для этого необходимо использовать оператор
ReDim с ключевым словом Preserve.
В следующем примере увеличивается размерность существующего
массива DinMas, на 10 элементов не теряя предыдущих значений.
ReDim Preserve Dinmas(Ubound(DinMas)+10)
Этот оператор можно использовать в любом месте программы и любое
количество раз.
Пример. В первом столбце рабочего листа, начиная с первой строки,
находятся произвольное число действительных чисел. Прочитать эти числа
в массив. Найти сколько элементов этого массива принимают значения
больше среднеарифметического значения элементов этого массива.
Sub ПримерНаРасширениеДинамическогоМассива()
Dim a() As Long, N As Long, S As Long, I as Long, NS as Long
N = 0: Sheets("Лист1").Select
ReDim a(10) ' Первые 10 элементов массива
While Cells(N + 1, 1) <> Empty
N=N+1
a(N) = Cells(N, 1)
S = S + a(N)
' Увеличить размерность массива на 10 элементов после каждых ’10
элементов сохраняя значения предыдущих элементов
If (N Mod 10) = 0 Then ReDim Preserve a(N + 10)
Wend
‘ N ─ это окончательная размерность массива A
S=S/N ‘ Среднеарифметическое значение
For I=1 to N
If a(i)>S Then NS=NS+1
Next i
MsgBox("Количество элементов > среднеарифметического=" & NS)
End Sub

41
3.3. Пользовательские типы данных
В современных языках программирования появились сложные, вводи-
мые пользователем типы данных, называемые структурами. Допустим, све-
дения о сотруднике учреждения являются типом данных, в котором опреде-
лены необходимые характеристики: фамилия, имя, отчество, домашний ад-
рес, телефон, возраст, время принятия на работу, день рождения и т.д. Вме-
сто того чтобы для каждого из этих сведений вводить отдельную перемен-
ную, можно ввести одну сложную структурированную переменную. В VB
такие типы данных называют пользовательскими.
Пользовательский тип создается оператором Type, который должен
быть помещен вначале модуля. При этом данное описание действует на все
программы, находящихся во всех программах текущего модуля.
Синтаксис оператора Type является следующим:
[Private | Public ] имяТипаДанных
имяПоля_1 [(размер)] As тип
имяПоля_2 [(размер)] As тип

имяПоля_n [(размер)] As тип
End Type
Параметр имяТипаДанных - имя нового типа данных, введенного поль-
зователем, которое в текущем модуле можно использовать так же, как и
обычные типы данных. Элементы введенного типа данных - имяПоля_1,
имяПоля_2, …, имяПоля_n называются полями и являются либо простыми
переменными, либо массивами, либо переменными других пользователь-
ских типов.
После описания пользовательского типа данных необходимо объявить
одну или несколько переменных этого типа. Для описания переменных ис-
пользуется оператор Dim:
Dim имяПеременной[(размер)] As имяТипаДанных
Для обращения к полям описанной переменной пользовательского типа
требуется указать имя переменной, точку, а затем имя поля. Если перемен-
ная является массивом, то после имени переменной необходимо в круглых
скобках поставить номер элемента массива, к которому обращаемся.
Пример 1. С клавиатуры вводятся координаты двух точек. Написать
программу для вычисления расстояния между ними.
Type Point2 'Введение пользовательского типа
x As Double
y As Double
End Type
Sub ПримерПользовательскогоТипа()
Dim A As Point2, B As Point2, z As Double
A.x = CDbl(InputBox("Введите абсциссу точки A"))
A.y = CDbl(InputBox("Введите ординату точки A"))
B.x = CDbl(InputBox("Введите абсциссу точки B"))

42
B.y = CDbl(InputBox("Введите ординату точки B"))
z = Sqr((B.x - A.x) ^ 2 + (B.y - A.y) ^ 2) ‘ расстояние
MsgBox ("Расстояние между точками A и B равно" & z)
End Sub
Пример 2. Ввести внутри программы переменную, описывающую све-
дения о человеке: фамилию, имя, отчество, телефон и возраст. Сведения о
трех человеках заполнить внутри программы операторами присваивания.
Подсчитать и вывести на монитор средний возраст и среднюю длину их фа-
милий.
Type FullName 'Введение пользовательского типа
firstName As String
lastName As String
pName As String
tell As String
ye As Double
End Type
Sub ТестНаСтруктурныеДанные()
Const N = 3
Dim MName(N) As FullName 'Описание массива структурного типа
' Заполнение полей структуры данными
MName(1).firstName = "Иванов"
MName(1).lastName = "Петр"
MName(1).pName = "Андреевич"
MName(1).tell = "277-xx-27"
MName(1).ye = 45
MName(2).firstName = "Петрова"
MName(2).lastName = "Мария"
MName(2).pName = "Николаевна"
MName(2).tell = "277-xx-77"
MName(2).ye = 17
MName(3).firstName = "Александров"
MName(3).lastName = "Петр"
MName(3).pName = "Владимирович"
MName(3).tell = "277-xx-77"
MName(3).ye = 60
Dim s As Double, d As String, k As Integer, I As Integer
For I = 1 To N
s = s + MName(I).ye ‘ Сумма возрастов
Next I
MsgBox ("Средний возраст =" + Str(s / N))
' Все фамилии в одну переменную. Для упрощения алгоритма
‘обработки
d = MName(1).firstName + MName(2).firstName + MName(3).firstName
k=0
For I = 1 To Len(d) ' Количество букв во всех фамилиях
If Mid(d, I, 1) <> " " Then k = k + 1
Next I

43
MsgBox ("Средняя длина фамилии = " + Str(k / N))
End Sub

4. Операторы организации функций и подпрограмм

4.1. Подпрограммы-функции

Подпрограмма-функция является отдельной программной единицей и


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

4.1.1. Оператор FUNCTION


Подпрограмма-функция определяется ключевым словом FUNCTION.
Общая форма подпрограммы-функции:
Function имя( [a1] [, a2] [,…] [,an] ) [As тип]
[неисполняемые операторы (операторы описания)]
[исполняемые операторы, среди которых должен быть оператор
присваивания: имя= значение или выражение]
[Exit Function]
[исполняемые операторы, среди которых должен быть оператор
присваивания: имя= значение или выражение]
End Function
где имя - имя функции; ai - формальные параметры (аргументы). Фор-
мальный параметр ai имеет следующий синтаксис :
[Optional] [ByVal | ByRef] [ParamArray] имяПеременной [() ] [As тип]
[=значениеПоУмолчанию]
Напомним, что выражение в квадратных скобках необязательно; верти-
кальная линия | означает, что выбирается один из предложенных вариантов.
Ключевые слова, стоящие перед именами переменных, называются атри-
бутами переменных. Приведем функции атрибутов аргументов.
Optional – указывает, что при вызове функции данный фактический па-
раметр необязателен.
ByVal – указывает, что параметр передается по значению. Т.е. после вы-
зова функции создается копия параметра, и все операторы тела функции ра-
ботают с этой копией, а перед возращением значения функции значения па-
раметра восстанавливается.

44
ByRef - указывает, что параметр передается по ссылке. Т.е. все измене-
ния параметра внутри функции остаются после выхода из нее. В Visual Basic
по умолчанию параметр передается по ссылке.
ParamArray – указывает, что при вызове функции вместо этого пара-
метра можно включать произвольное число формальных входных парамет-
ров. Формальный параметр с атрибутом ParamArray должен быть последним
в списке.
Формальные параметры могут быть именем простой переменной, име-
нем структуры, массивом.
Замечание. Список параметров может отсутствовать, но скобки обязаны
быть.
Вызов подпрограммы-функции осуществляется так же, как и встроенной
функции.
Пример. Написать программу для вычисления по введенным длинам
сторон треугольника значения его углов в радианах и градусах.
Sub УглыТреугольника() ‘ Основная программа
Dim a As Double, b As Double, c As Double, x As Double
a = CDbl(InputBox("Введите длину первой стороны треугольника"))
b = CDbl(InputBox("Введите длину второй стороны треугольника"))
c = CDbl(InputBox("Введите длину третьей стороны треугольника"))
If (a + b <= c Or b + c <= a Or a + c = b) Then
MsgBox ("Введенные числа не образуют треугольник")
Exit Sub ‘ Выйти из программы
End If
Debug.Print "Углы в радианах"
Debug.Print "alfa="; ugol(b, c, a); " beta="; ugol(a, c, b); _
; " hamma=", ugol(a, b, c)
Debug.Print "Углы в градусах"
Debug.Print " alfa="; Radgrad(ugol(b, c, a)); " beta="; _
Radgrad(ugol(a, c, b)); " hamma="; Radgrad(ugol(a, b, c))
End Sub
‘ Функция, возвращающая угол между двумя сторонами a и b
Function ugol(a As Double, b As Double, c as Double) As Double
ugol = Arccos((a ^ 2 + b ^ 2 - c ^ 2) / (2 * a * b))
End Function
‘ Перевод угла x из радианов в градусы
Function Radgrad(x As Double) As Double
Dim pi As Double
pi = Atn(1) * 4 ' Вычисление числа π
Radgrad = x / pi * 180
End Function
‘ Вычисление функции arccos(x) через встроенную функцию arctg(x)
Function Arccos(x As Double) As Double
Arccos = Atn(-x / Sqr(-x * x + 1)) + 2 * Atn(1)
End Function

45
В данном примере используются три функции: ugol - для вычисления уг-
ла между сторонами треугольника по теореме косинусов; Radgrad - для пе-
ревода угла, заданного в радианах, в угол, заданный в градусах, и функция
Arccos – для арккосинуса угла через арктангенс.
4.1.2. Необязательные параметры
Рассмотрим пример с использованием значений по умолчанию.
Sub testOptinal() ‘ Основная программа для теста
Debug.Print funOpt (1); : Debug.Print funOpt (1, 5);
Debug.Print funOpt (1, 5, 6); : Debug.Print funOpt (1, , 6)
End Sub
Function funOpt(a As Long, Optional b As Long = 7, _
Optional c As Long = 3) As Long
fun3 = a * 100 + b * 10 + c
End Function
В представленном примере рассмотрена функция funOpt, имеющая три
аргумента (a, b и c) и возвращающая сумму 100a +10b + c. Если a, b и c
однозначные числа, то результатом функции будет трехзначное число, где a
– число сотен, b – число десятков, а c – число единиц. Второй и третий ар-
гументы необязательные. Поэтому при вызове функции их можно опускать.
В этом случае они принимают значения по умолчанию b =7, c=3. В основ-
ной программе четыре раза вызывается функция funOpt с различным числом
фактических параметров. В случае если опускается средний параметр, то его
необходимо выделить запятыми. Результаты этой программы печатаются в
окне отладки и равны: 173 153 156 176.

4.1.3. Передача параметров по ссылке и значению


По умолчанию формальные параметры, используемые в подпрограм-
мах и функциях языка Visual Basic, передаются по ссылке или адресу. Это
означает, что для переменных не создается копия внутри подпрограммы
или функции, а все вычисления происходят в ячейках, отведенных компи-
ляторам для формального аргумента. После выхода из подпрограммы или
функции значения фактических параметров соответствуют значению в
подпрограмме после ее завершения. Этот метод имеет достоинства и не-
достатки. К достоинству следует отнести экономию памяти и время. К не-
достаткам – математическая некорректность с точки зрения определения
функции. В математике функция не меняет значения аргумента.
Во многих языках программирования (С++, Паскаль) параметры пере-
даются по значению. Это означает, что после входа в подпрограмму или
функцию создаются копии формальных параметров. Затем выполняются
операторы тела подпрограммы со значениями копией параметров, а после
возврата в вызвавший ее программный модуль происходит восстановление
значений фактических параметров.

46
Для передачи формальных параметров по значению необходимо таким
параметрам присваивать атрибут ByVal.
Рекомендуется по значению передавать входные параметры, а по ссыл-
ке — выходные и параметры, которые являются одновременно и входными
и выходными.

4.1.4. Произвольное число параметров

При использовании атрибута ParamArray в фактические параметры


можно включать произвольное число данных разделенных запятыми. Фор-
мальный параметр с атрибутом ParamArray должен быть последним в спи-
ске. При этом такой формальный параметр в функции используется как мас-
сив типа Variant. В качестве примера напишем функцию, которая вычисляет
среднеарифметическое знвачение всех своих аргументов.
Function Среднеарифметическое(ParamArray a() As Variant) As Double
Dim s As Double
s=0
'Цикл по всем формальным параметрам
'LBound - нижняя граница массива (0 или 1. Зависит от настройки
‘ Option Base)
'UBound - верхняя граница массива
For i = LBound(a) To UBound(a)
s = s + a(i)
Next i
'UBound(a) - LBound(a) + 1 - количество элементов в массиве
Среднеарифметическое = s / (UBound(a) - LBound(a) + 1)
End Function
Sub ТестParamArray()
Debug.Print "Пять параметров типа Integer "; _
Среднеарифметическое(1, 2, 3, 4, 5);”.”
Debug.Print "Четыре параметра типа Double "; _
Среднеарифметическое(3.57, 94.23, 10.22, 11);”.”
End Sub
Результаты работы программы:
Пять параметров типа Integer 3.
Четыре параметра типа Double 29,755.

Рассмотрим еще один пример на использование атрибута ParamArray.


Напишем функцию, которая вычисляет сумму всех фактических аргумен-
тов произвольного типа .

Function СуммаПеременногоЧислаСлагаемыхРазличныхТипов
(ParamArray a() As Variant) As Variant
Dim s As Variant

47
For i = LBound(a) To UBound(a)
s = s + a(i)
Next i
СуммаПеременногоЧислаСлагаемыхРазличныхТипов = s
End Function
Sub ТестParamArray1()
Debug.Print СуммаПеременногоЧислаСлагаемыхРазличныхТипов
("Петров", " ", "Иван", " ", "Леонидович");”.”
Debug.Print СуммаПеременногоЧислаСлагаемыхРазличныхТипов
(1, 2, 3);”.”
Debug.Print СуммаПеременногоЧислаСлагаемыхРазличныхТипов _
(3.57, 94.23, 10.22, 11);”.”
End Sub
Результаты работы программы:
Петров Иван Леонидович.
6.
119,02.

4.1.5. Оператор Exit Function


Если подпрограмму-функцию необходимо по каким-то причинам преры-
вать внутри, то можно использовать оператор Exit Function. При встрече
этого оператора происходит завершение работы функции и передача управ-
ления в то место программы, откуда была вызвана функция. При отсутствии
оператора Exit Function функция выполняется до оператора End Function.
4.1.6. Особенности использования в качестве формальных па-
раметров массивов
Память для формальных параметров определяется компилятором в вы-
зывающих функцию программных модулях (основной программе, другой
функции или подпрограмме), а в функцию передается только адрес начала
массива. Поэтому при описании массивов в функциях есть некоторые осо-
бенности.
Пример1. Написать функцию, которая вычисляет среднее значение эле-
ментов одномерного массива.
Для отладки функции напишем основную программу, в которой с кла-
виатуры введем размерность n динамического массива a; заполним массив
случайными числами в диапазоне от 0 до 100; напечатаем его в окне отладки
и вызовем функцию funs(a, n), в которой будет подсчитано среднее значение
элементов массива a. В качестве первого формального параметра указывает-
ся имя массива, но без размерности.
Sub ОдномерныеМассивыВКачествеФормальныхПараметров()
Dim n As Long, a() As Long, i As Long
n = Val(InputBox("Введите размерность массива"))
Randomize Timer ' Генерация ряда случайных чисел

48
ReDim a(1 To n) ' Создание динамического массива
Debug.Print " Массив a=";
For i = 1 To n ' Заполнение массива случайными числами
a(i) = Rnd * 100
Debug.Print a(i);
Next i
Debug.Print
Debug.Print "Среднее значение="; funs(a, n)
End Sub
' Функция, вычисляющая среднеарифметическое значение массива
Function funs(a() As Long, n As Long) As Double
Dim s As Long, i As Long
s=0
For i = 1 To n
s = s + a(i)
Next i
funs = s / n
End Function
Пример 2. Написать функцию, которая вычисляет среднее значение эле-
ментов двухмерного массива, состоящего из n строк и m столбцов.
Sub ДвухМерныеМассивыВКачествеФормальныхПараметров()
Dim n As Long, a() As Long, i As Long, j As Long, m As Long
n = Val(InputBox("Введите число строк"))
m = Val(InputBox("Введите число столбцов"))
Randomize Timer ‘ Построение ряда псевдослучайных чисел
ReDim a(1 To n, 1 To m) ‘ Двухмерный динамический массив
Debug.Print " Массив a=";: Debug.Print
For i = 1 To n
For j = 1 To m
a(i, j) = Rnd * 100: Debug.Print a(i, j);
Next j: Debug.Print ‘ Перейти на следующую строку
Next i
Debug.Print: Debug.Print "Среднее значение="; funs2(a, n, m): Debug.Print
End Sub
' Функция, вычисляющая среднеарифметическое значение массива
Function funs2(a() As Long, n As Long, m As Long) As Double
Dim s As Long, i As Long, j As Long
‘В этой переменной накапливаем сумму всех элементов матрицы
s=0
For i = 1 To n ‘ Обход по всем элементам матрицы
For j = 1 To m
s = s + a(i, j) ‘ Накапливаем сумму элемента ai,j
Next j, I
‘Вычисляем среднее значение элементов матрицы a
funs2 = s / (n * m)
End Function

49
4.2. Подпрограммы

Подпрограммой называется поименованная часть программы, имеющая


формальные параметры и которую можно вызвать на выполнение с любой
точки основной программы, а также других подпрограмм или функций.
Подпрограмма является расширением функции, и ее можно рассматривать
как математическое отображение n-мерного пространства множества значе-
ний аргументов на m-мерное пространство множества значений отображе-
ния. Обычно подпрограмма имеет входные и выходные параметры. Входные
параметры ⎯ это такие параметры, которые остаются без изменения в под-
программе. Выходные параметры — это параметры, которые при вызове
подпрограммы имеют неопределенное значения, а в ходе выполнения про-
граммы получают определенное значение, зависящее от входных парамет-
ров. Правда, часто параметры бывают одновременно и входными, и выход-
ными. Входные параметры должны иметь атрибуты ByVal.
4.2.1. Оператор описания подпрограммы SUB
Подпрограмма определяется ключевым словом SUB. Общая форма под-
программы почти такая же, как и подпрограммы-функции:
SUB имя( a1 ,a2, …, an )
неисполняемые операторы (операторы описания)
исполняемые операторы, среди которых могут быть
операторы [Exit Sub]
END
где имя - имя подпрограммы; ai - формальные параметры (аргументы).
Формальный параметр ai имеет синтаксис такой же, как и для функций:
[Optional] [ByVal | ByRef] [ParamArray] имяПеременной [() ] [As тип]
[=значениеПоУмолчанию]
При вызове программа выполняется от первого выполняемого оператора
до первого встреченного оператора Exit Sub или до оператора End Sub, кото-
рый является последним оператором в подпрограмме. В подпрограмме имя
подпрограммы не несет на себе числовую информацию.
4.2.2. Оператор вызова подпрограммы CALL
В отличие от функции подпрограмма вызывается отдельным оператором
вызова CALL следующим образом:
CALL ИМЯ(y1,y2,….,yn)
где y1,y2,…,yn - фактические параметры, которые могут быть констан-
тами (если формальные параметры являются только входными параметра-
ми), простыми переменными любого типа, элементами массивов, массивами,
элементами пользовательского типа, арифметическими выражениями, име-
нами подпрограмм или подпрограмм-функций, именами встроенных функ-
ций или подпрограмм. Естественно, между формальными и фактическими
переменными должно быть соответствие типов.

50
4.2.3. Примеры подпрограмм
Пример 1. Три матрицы A, B и C порядка N заполняются случайными
числами в диапазоне от -5 до 5. Вычислить нормы произведения матриц AB,
AC и BC. Норма матрицы равна корню квадратному от суммы квадратов
всех элементов матрицы.
Option Explicit
Option Base 1
Sub НормаМатриц()
Const n = 3 ' Порядок матриц
Dim a(n, n) As Long, b(n, n) As Long, c(n, n) As Long,
Dim d(n, n) As Long, i As Long, j As Long
Randomize Timer
For i = 1 To n ' Заполнение всех массивов случайными числами
For j = 1 To n
a(i, j) = Rnd * 10 - 5
b(i, j) = Rnd * 10 - 5
c(i, j) = Rnd * 10 - 5
Next j, i
' Вывод в окно отладки полученных матриц
Call printMatr(a, n, "матрица a=")
Call printMatr(b, n, "матрица b=")
Call printMatr(c, n, "матрица c=")
' Умножение матриц a на b, результат записать в d
Call MultMatr(a, b, d, n)
Call printMatr(d, n, "матрица ab")
' Вычисление и вывод нормы матрицы d
Debug.Print "Норма матрицы AB="; NormaMatr(d, n)
' Умножение матриц a на c, результат записать в d
Call MultMatr(a, c, d, n)
Call printMatr(d, n, "матрица ac")
' Вычисление и вывод нормы матрицы d
Debug.Print "Норма матрицы AC=", NormaMatr(d, n)
' Умножение матриц b на c, результат записать в d
Call MultMatr(b, c, d, n)
Call printMatr(d, n, "матрица bc")
Debug.Print "Норма матрицы BC=", NormaMatr(d, n)
End Sub
'Подпрограмма для вычисления произведения двух матриц C=AB
Sub MultMatr(a() As Long, b() As Long, c() As Long, n)
Dim s As Double, i As Long, j As Long, k As Long
For i = 1 To n
For j = 1 To n
s = 0 ' Скалярное произведение i-той строки на k-тый столбец
For k = 1 To n
s = s + a(i, k) * b(k, j)
Next k

51
c(i, j) = s
Next j, i
End Sub
' Функция для вычисления нормы матрицы a
Function NormaMatr(a() As Long, n) As Double
Dim s As Double, i As Long, j As Long
s=0
' Вычисление суммы квадратов всех n^2 элементов матрицы
For i = 1 To n
For j = 1 To n
s = s + a(i, j) ^ 2
Next j, i
NormaMatr = Sqr(s) ' Норма матрицы a
End Function
Sub printMatr(a() As Long, n, s As String) ' Вывести на экран массив
Dim i As Long, j As Long
Debug.Print s ' Вывести заглавие
For i = 1 To n
For j = 1 To n ' Вывод i - той строки матрицы a
Debug.Print a(i, j);
Next j
Debug.Print ' Перейти на новую строку
Next i
End Sub
В данном примере приведены две подпрограммы MultMatr и printMatr
и одна функция NormaMatr, которые вызываются несколько раз с различ-
ными фактическими параметрами. В подпрограмме MultMatr четыре фор-
мальных параметра a, b, c и n. Первые три параметра являются двухмер-
ными массивами. При этом a, b и n — только входные параметры, так как
внутри подпрограммы они не изменяются, а массив d является выходным
параметром, поскольку он получается внутри подпрограммы.
Умножение двух матриц A на B производится по формуле
n
cij = ∑ aik bkj ,
k =1
где cij - элементы результирующей матрицы.
В подпрограмме printMatr — два формальных параметра a и s. Эта про-
грамма печатает на одной строке заглавие содержащейся в строковой пе-
ременной s, а на следующих n строках построчно печатает матрицу A.
Необходимо отметить, что для перехода к решению задачи с матрица-
ми другого порядка необходимо всего лишь изменить одну цифру 3 в опе-
раторе Const n = 3. Правилом хорошего тона считается стремление к ра-
зумному универсализму программы.

52
4.2.4. Способы передачи формальных параметров
По умолчанию формальные параметры, используемые в подпрограм-
мах, передаются по ссылке или адресу. Это означает, что для переменных
не создается копия внутри подпрограммы или подпрограммы-функции, а
все вычисления происходят в ячейках, отведенных компиляторам для
формального аргумента. После выхода из подпрограммы или подпрограм-
мы-функции значения фактических параметров соответствуют значению в
подпрограмме.
Для передачи формальных параметров по значению необходимо таким
параметрам присваивать атрибут ByVal.
Пример. Рассмотрим простейшую подпрограмму с двумя формальны-
ми параметрами a и b. Подпрограмма должна переставлять значения фор-
мальных параметров местами. В программе, представленной ниже, приве-
дены три подпрограммы: Swap и SwapByRef, SwapByVal. Первые две пе-
редают оба параметра по ссылке, а третья — по значению. Ниже приведены
результаты работы программы. Перед вызовом всех подпрограмм задаются
значения фактических параметров a=1, b=2. Внутри подпрограмм парамет-
ры правильно обменивают свои значения. После возвращения в вызываю-
щую программу подпрограмма SwapByVal не изменяет значения фактиче-
ских параметров, а остальные подпрограммы инвертируют параметры.

Sub swap(a As Long, b As Long)


Dim c As Long
c = a: a = b: b = c
Debug.Print "Внутри подпрограммы Swap a="; a; " b= "; b
End Sub
Sub SwapByRef(ByRef a As Long, ByRef b As Long)
Dim c As Long
c = a: a = b: b = c
Debug.Print "Внутри подпрограммы SwapByRef a="; a; " b="; b
End Sub
Sub SwapByVal(ByVal a As Long, ByVal b As Long)
Dim c As Long
c = a: a = b: b = c
Debug.Print "Внутри подпрограммы SwapByVal a="; a; " b="; b
End Sub
Sub ОсновнаяПрограмммаТестирующаяТипыПередачиАргументов()
Dim a As Long, b As Long
Call swap(a, b)
Debug.Print "После подпрограммы Swap a="; a; " b="; b
a = 1: b = 2
Call SwapByRef(a, b)
Debug.Print "После подпрограммы SwapByRef a="; a; " b="; b
a = 1: b = 2
Call SwapByVal(a, b)

53
Debug.Print "После подпрограммы SwapByVal a="; a; " b="; b
End Sub

Вывод программы
Внутри подпрограммы Swap a=2 b=1
После подпрограммы Swap a=2 b=1
Внутри подпрограммы SwapByRef a = 2 b=1
После подпрограммы SwapByRef a = 2 b=1
Внутри подпрограммы SwapByVal a = 2 b=1
После подпрограммы SwapByVal a = 1 b=2

5. Ввод-вывод данных

Для работы программ часто необходимо вводить в оперативную память


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

Выводит на экран диалоговое окно, содержащее сообщение, устанав-


ливает режим ожидания нажатия кнопки пользователем, а затем возвраща-
ет значение типа Integer, указывающее, какая кнопка была нажата.
Синтаксис
MsgBox(prompt[, buttons] [, title] [, helpfile, context])
Функция MsgBox содержит один обязательный аргумент (prompt) и
четыре необязательных.
prompt. Строковое выражение, отображаемое как сообщение в диало-
говом окне. Максимальная длина строки prompt составляет приблизитель-
но 1024 символов и зависит от ширины используемых символов. Строко-
вое значение prompt может содержать нескольких физических строк. Для
разделения строк допускается использование символа возврата каретки
(Chr(13)), символа перевода строки (Chr(10)) или комбинации этих симво-
лов (Chr(13) & Chr(10)).
buttons. Необязательный параметр целого типа, указывающий число и
тип отображаемых кнопок, тип используемого значка, основную кнопку и
модальность окна сообщения. Значение по умолчанию этого аргумента
равняется 0.
title. Необязательный параметр являющийся заглавием диалогового ок-
на. Если этот аргумент опущен, в строку заголовка помещается имя при-
ложения.

54
helpfile. Необязательный параметр являющийся строковым выражени-
ем, определяющим имя файла справки, содержащего справочные сведения
о данном диалоговом окне. Если этот аргумент указан, необходимо ука-
зать также аргумент context.
context. Необязательный параметр, являющийся номером соответст-
вующего раздела справочной системы. Если этот аргумент указан, необхо-
димо указать также аргумент helpfile.
Значения переменной buttons можно задавать в виде целого числа, име-
нованной константы или арифметического выражения. Ниже перечислены
допустимые значения аргумента buttons и имена всех поименованных кон-
стант и в скобках ─ их значение:
vbOKOnly (0) — отображается только кнопка "OK".
vbOKCancel (1) — отображаются кнопки "OK" и "Отмена" (Cancel).
vbAbortRetryIgnore(2) — отображаются кнопки "Прервать" (Abort), "По-
вторить" (Retry) и "Пропустить" (Ignore).
vbYesNoCancel (3) — отображаются кнопки "Да" (Yes), "Нет" (No) и
"Отмена" (Cancel).
vbYesNo (4) — отображаются кнопки "Да" (Yes) и "Нет" (No).
vbRetryCancel (5) — отображаются кнопки "Повторить" (Retry) и "Отме-
на" (Cancel).
vbCritical (16) — используется значок "Критическое сообщение".
vbQuestion (32) — используется значок "Предупреждающий запрос".
vbExclamation (48) — используется значок "Предупреждение".
vbInformation (64) — используется значок "Информационное сообщение".
vbDefaultButton1 (0) — основной является первая кнопка.
vbDefaultButton2 (256) — основной является вторая кнопка.
vbDefaultButton3 (512) — основной является третья кнопка.
vbDefaultButton4 (768) — основной является четвертая кнопка.
vbApplicationModal (0) — модальное окно на уровне приложения: чтобы
продолжить работу с текущим приложением, необходимо ответить на дан-
ное сообщение.
vbSystemModal (4096) — модальное окно на уровне системы: все прило-
жения будут недоступны до тех пор, пока пользователь не ответит на дан-
ное сообщение.
Первая группа значений (0–5) указывает число и тип кнопок, отобра-
жаемых в окне диалога, вторая группа (16, 32, 48, 64) задает тип исполь-
зуемого значка, третья (0, 256, 512) определяет кнопку, которая является
основной, а четвертая (0, 4096) — модальность окна сообщения. При опре-
делении значения аргумента buttons следует суммировать не более одного
значения из каждой группы.
Примечание. Данные константы определены в языке Visual Basic для при-
ложений. Использование имен этих констант вместо их значений допуска-
ется в любом месте программы.
Возвращаемые значения MsgBox:

55
vbOK (1) – нажата кнопка OK.
vbCancel (2) — нажата кнопка Отмена (Cancel).
vbAbort (3) — нажата кнопка Прервать (Abort).
vbRetry (4) — нажата кнопка Повторить (Retry).
vbIgnore (5) — нажата кнопка Пропустить (Ignore).
vbYes (6) — нажата кнопка Да (Yes).
vbNo (7) — нажата кнопка Нет (No).
Если указаны оба аргумента — helpfile и context, — пользователь имеет
возможность нажатием клавиши F1 вызвать контекстную справку. Неко-
торые главные приложения, например Microsoft Excel, также автоматиче-
ски добавляют в диалоговое окно кнопку "Справка".
Если окно диалога содержит кнопку "Отмена" (Cancel), нажатие кла-
виши ESC эквивалентно нажатию этой кнопки. Если окно диалога содер-
жит кнопку "Справка" (Help), значит, существует связанный с ним раздел
справочной системы. Однако никакое значение не возвращается до тех
пор, пока не будет нажата какая-либо другая кнопка.
Примечание. Функцию MsgBox с двумя или большим числом аргументов
можно использовать только в выражении. Наличие запятых, соответст-
вующих отсутствующим аргументам, является обязательным.
Пример.
Sub TestMsgBox()
Dim Msg As String, Style As String, Title As String, _
Response As String, MyString As String
Msg = "Обнаружена ошибка.” + Chr(10) +”Продолжить?" ' Сообщение
Style = vbYesNo + vbCritical + vbDefaultButton2 ' Выводить Кнопки
Title = "Пример" ' Заголовок диалового окна
' Вывод сообщения и возврат типа нажатой кнопки.
Response = MsgBox(Msg, Style, Title)
If Response = vbYes Then ' Нажата кнопка "Да" (Yes)
MyString = "Да" ' Выполняет действие
Else ' Нажата кнопка "Нет" (No)
MyString = "Нет" ' Выполняет действие
End If
Response = MsgBox ("Была нажата кнопка "+ Chr(10) + MyString, _ “Воз-
вращаемое значение”)
MsgBox ("Программа закончила работу")
End Sub
В данном примере функция MsgBox вызывается три раза. При первом
вызове функция имеет три первых фактических параметра. Создается окно
диалога с сообщением об ошибке и кнопками "Да" (Yes) и "Нет" (No). Ос-
новной является кнопка "Нет" (No). Значение, возвращаемое функцией
MsgBox, зависит от того, какая кнопка была нажата пользователем. Второе
обращение к функции MsgBox имеет два параметра, а вместо второго па-
раметра стоит пробел. При обращении к функции MsgBox с одним пара-

56
метром допускается упрощенный вызов функции без использования воз-
вращаемого значения.

5.2. Функция InputBox

Выводит на экран диалоговое окно, содержащее сообщение и поле вво-


да, устанавливает режим ожидания ввода текста пользователем или нажа-
тия кнопки, а затем возвращает значение типа String, содержащее текст,
введенный в поле.
Синтаксис:
InputBox(Prompt[, Title] [, Default] [, Xpos] [, Ypos] [, Helpfile, Context])
Функция InputBox содержит один обязательный аргумент (prompt) и
шесть необязательных.
Prompt. Обязательный аргумент — строковое выражение, отображае-
мое как сообщение в диалоговом окне. Строковое значение prompt может
содержать нескольких физических строк. Для разделения строк допуска-
ется использование символа возврата каретки (Chr(13)), символа перевода
строки (Chr(10)) или комбинации этих символов (Chr(13) & Chr(10)).
Title. Необязательный параметр, являющийся строковым выражением,
отображаемым в строке заголовка диалогового окна. Если этот аргумент
опущен, в строку заголовка помещается имя приложения.
Default. Строковое выражение, отображаемое в поле ввода как исполь-
зуемое по умолчанию, если пользователь не введет другую строку. Если
этот аргумент опущен, поле ввода изображается пустым.
Xpos. Числовое выражение, задающее расстояние по горизонтали меж-
ду левой границей диалогового окна и левым краем экрана (в твипах). Ес-
ли этот аргумент опущен, диалоговое окно выравнивается по центру экра-
на по горизонтали.
Ypos. Числовое выражение, задающее расстояние по вертикали между
верхней границей диалогового окна и верхним краем экрана (в твипах).
Если этот аргумент опущен, диалоговое окно помещается по вертикали
примерно на одну треть высоты экрана.
Helpfile. Строковое выражение, определяющее имя файла справки, содер-
жащего справочные сведения о данном диалоговом окне. Если этот аргу-
мент указан, необходимо указать также аргумент Context.
Context. Числовое выражение, определяющее номер соответствующего
раздела справочной системы. Если этот аргумент указан, необходимо ука-
зать также аргумент Helpfile.
Примечание. Функцию InputBox с двумя или большим числом аргу-
ментов можно использовать только в выражении. Наличие запятых, соот-
ветствующих отсутствующим аргументам, является обязательным.

57
Пример 1.
Sub ТестНаФункциюInputBox()
Dim Message As String, Title As String, Default As String, MyValue As String
Message = "Введите число от 2 до 5" ' Сообщение-подсказка.
Title = "Пример использования функции InputBox" ' Заголовок
Default = "5" ' Значение по умолчанию
' Выводит на экран сообщение, заголовок и значение по умолчанию
MyValue = InputBox(Message, Title, Default)
MsgBox( MyValue ) ‘ Вывод введенного значения
' Размещает верхний левый угол окна диалога в точке 100, 100
MyValue = InputBox(Message, Title, Default, 100, 100)
MsgBox( MyValue )
End Sub
В данном примере приведены различные способы получения сведений
от пользователя с помощью функции InputBox. Если четвертый и пятый
аргументы опущены, окно диалога автоматически выравнивается по цен-
тру по соответствующим осям. Переменная MyValue содержит значение,
введенное пользователем, если была нажата кнопка OK или клавиша
ENTER. Если пользователь нажмет кнопку Отмена, функция возвратит
пустую строку.
Функция InputBox вводит текстовую информацию. В случае если не-
обходимо ввести числовую информацию, применяется функция Val, кото-
рая преобразует переменные типа String в Double.
Пример 2. Ввести 10 чисел и найти максимальное из них.
Sub МаксимальноеИз10Чисел()
Const N = 10
Dim Numb As Double, max As Double, i As Long
max = -1.7E+308 ' Это минус бесконечность
For i = 1 To N
Numb = CDbl(InputBox("Введите " & i & "-ое число"))
If Numb > max Then max = Numb
Next i
MsgBox ("Максимальное из введенных чисел =" & max)
End Sub

5.3. Вывод результатов в окно отладки

Часто бывает удобно выводить результаты работы программы в окно


отладки. Для этого используется объект Debug. Этот объект имеет всего
лишь один метод Print, который выводит информацию в окно отладки.
Метод Print выводит текст на панель проверки окна отладки.
Синтаксис
Debug.Print [списокПечати]

58
Синтаксис метода Print содержит следующий указатель объекта и ар-
гумент:
СписокПечати. Выражение или список печатающихся значений. Если
этот аргумент опущен, выводится пустая строка.
Для аргумента списокПечати используется следующий синтаксис и
элементы:
{Spc(n) | Tab(n)} выражение позиция
Spc(n). Указывает количество пробелов n, вставляемых в выводящийся
текст.
Tab(n). Помещает курсор в экранный столбец с номером n. Элемент
Tab без аргумента помещает курсор в первый столбец следующей зоны пе-
чати.
Выражение. Числовое выражение или строковое выражение, опреде-
ляющее выводящийся текст.
Позиция. Указывает позицию, в которой выводится следующий сим-
вол. Точка с запятой (;) помещает курсор непосредственно за последним
выведенным символом. Tab(n) помещает курсор в экранный столбец с но-
мером n. Элемент Tab без аргумента помещает курсор в первый столбец
следующей зоны печати. Если аргумент позиция опущен, следующий
символ выводится в начале новой строки.
Для печати нескольких выражений следует разделять их точкой с запя-
той или пробелом.
Все данные отображаются в окне отладки с учетом национальной на-
стройки. Используется соответствующее форматирование (с указанным
символом десятичного разделителя), а ключевые слова выводятся на язы-
ке, используемом в главном приложении.
Пример. Затабулировать функцию двух переменных z(x,y) на прямо-
угольнике x∈[a, b], y∈[c, d]. В точках, где функция не определена, поста-
вить звездочки.

z = 1 − x2 − y2

Sub ТабуляцияФункций()
Const N = 10, M = 10
Dim a As Double, b As Double, U As Double, hx As Double, hy As Double
Dim c As Double, d As Double, x As Double, y As Double, j As Long
Dim z As Double
a = 0: b = 1: c = 0: d = 1
hx = (b - a) / N: hy = (d - c) / M: ' Приращение координат по оси x и y
j = 0 ' Позиция, с которой выводить очередное значение
For y = c To d + hy / 10 Step hy ' Вывод координат y
j=j+7
‘ Вывести вертикальную линию и 6 левых символов
‘числа Left(Str(y), 6);

59
Debug.Print Tab(j); "|"; Left(Str(y), 6);
Next y
Debug.Print Tab(84); "|" '
Debug.Print String(84, "-") ' Горизонтальная линия
For x = a To b + hx / 10 Step hx ' Цикл по всем строкам таблицы
' Печать значения координаты x
j = 0: Debug.Print Tab(1); Left(Str(x), 5); Tab(6); "|";
For y = c To d + hy / 10 Step hy ' Цикл по всем строкам таблицы
j = j + 7: U = 1 - x ^ 2 - y ^ 2
If U > -0.1e-30 Then ' Если подкоренное выражение больше или ‘рав-
но 0
z = Sqr(Abs(U)) : If z<0.1e-6 Then z=0
Debug.Print Tab(j); "|"; Left(Str(z), 6);
Else ' Если подкоренное выражение меньше 0
Debug.Print Tab(j); "|"; "******";
End If
Next y
Debug.Print Tab(j + 7); "|"
Next x
Debug.Print String(84, "-")
End Sub
Результаты работы данной программы представлены ниже.
|0 |0,1 |0,2 |0,3 |0,4 |0,5 |0,6 |0,7 | 0,8 |0,9 |1
--------------------------------------------------------------------------------------------------------|
0 ||1 |0,9949|0,9797|0,9539|0,9165|0,8660|0,8 |0,7141|0,6 |0,4358|0 |
0,1 ||0,9949|0,9899|0,9746|0,9486|0,9110|0,8602|0,7937|0,7071 |0,5916|0,4242 |******|
0,2 ||0,9797|0,9746|0,9591|0,9327|0,8944|0,8426|0,7745|0,6855 |0,5656 |0,3872|******|
0,3 ||0,9539|0,9486|0,9327|0,9055|0,8660|0,8124|0,7416|0,6480 |0,5196 |0,3162|******|
0,4 ||0,9165|0,9110|0,8944|0,8660|0,8246|0,7681|0,6928 |0,5916 |0,4472|0,1732|******|
0,5 ||0,8660|0,8602|0,8426|0,8124|0,7681|0,7071|0,6244 |0,5099 |0,3316|******|******|
0,6 ||0,8 |0,7937|0,7745|0,7416|0,6928|0,6244|0,5291 |0,3872 |1,0536|******|******|
0,7 ||0,7141|0,7071|0,6855|0,6480|0,5916|0,5099|0,3872 |0,1414|******|******|******|
0,8 ||0,6 |0,5916|0,5656|0,5196|0,4472|0,3316|0 |******|******|******|******|
0,9||0,4358 |0,4242|0,3872|0,3162|0,1732|******|*****|******|******|******|******|
1,0||0 |***** |***** |*****|******|******|******|******|******|******|*****|
----------------------------------------------------------------------------------------------------------
Результаты работы программы представлены в таблице. Для того что-
бы вывести фиксированное количество знаков действительного числа, в
программе используются функции Str для перевода числа в строку и Left
для вывода заказанного числа левых символов строки. Кроме того, для вы-
вода горизонтальной линии используется функция String, которая выводит
84 символа -. Для вывода чисел, начиная с нужной позиции, используется
функция Tab.

60
5.4. Форматирование данных
5.4.1. Функция Format
Для вывода чисел в нужном формате можно еще использовать функ-
цию Format. Эта функция переводит числовую информацию в строковую,
и при этом можно указывать в каком виде нужно выводить эту информа-
цию. Синтаксис функции следующий:
Format(выражение [,формат])
Параметр выражение определяет число, которое необходимо
преобразовать.
Параметр формат задает вид преобразованного числа. Этот параметр
либо является именем стандартного формата, либо состоит из управляю-
щих символов:
0 – в этой позиции печатается цифра;
# – не печатать замыкающие или ведущие нули;
. – десятичная точка, отделяющая целую и дробную часть;
, – разделитель тысяч;
% – вывод числа в процентах. При этом число автоматически
увеличивается в 100 раз;
-+$() пробел – эти символы печатаются точно так, как показаны в стро-
ке формата;
(E- E+ e- e+) – экспоненциальный формат. Число цифр в целой части
определяется числом символов 0 или # до десятичной точки. Число цифр в
дробной части равно числу символов 0 после десятичной точки. Число
цифр в показателе степени определяется числом символов 0 справа от сим-
вола экспоненциального формата (но не больше 3).
5.4.2. Примеры форматов
Пример 1.
Sub ТестОператораФормат1()
Dim a As Double
a = Atn(1) * 4000000 ' Это 1000000* π
Debug.Print a; Format(a, "|# , ##0%"); Format(a, "| #,##0.0"); _
Format(a, "| # ##0руб. 00коп "); Format(a, "| $# ### ##0")
End Sub
Результат этой программы представлен в следующей строке:
3141592,65358979 |314 159 265%| 3 141 592,7| 3141 592руб, 65коп | $3 141 593
Здесь в разном формате пять раз печатается одно и то же число
1000000 π.

61
Пример 2. Вывести числа в экспоненциальном формате.
Sub ТестОператораФормат2()
Debug.Print Format(123456789," .0E-0"); Format(123456789, _
" ##0.00e+0"); Format(123456789, " ## ##0.0000e-00"); _
Format(123456789," # ##0.00e+000"); Format(123456789, _
" .### ##0e+00")
Debug.Print Format(0.001234, "0.00e-0"); Format(0.001234, _
" .00000E+00")
End Sub
Результаты работы данной программы:
,1E9 123,46e+6 12 345,6789e04 1 234,57e+005 ,123 457e+09
1,23e-3 ,12340E-02
В VB можно в одной функции Format задавать различные типы форма-
тов для положительных, отрицательных, нулевых и неопределенных чи-
словых значений.
Пример 3. Вывести числа в формате, зависящем от знака числа.
Sub ТестОператораФормат3()
Dim a As Double, s As String, r
a = Atn(1) * 4000000 ' Это 1000000* π
s = " ##0.00e+0; (-#); 0; Число Не определено"
Debug.Print Format(a, s); Format(-a, s); Format(0, s); Format(r, s)
s = " ##0.00e+0; (-#); 0 "
Debug.Print Format(a, s); Format(-a, s); Format(0, s); Format(r, s)
s = " ##0.00e+0; (-#) "
Debug.Print Format(a, s); Format(-a, s); Format(0, s); Format(r, s)
End Sub
В этом примере в окно отладки три раза выводятся четыре числа: по-
ложительное, отрицательное, нулевое и неопределенное по формату, опре-
деленному в строковой переменной s. Результаты работы программы:
314,16e+4 (-3141593) 0 Число Не определено
314,16e+4 (-3141593) 0
314,16e+4 (-3141593) 000,00e+0
Можно написать личную функцию, которая автоматически выбирает
формат вывода числа в зависимости от диапазона числа.
Пример 4. Вывести числа в формате, зависящем от значения числа.
Напишем вначале функцию fprint, выбирающую формат вывода в за-
висимости от значения аргумента и печатающую аргумент в выбранном
формате.
Function fprint(x As Double)
Dim s As String, a As Double
a = Abs(x)
‘Выбор формата в зависимости от абсолютного значения
‘величины x
If a > 1000000 Then
s = " # ##0.000e-00"

62
ElseIf a > 1000 Then
s = " #0.000e-0"
ElseIf a > 10 Then
s = " ##0.000"
ElseIf a > 0.1 Then
s = " 0.### ##0"
ElseIf a > 0.00001 Then
s = " 0.0000e-0"
Else
s = " 0.0000000e-000"
End If
' Вывод числа a по полученному формату s
Debug.Print Format(x, s); " ";
End Function
Напишем теперь тестирующую программу для широкого диапазона чи-
сел.
Sub ТестОператораФормат4()
fprint (123456789): fprint (123456.789): fprint (123.456789)
fprint (1.23456789): Debug.Print
fprint (0.123456789): fprint (0.000123456)
fprint (1230000000000#): fprint (0.0000000123)
End Sub
В этой программе 8 раз вызывается наша функция fprint. Оператор
Debug.Print необходим для перевода выводимой информации на другую
строку.
Результаты работы данной программы:
1 234,568e05 12,346e4 123,457 1,234 568
0,123 457 1,2346e-4 1 230,000e09 1,2300000e-008
5.4.3. Стандартные форматы
Для вывода различной информации в VB существуют стандартные
именованные числовые форматы:
General Number – отображает число без разделителей групп разрядов.
Currency – отображает значение с разделителями групп разрядов (если
требуется). Обозначение денежной единицы и ее положение относительно
числа определяется текущей национальной настройкой.
Fixed – отображает по крайней мере одну цифру слева и две цифры
справа от десятичного разделителя.
Standard – отображает по крайней мере одну цифру слева и две цифры
справа от десятичного разделителя, а также разделители групп разрядов.
Percent – отображает число, умноженное на 100, со знаком процентов
(%), добавленным справа. Всегда отображает две цифры справа от деся-
тичного разделителя.
Scientific – использует стандартную экспоненциальную нотацию.

63
Yes/No – отображает значение "No" (Нет), если число равно 0; в
противном случае отображает "Yes" (Да).
True/False – отображает значение False, если число равно 0; в про-
тивном случае отображает True.
On/Off – отображает значение "Off" (Выкл), если число равно 0; в
противном случае отображает "On" (Вкл).
Пример 5. Вывести числа в стандартных именованных форматах.
Sub ТестОператораФорматСтандартные()
Dim a As Double: a = Atn(1) * 4000
Debug.Print Format(a, "General Number") + " " + Format(a, _
"Currency") + " " + Format(a, "Percent") + " " + Format(a, "fixed") + _
" " + Format(a, "Scientific")
Debug.Print Format(a, "Yes/No") + " " + Format(0, "Yes/No") + " " _
+ Format(a = a, "True/False") + " " + Format(-a, "On/Off")
End Sub
Результаты работы программы:
3141,59265358979 3 142р. 314159,27% 3141,59 3,14E+03
Да Нет Истина Вкл
5.4.4. Форматы даты и время
Для вывода даты и времени существуют свои спецификации:
: – разделитель компонентов времени. Используется для разделения
компонентов времени (часов, минут и секунд).
/ – разделитель компонентов даты. Используется для разделения ком-
понентов даты (дня, месяца и года);
d – выводит номер дня, содержащий одну или две цифры (1 – 31);
dd – выводит номер дня, содержащий две цифры (01 – 31);
ddd – выводит сокращенное название дня недели (Пн– Вс);
dddd – выводит полное название дня недели (Понедельник–
Воскресенье);
ddddd – отображает соответствующую числу полную дату (день, ме-
сяц и год) согласно краткому системному формату даты;
dddddd – отображает соответствующую числу полную дату (день, ме-
сяц и год) согласно длинному системному формату даты;
w – выводит номер дня недели (по умолчанию, от 1 — для воскресенья
до 7 для субботы).
ww – выводит номер недели года (1 – 54);
m – выводит номер месяца, содержащий одну или две цифры (1 – 12).
Если символ m следует сразу после символов h или hh, выводится число
минут;
mm – выводит номер месяца, содержащий две цифры (01 – 12).
Если символ m следует сразу после символов h или hh, выводится число
минут;
mmm – выводит сокращенное название месяца (Янв – Дек);

64
mmmm – выводит полное название месяца (Январь – Декабрь);
q – выводит номер квартала года (1 – 4);
y – выводит номер дня года (1 – 366);
yy – выводит номер года, состоящий из двух цифр (00 – 99);
yyyy – выводит номер года, состоящий из трех или четырех цифр
(100 – 9999);
h – выводит число часов, состоящее из одной или двух цифр (0 – 23);
hh – выводит число часов, состоящее из двух цифр (00 – 23);
n – выводит число минут, состоящее из одной или двух цифр (0 – 59);
nn – выводит число минут, состоящее из двух цифр (00 – 59);
s – выводит число секунд, состоящее из одной или двух цифр (0 – 59);
ss – выводит число секунд, состоящее из двух цифр (00 – 59);
ttttt – отображает полное время (часы, минуты и секунды) согласно
текущему системному формату времени;
AM/PM – использует 12-часовую шкалу, добавляя прописные буквы
"AM" (до полудня) или "PM" (между полуднем и полуночью);
am/pm – использует 12-часовую шкалу, добавляя строчные буквы
"am" (до полудня) или "pm" (между полуднем и полуночью);
A/P – использует 12-часовую шкалу, добавляя прописные буквы "A"
(до полудня) или "P" (между полуднем и полуночью);
a/p – использует 12-часовую шкалу, добавляя строчные буквы "a" (до
полудня) или "p" (между полуднем и полуночью).
Пример 6.
Sub ТестОператораФорматДатаВремя()
Dim D As Date
D = Now() ' Дата и время в момент вызова функции
Debug.Print D; Format(D, "| yy/m/dd"); Format(D, "|| d,d mmmm, _
yyy")
Debug.Print Format(D, " hh:nn:ss a/p"); Format(D, "| h:nn:ss AM/PM"); _
Format(D, "|| ttttt")
End Sub
Результаты вывода данной программы:
02.01.99 13:19:13 | 99.1.02|| 2,2 января, 992
01:19:13 p| 1:19:13 PM|| 13:19:13

5.5. Ввод-вывод в ячейки рабочего листа


Часто для отладки программы или получения результатов программы с
целью дальнейшей обработки результаты удобнее выводить в ячейки ра-
бочего листа электронной таблицы Excel. Для этого используется свойство
рабочего листа Cells. Cells — это ячейка рабочего листа. Ячейка рабочего
листа имеет две координаты: номер строки и номер столбца. Рабочий лист
табличного процессора Excel 97 имеет 65536 строк и 256 столбцов. Кроме
того, в любой книге Excel имеется несколько рабочих листов, имеющих

65
свои имена. Поэтому при записи данных при помощи свойства Cells необ-
ходимо либо выделить конкретный рабочий лист при помощи свойства ра-
бочей книги Sheets, либо при вызове указывать имя рабочего листа. При
помощи свойства Cells можно выводить результаты в ячейки рабочего лис-
та либо вводить данные с ячеек в оперативную память. Рассмотрим две
программы: первая для вывода результатов, а вторая для ввода данных в
ячейки рабочего листа.
Пример 1. Ввести 10 случайных действительных чисел в диапазоне от
0 до 100 в ячейки рабочего листа ЛИСТ1.
Sub ВводВЯчейки()
Const N = 10
Dim a As Single, i As Long
Sheets("Лист1").Select ‘ Выделить рабочий лист с именем Лист1
Randomize Timer
For i = 1 To N
a = Rnd * 100
'Вывод числа a в первый столбец строки i
Cells(i, 1) = Format(a, "##0.00")
Next i
End Sub
Пример 2. Найти максимальное значение чисел, находящихся в начале
первого столбца.
Sub ВводДанныхИзЯчеекРабочегоЛиста()
Const N = 10
Dim a As Single, i As Long, max As Single, imax As Long
a = -3.4E+38: imax = 0: i = 0
Do ‘ Бесконечный цикл
i=i+1
‘ Прочитать значение в ячейке рабочего листа Лист1 текущей
‘ книги и присвоить прочитанное значение переменной a
a = Worksheets("Лист1").Cells(i, 1)
If a = Empty Then Exit Do ‘ Если ячейка пустая, то выйти из цикла
If a > max Then
‘ Запомнить максимальное значение и номер строки
imax = i: max = a
End If
Loop
' Если в первом столбце были числа, то напечатать максимальное
' значение этих чисел и номер строки, где оно встретилось
‘первый раз
If max > -3.3e38 Then MsgBox (" Максимальное значение = " + _
Str(max) + " в " + Str(imax) + "-той строке")
End Sub

66
5.6. Методы форматирования ячеек рабочего листа

При выводе результатов работы программ в ячейки рабочего листа,


можно применять методы форматирования ячеек. Форматирование приме-
няется:
1. Для выделения цветом некоторых ячеек с целью более привлекательной
наглядности полученных данных.
2. Для подготовки ячеек рабочего листа к приему очередных данных.
3. Для вывода данных определенного типа.
С точки зрения объектно-ориентированного программирования ячейка
рабочего листа является объектом. Объекты имеют различные свойства.
Для изменения свойств объектов используются различные методы и функ-
ции. Для того чтобы узнать какие свойства имеет объект ячейка, необхо-
димо в программе ввести ключевое слово Cells и поставить точку. После
этого возникает окошко, в котором выводится список свойств данного ме-
тода. При помощи мышки, или клавиатуры можно выбрать любое свойство
и нажать клавишу Tab или пробел.
5.6.1. Методы выделения ячеек цветом
Среди всех многочисленных свойств объекта Cells, рассмотрим свойст-
во Interior. Данное свойство определяет способ заполнения ячейки. Это
свойство в свою очередь имеет под свойства. Поэтому свойство Interior
можно считать подобъектом объекта Cells. Список свойств объекта
Interior появляется после набора следующей команды: Cells.Interior. Два
свойства объекта Interior: Color и ColorIndex задают цвет заполнения
ячейки. Рассмотрим более подробно оба этих свойства.
Свойство Color имеет две функции RGB и QBColor.
Функция RGB возвращает номер цвета для свойства Color. Эта функ-
ция имеет три аргумента целого типа: RGB(red, green, blue).
Каждый из этих аргументов принимает значения в диапазоне от 0 до
255. Цвет ячейки, точно так же как и цвет точки на экране монитора, фор-
мируется при помощи смешивания трех основных (базисных) цветов:
красного (red), зеленого (green) и голубого (blue). Смешивая в разных про-
порциях эти три базисные цвета можно получить 2563 = 16777215 различ-
ных оттенков.
Рассмотрим самые распространенные комбинации базисных цветов для
функции RGB.
• RGB( 255, 255 ,255 ) ─ белый.
• RGB( 192 , 192 , 192 ) ─ светло-серый.
• RGB( 128 , 128 , 128 ) ─ серый.
• RGB( 64 , 64 , 64 ) ─ темно-серый.
• RGB( 0 , 0 , 0 ) ─ черный.
• RGB( 255 , 0 , 0 ) ─ красный.

67
• RGB( 255 , 175 , 175 ) ─ розовый.
• RGB( 255 , 200 , 0 ) ─ оранжевый.
• RGB( 255 , 255 , 0 ) ─ желтый.
• RGB( 0 , 255 , 0 ) ─ зеленый.
• RGB( 255 , 0 , 255 ) ─ малиновый.
• RGB( 0 , 255 , 255 ) ─ циан.
• RGB( 0 , 0 , 255 ) ─ синий.
Номер цвета можно задать при помощи шестнадцатеричной константы,
имеющей шесть цифр: &Hbbggrr. При этом первая пара цифр задает
количество голубого цвета, вторая пара ─ количество зеленого цвета и
третья пара ─ количество красного цвета в свойстве Color. Каждая пара
шестнадцатеричных цифр изменяется в диапазоне от 00 до FF, или от 0 до
255 в десятичном представлении. Например, константа &H123456 задает
цвет со значением красного &H12 (18 в десятичном представлении),
зеленого &H34 (52 в десятичном представлении) и голубого &H56 (96 в
десятичном представлении). Т.е. эта константа соответствует следующему
вызову функции RGB(96, 52, 18) или RGB( &H56, &H34, &H12).
Замечание. Если номер цвета задается шестнадцатеричной константой
имеющей меньше пяти цифр, то она хранится в виде целого числа типа In-
teger в дополнительном коде. Поэтому, если первый бит числа в двоичном
формате равен единице, то это отрицательное число. Например: &FF00 =-
256. Для таких чисел можно применить нехитрый прием. Вместо отрица-
тельной константы &HFF00 типа Integer, используем константу $H1FF00-
&10000, имеющую тип Long.
Часто пользователю достаточно палитры, состоящей всего лишь из 16
основных цветов. Для этого имеется функция QBColor(color). Эта возвра-
щает номер цвета в формате RGB для 16 основных цветов. Единственный
аргумент этой функции принимает значение в диапазоне от 0 до 15.
Перечислим название цвета при различных значениях параметра color:
0 ─ белый; 1 ─ синий; 2 ─ зеленый; 3 ─ циан; 4 ─ красный; 5 ─ мали-
новый; 6 ─ желтый; 7 ─ белый; 8 ─ серый; 9 ─ светло-голубой; 10 ─ свет-
ло-серый; 11 ─ светло-зеленый; 12 ─ светло-красный; 13 ─ светло-
малиновый; 14 ─ светло-желтый; 15 ─ светло-белый.
Кроме того, номера восьми цветов можно задавать при помощи кон-
стант.
vbBlack 0x0 Черный
vbRed 0xFF Красный
vbGreen 0xFF00 Зеленый
vbYellow 0xFFFF Желтый
vbBlue 0xFF0000 Голубой

68
vbMagenta 0xFF00FF Малиновый
vbCyan 0xFFFF00 Циан
vbWhite 0xFFFFFF Белый
Свойства ColorIndex для объекта Interior устанавливает номер цвета в
диапазоне от 1 до 56 для цветового заполнения ячейки. Для того чтобы
правильно выбрать номер цвета свойства ColorIndex необходимо выделить
ключевое слово ColorIndex и нажать клавишу вызова контекстной справки
F1. В конце текста, соответствующего справке для этого свойства приве-
дена палитра цветов.
Рассмотрим примеры программ на цветовое выделение ячеек.
Пример 1. Раскрасить 256 ячеек разными цветами из основной 16-ти
цветной палитры.
Sub TestColor1()
Dim i As Integer, NColor As Integer
Sheets("Лист1").Select
'Цикл по 256 ячеек рабочего листа
For i = 1 To 256
NColor = (i - 1) Mod 16 ' Номер цвета в диапазоне от 0 до 15
Cells(i, 1) = Hex(QBColor(NColor)) 'Выводим номер цвета в формате
RGB
' Заполнить ячейку указанным цветом
Cells(i, 1).Interior.Color = QBColor(NColor)
Next i
End Sub
Пример 2. Получить палитру всех возможных расцветок, смешивая три
базисных цвета с шагом 16 по числовому значению каждого цвета.
Решение:
Sub TestColor2()
Dim i As Integer, j As Integer, k As Integer, NColor As Long
Dim Ri As Integer, Rj As Integer
Sheets("Лист2").Select: Cells.Clear
' Форматировать 16 первых столбцов для хранения текстовой
' информации. Данные выводятся в шестнадцатеричном формате
‘ при помощи функции Hex, переводящей десятичное число в
‘ текстовый тип шестнадцатеричного числа
Columns("a:P").NumberFormat = "@"
For i = 1 To 256 Step 16 ' Количество синего цвета
Ri = i \ 16 + 1 'Номер строки для первого блока
For j = 1 To 256 Step 16 ' Количество зеленого цвета
Rj = j \ 16 + 1 'Номер столбца
For k = 1 To 256 Step 16 ' Количество красного цвета
' Формирование номера цвета
NColor = 16 ^ 4 * i + 16 ^ 2 * j + k
‘Вывод номера цвета в шестнадцатеричном формате

69
Cells(Ri+k, Rj) = Hex(NColor)
Cells(Ri+k, Rj).Interior.Color = NColor ' Заполнение цветом
‘ Второй эквивалентный вариант заполнения цветом
‘ Cells(Ri + k, Rj).Interior.Color = RGB(k, j, i)
Next k, j, I
' Автоматический подбор ширины столбцов
Columns("A:P").EntireColumn.AutoFit
End Sub
При помощи данной программы можно подобрать нужный оттенок.
5.6.2. Методы форматирования и очистки ячеек

Ячейки рабочего листа, в которых уже находятся или должны быть


получены данные, необходимо форматировать. Это можно сделать либо
вне программы при помощи различных команд, используя меню Excel, ли-
бо при помощи различных методов, примененных к объектам, содержа-
щим ячейки рабочего листа. К таким объектам относятся:
• WorkSheets ─ рабочий лист.
• Range ─ прямоугольная область данных на рабочем листе.
• Columns ─ столбец рабочего листа.
• Rows ─ строка рабочего листа.
• Cells ─ ячейки рабочего листа.
К этим объектам можно применять некоторые методы меняющие
свойства этих объектов.
Основные методы и свойства объекта WorkSheets.
В пакете Microsoft Office 2000 поддерживается 17 свойств и методов
объектов типа Workshets. Список всех этих свойств и методов автоматиче-
ски появляется при наборе имени объекта. Мы рассмотрим некоторые наи-
более важные из них.
1. Свойство Count выдает количество объектов находящихся в
семействе. В данном случае количество страниц в рабочей книге.
2. Метод Add добавляет рабочий лист в активную книгу. Метод
имеет следующий синтаксис:
WorkSheets.Add [Before | After ] [, Count]
Все параметры являются необязательными. Параметры Before | After
применяются, для того чтобы, вставить объект либо перед указанным в
параметре Count листом, либо после него.
Примеры.
Вставить лист перед первым листом:
Worksheets.Add Before := Worksheets(1)
Команда:= означает ─ присвоить параметру, указанное справа значе-
ние.
Вставить лист в конец книги:
Worksheets.Add After := Worksheets(Worksheets.Count)

70
Вставить лист перед листом с именем Лист6:
Worksheets.Add Before := Worksheets("Лист6")
Параметр Count задает количество добавляемых листов. По умолчанию
добавляется один лист.
3. Метод Select.
Этот метод мы уже достаточно часто применяли для перехода на рабо-
чий лист. При помощи метода Select производится выделение объектов
различных типов.
4. Свойство Name.
В этом свойстве хранится имя рабочего листа.
Приведем пример программы, в котором все рабочие листы получает
значение, равное имени пользователя Excel c добавлением номера листа.
Sub testСвойствоИмяЛиста()
Dim i As Integer
' Обход по всем рабочим листам открытой книги
For i = 1 To Worksheets.Count
'Присвоить свойству Name имена: имя пользователя +
‘номер листа
Worksheets(i).Name = Application.UserName + Trim(Str(i))
Next i
End Sub
На моем персональном компьютере имена листов примут значения:
Берков1, Берков2, Берков3 и т.д.
5. Свойство Visible.
Данное свойство позволяет сделать лист невидимым или наоборот ви-
димым.
Worksheets(1).Visible = True ‘ Сделать 1 рабочий лист видимым
Worksheets(”Лист1”).Visible = False ‘ Сделать лист невидимым
6. Метод Delete.
Данный метод удаляет листы.
Worksheets("Лист1").Delete' Удалить рабочий лист с именем Лист1.
Основные методы и свойства объекта Range, Cells, Columns и Rows.
Все объекты данных типов имеют общие методы и свойства. В Micro-
soft Office 2000 количество методов и свойств для объектов указанных
типов, более ста. Мы рассмотрим только некоторые.
Объектом Range является ячейка или прямоугольник. Объект Range
имеет более ста свойств и методов.
Range(“B10”) ─ одна ячейка.
Range(“A1:D5”) ─ прямоугольник.
1. В свойстве Address хранится диапазон области на рабочем листе.
2. Свойство Formula используется для задания или чтения форму-
лы.
Например:
Range(“B10”).Formula= ”=Sum(“A1:D9”)”
В ячейку B10 записать формулу: ”=Sum(“A1:D9”).

71
3. Свойство Value используется для установки или чтения данных.
4. Метод AutoFit используется для автоматической настройки ши-
рины столбцов и высоты строк, указанного диапазона.
5. Метод Clear используется для очистки области.
Примеры:
Cells.Clear ‘ Очистить все ячейки рабочего листа
Range("a1:G4").Clear ’ Очистить прямоугольную область A1:G4
Columns("a:b").Clear ‘ Очистить столбцы a и b
Rows("2:4").Clear ‘ Очистить строки. Со второй по четвертую
6. Методы ClearComments, ClearContents, ClearFormats и Clear-
Notes позволяют очистить область от комментариев, значений,
форматов и примечаний.
7. Свойство NumberFormat используется для форматирования
объектов.
Примеры.
‘ Первую строку отформатировать для хранения времени
Rows(1).NumberFormat = "hh:mm:ss"
‘Третий столбец форматируется как денежный. Отрицательные
‘ числа выводятся красным цветом
Columns("C").NumberFormat = "$#,##0.00_);[Red]($#,##0.00)"
‘Ячейка A1 ─ общий числовой формат
Range("A1").NumberFormat = "General"
‘ Столбцы E, F и G форматируются числовым форматом с двумя
‘ знаками после запятой и с группировкой по три знака в целой
‘ части
Columns("E:G").NumberFormat = "# ##0.00"
‘Область D1:K1, вместо формата времени переформатируется
‘ на текстовый формат
Columns("D1:K1").NumberFormat = "@"

5.7. Операции ввода-вывода с файлами данных

Иногда приходится производить операции ввода-вывода данных, нахо-


дящихся в файлах организованных на внешних устройствах. В данной ра-
боте ограничимся только простейшими сведениями об операторах работы
с файлами на диске. Рассмотрим общий вид основных операторов работы с
файлами: open, close, print и input.
Для того чтобы начать работу с файлом, его необходимо открыть при
помощи оператора open. Синтаксис оператора open:
Open Путь For Режим [Access доступ] [Блокировка] As [#]Номер-
файла [Len=длина]
Путь − строковое выражение, указывающее имя файла; может содержать
имя каталога или папки и имя диска.

72
Режим − ключевое слово, указывающее режим файла: Append, Binary,
Input, Output или Random. По умолчанию файл открывается для доступа
в режиме Random.
Доступ − ключевое слово, указывающее операции, разрешенные с откры-
тым файлом: Read, Write или Read Write.
Блокировка − ключевое слово, указывающее операции, разрешенные с
открытым файлом другим процессам: Shared, Lock Read, Lock Write и
Lock Read Write.
НомерФайла − допустимый номер файла в интервале от 1 до 511 включи-
тельно. Для определения следующего свободного номера файла можно
использовать функцию FreeFile.
Длина − число, меньшее либо равное 32767 (байт). Для файлов, открытых
в режиме Random, это значение является длиной записи. Для файлов с по-
следовательным доступом это значение является числом буферизуемых
символов.
Чтобы получить возможность выполнить любую операцию вво-
да/вывода, файл необходимо открыть. Инструкция Open резервирует бу-
фер ввода/вывода для файла и определяет режим использования этого бу-
фера.
Если аргумент путь описывает несуществующий файл, такой файл бу-
дет создан при открытии в режиме Append, Binary, Output или Random.
Если файл уже открыт другим процессом и указанный режим доступа
не разрешен, инструкция Open не будет выполнена и возникнет ошибка.
Если аргумент режим имеет значение Binary, то предложение Len иг-
норируется.
Внимание! В режимах Binary, Input и Random можно еще раз открыть
уже открытый файл под другим номером, не закрывая его. В режиме
Append и Output необходимо закрыть файл, чтобы получить возможность
открыть его еще раз под другим номером.
После работы с файлом его необходимо закрыть оператором Close.
Общий вид оператора Close:
Close [списокНомеровФайлов]
Необязательный аргумент списокНомеровФайлов может представлять
один или несколько номеров файлов. При этом используется следующий
синтаксис, где номерФайла представляет любой допустимый номер файла:
[[#]номерФайла] [, [#]номерФайла] . . .
Если аргумент списокНомеровФайлов опущен, закрываются все актив-
ные файлы, открытые с помощью инструкции Open.
При закрытии файла, открытого в режиме Output или Append, в него
добавляется содержимое последнего буфера вывода. Все буферы, связан-
ные с закрытым файлом, освобождаются.
Запись данных в файл производиться операторами Write или Print.
Синтаксис оператора Write:
Write #номерФайла, [списокВывода]

73
НомерФайла − любой допустимый номер файла.
СписокВывода − одно или несколько разделяемых запятыми числовых вы-
ражений или строковых выражений, которые следует записать в файл.
Данные, записанные с помощью инструкции Write #, обычно считыва-
ются из файла с помощью инструкции Input #.
Если аргумент списокВывода опущен, а после аргумента номерФайла
идет только разделитель списка, в файл будет напечатана пустая строка.
Для разделения выражений можно использовать пробелы, точки с запятой
или запятые, которые в данной ситуации полностью эквивалентны.
Ниже приведены правила, которые используются при записи данных в
файл с помощью инструкции Write #. Записанные данные могут быть кор-
ректно прочитаны с помощью инструкции Input # при наличии любой
национальной настройки:
• в качестве десятичного разделителя при записи числовых данных всегда
используется точка;
• при выводе логических данных (тип Boolean) в файл записываются
ключевые слова #TRUE# или #FALSE#. Ключевые слова True и False не
переводятся;
• при выводе в файл данных типа Date используется универсальный фор-
мат даты. Если компонент, соответствующий дате или времени, отсут-
ствует или равен нулю, в файл записывается только имеющийся в нали-
чии компонент;
• если аргумент списокВывода имеет значение Empty, в файл ничего не
записывается;
• если списокВывода имеет значение Null, в файл записывается #NULL#;
• данные типа Error записываются в файл как #ERROR кодОшибки#.
Ключевое слово Error не переводится.
В отличие от инструкции Print #, инструкция Write # вставляет запятые
между элементами и заключает строки в кавычки по мере записи их в
файл. Разработчику не требуется включать разделители в список явным
образом. Write # вставляет символ новой строки, т.е. комбинацию симво-
лов возврата каретки и перевода строки (Chr(13) + Chr(10)), после записи в
файл последнего символа, включенного в списокВывода.
Для ввода данных с файла используется оператор Input.
Синтаксис:
Input #номерФайла, списокПеременных
НомерФайла − любой допустимый номер файла.
СписокПеременных − разделяемый запятыми список переменных, ко-
торым следует присвоить значения, считанные из файла. Нельзя использо-
вать массивы или объектные переменные. Однако допускается использо-
вание переменных, описывающих элементы массива или определяемого
пользователем типа.

74
Данные, считываемые с помощью инструкции Input #, обычно
записываются в файл с помощью инструкции Write #. Эта инструкция
применима только к файлам, открытым в режиме Input или Binary.
Пример. Открыть файл на запись. Записать в него первые 100 членов
натурального ряда. Закрыть файл. Открыть его на чтение, прочитать запи-
санные в файл данные и найти их сумму.
Sub РаботаСФайлами()
Dim a As Long, s As Long, i As Long
' Открыть файл на чтение и присвоить ему отсылочное число 1
Open "TESTFILE" For Output As #1
' Записать в файл первые 100 членов натурального ряда
For i = 1 To 100
Write #1, i
Next i
Close #1 ' Закрыть файл
Open "TESTFILE" For Input As #1 ' Открыть файл на чтение
' Прочитать 100 чисел из файла и подсчитать их сумму
For i = 1 To 100
Input #1, a
s=s+a
Next i
' Вывести для контроля полученную сумму
MsgBox ("Сумма = " + Str(s))
Close #1 ' Закрыть файл
End Sub
Можете посмотреть в папке МОИ ДОКУМЕНТЫ содержимое этого
файла.
Файлы можно использовать для хранения промежуточных данных
больших объемов.

75
6. Отладка программ

Написанную программу необходимо выполнить и обработать результа-


ты. При введении и выполнении программы возможно возникновение
ошибок. Полученные результаты также могут содержать неверные значе-
ния. Поэтому программу необходимо отладить. При отладке и выполнении
программ могут возникать ошибки трех типов:
• Синтаксические. Ошибки, возникающие на этапе ввода кода
программ, связанные с неправильным написанием ключевых
слов, операторов, математических, логических и текстовых вы-
ражений. Эти ошибки обнаруживаются редактором программы
сразу же после ввода текущей строки. При этом возникает окно,
определяющее тип ошибки и подробное описание ошибки. Оши-
бочная строка выделяется красным цветом. Строка Программист
сразу же может исправить такую ошибку и продолжить вводить
программу.
• Ошибки этапа выполнения. Во время выполнения программы
могут возникать ошибки связанные с неправильным описанием
типов переменных в различных программных единицах проекта,
неправильными именами функций, арифметическими ошибками
и так далее.
• Логические ошибки. Ошибки, при которых программа выпол-
няется полностью, но полученные результаты неправильны. Ис-
правления таких ошибок является достаточно трудоемкой и
сложной операцией.
В Visual Basic встроены средства, которые после ввода имени функции
или подпрограммы, отображают список формальных параметров. При
описании типов переменных возникает контекстное меню со списком ти-
пов объектов. Программист может при помощи мышки или клавиатуры
выбрать необходимый тип данных. В процессе ввода имени данных, кон-
текстное меню автоматически по алфавиту перемещается к нужному эле-
менту. Набрав первые символы элемента, и убедившись, что необходимый
элемент выделен, можно нажатием клавиши Tab ввести имя элемента в код
программы. Для ввода данного элемента из списка и перехода на следую-
щую строку используется клавиша Enter.
Список типов данных, имен, свойств и методов объектов можно вы-
звать при помощи комбинации клавиш Ctrl+J или команды меню Edit/List
Properties/Method.
При использовании длинных имен удобно использовать метод допол-
нения слова. После ввода начальных символов слова, можно нажать ком-
бинацию клавиш Ctrl+Пробел. В возникшем списке будет отмечен элемент
имеющий начальное имя совпадающее с введенным. Нажатие клавиши Tab
или Enter автоматически дописывает имя.

76
Если на этапе выполнения программы происходит ошибка, то данная
ошибка перехватывается стандартным обработчиком ошибок. При этом
появляется окно, в котором дается краткая информация о возникшей
ошибке. Окно имеет командные кнопки: End, Debug, Help. При нажатии
на кнопку End, программа завершает работу. При нажатии на кнопку De-
bug, программа переходит в режим отладки. В этом режиме можно подвес-
ти курсор мыши к любой переменной и через некоторый момент внизу
показывается значение данной переменной. Проанализировав возникшую
ситуацию можно исправить программу и запустить ее заново или продо-
лить с данной точки.
В режим отладки можно войти при помощи расстановки точек преры-
вания. В модуле программ слева от первого символа имеется узкая выде-
ленная прямоугольная область, являющаяся полем отладчика. Если пере-
местить курсор в это поле напротив любого оператора и нажать левую
кнопку мышки, то оператор, находящийся в данной строке, выделяется и в
поле отладки ставится точка. В процессе выполнения программы происхо-
дит остановка на каждом отмеченном операторе. При этом программист
может посмотреть значения всех переменных величин в момент остановки
программы. В любой момент программист может убрать точки останова
программы или добавить новые. Удалить точки останова можно при по-
мощи повторного нажатия мышкой на точке прерывания. Кроме того, на
любом этапе отладки программы можно изменить любые операторы про-
граммы и, нажав на кнопку сброс (черный прямоугольник на панели инст-
рументов Visual Basic), заново начать выполнять программу. Такой метод
отладки сложных программ существенно уменьшает время отладки.
При запуске программ при помощи команды F8, включается пошаго-
вый режим выполнения программы. В этом режиме после выполнения
очередного оператора происходит останов программы. После анализа со-
стояния переменных можно выполнить очередную строку, нажав еще раз
клавишу F8. Для выхода из пошагового режима необходимо нажать ком-
бинацию клавиш Ctrl+Shift+F8.

7. Примеры решения простейших стандартных задач

7.1. Задачи на линейные алгоритмы


7.1.1. Написать программу, которая переводит длину, заданную в дюй-
мах, в сантиметры.
Решение. Описываем переменную вещественного типа L, в которую
вводим значение длины в дюймах. Умножая L на 2,54 см, получаем значе-
ние длины в сантиметрах.

77
Sub ПереводДюймыВСантиметры()
Dim L As Double
L = CDbl(InputBox("Введите длину объекта в дюймах"))
L = L * 2.54 ' Пересчет сантиметров в дюймы
MsgBox ("Длина объекта в сантиметрах=" + Str(L))
End Sub
7.1.2. Найти площадь треугольника по трем заданным сторонам.
Решение. Если известны все три стороны треугольника, то площадь его
вычисляется по формуле Герона:
S = p( p − a )( p − b)( p − c) , где a, b, c − стороны треугольника;
a+b+c
p − полупериметр треугольника, p = .
2
Вычислительную программу разобьем на две части: основную про-
грамму и функцию, реализующую формулу Герона. В основной программе
мы введем исходные данные a, b и c и вызовем функцию с именем SqGeron,
в которой подсчитывается площадь треугольника. В функции вычисляется
подкоренное выражение формулы Герона и запоминается в переменной D.
Sub ПлощадьТреугольникаПоТремСторонам()
Dim a As Double, b As Double, c As Double
'ввести длину трех сторон
a = CDbl(InputBox("Введите длину первой стороны треугольника"))
b = CDbl(InputBox("Введите длину второй стороны треугольника"))
c = CDbl(InputBox("Введите длину третьей стороны треугольника"))
MsgBox ("Площадь треугольника= " + Str(SqGeron(a, b, c)))
End Sub
Function SqGeron(a As Double, b As Double, c As Double) As Double
Dim p As Double, D As Double
p = (a + b + c) / 2 ' Полупериметр треугольника
' Площадь треугольника по формуле Герона
D = p * (p - a) * (p - b) * (p - c)
' Если D>0, то a, b, c образуют треугольник и возвращается его
' площадь, иначе возвращается отрицательное число -1
If D >= 0 Then SqGeron = Sqr(D) Else SqGeron = -1
End Function
7.1.3. Найти радиусы описанной и вписанной окружности треугольника
по трем заданным сторонам.
Решение. Если известны все три стороны треугольника, то радиусы

S abc
r= , R= , где S − площадь Δ; p − полупериметр треугольника.
p 4S
вписанной r и описанной R окружностей вычисляются по формулам:
Для решения этой задачи используем функцию SqGeron предыдущего
примера. В VB большие и маленькие буквы в идентификаторах перемен-

78
ных считаются одинаковыми, поэтому для переменной r выбран иденти-
фикатор rOp, а для R - Rvp.
Sub РадиусыОкружностейВписаннойИОписаннойПо3Сторонам()
Dim a As Double, b As Double, c As Double, p As Double, S As Double
Dim rOp As Double, Rvp As Double
'Ввести длину трех сторон
a = CDbl(InputBox("Введите длину первой стороны треугольника"))
b = CDbl(InputBox("Введите длину второй стороны треугольника"))
c = CDbl(InputBox("Введите длину третьей стороны треугольника"))
p = (a + b + c) / 2 ‘ Полупериметр треугольника
S = SqGeron(a, b, c) ‘ Площадь треугольника
rOp = S / p ‘ Радиус вписанной окружности
Rvp = a * b * c / (4 * S) ‘ Радиус описанной окружности
MsgBox ("Радиус вписанной окружности = " & rOp & _
" Радиус описанной окружности = " & Rvp)
End Sub

7.1.4. Написать программу для вычисления значения следующей функ-


4
⎛ 1+ 3 x +1 ⎞
ции: F ( x ) = ⎜⎜ 5 4 ⎟⎟ .
⎝ 1 + 5 x + 4 ⎠
Значение аргумента функции ввести с ячейки рабочего листа.
Sub ФункцияДляАлгебраическогоВыражения1()
Dim x As Double, F As Double
' Считать значение аргумента с ячейки A1
x = Sheets("Лист1").Cells(1, 1)
' Вычислить значение функции
F = ((1 + (x + 1) ^ (1 / 3)) / (1 + (5 * x ^ 4 + 1) ^ (1 / 5))) ^ 4
'В ячейку B2 вывести значение функции
Sheets("Лист1").Cells(1, 2) = F
End Sub
7.1.5. Написать программу для вычисления значения следующей функ-

3
2sin x
+ lg(arctgx )
F ( x) = .
cos x
ции:
Аргумент функции ввести с клавиатуры, а значение функции вывести в
окно отладки.
Sub ФункцияДляАлгебраическогоВыражения1()
Dim X As Double, F As Double
X = CDbl(InputBox("Введите аргумент функции"))
F = (2 ^ Sin(X) ^ 3 + Log10(Atn(X))) / Cos(X)
Debug.Print "Значение функции= "; F
End Sub
‘ Функция вычисления lgx через функцию lnx

79
Function Log10(X As Double) As Double
Log10 = Log(X) / Log(10)
End Function
7.1.6. Написать программу для вычисления значения следующей функ-
ции:
x
F ( x) = − tgx .
x2
1−
x2
3−
x2
5−
7
Аргумент функции ввести с клавиатуры, а значение функции вывести в
окно отладки.
Sub ФункцияДляАлгебраическогоВыражения2()
Dim X As Double, F As Double, x1 As Double
X = CDbl(InputBox("Введите аргумент функции"))
x1 = 3 - X ^ 2 / (5 - X ^ 2 / 7)
F = X / (1 - X ^ 2 / x1) - Tan(X)
Debug.Print "Значение функции= "; F
End Sub

7.1.7. Написать программу для решения системы линейных алгебраиче-


ских уравнений
⎧ ax + by = c
⎨dx + ey = f .

a, b, c, d ,e и f ввести с рабочего листа. Предполагается, что система
имеет единственное решение. Кроме того, все коэффициенты не равны ну-
лю.
Решение. Решаем методом исключения неизвестных. Из первого урав-
нения получаем x=(c-by)/a. Подставляем это выражение во второе уравне-
ние системы. Получаем: y=(af-dc)/(ae-db).
Sub РешениеСистемыДвухЛинейныхУравнений()
Dim a As Double, b As Double, c As Double, d As Double
Dim e As Double, f As Double, x As Double, y As Double
Sheets("Лист1").Select ' Перейти на рабочий лист с именем Лист1
a = Cells(1, 1): b = Cells(1, 2): c = Cells(1, 3)
d = Cells(2, 1): e = Cells(2, 2): f = Cells(2, 3)
y = (a * f - d * c) / (a * e - d * b)
x = (c - b * y) / a
Debug.Print "x= "; x; " y= "; y
Debug.Print "ax+by= "; a * x + b * y; " dx+ey= "; d * x + e * y
End Sub

80
7.2. Задачи на циклические алгоритмы
Циклом – называется многократное выполнение одних и тех же дейст-
вий при разном значении параметров цикла.
7.2.1. Арифметическая прогрессия
7.2.1. В первый столбец рабочего листа вывести последовательность
чисел 1, 2 ,3,….,100.
Решение. Выделяем рабочий лист с именем Лист1. Организуем цикл
For с параметром цикла i. Параметр цикла i меняется от 1 до 100 с шагом 1.
И на каждой итерации цикла в ячейку рабочего листа, стоящей в i-той
строке и 1-ом столбце, записываем число i.
Sub АрифметическаяПрогрессия1()
Dim i As Long
Sheets("Лист1").Select ' Выделяем рабочий лист с именем Лист1
For i = 1 To 100
Cells(i, 1) = i ' Записываем числа в i-тую строку первого столбца
Next i
End Sub

7.2.2. Во второй столбец рабочего листа вывести последовательность


чисел 0, 10, 20 ,30,….,100.
Sub АрифметическаяПрогрессия()
Dim i As Long
Sheets("Лист1").Select
For i = 1 To 11
Cells(i, 2) = 10*(i-1)
Next i
End Sub

7.2.3. В третий столбец рабочего листа вывести последовательность чи-


сел -20, 20, 60, … , 500, 540.
Sub АрифметическаяПрогрессия3()
Dim i As Long
Sheets("Лист1").Select
For i = 1 To 15
Cells(i, 3) = -20 + 40 * (i - 1)
Next i
End Sub
7.2.4. В четвертый столбец рабочего листа вывести последовательность
чисел 10, -30, -70, …, -710, -750.

81
Sub АрифметическаяПрогрессия4()
Dim i As Long
Sheets("Лист1").Select
For i = 1 To 20
Cells(i, 4) = 10 - 40 * (i - 1)
Next i
End Sub
7.2.5. В пятый столбец рабочего листа вывести последовательность чи-
сел 10, 30, 60, 0, 110, -30, …, 410, -210, 460, -240.
Решение. Нетрудно заметить, что здесь вперемежку записаны две
арифметические прогрессии 10, 60, 110, … , 410,460 и 30, 0, -30, …, -210, -
240. Поэтому в нечетные строки пятого столбца пишем элементы первой
прогрессии, а в четные – второй прогрессии.
Sub АрифметическиеПрогрессии5()
Dim i As Long
Sheets("Лист1").Select
'Тело цикла выполняется 11 раз. При i=1, 3, 5, 7, 9, 11, 13, 15, 17, 19.
For i = 1 To 20 Step 2
' В нечетные строки пишем члены первой последовательности
Cells(i, 5) = 10 + 50 * (i - 1) \ 2
' В четные строки пишем члены второй последовательности
Cells(i + 1, 5) = 30 - 30 * (i - 1) \ 2
Next i
End Sub

7.2.2. Геометрическая прогрессия


7.2.6. В первый столбец рабочего листа Лист2 вывести последователь-
ность чисел 1, 2, 4, …, 1024, 16384, 32768.
Решение. Это геометрическая прогрессия со знаменателем, равным 2, и
первым элементом, равным 1. Здесь 11 членов последовательности. Чтобы
получить очередной член прогрессии, необходимо текущий умножить на
2. В приведенной программе в качестве текущего члена прогрессии высту-
пает переменная b.
Sub ГеометрическаяПрогрессия1()
Dim i As Integer, b As Integer
Sheets("Лист2").Select
b = 1 ' Первый член геометрической прогрессии
' Цикл по всем 11 членам геометрической прогрессии
For i = 1 To 11
Cells(i, 1) = b ' Записать в ячейку
b = b * 2 'Получить следующий член геометрической прогрессии
Next i
End Sub
Внимание. Если по данной программе мы попытаемся получить 15
членов данной прогрессии, заменив конечное значение параметра цикла 11

82
на число 15, то произойдет ошибка выполнения программы – переполне-
ние. Так как при i=15 будет выведено число b=16384, а при умножении b*2
должно получиться число 32768, которое превышает максимально воз-
можное число типа Integer. В этом случае необходимо для переменной b
использовать тип Long.
7.2.7. Во второй столбец рабочего листа Лист2 вывести последователь-
ность чисел 2, -4, 8. …, 1024, -16384, 32768.
Решение. Это также геометрическая прогрессия со знаменателем, рав-
ным –2, и первым членом прогрессии, равным 2.
Sub ГеометрическаяПрогрессия2()
Dim i As Integer, a As Long
Sheets("Лист2").Select
a = 2 ' Общий член геометрической прогрессии
For i = 1 To 15
Cells(i, 2) = a
a = -a * 2 'Получить следующий член геометрической прогрессии
Next i
End Sub
7.2.8. В третий столбец рабочего листа Лист2 вывести последователь-
ность из 100 чисел, 1, 2, 0.5, 6, 0.25, 18, …
Решение. Эта числовая последовательность состоит из двух геометри-
ческих прогрессий. Первая прогрессия имеет первый член, равный 1, и
знаменатель 0.5. Вторая прогрессия имеет первый член, равный 2, и знаме-
натель 3.
Sub ГеометрическаяПрогрессия3()
Dim i As Integer, b As Double, a As Double
Sheets("Лист2").Select
a = 1: b = 2
For i = 1 To 50 Step 2
Cells(i, 3) = a
Cells(i + 1, 3) = b
a = a * 0.5: b = b * 3
Next i
End Sub

7.2.3. Вычисление суммы арифметической последовательности


Вычисление суммы N слагаемых производится по следующему алго-
ритму:
1) для значения суммы отводится переменная типа соответствующего
типу слагаемых. Обнуляется значение этой переменной. Иногда
сумме присваивается значение первого слагаемого;
2) организуется цикл при помощи операторов цикла. Внутри тела цик-
ла вычисляется значение очередного слагаемого, которое затем на-
капливается в переменной, соответствующей сумме
последовательности.

83
7.2.9. Найти сумму 10 слагаемых действительного типа, значения кото-
рых вводятся с клавиатуры.
Sub СуммаЧисловойПоследовательности1()
Const N = 10
Dim s As Double, i As Long, a As Double
s = 0 ' Переменная, в которой накапливаем значения суммы
For i = 1 To N
a = CDbl(InputBox("Введите " + Str(i) + "-ое слагаемое"))
s = s + a ' Накопление очередного слагаемого
Next i
MsgBox ("Сумма = " & s) ' Вывод результата
End Sub
7.2.10. Найти сумму 100 слагаемых действительного типа
100 n +1
S= ∑ .
n =1 n3 + n2 + 6
Решение. В развернутом виде эта сумма представляется в виде 100 сла-
гаемых:
S=2/8 + 3/18 + 4/42 + 5/86 + 6/156 + 7/258 + 8/398 + … + 101/1010006.
Sub СуммаЧисловойПоследовательности2()
Dim S As Double, n As Long
‘ Обнулить переменную, в которой будет накапливаться сумма
S=0
For n = 1 To 100
‘ Накопить в переменной S очередное n-ное слагаемое
S = S +( n+1) / (n ^ 3 + n ^ 2 + 6)
Next n
‘ Вывести переменную S. После запятой выводить четыре знака.
Debug.Print "Сумма = "; format(S,”#0.0000”)
End Sub
Ответ: Сумма = 0,7785.
7.2.11. Найти сумму 100 слагаемых действительного типа
100 ( −1) n n
∑ 2
.
n =1 n +n+6
Решение. Знаки слагаемых этой суммы чередуются. Знак первого сла-
гаемого ─ плюс; второго –– минус; третьего –– плюс; и т.д. Для знака вве-
дем переменную z. Присвоим ей начальное значение –1, а после накопле-
ния суммы изменяем знак оператором z=-z.

84
Sub СуммаЧисловойПоследовательности3()
Dim S As Double, n As Long, Z as Integer
S = 0 ' В этой переменной накапливается сумма слагаемый
Z=-1 ' В этой переменной хранится знак очередного слагаемого
For n = 1 To 100
S = S +Z*( n+1) / (n ^ 3 + n ^ 2 + 6)
Z=-Z ' Изменить знак слагаемого
Next n
Debug.Print "Сумма = "; format(S,”#0.0000”)
End Sub
Ответ: Сумма = -0,1431.

7.2.4. Сумма индуктивных слагаемых


Слагаемые называются индуктивными, если следующее слагаемое по-
лучается как функция текущего слагаемого. 20
7.2.12. Найти сумму 20 слагаемых действительного типа: S = ∑ 2n .
n =1
В развернутом виде эта сумма представляется в виде 20 слагаемых:
S = 2 + 2 2 + 23 + + 2 20 .
В качестве текущего слагаемого выберем переменную типа Long,
имеющую идентификатор a. Перед циклом присвоим переменной a на-
чальное значение, совпадающее с первым слагаемым. В переменной S бу-
дем накапливать сумму. Начальное значение S=a. Для вычисления суммы
остальных 19 слагаемых применяем оператор цикла с параметром цикла n,
меняющимся от 2 до 20 с шагом 1. Внутри цикла получаем очередное сла-
гаемое, умножая предыдущее значение на 2, и накапливаем полученное
слагаемое в переменной S.
Sub СуммаИндуктивнойПоследовательности1()
Dim S As Long, n As Long, a As Long
a = 2: S = a
For n = 2 To 20
a = a * 2 ' Очередное слагаемое
S = S + a ' Накопление суммы
Next n
Debug.Print "Сумма = "; Format(S, "#,##0")

End Sub

Ответ: Сумма = 2 097 150.


100
2n
7.2.13. Найти сумму 100 слагаемых действительного типа S = ∑ n! .
n =1

Решение. Функция n! =1· 2 · 3· 4· …· n представляет собой произ-

85
ведение первых n чисел натурального ряда. В развернутом виде эта сумма
представляется в виде 100 слагаемых:

2 22 23 299 2100
S= + + +…+ + .
1 1⋅ 2 1⋅ 2 ⋅ 3 1 ⋅ 2 ⋅ 3 ⋅ … ⋅ 99 1 ⋅ 2 ⋅ 3 ⋅ … ⋅ 99 ⋅ 100
Введем две переменные типа Double a – общий член этой суммы и S –
сумма. Перед циклом этим переменным присвоим начальные значения,
равные первому слагаемому: a=2, S=2. Чтобы получить следующее слагае-
мое, необходимо текущее слагаемое умножить на 2 и разделить на номер
следующего слагаемого.
Sub СуммаИндуктивнойПоследовательности2()
Dim S As Double, n As Long, a As Double
a = 2: S = 2
For n = 2 To 100
a = a * 2 / n ' Получить очередное слагаемое
S = S + a ' Накопить его в переменной S
Next n
Debug.Print "Сумма = "; Format(S, "#.00000000")
End Sub
Ответ: Сумма = 6,38905610.
Ответ выведен с точностью восьми знаков после запятой. Нетрудно за-
метить, что слагаемые данной суммы уменьшаются. Если перед операто-
ром Next n вставить оператор Debug.Print Format(a,"#.00000000") для вы-
вода слагаемых a с точностью 8 знаков после запятой , то получим сле-
дующие результаты:
2,00000000 1,33333333 ,66666667 ,26666667 ,08888889
,02539683 ,00634921 ,00141093 ,00028219 ,00005131
,00000855 ,00000132 ,00000019 ,00000003 ,00000000
Остальные слагаемые равны 0. Так как функция N! быстро возрастает,
слагаемые быстро убывают, и уже 16 слагаемое при суммировании можно
не учитывать. Программу можно модифицировать, используя оператор
цикла While.
Sub СуммаИндуктивнойПоследовательности3()
Dim S As Double, n As Long, a As Double
a = 2: S = 2: n = 1
' Выполнять цикл пока a> 0.00000001
While a > 0.00000001
n = n + 1: a = a * 2 / n: S = S + a
Wend
Debug.Print "Сумма = "; Format(S, "#.00000000"); ", n="; n
End Sub
Ответ: Сумма = 6,38905610, n= 16.
7.2.14. Найти сумму 100 слагаемых действительного типа

86
∞ ( −1) n
S= ∑ .
n =1 ( 2 n )!
Решение. В развернутом виде эта сумма представляется в виде :
S =− 1 + 1 − 1 + 1 −… .
1⋅ 2 1⋅ 2 ⋅ 3⋅ 4 1⋅ 2 ⋅ 3⋅ 4 ⋅ 5⋅ 6 1⋅ 2 ⋅ 3⋅ 4 ⋅ 5⋅ 6 ⋅ 7 ⋅8
Чтобы получить следующее слагаемое, необходимо текущее слагаемое
умножить на –1 и разделить на произведение двух целых чисел (2n-1)2n,
где n – номер слагаемого. Слагаемые этой суммы очень быстро убывают.
Так как часть слагаемых отрицательна, в условии выхода из цикла исполь-
зуется функция вычисления модуля числа Abs.
Sub СуммаИндуктивнойПоследовательности4()
Dim S As Double, n As Long, a As Double
a = -0.5: S = a: n = 1
Do
Debug.Print Format(a, "#.00000000"); " ";
n = n + 1: a = -a / ((2 * n - 1) * 2 * n): S = S + a
Loop While Abs(a) > 0.00000001
Debug.Print Format(a, "#.00000000")
Debug.Print "Сумма = "; Format(S, "#.00000000"); ", n="; n
End Sub
Ответ:
-,50000000 ,04166667 -,00138889 ,00002480 -,00000028 ,00000000
Сумма = -,45969769, n= 6.

7.3. Задачи на разветвляющиеся алгоритмы


Алгоритмы называются разветвляющимися, если в произвольной точке
программы в зависимости от выполнения или невыполнения некоторых
условий происходит переход управления в разные точки программы.
В разветвляющихся алгоритмах применяются операторы if, select и
goto.

1
13 ln 9 − lg 2 ⎛ 1 ⎞
a = 0.75 0.5 − 4 ; b = 100 2 tg ⎜ ⎟ ;
2 ⎝ 3⎠
⎧⎪ 15a 2 + 21b 2 при a > b,
k=⎨
⎪⎩ 21a 2 + 15b 2 при a ≤ b.
7.3.1. Вычислить значение числа k.

Sub Ветвление1()

87
Dim a As Double, b As Double, k As Double
a = 0.75 * Sqr(0.5) - 1 / 2 * 4 ^ (1 / 3)
b = 100 ^ (1 / 2 * Log(9) - Log(2) / Log(10)) * Tan(1 / 3)
If a > b Then k = Sqr(15 * a ^ 2 + 21 * b ^ 2) Else _
k = Sqr(21 * a ^ 2 + 15 * b ^ 2)
Debug.Print "a= "; a; "; b= "; b; "; k= "; k; ”.”
End Sub
Ответ:
a= -0,263370440094189; b= 13,6319762297472; k=
52,8102100231471.
7.3.2. Вычислить значение функции
⎧ 0, x ∈ ( −∞;0]
⎪⎪ x 2 , x ∈ (0;1]
F ( x) = ⎨ 2
⎪ 2 − x , x ∈ (1; 2 ]
⎪⎩ 0 x ∈ ( 2; ∞) .

Sub ПримерНаСоставнойIf()
Dim x As Double
x = CDbl(InputBox("Введите значение аргумента функции"))
Debug.Print "Значение функции= "; Funct1(x)
End Sub
Function Funct1(x As Double) As Double
Dim y As Double
If x <= 0 Or x > Sqr(2) Then
y=0
ElseIf x <= 1 Then y = x ^ 2
Else: y = 2 - x ^ 2
End If
Funct1 = y
End Function
7.3.3. По введенному номеру месяца вывести количество дней в этом
месяце, название месяца и название сезона.
Sub ЧислоДнейНазваниеМесяцаСезона()
Dim Month As String, Days As Integer, Season As String, Ye As Integer
Dim NumbM As Integer
beg: NumbM = Val(InputBox("Введите номер месяца"))
If NumbM < 1 Or NumbM > 12 Then
MsgBox ("Ошибочно введен номер месяца. Повторите ввод!")
GoTo beg
End If
' Определение числа дней в месяце
Days = 31
If NumbM = 4 Or NumbM = 6 Or NumbM = 9 Or NumbM = 11 Then _
Days = 30

88
If NumbM = 2 Then
Days = 28
Ye = Val(InputBox("Введите год"))
' Если год високосный и месяц Февраль
If (Ye Mod 4) = 0 Then Days = 29
End If
' Определение название месяца
Dim NameMonth As Variant
NameMonth = Array("Январь", "Февраль", "Март", "Апрель", "Май", _
"Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь")
Month = NameMonth(NumbM) ' название месяца
' Определение название сезона, к которому относится месяц
Select Case NumbM
Case 12, 1, 2
Season = "Зима"
Case 3 To 5
Season = "Весна"
Case 6 To 8
Season = "Лето"
Case 9 To 11
Season = "Осень"
End Select
MsgBox ("Месяц номер" + Str(NumbM) + " называется" + _
Month +Chr(13)+ " содержит "+Str(Days)+"дней"+ Chr(13) + _
" и относится к сезону " + Season)
End Sub
7.3.4. По введенному номеру дня, месяца и года вывести номер, месяц
и год предыдущего дня.
Sub ВчерашнийДень()
Dim Day As Integer, Month As Integer, Year As Integer, _
NameMonth As Variant
NameMonth = Array("Январь", "Февраль", "Март", "Апрель", "Май", _
"Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", _
"Декабрь")
Day = Val(InputBox("Введите день"))
Month = Val(InputBox("Введите номер месяца"))
Year = Val(InputBox("Введите год"))
Day = Day - 1
If Day = 0 Then
Month = Month - 1
If Month = 0 Then
Year = Year - 1: Month = 12
End If
Select Case Month
Case 1, 3, 5, 7, 8, 10, 12
Day = 31
Case 4, 6, 9, 11

89
Day = 30
Case 2
If (Year Mod 4) = 0 Then Day = 29 Else Day = 28
End Select
End If
MsgBox ("Вчера было " + Str(Day) + " " + NameMonth(Month) + _
" Год " + Str(Year))
End Sub

8. Задачи сортировки
Задача сортировки элементов массивов является одной из наиболее
важных и популярных задач для компьютеров. Во многих вычислительных
системах на нее уходит более половины вычислительного времени. По-
пробуйте в не отсортированном списке учеников школы или института
найти свою фамилию. Для этого Вы должны внимательно прочитать спи-
сок от начала до нужной фамилии, что займет значительное время. А в
списке, написанном по алфавиту, Вы быстро подойдете к необходимому
листу и найдете Вашу фамилию.
8.1. Перестановка элементов в массиве
При решении задач сортировки постоянно необходимо решать более
простые задачи:
• находить в массиве наибольший или наименьший элемент;
• менять местами два элемента.
8.1.1. Найти наименьшее значение среди 20 введенных с клавиатуры
вещественных чисел и указать, на каком месте оно находится.
Sub МинимальноеИз20Чисел()
Const n = 20
Dim numb As Double, min As Double, i As Long, imin As Long
min = 1.7E+308 ' Это +∞
imin = 0 ' Номер минимального числа
For i = 1 To n
numb = CDbl(InputBox("Введите " + Str(i) + "-ое число"))
' Если введено число меньшее, чем все предыдущие, то
‘ запомнить новое минимальное значение и его номер
' Здесь оба оператора присваивания выполняются, только
‘ если numb<min
If numb < min Then min = numb: imin = i
Next i
MsgBox ("Минимальное из введенных чисел =" + Str(min) + Chr(13) _
+ "это число номер " + Str(imin))
End Sub
8.1.2. В последовательности вещественных чисел, находящихся в
столбце A рабочего листа “Лист1”, подсчитать количество чисел равных
максимальному значению.

90
Sub КоличествоМаксимальныхЧисел()
Dim numb As Double, max As Double, n As Long, NMax As Long
max = -1.7E+308 ' Это - ∞. Здесь получим максимальное значение
NMax = 0 ' Число элементов равных максимальному
Sheets(“Лист1”).Select ‘ Перейти на рабочий лист с именем Лист1
‘Номер строки, с которой будем начинать считывать данные
n=1
Do
numb = Cells(n, 1) ‘ Считать число с ячейки n первого столбца
‘ Если в ячейки пусто выйти из цикла
If numb = Empty Then Exit Do
If numb > max Then
'Если встретили число, которое больше предыдущих, то обнуляем
'счетчик количества максимальных чисел и запоминаем значение ‘max
NMax = 0: max = numb
End If
' Если число равно максимальному значению, то счетчик
‘максимальных чисел увеличить на 1
If numb = max Then NMax = NMax + 1
n = n + 1 ' Перейти к следующей строке
Loop
Debug.Print "Количество чисел, равных максимальному "; max; " = "; _
NMax; " Всего чисел в столбце="; n-1
End Sub
8.1.3. В одномерном массиве случайных действительных чисел размер-
ности N подсчитать количество элементов, которые меньше всех преды-
дущих элементов.
Sub КоличествоЭлементовМеньшихПредыдущих()
Dim a() As Double, i As Integer, n As Integer, numb As Integer, _
j As Integer
Sheets("Лист1").Select
Range("a1:b100").Clear ‘ Очистить ячейки
n = Val(InputBox("Введите N"))
ReDim a(n) ‘ Создать динамический массив a
Randomize Timer
For i = 1 To n
' Заполнение массива случайными действительными числами
‘в диапазоне от 0 до 100
a(i) = Rnd * 100 : Cells(i, 1) = a(i)
Next i
numb = 1
‘ Нумеруем элементы < всех предыдущих и выводим
' их номера во втором столбце

Cells(1, 2) = numb
For i = 2 To n
For j = 1 To i - 1

91
If a(j) >= a(i) Then GoTo m
Next j
numb = numb + 1 : Cells(i, 2) = numb
m: Next i
MsgBox ("В данной последовательности " + Str(numb) + _
" элементов меньших предыдущих")
End Sub
8.1.4. В одномерный массив A записать 30 целых положительных слу-
чайных трехзначных чисел. Полученный массив вывести в первый столбец
рабочего листа. В массиве A поменять местами элементы, стоящие на не-
четном месте со следующими элементами, стоящими на четных местах.
Полученный массив записать во второй столбец.
Sub ИнверсияНеЧетныеНаЧетные()
Const N = 30
Dim a(N) As Integer, t As Integer, i As Integer
Sheets("Лист1").Select : Range("A1:b100").Clear
Randomize Timer
For i = 1 To N
' Заполнение массива случайными трехзначными числами
a(i) = 899 * Rnd + 100
' Вывод полученного массива в первый столбец
Cells(i, 1) = a(i)
Next i
For i = 1 To N - 1 Step 2
' Перестановка двух соседних элементов массива местами
t = a(i): a(i) = a(i + 1): a(i + 1) = t
Next i
' Вывод во второй столбец полученного массива
For i = 1 To N
Cells(i, 2) = a(i)
Next i
End Sub
8.1.5. В одномерный массив A записать 20 случайных действительных
чисел в диапазоне от 100 до 10000. Поменять местами максимальный и
минимальный элементы. В третий столбец вывести исходный массив, а в
четвертый – полученный массив.
Sub ИнверсияМаксимальныйНаМинимальный()
Const N = 20
Dim a(N) As Double, t As Double, i As Integer, imax As Integer, _
imin As Integer
Sheets("Лист1").Select
Randomize Timer
' Заполнение массива случайными числами в диапазоне (100,10000)
For i = 1 To N
' Получить элементы массива с двумя знаками после запятой
a(i) = Int((9900 * Rnd + 100) * 100) / 100

92
' Вывод полученного массива в третий столбец
Cells(i, 3) = a(i)
Next i
' Номер максимального и минимального элементов
imax = 1: imin = 1
For i = 2 To N
'Поиск месторасположения максимального и минимального
‘элементов
If a(i) > a(imax) Then imax = i
If a(i) < a(imin) Then imin = i
Next i
' Обмен элементов местами
t = a(imax): a(imax) = a(imin): a(imin) = t
For i = 1 To N ‘ Вывод результата в 4 столбец
Cells(i, 4) = a(i)
Next i
MsgBox ("Совершен обмен в строках " + Str(imin) + " и " + Str(imax))
End Sub

8.2. Сортировка методом “пузырька”


Рассмотрим в начале сортировку числовых массивов по возрастанию
или убыванию элементов.
Дан числовой массив действительных или целых чисел. Элементы мас-
сива обозначим: A1, A2, A3, A4, … , AN. Необходимо при помощи конечно-
го числа перестановок пар элементов расставить элементы в порядке воз-
растания или убывания. Т.е. чтобы выполнялись условия:
A1≥ A2≥A3≥A4≥… ≥AN – для сортировки по убыванию и A1≤
A2≤A3≤A4≤… ≤AN – для сортировки по возрастанию.

8.2.1. Метод "пузырька" для массивов


Самой простой сортировкой массивов является сортировка методом
"пузырька". Рассмотрим для однозначности сортировку по убыванию
элементов. Для сортировки по возрастанию необходимо поменять знаки
неравенства на противоположные. Смысл сортировки методом "пузырька"
заключается в следующем.
Начиная с первого элемента, сравниваем два соседних элемента i-тый и
(i+1)-ый. Если Ai+1 > Ai , то переставляем эти два элемента местами. И так
до N-1-го элемента. В результате на место N-го элемента переместился са-
мый малый элемент. Т.е. самый “легкий” элемент всплыл “наверх”. Затем
повторяем эту же процедуру с 1-го до N-2-го элементов. В результате N-2-
ой элемент становится на место. И так до тех пор, пока 2-ой элемент не
станет на свое место. В этом случае первый элемент автоматически встал
на свое место.
1. i=1.
2. j=1.

93
3. Если Aj+1 > Aj , то переставить их местами.
4. j=j+1.
5. Если j≤N-i, перейти на 3.
6. i=i+1.
7. Если i≤N-1, перейти на 2.
В этом алгоритме используется двухмерный цикл. Первый (внешний)
цикл с параметром цикла i изменяется от 1 (пункт 1) до N-1 (пункт 7). Вто-
рой (внутренний цикл) с параметром цикла j изменяется от 1 (пункт 2) до
N-i (пункт 5). Тело внутреннего цикла (пункт 3) выполняется (N-1) раз при
i=1; (N-2) раза при i=2; …и 1 раз при i=N-1. Таким образом, общее число
выполнения внутреннего цикла k, определяющее трудоемкость метода,
равно N2/2. Значит, при увеличении N в 2 раза время сортировки увеличит-
( N − 1) + 1 N2
ся примерно в четыре раза. k= ⋅ ( N − 1) ≈ .
2 2
На примере числового массива, состоящего из 6 элементов, рассмотрим
данный алгоритм сортировки. Затененные элементы не участвуют в сорти-
ровке на следующем шаге.
7 1 8 3 6 9 Исходный массив
7 8 3 6 9 1 1-ый шаг. 4 перестановки (1-8;1-3;1-6;1-9.)
8 7 6 9 3 1 2-ый шаг. 3 перестановки (7-8;3-6;3-9)
8 7 9 6 3 1 3-ий шаг. 1 перестановка (6-9)
8 9 7 6 3 1 4-ый шаг. 1 перестановка (7-9)
9 8 7 6 3 1 5-ый шаг. 1 перестановка (8-9)
Ниже представлена подпрограмма, реализующая этот алгоритм.
Sub СортировкаМассиваМетодомПузырька(a() As Double, N As Long)
Dim t As Double, i As Long, j As Long
For i = 1 To N - 1
For j = 1 To N - i
If a(j + 1) > a(j) Then ' Переставить j-тый и j+1-ый элементы
t = a(j): a(j) = a(j + 1): a(j + 1) = t
End If
Next j, i
End Sub
Для отладки представленной подпрограммы напишем основную про-
грамму, в которой заполним случайными числами массив a, выведем его в
первый столбец рабочего листа “Лист3”, вызовем подпрограмму Сорти-
ровкаМассиваМетодомПузырька, а результаты выведем в третий столбец.
Sub ТестСортировкиМассиваМетодомПузырка()
Const N = 20
Dim a(N) As Double, i As Long
Randomize Timer
Sheets("Лист3").Select
For i = 1 To N
a(i) = Int(Rnd * 10000) / 100 ' Два знака после запятой

94
Cells(i, 1) = a(i)
Next i
Call СортировкаМассиваМетодомПузырька(a, N)
For i = 1 To N
Cells(i, 2) = a(i)
Next i
End Sub
Часто возникает необходимость сортировать символьные массивы по
алфавиту. В VB эта задача решается так же, как для числового массива.
Только массив a и временную переменную t необходимо описать как пе-
ременную типа String. Вместо типа String можно использовать более об-
щий тип Variant.
' Сортировка символьного массива по алфавиту от А до Я
Sub СортировкаСимвольногоМассиваМетодомПузырька(a As Variant, _
N As Long)
Dim t As String, i As Long, j As Long
For i = 1 To N - 1
For j = 1 To N - i
If a(j + 1) < a(j) Then ' Переставить j-тый и j+1-ый элементы
t = a(j): a(j) = a(j + 1): a(j + 1) = t
End If
Next j, i
End Sub

В качестве тестового примера введем внутри программы при помощи


функции Array список из 10 фамилий. После чего вызовем подпрограмму
СортировкаСимвольногоМассиваМетодомПузырька на выполнение. В
четвертый столбец выводятся фамилии, отсортированные по алфавиту.
Sub ТестСортировкиСимвольногоМассиваМетодомПузырка()
Const N = 10
Dim a As Variant, i As Long
' инициализация тестового массива a
a = Array( "Иванов", "Петров", "Сидоров", "Сидорова", "Ядренцев", _
"Симонян", "Андреев", "Вяхирев", "Шашилов", "Нестеров")
Sheets("Лист3").Select
Call СортировкаСимвольногоМассиваМетодомПузырька(a, N)
For i = 1 To N
Cells(i, 4) = a(i)
Next i
End Sub

8.2.2. Метод "пузырька" для структур


Обычно сортировать необходимо массивы сложных структурных пе-
ременных. Для примера возьмем список сотрудников, в котором имеются
следующие сведения: фамилия, имя, отчество, возраст и зарплата. Напи-

95
сать подпрограмму, которая сортирует этот массив по любому заказанному
ключу.
Введем пользовательский тип данных FullName, состоящий из пяти по-
лей разного типа: Fam - фамилия; Name1 - имя; Name2 - отчество; Age -
возраст; Zarpl - зарплата сотрудников. В подпрограмме введем еще один
формальный параметр Par, задающий номер поля, по которому необходи-
мо сортировать список.
‘ описание пользовательского типа должно находиться вначале
‘ модуля
Type FullName
Fam As String: Name1 As String: Name2 As String
Age As Integer: Zarpl As Double
End Type
‘ Подпрограмма сортировки по разным параметрам
Sub СортировкаСтруктурногоМассиваМетодомПузырька(a() _
As FullName, n As Long, Par As Integer)
Dim t As FullName, i As Long, j As Long, B As Boolean
For i = 1 To n - 1
For j = 1 To n - i
'Переменная B отвечает на вопрос: нужно ли переставлять
’ записи?
Select Case Par
Case 1: B = a(j + 1).Fam < a(j).Fam ‘ По фамилии
Case 2: B = a(j + 1).Name1 < a(j).Name1 ‘ По имени
Case 3: B = a(j + 1).Name2 < a(j).Name2 ‘ По отчеству
Case 4: B = a(j + 1).Age < a(j).Age ‘ По возрасту
Case 5: B = a(j + 1).Zarpl < a(j).Zarpl ‘ По зарплате
End Select
If B Then
' Перестановка элементов массива пользовательского типа
t = a(j): a(j) = a(j + 1): a(j + 1) = t
End If
Next j, i
End Sub
Для тестирования подпрограммы введем в первые пять столбцов рабо-
чего листа “Лист4” список из 10 элементов структурного типа: в первый
столбец – фамилии, во второй – имя, в третий – отчество, в четвертый –
возраст и в пятый – величины зарплаты всех сотрудников. После сорти-
ровки в шестой, седьмой, восьмой, девятый и десятый столбцы выводится
отсортированный массив.
Sub ТестСортировкиСтруктурногоМассиваМетодомПузырка()
Const n = 10
Dim a(10) As FullName, i As Long, Par As Integer
Sheets("Лист4").Select
For i = 1 To n ' Считывание списка сотрудников
a(i).Fam = Cells(i, 1)

96
a(i).Name1 = Cells(i, 2)
a(i).Name2 = Cells(i, 3)
a(i).Age = Cells(i, 4)
a(i).Zarpl = Cells(i, 5)
Next i
Par = Val(InputBox("Введите параметр сортировки" + Chr(13) + _
"1. По фамилии" + Chr(13) + "2. По имени" + Chr(13) + _
"3. По отчеству" + Chr(13) + "4. По возрасту" + Chr(13) + _
"5. По зарплате"))
Call СортировкаСтруктурногоМассиваМетодомПузырька(a, n, Par)
For i = 1 To n ' Запись отсортированного списка сотрудников
Cells(i, 6) = a(i).Fam
Cells(i, 7) = a(i).Name1
Cells(i, 8) = a(i).Name2
Cells(i, 9) = a(i).Age
Cells(i, 10) = a(i).Zarpl
Next i
End Sub

8.3. Сортировка методом выбора


К существенным недостаткам пузырьковой сортировки следует отне-
сти большое количество перестановок. Следующая простая сортировка,
уменьшающая количество перестановок – сортировка методом выбора.
Смысл такой сортировки заключается в следующем.
Находим положение максимального элемента во всем массиве и пере-
ставляем его с первым элементом. В результате первый элемент встал на
свое место. Дальше проделываем такие же операции для второго элемента,
затем для третьего и так до N-1-го. В этом случае последний элемент авто-
матически встает на свое место.
1. i=1.
2. j=i+1; jmax=i.
3. Если Aj> Ajmax , то jmax=j.
4. j=j+1.
5. Если j<N, то перейти на 3.
6. Если Aj > Ajmax , то переставить Ai и Ajmax .
7. i=i+1.
8. Если i≤N-1, перейти на 2.
Нетрудно заметить, что в данном алгоритме тело внутреннего цикла
выполняется столько же раз, как и в методе "пузырька".
На примере числового массива, состоящего из 6 элементов, рассмотрим
данный алгоритм сортировки. Затененные элементы не участвуют в сорти-
ровке на следующем шаге.

97
7 1 8 3 6 9 Исходный массив
9 1 8 3 6 7 1-ый шаг. 1 перестановка (7-9)
9 8 1 3 6 7 2-ый шаг. 1 перестановка (1-8)
9 8 7 3 6 1 3-ий шаг. 1 перестановка (1-7)
9 8 7 6 3 1 4-ый шаг. 1 перестановка (3-6)
9 8 7 6 3 1 5-ый шаг. Нет перестановок

Ниже представлена подпрограмма, реализующая этот алгоритм.


Sub СортировкаМассиваМетодомВыбора(a() As Double, n As Long)
Dim t As Double, i As Long, j As Long, jmax As Long
For i = 1 To n - 1
jmax = i ‘ imax – номер максимального элемента
For j = i + 1 To n ‘ Поиск положения максимального элемента
If a(j) > a(jmax) Then jmax = j
Next j
If a(jmax) > a(i) Then
' Перестановка i-того и максимального элементов
t = a(jmax): a(jmax) = a(i): a(i) = t
End If
Next i
End Sub

8.4. Сортировка методом вставки


В этом методе каждый очередной элемент вставляется в упорядочен-
ный к этому времени подмассив так, чтобы не нарушить упорядоченности.
Рассмотрим алгоритм данной сортировки на том же примере.
7 1 8 3 6 9 Первый элемент всегда упорядочен
7 1 8 3 6 9 Второй элемент (1) ставим на свое место в
подмассиве из двух элементов
8 7 1 3 6 9 Третий элемент (8) ставим на свое место
8 7 3 1 6 9 Четвертый элемент (3) ставим на свое место
8 7 6 3 1 9 Пятый элемент (6) ставим на свое место
9 8 7 6 3 1 Шестой элемент (9) ставим на свое место

Sub СортировкаМассиваМетодомВставки(a() As Double, n As Long)


Dim t As Double, i As Long, j As Long
For i = 2 To n
t = a(i) ‘ Этот элемент надо поставить в упорядоченный массив
‘ первых i-1 элементов
For j = i To 2 Step –1 ‘ Шагаем от i-того до 1-го элемента
If a(j - 1) > t Then Exit For
‘ Сдвигаем вправо все элементы, освобождая место под
‘ i-тый элемент
a(j) = a(j - 1)
Next j

98
a(j) = t ‘Ставим i-тый элемент на свое место так, чтобы
‘ i-первых элементов были упорядочены
Next i
End Sub

8.5. Быстрая сортировка


На практике применяется огромное количество методов сортировки
массивов. Рассмотрим теперь более сложную сортировку, получившую на-
звание быстрая сортировка. Ниже будет показано, что на больших мас-
сивах она работает значительно быстрее, чем рассмотренные простые сор-
тировки.
Алгоритм быстрой сортировки заключается в следующем. Начинаем
сортировать массив от 1-го до n-го элементов. Выбираем средний элемент
e=a([(1+n)/2]) и путем минимального количества перестановок добиваемся,
чтобы он стоял так, чтобы слева от него все элементы были ≥e, а справа <e.
Затем так же поступаем с левым и правым подмассивами, если длина их
>1. Затем для каждого из новых подмассивов поступаем так же. И так до
тех пор, пока длина всех подмассивов будет =1. Внизу рассмотрены этапы
сортировки массива из 10 элементов. Элементы, которые необходимо по-
ставить на данном шаге на свое место, затенены. Переменные L и R озна-
чают левую и правую границу сортируемых подмассивов. Переменные i и
j описаны в программе.

99
1 2 3 4 5 6 7 8 9 10 Номера элементов
74 12 94 39 50 77 55 73 22 60 i=2, j=10, L=1, R=10
60 12 Меняем 12 с 60 местами и i=3,
j=9
73 39 Меняем 73 с 39 местами и i=5,
j=7
55 50 Меняем 55 с 50 местами и i=6,
j=6
74 60 94 73 55 77 50 39 22 12 i=7, j=6. Теперь подмассив
слева от 50 содержит элемен-
ты которые>50, а справа
меньше 50
74 60 94 73 55 77 L=1, R=6 , i=1, j=3. Сортируем теперь под-
массив от 1-го до 6-го элементов. L=1, R=6
94 74 Меняем 74 с 94 местами и i=2, j=2.
94 60 74 73 55 77 Сортируем теперь подмассив от 2-го до 6-го
элемента. L=2, R=6, i=2,j=6
77 60 i=4, j=4
77 74 73 55 60 L=2, R=3,i=2, j=3
77 74 L=5, R=6, i=3, j=2
94 77 74 73 55 60 50 39 22 12 L=5,R=6
94 77 74 73 60 55 50 39 22 12 Окончательно отсортирован-
ный массив
Ниже представлена подпрограмма для сортировки массива по убыва-
нию методом быстрой сортировки. Внутри подпрограммы происходит об-
ращение к самой себе. Такие программы называются рекурсивными.

Sub СортировкаМассиваБыстрая(a() As Double, L As Long, R As Long)


Dim e As Double, t As Double, i As Long, j As Long
i = L: j = R: e = a((i + j) \ 2)
' Цикл, в котором элемент e ставится так, что слева от него все
' элементы > e, а справа <e.
Do
' Найти слева первый элемент, который не больше e
While a(i) > e : i = i + 1 : Wend
' Найти справа элемент, который не меньше e
While a(j) < e : j = j – 1 : Wend
If i <= j Then
t = a(i): a(i) = a(j): a(j) = t ‘ Перестановка элементов
i = i + 1: j = j - 1
End If
Loop While i <= j
' Рекурсивно вызвать программу быстрой сортировки, но уже с
‘ другими левой и правой границами
If (L < j) Then Call СортировкаМассиваБыстрая(a, L, j) ' Правая часть
If (i < R) Then Call СортировкаМассиваБыстрая(a, i, R)' Левая часть

100
' Сюда попадаем, если L>=j и R<=j. Т.е., когда весь массив
‘отсортирован
End Sub

8.6. Сравнения быстродействия основных типов сорти-


ровок

Попробуем оценить эффективность приведенных методов сортировок


на примере числового массива случайных вещественных чисел с двойной
точностью. Тестировать разработанные программы будем на массивах
большой размерности. Так как визуальный контроль требует значительно-
го времени, мы напишем вначале две логические подпрограммы, которые
контролируют правильность отсортированного массива.
‘ Функция, которая возвращает значение True, если массив
‘ отсортирован правильно. Т.е. ai+1, ≤ ai
Function ControlSortMas(a() As Double, n As Long) As Boolean
Dim i As Long
' Действуем от противного. Вначале считаем, что массив
' не отсортирован
ControlSortMas = False
For i = 1 To n – 1
' Массив отсортирован не правильно
If a(i) < a(i + 1) Then Exit Function
Next i
' Массив отсортирован правильно
ControlSortMas = True
End Function
Вторая логическая программа контролирует равенство сумм первона-
чального и отсортированного массивов. Это необходимо для уверенности в
том, что отсортирован именно исходный массив. В этой функции исполь-
зуется передача параметра S по значению. Т.е. значение переменной S по-
сле выхода из функции восстанавливается.
Function ControlSummMas(a() As Double, N As Long, _
ByVal S As Double) As Boolean
Dim i As Long
For i = 1 To N : S = S - a(i) : Next i
ControlSummMas = Abs(S) / N < 0.000001
If Not ControlSummMas Then Debug.Print " S="; S;
End Function
Теперь напишем основную программу, в которой сформируем два оди-
наковых массива a и b. Затем поочередно вызовем подпрограммы сорти-
ровки, различными методами восстанавливая каждый раз массив a, ис-
пользуя массив b. Между вызовами подпрограмм при помощи функции
time считываем текущее время.

101
Sub ТестВсехСортировокНаБыстродействие()
Const N = 1000
Dim a(N) As Double, b(N) As Double, i As Long, S As Double
Debug.Print " ************N="; N; " ********************"
Randomize Timer: S = 0
For i = 1 To N
b(i) = Rnd * 10000
S = S + b(i) ' Контрольная сумма
a(i) = b(i)
Next i
Dim time1 As Single
' Время до начала сортировки в секундах от начала суток
time1 = Timer
Call СортировкаМассиваМетодомПузырька(a, N)
time1 = Timer - time1 ' Время сортировки в секундах
Debug.Print "Время сортировки методом пузырька="; time1;
' Если обе контролирующие программы возвращают значение True
‘ напечатать Ok!
If ControlSortMas(a, N) And ControlSummMas(a, N, S) Then _
Debug.Print "Ok!"
time1 = Timer
Call СортировкаМассиваМетодомВыбора(a, N)
time1 = Timer - time1
Debug.Print "Время сортировки методом Выбора="; time1;
If ControlSortMas(a, N) And ControlSummMas(a, N, S) Then _
Debug.Print "Ok!"
For i = 1 To N ' Восстановить первоначальный массив
a(i) = b(i)
Next i
time1 = Timer
Call СортировкаМассиваМетодомВставки(a, N)
time1 = Timer - time1
Debug.Print "Время сортировки методом Вставки="; time1;
If ControlSortMas(a, N) And ControlSummMas(a, N, S) Then _
Debug.Print "Ok!"
time1 = Timer
Call СортировкаМассиваБыстрая(a, 1, N)
time1 = Timer - time1
Debug.Print "Время сортировки Быстрая="; time1;
If ControlSortMas(a, N) And ControlSummMas(a, N, S) Then _
Debug.Print "Ok!"
End Sub
На приведенной диаграмме рис. 8.1, представлены результаты сравни-
тельного анализа быстродействия четырех методов сортировки. Число
элементов массива N изменялось от 1000 до 10000. Время t измерялось в
секундах. Самой эффективной является быстрая сортировка. График для
нее практически слился с горизонтальной осью. Для простых сортировок с

102
увеличением количества элементов время увеличивается по квадратному
закону. Наиболее неэффективной является самая простая сортировка мето-
дом "пузырька". Сортировка методами выбора и вставки являются одина-
ковыми по быстродействию и примерно в три раза эффективнее сортиров-
ки методом "пузырька".

t
80
П узы р ько ва я
70 Выбор
В ста вки
60 Б ы стр а я

50

40

30

20

10
N
0
0 2000 4000 6000 8000 10000

Рис. 8.1. Зависимость времени сортировки от количество элементов


массива

Рассмотрим отдельно зависимость быстрой сортировки от числа эле-


ментов (табл.8.1). От N=100000 до N=2000000 время растет линейно. Т.е.
при увеличении N в два раза время t (с) также увеличивается в два раза.
При N=4000000 время увеличилось в 4 раза. Это связано с тем, что рас-
чет проводился на компьютере, имеющем объем оперативной памяти 32
Мб. Массив в 4000000 элементов типа Double занимает 32 Мб. Поэтому
при сортировке такого огромного массива используется виртуальная па-
мять на диске.
Таблица 8.1
N 100 000 200 000 400 000 800 000
t 1,9818 4,0106 8,4584 17,633
N 1 000 000 2 000 000 4 000 000 8 000 000 16 000 000
t 22,24125 46,74094 196,081 536,1816 1689,729

9. Задачи на символьные переменные


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

103
стовых функций и операции конкатенации строк. Операция конкатенации
строк обозначается символов + или &.

9.1. Задачи обработки текстовой информации


9.1.1. Подсчитать общее количество символов, количество цифр и
пробелов в текстовом файле.
Решение. Предполагается, что текстовый файл существует и в нем на-
ходится некоторая текстовая информация. Для получения текстового фай-
ла при помощи Word необходимо после подготовки файла сохранить его в
формате только текст. Следует отметить, что в конце текстовой строки
стоят два невидимых символа с кодом ASCII 10 и 13, означающие конец
строки и возврат каретки. В конце файла стоят управляющие символы, оз-
начающие конец файла. Логическая функция EOF возвращает значение
True, если код следующего символа файла является кодом конца файла.
Кроме перечисленных управляющих символов существуют другие, коды
их находятся в диапазоне 0-31. Для того чтобы узнать код символа, ис-
пользуется строковая функция Asc, возвращающая код символа.
Sub ЧислоСимволовВФайле ()
Dim s As String, c As String * 1
Dim NBlanks As Long, NDigits As Long, Nsimb As Long
' открыть текстовый файл на чтение и связать его с номером 5
' d:\aa\docword\metodic\t1.txt - полное имя файла
Open "d:\aa\docword\metodic\t1.txt" For Input As #5
NBlanks = 0: NDigits = 0: Nsimb = 0
‘ Пройти по всем символам файла с номером 5
Do While Not EOF(5) ' Цикл до конца файла с номером 5.
‘В переменную c считать очередной символ из файла
c = Input(1, #5)
If Asc( с ) >31 Then ‘ Если не управляющий символ
Nsimb = Nsimb + 1 ' Общее число символов
Select Case c
Case "1" To "9" ‘ Символ является цифрой
NDigits = NDigits + 1
Case " " ‘ Символ является пробелом
NBlanks = NBlanks + 1
End Select
End if
Loop
Close #5 ' Закрывает файл.
Debug.Print "Количество цифр в файле="; NDigits; _
" Количество пробелов в файле ="; NBlanks; _
"Количество символов в файле="; Nsimb
End Sub

9.1.2. В текстовом файле поменять все символы # на слово файл.


Решение.

104
Sub ЗаменаСимволовВФайле ()
Dim s As String, i As Long, c As String * 1
‘ открыть текстовый файл на чтение и связать его с номером 1
Open "d:\aa\docword\metodic\t2.txt" For Input As #1
Do While Not EOF(1) ' Цикл до конца файла номер 1.
c = Input(1, #1) ' Читает один символ в переменной c.
‘ Копирует в строку s либо слово файл, либо очередной символ
If c = "#" Then s = s + "файл" Else s = s + c
Loop
n = Len(s) ' Длина строки
Close #1 ' Закрывает файл.
‘ Открыть текстовый файл на запись и связать его с номером 1
Open "d:\aa\docword\metodic\t2.txt" For Output As #1
‘ Записывает преобразованную строку s в файл
Write #1, s
Close #1
End Sub
9.1.3. В текстовом файле поменять слово Дима на два слова – Дмитрий
Петрович.
Решение. Открываем файл на чтение и считываем первые 3 символа.
Затем в цикле считываем с файла один очередной символ и накапливаем
его в переменной s. После чего проверяем, является ли цепочка из послед-
них 4 символов строки s словом Дима. Если да, то вместо последних 4
символов Дима пишем 16 символов – Дмитрий Петрович. Выход из цик-
ла происходит при достижении конца файла. После выхода из цикла за-
крываем открытый на чтение файл номер 1. Затем открываем его же на за-
пись и при помощи оператора Print выводим полученную строку s.
Sub ЗаменаДимаНаДмитрийПетровичВФайле ()
Dim s As String, n As Long, c As String * 1, nSimb As Long
Open "d:\aa\docword\metodic\t2.txt" For Input As #1
s = Input(3, #1) ' Прочитать первые 3 символа
nSimb = 3 ' Число обработанных символов в строке s
Do While Not EOF(1) ' Цикл до конца файла номер 1
c = Input(1, #1) ' Читает один символ в переменной c
s = s + c : nSimb = nSimb + 1
If Mid(s, nSimb - 3, 4) = "Дима" Then
s = Left(s, nSimb - 4) + "Дмитрий Петрович" : nSimb = nSimb + 12
End If
Loop
Close #1 ' Закрывает файл
Open "d:\aa\docword\metodic\t2.txt" For Output As #1
Print #1, s; : Close #1
End Sub
9.1.4. Во введенном с клавиатуры тексте подсчитать количество рус-
ских букв, латинских букв и заглавных букв.

105
Sub КоличествоЦифрБуквРусскихЛатинских()
Dim s As String, RusCh As Long, LatCh As Long
Dim i As Long, ZgCh As Long, c As String * 1
s = InputBox("Введите текст")
For i = 1 To Len(s)
c = Mid(s, i, 1) ' i-тая буква введенной строки
Select Case c
Case "А" To "я" ‘ Русская буква
RusCh = RusCh + 1
Case "A" To "z" ‘ Латинская буква
LatCh = LatCh + 1
End Select
‘ Заглавная латинская или русская буквы
If (c > "A" And c < "Z") Or (c > "А" And c < "Я") Then ZgCh = ZgCh + 1
Next i
Debug.Print "Число русских букв в тексте ="; RusCh
Debug.Print "Число латинских букв в тексте ="; LatCh
Debug.Print "Число заглавных букв в тексте ="; ZgCh
End Sub
9.1.5. Во введенном с клавиатуры тексте подсчитать количество рус-
ских гласных букв.
Решение. В переменную RusGl записываем все гласные буквы. Вводим
текст в переменную s. В цикле по всем символам строки s, с помощью
функция InStr, проверяем, есть ли i-тый символ в строке RusGl. Функция
InStr возвращает либо номер гласной буквы, если этот символ является
гласной буквой, либо 0, если этот символ не является гласной буквой. Чет-
вертый параметр функции InStr равен 1, поэтому при сравнении большие и
маленькие буквы считаются одинаковыми.
Sub КоличествоРусскихГласныхБукв()
Dim s As String, NGl As Long, RusGl As String, i As Long
RusGl = "аеёиоуыэюя"
s = InputBox("Введите текст")
For i = 1 To Len(s)
If InStr(1, RusGl, Mid(s, i, 1), 1) > 0 Then NGl = NGl + 1
Next i
Debug.Print "Число гласных русских букв в тексте ="; NGl
End Sub
9.1.6. Во введенном с клавиатуры тексте подсчитать количество слов.
Решение. Для простоты программы словом будем называть последова-
тельность символов, отличных от пробелов, заключенных между пробела-
ми. Вводим логическую переменную inWord, принимающую значение Ис-
тина, если текущий i-тый символ входит в какое-то слово. Обходим по
всем символам введенного текста и подсчитываем количество символов,
являющихся последним символом в слове. Символ является последним в

106
слове, если переменная inWord принимает значение Истина и следующий
символ – пробел или конец текста.
Sub ПодсчетКоличестваСлов()
Dim nWord As Long, Text As String, i As Long, c As String * 1
Dim endWord As String, inWord As Boolean
endWord = ",;: !?" ' Символы конца слова
'Ввести текст и для упрощения алгоритма добавить пробелы
‘справа и слева
Text = “ “+InputBox("Введите текст")+” ”
inWord = false ' Обработка первого символа текста
For i = 2 To Len(Text)
c = Mid(Text, i, 1) ' i-тый символ текста
If inWord Then ' Символ находится внутри слова
If InStr(1, endWord, C, 0) > 0 Then ' Вышли из слова
‘ Сбросить флажок inWord и накопить 1
inWord = False: nWord = nWord + 1
End If
Else
' Вне слова и не пробел. Установить флажок внутри слова
If c <> " " Then inWord = True
End If
Next i
Debug.Print "Количество слов в тексте = "; nWord
End Sub
9.1.7. Написать программу, которая убирает лишние пробелы в
выделенном в Word фрагменте.
Данная программа может быть полезна при работе c документами
текстового процессора Word 97.
Sub УбратьЛишниеПробелы()
Dim st As String, st1 As String, c As String * 1, i As Long, P As String * 1
P = " " ' пробел
'Переписать выделенный фрагмент в переменную st
st = Selection.Text
For i = 1 To Len(st) ' Обойти все символе в фрагменте
c = Mid(st, i, 1): st1 = st1 + c
If c = P Then ' Если текущий символ пробел
' Пропустить все пробелы после текущего пробела
While Mid(st, i + 1, 1) = P ´Пока пробел, выполнять цикл
i = i + 1 ' Перейти к следующему символу
Wend
End If
Next i
Selection.Text = st1 ' Переписать полученную строку без пробелов
End Sub
9.1.8. Написать программу, которая убирает все символы конца абзаца
в выделенном фрагменте текста текстового процессора Word.

107
Очень полезная программа для обработки текстов, полученных при
помощи текстовых редакторов в операционной системе Dos и преобразо-
ванных в формат документов Word.
Sub УбратьСимволыКонецАбзаца()
Dim st As String, st1 As String, c As String * 1, i As Long
'Переписать выделенный фрагмент в переменную st
st = Selection.Text
For i = 1 To Len(st) ' Обойти все символы в фрагменте
c = Mid(st, i, 1) ‘ i-тый символ
‘ Если символ является символом конца абзаца (код 13),
‘ то его не включать в преобразованный текст st1
If Asc( c ) <> 13 Then st1 = st1 + c
Next i
Selection.Text = st1 ' Переписать полученную строку без пробелов
End Sub
9.1.9. В выделенном фрагменте текста подсчитать количество слов,
имеющих три гласных буквы.
Sub ПодсчетКоличестваСловСТремяГласными()
Dim nWord As Long, Text As String, inWord As Boolean, i As Long, _
c As String*1, Gl As String, NGlInWord As Long, nWodr As Long, _
endWord As String
Gl = "аеёиоуыэюя" ' Все русские гласные буквы
endWord = ",;: !?" ' Символы конца слова
Text = Selection.Text
Text = " " + Text + " " ' Добавляем пробелы справа и слева
nWord = 0 ' Число слов с тремя гласными
NGlInWord = 0 ' Число гласных в слове
inWord = False ' =true, если обрабатываемый символ внутри слова
For i = 1 To Len(Text)
c = Mid(Text, i, 1) ' i-тый символ обрабатываемого текста
If inWord Then ' Символ находится внутри слова
If InStr(1, Gl, c, 1) > 0 Then NGlInWord = NGlInWord + 1
If InStr(endWord, c) > 0 Then
' Вышли из слова. Сбросить флажок inWord и накопить 1
inWord = False ' Последний символ вне слова
If NGlInWord = 3 Then nWord = nWord + 1 'Три гласных в слове
End If
Else
' Вне слова и не пробел. Установить флажок вошли в слово
If c <> " " Then ' Первая буква слова
inWord = True 'Последний символ внутри слова
' если гласная, то NGlInWord = 1, иначе NGlInWord = 0
If InStr(1, Gl, c, 1) > 0 Then NGlInWord = 1 Else NGlInWord = 0
End If
End If
Next i
Debug.Print "Количество слов с тремя гласными = "; nWord

108
End Sub

9.2. Задачи шифрования текста


Часто возникает необходимость передать некоторую текстовую ин-
формацию таким образом, чтобы она была непонятна посторонним поль-
зователям компьютерных сетей. Спрятать информацию от посторонних
глаз можно при помощи программ шифровальщиков. Программа-
шифровальщик по некоторым правилам изменяет текст до неузнаваемости
и записывает в файл. После чего файл по сети или другим способом пере-
дается адресату, который запускает программу-расшифровщик и получает
исходный файл.
Приведем некоторые простейшие алгоритмы и программы шифрования
и расшифрования русских текстов.
9.2.1. Зашифровать текст, находящийся в ячейке рабочего листа, по
следующему правилу: 1) в конце строки добавить три произвольных сим-
вола; 2) после каждой гласной буквы добавить два очередных символа из
введенного в программе ключевого предложения; 3) в полученном тексте
переставить 1ый символ с 4ым, 2ой – 3ий, 5ый – 8ым, 6ой – 7ым, и так по всем
полным четверкам символов.
Решение. При отладке программы будем использовать рабочий лист
EXCEL. В ячейку (1,3) запишем текст, который надо закодировать. В ячей-
ку (2,3) запишем результат первого шага, а в ячейку (3,3) – окончательно
закодированный текст. Для перестановки двух символов в строке напишем
подпрограмму Swap с тремя формальными параметрами: s – строка, в ко-
торой необходимо переставить элементы; i и j – номера символов, которые
необходимо переставить.
Sub swap(s As String, i As Long, j As Long)
Dim c As String * 1
c = Mid(s, i, 1): Mid(s, i, 1) = Mid(s, j, 1): Mid(s, j, 1) = c
End Sub
Sub Кодировщик()
Dim s As String, s1 As String, i As Long, Gl As String
Dim KL As String, c As String * 1, k As Long
Gl = "аеёиоыуэюя" ' алфавит гласных букв
' Символы, которые необходимо вставлять после гласных
KL = "фжшцщфхйчгфжщшцшжэюйцкнгшщзх"
Sheets("Лист2").Select : s = Cells(1, 3)
s = s + "фжщ" ‘ В конец строки добавить три символа фжщ
s1 = "" ‘ В s1 получим новую более длинную строку
' В этом цикле в переменную s1 копируются символы из s и после
‘ каждой гласной добавить два редко встречающихсяе символа
‘ из строки KL
k=1
‘Номер символа из KL, который нужно вставлять после гласных

109
For i = 1 To Len(s)
c = Mid(s, i, 1): s1 = s1 + c
If InStr(1, Gl, c, 1) > 0 Then
If k > Len(KL) - 1 Then k = 1
'Символы кончились в KL, начинаем сначала
s1 = s1 + Mid(KL, k, 2) ' Добавляем два символа из KL
k = k + 2 ‘ Перейти к следующей паре символов
End If
Next i
Cells(2, 3) = s1 ‘Выводим промежуточный результат
' Переставить 1-ый символ с 4-ым, 2-ой с 3-им и т.д.
For i = 1 To Len(s1) - 3 Step 4
‘поменять i-тый и i+3-тий символы в строке s1
Call swap(s1, i, i + 3)
Call swap(s1, i + 1, i + 2)
Next i
Cells(3, 3) = s1 ‘ Вывести зашифрованный текст в ячейку
End Sub
9.2.2. Расшифровать текст, зашифрованный по предыдущему правилу.
Sub Раскодировщик()
Dim s As String, s1 As String, i As Long, Gl As String, c As String * 1
Sheets("Лист2").Select
s1 = Cells(3, 3) ‘ Ввести зашифрованный текст в строку s1
' Переставить 1-ый символ с 4-ым, 2-ой с 3-им
For i = 1 To Len(s1) - 3 Step 4
‘Поменять i-тый и i+3-тий символы в строке s1
Call swap(s1, i, i + 3)
Call swap(s1, i + 1, i + 2)
Next i
Gl = "аеёиоыуэюя": s = ""
' Копировать s1 в s, при этом пропускать два символа после
‘ гласных
For i = 1 To Len(s1) –3 ‘Последние 3 символа не копировать в s
c = Mid(s1, i, 1): s = s + c
If InStr(1, Gl, c, 1) > 0 Then i = i + 2 ‘ Пропустить два символа
Next I
‘Записать расшифрованный текст в ячейку рабочего листа
Cells(4, 3) = s
End Sub
9.2.3. При работе в текстовом процессоре Word часто пользователь за-
бывает перейти на нужный алфавит (русский или латинский) и набирает
текст на альтернативном алфавите. Написать программу, которая преобра-
зует в выделенном тексте символы, набранные на латинском регистре на
символы русского регистра.
Решение. Введем две символьные переменные alphRus и alphEng. В
первую переменную запишем все русские символы, кроме букв э и Э. Во

110
вторую переменную запишем те же буквы, но на латинском регистре.
Дальше в переменную st считывается выделенный текст. В цикле по всем
символам проверяем каждый символ, является ли он русским символом,
набранным на латинском регистре. Если является, то меняем на соответст-
вующий символ, набранный на русском алфавите. Символ “, имеющий код
34, ищем при помощи функции Asc и заменяем его на букву Э. Символы с
кодом 145 или 146 соответствуют апострофам ‘’, заменяем их на букву э.
Sub ИнвертироватьEnglishНаРусские()
Dim st, sn, alphRus As String, alphEng As String, i, Nc, c As String * 1
' Все клавиши на русском регистре
alphRus = "йцукенгшщзхъфывапролджячсмитьбюё" + _
"ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЯЧСМИТЬБЮЁ"
' Соответствующие русским клавиши на латинском регистре
alphEng = "qwertyuiop[]asdfghjkl;zxcvbnm,.`" + _
"QWERTYUIOP{}ASDFGHJKL:ZXCVBNM<>~"
'Переписать выделенный фрагмент в переменную st
st = Selection.Text
For i = 1 To Len(st) ‘ Обойти по всем символам строки st
c = Mid(st, i, 1) ' Считать i-тый символ из строки st
If Asc( с ) = 34 Then Mid(st, i, 1) = "Э" ' Символ "
If Asc( с ) = 145 Or Asc( с ) = 146 Then Mid(st, i, 1) = "э" ' Символы '’
Nc = InStr(alphEng, c) ' Номер символа в переменной alphEng
‘ Если c символ из alphEngl, то заменить
‘соответстветствующим русским символом
If Nc > 0 Then Mid(st, i, 1) = Mid(alphRus, Nc, 1)
Next i
' Перезаписать st в выделенный фрагмент текста
Selection.Text = st
End Sub
9.2.4. Написать программу, которая инвертирует текст, ошибочно
набранный на русском регистре вместо латинского.
Sub ИнвертироватьРусскиеНаEnglish()
Dim st, sn, i, Nc, alphRus As String, alphEng As String, c As String * 1
alphRus = "йцукенгшщзхъфывапролджячсмитьбюё” + _
”ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЯЧСМИТЬБЮЁ"
alphEng = "qwertyuiop[]asdfghjkl;zxcvbnm,.`” + _
QWERTYUIOP[]ASDFGHJKL;ZXCVBNM,.~"
st = Selection.Text
For i = 1 To Len(st) ‘ Обойти по всем символам строки st
c = Mid(st, i, 1) ' Считать i-тый символ из строки st
If c = "Э" Then Mid(st, i, 1) = Chr(34) ' Символ " (кавычки)
If c = "э" Then Mid(st, i, 1) = Chr(146) ' Символ ' (апостроф)
Nc = InStr(alphRus, c)
If Nc > 0 Then Mid(st, i, 1) = Mid(alphEng, Nc, 1)
Next i
Selection.Text = st

111
End Sub

10. Задачи на массивы


10.1. Одномерные массивы натуральных чисел
10.1.1. Подсчитать количество простых натуральных пятизначных чи-
сел.
Sub ПростыхПятизначныхЧисел()
Dim NSimple As Long, a As Long, i As Long
‘ Обойти все пятизначные числа
For i = 10000 To 99999
If Simple(i) Then NSimple = NSimple + 1
Next i
Debug.Print "Простых пятизначныхчисел="; NSimple
End Sub
‘ Логическая функция, отвечающая на вопрос: простое ли число а?
Function Simple(a As Long) As Boolean
Dim i As Long
Simple = False
For i = 2 To a \ 2 ‘ Обойти по всем целым числам от 2 до a\2
If a Mod i = 0 Then Exit Function ‘ Если a делится на i, то a простое
Next i
‘ a не делится на целые числа от 2 до a\2. Да, простое.
Simple = True
End Function
Замечание. Нетрудно заметить, что проверку на делимость исследуемо-
го числа a, можно проводить до значения равного a . При этом заглавие
цикла будет следующим:
For i = 2 To sqr(a)
В этом случае для больших значений исследуемого числа a, программа
будет работать значительно быстрее.
10.1.2. При помощи датчика случайных чисел сгенерировать N случай-
ных трехзначных чисел и вывести их в первый столбец рабочего листа
Excel. При этом ячейки, в которых находятся простые числа, выделить
цветом. Число N ввести с клавиатуры.
Sub ПростыеЧислаВыделитьЦветом()
Dim a As Long, N As Long, i As Integer
Randomize Timer ' Построить ряд случайных чисел
N = Val(InputBox("Введите количество элементов"))
Sheets("Лист1").Select
Columns("A:A").Clear ' Очистить столбец A
For i = 1 To N
a = Rnd * 899 + 100 ' Получить трехзначное случайное число a
Cells(i, 1) = a ' Записать его в i-тую строку столбца A

112
' если a простое число, то вызвать подпрограмму
’ для заполнения ячейки ai цветом номер 22
If Simple(a) Then Call FillColor(i, "a", 22)
Next i
End Sub
' Подпрограмма, которая закрашивает ячейку, стоящую в i – той
‘строке столбца c и цветом номер Color (от 0 до 55)
' функция Trim удаляет пробелы слева и справа в строке Str(i)
Sub FillColor(i As Integer, c As String, Color As Integer)
Range(c + Trim(Str(i))).Select ' выделить ячейку ci
With Selection.Interior ‘ залить ячейку цветом
.ColorIndex = Color ‘ номер цвета
.Pattern = xlSolid ‘ стиль заполнения
End With
End Sub
10.1.3. При помощи датчика случайных чисел сгенерировать массив из
N случайных шестизначных чисел и вывести их во второй столбец рабоче-
го листа Excel. Подсчитать количество счастливых чисел. Если количество
счастливых чисел четно, то ячейки, в которых находятся счастливые числа,
выделить цветом. N вводится с клавиатуры. Шестизначное число называ-
ется счастливым, если сумма первых трех цифр равна сумме последних
трех цифр.
Sub СчастливыеЧислаВыделитьЦветом()
Dim a() As Long, N As Long, i As Integer, NHappy As Integer
Randomize Timer ' построить ряд случайных чисел
N = Val(InputBox("Введите количество элементов"))
ReDim a(N) ‘ создать динамический массив
Sheets("Лист1").Select
Columns("B:B").Clear ' очистить столбец A
For i = 1 To N
' Получить случайное шестизначное число a
a(i) = Rnd * 899999 + 100000
Cells(i, 2) = a(i) ' Записать его в i-тую строку столбца B
' подсчет количества счастливых чисел
If Happy(a(i)) Then NHappy = NHappy + 1
Next i
If (NHappy Mod 2) = 0 Then ‘ Если Nhappy четно
For i = 1 To N
' Если a счастливое число, то вызвать подпрограмму FillColor
If Happy(a(i)) Then Call FillColor(i, "B", 35)
Next i
End If
MsgBox ("Всего счастливых чисел=" + Str(NHappy))
End Sub
Function Happy(a As Long) As Boolean
Dim N1 As Integer, N2 As Integer, N3 As Integer, N4 As Integer, N5 As Integer

113
Dim N6 As Integer ' Ni - i-тая цифра в числе
N1 = a \ 100000 : N2 = (a \ 10000) Mod 10
N3 = (a \ 1000) Mod 10 : N4 = (a \ 100) Mod 10
N5 = (a \ 10) Mod 10 : N6 = a Mod 10
‘ Истина, если сумма первых трех цифр равна сумме вторых
‘ трех цифр
Happy = N1 + N2 + N3 = N4 + N5 + N6
End Function
10.1.4. При помощи датчика случайных чисел сгенерировать массив из
N случайных натуральных чисел различных порядков и вывести их в чет-
вертый столбец рабочего листа Excel. В пятый столбец вывести преобра-
зованные числа по следующему правилу:
• если число простое, то вывести то же число, но ячейку выделить цве-
том, номер которого равен остатку от деления количества простых чи-
сел на 55;
• если число составное, то его инвертировать. Т.е. записать цифры в
обратном порядке.
Решение. Задача решается двумя методами.
Sub ИнвертироватьНепростыеЧисла()
Dim a() As Long, N As Long, i As Integer, NSimple As Integer
Dim Color As Integer, st As Long
Randomize Timer ' Построить ряд случайных чисел
N = Val(InputBox("Введите количество элементов"))
ReDim a(N)
Sheets("Лист1").Select
Columns("D:E").Clear ' Очистить столбцы D и E
For i = 1 To N
st = 10 ^ Int(Rnd * 6 + 1.5) ' Случайное количество цифр в числе
a(i) = Rnd * st ' Получить случайное число в диапазоне от 0 до st
Cells(i, 4) = a(i)
If Simple(a(i)) Then NSimple = NSimple + 1’ Кол-во простых чисел
Next i
Color = NSimple Mod 55 ‘ Выбрать номер цвета
For i = 1 To N
If Simple(a(i)) Then
Cells(i, 5) = a(i): Call FillColor(i, "E", Color)
Else
‘ Записать инвертированное число
Cells(i, 5) = InvertNumber1(a(i)) ‘Первый метод
‘ Cells(i, 5) = InvertNumber2(a(i)) ‘Второй метод
End If
Next i
End Sub
‘ Первый метод инвертирования целого числа
Function InvertNumber1(ByVal a As Long) As Long
Dim numb As Integer, inva As Long, b As Long, e As Long, k As Integer

114
Dim d As Integer
numb = Int(Log10(a + 0.0001)) + 1 ‘ Количество цифр в числе a
b = 10 ^ (numb - 1): e = 1
For k = 1 To numb ‘ Цикл по всем цифрам числа
d=a\b ' 1-ая цифра слева числа a
a = a - d * b 'Убрать 1-ую цифру слева числа a
b = b \ 10
inva = inva + d * e ‘ Добавить цифру d слева к числу inva
e = e * 10
Next k
InvertNumber1 = inva ‘Инвертированное число
End Function
‘ Второй метод инвертирования целого числа с использованием
‘строковых функций
Function InvertNumber2(ByVal a As Long) As Long
Dim numb As Integer, inva As String, t As String * 1, i As Integer
inva = Str(a) ‘Преобразовать целое число в строку
numb = Len(inva) ‘ Длина строки
For i = 1 To numb \ 2
‘ Обмен симметричных относительно центра строки символов
t = Mid(inva, i, 1): Mid(inva, i, 1) = Mid(inva, numb + 1 - i)
Mid(inva, numb + 1 - i) = t
Next i
InvertNumber2 = Val(inva) ‘ Преобразовать строку в целое число
End Function

10.2. Задачи на одномерные массивы действительных


чисел
10.2.1. С клавиатуры вводится массив положительных действительных
чисел размерности N. Не изменяя целую часть всех элементов массива,
дробной части присвоить среднеарифметическое значение дробных частей
всего массива с точностью три знака после запятой.
Sub СреднееЗначениеДробныхЧастей()
Dim s As Double, a() As Double, i As Long, N As Long, d As Double
N = Val(InputBox("Введите размерность массива"))
ReDim a(N)
s=0
For i = 1 To N
a(i) = CDbl(InputBox("Введите элемент массива номер " + Str(i)))
d = a(i) - Fix(a(i)) ‘ Дробная часть числа
s = s + d ‘ Накопление суммы дробных частей
Debug.Print Tab((i - 1) * 10); Format(a(i), "#0.000");
‘ После 8 элем. перейти к другой строке
If (i Mod 8) = 0 Then Debug.Print
Next i
s = Int(1000 * s / N+0.5) / 1000 ‘Округлить до трех знаков

115
Debug.Print ‘Перейти на другую строку
For i = 1 To N
‘К целой части добавить среднее значение дробной
a(i) = Int(a(i)) + s
Debug.Print Tab((i - 1) * 10); Format(a(i), "#0.000");
If (i Mod 8) = 0 Then Debug.Print
Next i
End Sub
10.2.2. При помощи датчика случайных чисел получить массив A из N
положительных действительных чисел в диапазоне от 1 до 1000 с тремя
знаками после запятой. На базе массива A получить массив B, поменяв
целую и дробную части местами.
Sub ЦелуюЧастьПоменятьНаДробную()
Dim a() As Double, b() As Double, d As Double
Dim i As Long, N As Long, numb As Long
N = Val(InputBox("Введите размерность массива"))
ReDim a(N), b(N)
Randomize Timer
Sheets("Лист1").Select: Range("a1:b100").Clear
For i = 1 To N
' Это случайные действительные числа от 1 до 1000
d = Rnd * 899 + 100
' Округлить d до трех знаков после запятой
a(i) = Int(d * 1000 + 0.5) / 1000
Cells(i, 1) = a(i) ' Вывести в первый столбец рабочего листа
Next i
For i = 1 To N
numb = Int(a(i)) ' Целая часть числа
d = a(i) - numb ' Дробная часть числа
' + 0.0000000001 из-за небольшой ошибки при вычитании d
‘ может быть <
b(i) = Int(d * 1000 + 0.0000000001) + numb / 1000
Cells(i, 2) = b(i) ‘ Вывести результат во второй столбец
Next i
End Sub
10.2.3. При помощи датчика случайных чисел получить массив A из N
действительных чисел в диапазоне от –999 до 999. На основании массива
A получить массив B по следующему правилу: если Ai отрицательное, то
Bi равно сумме цифр целой части числа, а если Ai положительное, то Bi
равно сумме первых трех цифр дробной части.
Sub СуммаЦифрЦелойИДробнойЧастей()
Dim a() As Double, b() As Double, d As Double
Dim i As Long, N As Long, numb As Long
N = Val(InputBox("Введите размерность массива"))
ReDim a(N), b(N)
Randomize Timer

116
Sheets("Лист1").Select: Range("a1:b100").Clear
For i = 1 To N
d = Rnd * 1998 - 999 ' Это действительные числа от -999 до 999
' округлить d до 4 знаков после запятой
a(i) = Int(d * 10000 + 0.5) / 10000
Cells(i, 1) = a(i) ' Вывести в первый столбец рабочего листа
Next i
For i = 1 To N
numb = Int(Abs(a(i))) ' Целая положительная часть числа
d = Abs(a(i)) - numb ' Дробная часть числа
If a(i) < 0 Then
' Первая цифра + вторая цифра + третья цифра целой части
‘ трехзначного числа
b(i) = numb \ 100 + (numb - (numb \ 100) * 100) \ 10 + (numb Mod 10)
Else
' Первая цифра + вторая цифра + третья цифра дробной части
b(i) = Int(d * 10) + (Int(d * 100) Mod 10) + (Int(d * 1000) Mod 10)
End If
Cells(i, 2) = b(i)
Next i
End Sub
10.2.4. При помощи датчика случайных чисел получить последователь-
ность действительных чисел в диапазоне от –100 до 200. Подсчитать мак-
симальную длину подпоследовательностей отрицательных элементов, за-
ключенных между двумя неположительными элементами.
Sub ДлинаПодпоследовательностиОтрицательныхЧисел()
Dim a As Long, maxnumb As Long, numb As Long, N As Long
Dim flag As Boolean, i As Long
N=_
Val(InputBox("Введите количество элементов последовательности"))
Randomize Timer
Sheets("Лист1").Select: Range("a1:a100").Clear
flag = True: numb = 0: maxnumb = 0
For i = 1 To N
' Это случайные действительные числа от -100 до 200
a = Rnd * 300 - 100
Cells(i, 1) = a ' Вывести в первый столбец рабочего листа
If flag Then
‘ Находится внутри цепочки отрицательных элементов
If a < 0 Then
numb = numb + 1
Else ‘ Вышли из цепочки отрицательных элементов
‘ Флажок “в цепочке отрицательных элементов” сбросить
flag = False
If numb > maxnumb Then maxnumb = numb ‘Длина > предыдущих?
End If
Else ’ Вне цепочки отрицательных элементов

117
If a < 0 Then ‘ Вошли в цепочку отрицательных элементов
numb = 1: flag = True
End If
End If
Next i
Debug.Print "максимальная длина отрицательных элементов = "; _
maxnumb
End Sub
10.2.5. При помощи датчика случайных чисел получить последователь-
ность действительных чисел в диапазоне от –100 до 200. Подсчитать мак-
симальную сумму подпоследовательностей положительных элементов, за-
ключенных между двумя неотрицательными элементами.
Sub СуммаПодпоследовательностиПоложительныхЧисел()
Dim a As Double, maxSum As Double, Sum As Double, N As Long
Dim flag As Boolean, i As Long
N=_
Val(InputBox("Введите количество элементов последовательности"))
Randomize Timer
Sheets("Лист1").Select: Range("a1:a100").Clear
flag = True: Sum = 0: maxSum = 0
For i = 1 To N
a = Rnd * 300 – 100
' Это случайные действительные числа от -100 до 200
Cells(i, 1) = a ' Вывести в первый столбец рабочего листа
If flag Then
‘ Находится внутри цепочки положительных элементов
If a > 0 Then
Sum = Sum + a
Else ‘ Вышли из цепочки положительных элементов
‘ Флажок “в цепочке положительных элементов” сбросить
If Sum > maxSum Then maxSum = Sum
flag = False
‘ Сумма > предыдущих сумм?
End If
Else ’ Вне цепочки положительных элементов
If a > 0 Then ‘ Вошли в цепочку положительных элементов
Sum = a: flag = True
End If
End If
Next i
Debug.Print "максимальная сумма положительных элементов = "; maxSum
End Sub
10.2.6. Из массива действительных чисел, находящихся с первой строки
и до первой пустой строки столбца A рабочего листа Excel, убрать повто-
ряющиеся числа.

118
Sub УбратьПовторяющиесяЧисла()
Dim a() As Double, n As Long, k As Long, i As Long, j As Long
Sheets("Лист1").Select
n = 0: k = 0
While Cells(n + 1, 1) <> Empty ' пока в следующей строке не пусто
n=n+1
' Изменить размер массива сохраняя (Preserve) значения
‘ элементов массива до изменения размерности
ReDim Preserve a(n)
a(n) = Cells(n, 1) ‘ Считать содержимое ячейки в массив a
Wend
Range("b1:b" + Trim(Str(n))).Clear ' Очистить ячейки
For i = 1 To n
For j = 1 To i - 1 ' Есть ли a(i) среди первых i-1 элементов
If a(j) = a(i) Then GoTo nexti ' Есть, поэтому его пропустить
Next j
k = k + 1 ' Элемент не повторяющийся
Cells(k, 2) = a(i) ' Записать его в строку номер k второго столбца
nexti: Next i
End Sub
10.2.7. В области “a1:i100” рабочего листа Excel находятся действи-
тельные числа или пустые ячейки. Подсчитать общее число пустых ячеек и
какое число чаще других встречается в указанных ячейках.
Sub КакоеЧислоЧащеВстречается()
Dim a(900) As Double, k As Long, nEmpty As Long, numb As Long
Dim i As Long, j As Long, max As Double, NMax As Long
Sheets("Лист1").Select
k = 0 ' Номер непустой ячейки
' Обход по всем ячейкам области "a1:i100"
For i = 1 To 100
For j = 1 To 9
If Cells(i, j) <> Empty Then
k=k+1
' Если ячейка не пустая, считать ее содержимое в массив a
a(k) = Cells(i, j) ' Запомнить очередной элемент в массиве
End If
Next j, i
Debug.Print "Число непустых ячеек= "; 900 - k
NMax = 0 ' Максимальное количество одинаковых чисел
For i = 1 To k
numb = 0 ' Число элементов = a(i)
For j = 1 To k ' Сколько элементов массива a = элементу a(i)
If a(j) = a(i) Then numb = numb + 1
Next j
'Если элементов a(i) > чем других элементов a(k), где k<i
If numb > NMax Then
NMax = numb: max = a(i) ' Запомнить новые значения

119
End If
Next i
Debug.Print "Наиболее часто встречается число "; max; _
" Оно встречается "; NMax; " раза"
End Sub

10.3. Задачи на двухмерные массивы действительных


чисел
10.3.1. Написать программу, которая получает единичную матрицу
размерности N, где N случайное число в диапазоне от 5 до 20. Полученную
матрицу вывести на рабочий лист Excel.
Sub МатрицаЕдиничная()
Dim a() As Long, i As Long, j As Long, N As Long
Randomize Timer ' Построить ряд случайных чисел
N = Rnd * 15 + 5 ' N -- случайное число [5,20]
ReDim a(N, N) ' Динамический двухмерный массив
Sheets("Лист2").Select
For i = 1 To N
For j = 1 To N
a(i, j) = 0 ‘ Все элементы обнулить
Next j
a(i, i) = 1 ' Записать на диагональ 1
Next i
For i = 1 To N ' Вывести двухмерный массив на рабочий лист
For j = 1 To N
Cells(i, j) = a(i, j)
Next j, i
End Sub
10.3.2. Написать программу, которая получает матрицу размерности N,
в которой элементы выше побочной диагонали равны 1, на побочной диа-
гонали 0, а ниже побочной диагонали –1. N случайное число в диапазоне
от 5 до 20. Полученную матрицу вывести в окно отладки.
Sub МатрицаПобочнаяДиагональ1()
Dim a() As Long, i As Long, j As Long, N As Long
Randomize Timer ' Построить ряд случайных чисел
N = Rnd * 15 + 5 ' N – случайное число [5,20]
ReDim a(N, N) ' Динамический двухмерный массив
For i = 1 To N
For j = 1 To N
If i + j < N + 1 Then 'Выше побочной диагонали
a(i, j) = 1
ElseIf i + j = N + 1 Then ' На побочной диагонали
a(i, j) = 0
Else 'Ниже побочной диагонали
a(i, j) = -1

120
End If
Next j, i
For i = 1 To N ' Вывести массив в окно отладки
For j = 1 To N
Debug.Print Tab((j - 1) * 4); a(i, j);
Next j
Debug.Print ‘ Перейти на другую строку
Next i
End Sub
10.3.3. Написать программу, которая получает матрицу размерности N.
N случайное число в диапазоне от 5 до 20. Полученную матрицу вывести в
ячейки рабочего листа Excel. Раскрасить различными цветами ячейки с
разными числами.
10 1 1 1 … 1 1 1 20
4 10 1 1 … 1 1 20 2
4 4 10 1 … 1 20 2 2
… … … … … … … … …
4 4 4 20 … 10 2 2 2
4 4 20 3 … 3 10 2 2
4 20 3 3 … 3 3 10 2
20 3 3 3 … 3 3 3 10
Sub Матрица933()
Dim a() As Long, i As Integer, j As Integer, N As Long, alph As String
Randomize Timer ' Построить ряд случайных чисел
N = Rnd * 15 + 5 ' N -- случайное число [5,20]
ReDim a(N, N) ' Динамический двухмерный массив
Sheets("Лист1").Select
alph = "abcdefghijklmnopqrstuvwxyz"
Range("a1:z26").Clear
For i = 1 To N
For j = 1 To N
If j > i And i + j < N + 1 Then
a(i, j) = 1: Call FillColor(i, Mid(alph, j, 1), 22)
ElseIf j > i And i + j > N + 1 Then
a(i, j) = 2: Call FillColor(i, Mid(alph, j, 1), 23)
ElseIf j < i And i + j > N + 1 Then
a(i, j) = 3: Call FillColor(i, Mid(alph, j, 1), 24)
ElseIf j < i And i + j < N + 1 Then
a(i, j) = 4: Call FillColor(i, Mid(alph, j, 1), 27)
ElseIf i = j Then
a(i, j) = 10: Call FillColor(i, Mid(alph, j, 1), 26)
Else
a(i, j) = 20: Call FillColor(i, Mid(alph, j, 1), 28)
End If
Next j, i
For i = 1 To N ' вывести массив на рабочий лист

121
For j = 1 To N
Cells(i, j) = a(i, j)
Next j, i
End Sub
‘ закрасить ячейку ci цветом Color
Sub FillColor(i As Integer, c As String, Color As Integer)
Range(c + Trim(Str(i))).Interior.ColorIndex = Color
End Sub

10.3.4. Написать програм- 1 2 4 8 ... 2N − 2 2 N −1 2 N


му, которая получает 0 1 2 4 ... 2 N −3 2N − 2 2 N −1
приведенную справа матрицу 0 0 1 2 ... 2N − 4 2 N −3 2 N − 2
размерности N+1. N ... ... ... ... ... ... ... ...
случайное число в диапазоне 0 0 0 0 ... 0 1 2 от
5 до 15. 0 0 0 0 ... 0 0 1
Sub Матрица934()
Dim a() As Long, i As Integer, j As Integer, N As Long
Randomize Timer ' Построить ряд случайных чисел
N = Rnd * 10 + 5 ' Т -- случайное число [5,15]
ReDim a(N, N) ' Динамический двухмерный массив
For i = 1 To N ' Это заполнение матрицы ниже главной диагонали
a(i, i) = 1 ' На главной диагонали
For j = 1 To i - 1 'Ниже главной диагонали элементы=0
a(i, j) = 0
Next j, i
For i = 1 To N - 1 ' Выше главной диагонали
For j = i + 1 To N
a(i, j) = a(i, j - 1) * 2
Next j, i
For i = 1 To N ' Вывод полученной матрицы
For j = 1 To N
Debug.Print Tab((j - 1) * 6); a(i, j);
Next j, i
End Sub
10.3.5. При помощи датчика случайных чисел получить матрицу A по-
рядка N. (N – целое случайное число в диапазоне от 6 до 15). Отсортиро-
вать по убыванию только те строки матрицы A, в которых среднеарифме-
тическая сумма элементов больше среднеарифметического значения сум-
мы элементов матрицы A . Вывести обе матрицы в ячейки рабочего листа.
Sub Матрица935()
Dim a() As Long, i As Integer, j As Integer, N As Long, sm As Double
Dim sc As Long, k As Long, t As Long, Alph As String
Randomize Timer ' Построить ряд случайных чисел
N = Rnd * 10 + 5 ' N – случайное число [5,15]
ReDim a(N, N) ' Динамический двухмерный массив

122
Sheets("Лист3").Select
Alph = "abcdefghijklmnop"
' Очистить область вывода матриц
Range("a1:" + Mid(Alph, N + 3, 1) + Trim(Str(2 * N + 2))).Clear
'Закрасить область вывода матриц
Range("a1:" + Mid(Alph, N, 1) + Trim(Str(N))).Interior.ColorIndex = 35
Range("a" + Trim(Str(N + 2)) + ":" + Mid(Alph, N, 1) + _
Trim(Str(2 * N + 1))).Interior.ColorIndex = 36
sm = 0 ' Сумма всех элементов матрицы
For i = 1 To N
For j = 1 To N
a(i, j) = Rnd * 100
sm = sm + a(i, j)
Cells(i, j) = a(i, j)
Next j, i
sm = sm / N ^ 2 ' Среднее значение элементов матрицы
Debug.Print "среднее значение элементов матрицы ="; sm
For i = 1 To N
sc = 0
For j = 1 To N ' Сумма элементов j-того столбца
sc = sc + a(i, j)
Next j
' Среднеарифметическое значение элементов j-того столбца
sc = sc / N
Cells(i, N + 2) = sc
If sc > sm Then
' Выделить строку, которую изменяли, цветом номер 37
Range("a" + Trim(Str(N + 1 + i)) + ":" + Mid(Alph, N, 1) + _
Trim(Str(N + 1 + i))).Interior.ColorIndex = 37
For k = 1 To N - 1 ' Это сортировка методом пузырька
For j = 1 To N - k
If a(i, j + 1) > a(i, j) Then
t = a(i, j + 1): a(i, j + 1) = a(i, j): a(i, j) = t
End If
Next j, k
End If
For j = 1 To N ' Вывод преобразованной матрицы
Cells(N + 1 + i, j) = a(i, j)
Next j
Next i
End Sub
10.3.6. Дана действительная квадратная матрица A порядка N. Получить
одномерный массив b размерности 2N-1 по формулам:
b1 = a n ,1 ; b2 = a n −1,1 + a n ,2 ; b3 = a n − 2,1 + a n −1,2 + a n ,3 ;… ;
bn = a1,1 + a 2,2 + … + a n , n ;… ;
b2 n − 2 = a1, n −1 + a 2, n ; b2 n −1 = a1, n .

123
Т.е. сумма элементов по поддиагоналям параллельным главной диаго-
нали.
Sub Матрица936()
Dim a() As Long, b() As Long, i As Integer, j As Integer, N As Long, _
k As Long
Randomize Timer ' Построить ряд случайных чисел
N = Val(InputBox("Введите размерность матрицы"))
ReDim a(N, N), b(2 * N - 1) ' Динамические массивы
Sheets("Лист1").Select
For i = 1 To N
For j = 1 To N
a(i, j) = Rnd * 100
Cells(i, j) = a(i, j)
' Номер элемента массива b, соответст. элементу a(i,j)
k = N - (i - j)
b(k) = b(k) + a(i, j) ' Накопить в массиве b
Next j, i
For i = 1 To 2 * N - 1
Cells(N + 2, i) = b(i)
Next i
End Sub
10.3.7. Дана действительная квадратная матрица A порядка N. Повер-
нуть ее на 900 против часовой стрелки.
Решение. Нетрудно доказать, что поворот матрицы на 900 можно осу-
ществить при помощи двух последовательных преобразований:
1) транспонирования матрицы, т.е. перестановки местами строк и
столбцов;
2) инвертирования строк матрицы, т.е. перестановки 1-ой строки с по-
следней; 2-ой с предпоследней и так до средней строки.
Sub Матрица937()
Dim a() As Long, i As Integer, j As Integer, N As Long, t As Long
Randomize Timer ' построить ряд случайных чисел
N = Val(InputBox("Введите размерность матрицы"))
ReDim a(N, N): Sheets("Лист1").Select
For i = 1 To N ' Получить матрицу и вывести на Лист1
For j = 1 To N
a(i, j) = Rnd * 100
Cells(i, j) = a(i, j)
Next j, i
' Транспонировать матрицу (поменять местами строки со
‘столбцами)
For i = 2 To N
For j = 1 To i - 1
t = a(i, j): a(i, j) = a(j, i): a(j, i) = t
Next j, i
' Переставить местами 1-ю строку с N-ой; 2-ую с N-1 и

124
‘так до средней
For i = 1 To N \ 2
For j = 1 To N
t = a(i, j): a(i, j) = a(N + 1 - i, j): a(N + 1 - i, j) = t
Next j, i
For i = 1 To N ' Вывести преобразованную матрицу
For j = 1 To N
Cells(N + 1 + i, j) = a(i, j)
Next j, i
End Sub

11. Хранение чисел в памяти компьютера


К числовой информации относятся следующие типы данных:
• Целые числа ─ Byte, Integer, Long.
• Числа с фиксированной запятой ─ Currency, Decimal.
• Вещественные числа ─ Single, Double.
• Числа для описания даты ─ Date.
• Логические числа ─ Boolean.
Все эти числа в памяти компьютера хранятся в двоичном виде, но раз-
ными методами. Мы рассмотрим методы хранения некоторых из стан-
дартных типов.
11.1. Перевод натуральных чисел в различные системы
счисления

Существуют несколько систем счета и записи числовой информации.


Наиболее известные системы счисления, дошедшие до наших дней, это
римская система счисления и десятичная позиционная система.
Римская система счисления основана на семи символах: I, V, X, L, C, D
и M. Каждый символ равен определенному десятичному числу. Символ I
=1, V=5, X=10, L=50, C=100, D =500 и M=1000. Любое число записывает-
ся в виде комбинации этих цифр, при этом действуют следующие правила.
Если в комбинации буквы идут в порядке от больших к меньшим, то соот-
ветствующие числа складываются, а если какие-то буквы нарушают этот
порядок, то их значения вычитаются из следующей буквы.
Примеры.
XXXVII = 10+10+10+5+1+1=37.
MMDCXVIII = 1000+1000+500+100+10+5+1+1+1=2617.
IV = (5-1) = 4.
MCMXCIX = 1000+(1000-100)+(100-10)+(10-1)=1999.
В настоящее время особую роль играет десятичная позиционная систе-
ма счисления. Она основана на десяти цифрах: 0, 1, 2, 3, 4, 5, 6, 7, 8 и 9.
Кроме того, информацию несет не только цифра, но и ее позиция в числе.

125
Любое n-значное число A в десятичной системе счисления можно записать
в виде суммы n+1 слагаемого:
A=αn10n+ αn-110n-1 +…+ α2102 + α1101 + α0100 .
С появлением компьютеров особое значение приобрела двоичная,
восьмеричная и шестнадцатеричная системы счисления.
В двоичной системе счисления используются только две цифры: 0 и 1.
В восьмеричной системе – восемь цифр: 0, 1, 2, 3, 4, 5, 6 и 7. В шестна-
дцатеричной – 16 цифр: 0,1,2,3,4,5,6,7,8,9,a, b, c, d, e и f. Можно все по-
следние системы обобщить и назвать p-ичной системой. Число p называет-
ся основанием системы счисления. Мы будем рассматривать системы
счисления с основанием p в пределах от 2 до 36. Для p–ичной системы
счисления выбираем p первых цифр из строки Alph, состоящей из 36 сим-
волов:
Alph=”0123456789abcdefghijklmnopqrstuvwxyz”. (11.1)
При этом маленькие и большие латинские буквы принимаются
одинаковыми.
Запись числа A в p-ичной системе счисления представляется в виде по-
следовательности цифр, после которой на нижнем индексе записывается
число p, указывающее основание системы счисления. A=αnαn-1…α1α0 p.
Это же число можно представить в виде суммы n+1-го слагаемого:
A= pn+ αn-1pn-1 +…+ α2p2 + α1p1 + α0p0 , (11.2)
где αi – i-тая цифра числа.
Алгоритм перевода числа A=αnαn-1…α1α0 p в десятичную систему
счисления.
По формуле (11.2) находим сумму n-1-го слагаемого, при этом вместо
цифр αi берется десятичное число, которое на единицу меньше положения
символа αi в строке Alph (11.1).
Примеры. 7CF 16 =7.162 + 12.161 + 15.160 = 1999.
37178 =3.83 +7.82 +5.81 +6.80=1999.
111110011112 =1.211 +1.210 +1.29 +1.28 +1.27 +1.26 +0.25 +0.24 +1.23 + 1.22 +
1.21 + 1.20 = 1999.
1jj36=1.362+ 19.361 +19.360 =1999.
Рассмотрим теперь обратную задачу – перевод десятичного числа в
произвольную систему. Результатом перевода является строка S, состоя-
щая из символов соответствующей системы счисления.
Алгоритм перевода положительного десятичного числа A в p-ичную
систему счисления:
1. S=””.
2. Вычисляем остаток от деления A на p. α = A Mod p. Дописываем
слева к символьной переменной S символ номер α+1 из строки Alph
(11.1).
3. Делим нацело десятичное число A на p, записав результат в ту же
переменную A.

126
4. Если A≠0, перейти на пункт 2.
5. Вывести полученное в p-ичной системе счисления число S.
Пример 1. Число 172 перевести в двоичную систему счисления.
В таблице представлены этапы перевода этого числа в двоичную сис-
тему счисления. Таким образом, 172=101011002 .
Делимое 172 86 43 21 10 5 2 1
Результат деления 86 43 21 10 5 2 1 0
Остаток 0 0 1 1 0 1 0 1
Строка S 0 00 100 1100 01100 101100 0101100 10101100
Пример 2. Число 1999 перевести в шестнадцатеричную и тридцатише-
стеричную системы счисления.
1999=7CF16 =1JJ36 .
16-ричная 36-ричная
Делимое 1999 124 7 Делимое 1999 55 1
Частное 124 7 0 Частное 55 1 0
Остаток 15 12 7 Остаток 19 19 1
Строка S F CF 7CF Строка S J JJ 1JJ

11.2. Программы перевода чисел в p-ичную систему


счисления
11.2.1. Написать программу, которая переводит введенное с клавиату-
ры число в двоичную, восьмеричную, шестнадцатеричную и тридцатише-
стеричную системы счисления.
Решение: Напишем вначале функцию, которая по приведенному выше
алгоритму переводит целое неотрицательное число в произвольную систе-
му счисления.
Функция имеет два параметра a и p. Параметр a внутри функции из-
меняется, поэтому он передается по значению. Т.е. при вызове функции
создается копия переменной a и в программе происходят изменения толь-
ко копии параметра.
Function ПереводЧиселИз10ВP(ByVal a As Long, p As Integer) _
As String
Dim alph As String, k As Integer, i As Integer, s As String
alph = "0123456789abcdefghijklmnopqrstuvwxyz"
ПереводЧиселИз10ВP = "" ‘ Если ошибка входных параметров
If p< 2 Or p > 36 Then 'Контроль основания системы счисления
MsgBox "Ошибка в основании системы счисления!” +
“ Основание системы не может быть равно" + Str(p)
Exit Function
End If
If a < 0 Then ' Контроль. Число должно быть положительное
MsgBox "Ошибка! Число должно быть >0. Число = " + Str(a)
Exit Function

127
End If
Do ‘ Алгоритм перевода числа из десятичной в p-ичную
' К строке s слева дописываем цифру, соответствующую
‘ остатку от деления a на p
s = Mid(alph, (a Mod p) + 1, 1) + s
a=a\p
Loop While a <> 0
ПереводЧиселИз10ВP = s
End Function
Ниже приведена основная программа, в которой при помощи функции
InputBox вводится число a. В окно отладки выводятся само число a, а так-
же двоичное, восьмеричное, шестнадцатеричное и тридцатишестеричное
значения этого числа.
Sub ТестПереводЧиселИз10()
Dim a As Long
a = Val(InputBox("Введите натуральное число"))
Debug.Print "Десятичное ="; a
Debug.Print "Двоичное ="; ПереводЧиселИз10ВP(a, 2)
Debug.Print "Восьмеричное ="; ПереводЧиселИз10ВP (a, 8)
Debug.Print "Шестнадцатеричное ="; ПереводЧиселИз10ВP (a, 16)
Debug.Print "Тридцатишестеричное ="; ПереводЧиселИз10ВP (a, 36)
End Sub

11.2.2. Написать программу, которая переводит введенное с клавиату-


ры число, записанное в произвольной системе счисления, в десятичную
систему счисления.
Function ПереводЧиселИзПроизвольнойВ10(S As String, p As Integer) _
As Long
Dim i As Integer, n As Integer, pow As Long, a As Long, alph As String
Dim digit As Integer
alph = "0123456789abcdefghijklmnopqrstuvwxyz"
n = Len(Trim(S)) ' Количество цифр в числе
pow = 1: a = 0
For i = 1 To n
' Код цифры в десятичной системе счисления. Цифры выбираем
‘ справа налево (с младшего разряда к старшему)
digit = Val(InStr(alph, Mid(S, n + 1 - i, 1)) - 1)
If digit > p Or digit < 0 Then
' Если цифра выходит из диапазона [0,p-1]
MsgBox ("Ошибка при вводе числа")
Exit Function
End If
a = a + digit * pow ' Накопление суммы (11.2) digit*p^(i-1)
if i < n then pow = pow * p 'p в степени i
Next i
ПереводЧиселИзПроизвольнойВ10 = a

128
End Function
Для проверки правильности работы функции напишем основную про-
грамму.
Sub ТестПереводЧиселИзПроизвольнойВ10()
Dim a As String, p As Integer
a = InputBox("Введите число в произвольной системе счисления")
p = Val(InputBox("Введите основание системы счисления"))
Debug.Print "Число в "; p; "-pичной системе ="; a
Debug.Print "Десятичное значение числа="; _
ПереводЧиселИзПроизвольнойВ10(a, p)
End Sub

11.3. Перевод натуральных чисел в системы счисления,


кратные двоичной
Вся информация в компьютере представляется в двоичной системе.
Двоичная система удобна для компьютера, но не удобна для человека.
Числа получаются очень длинными и визуально похожими друг на друга.
Поэтому обычно программисты выводят двоичные числа в шестнадцате-
ричной или восьмеричной системах счисления. Перевод из этих систем в
двоичную и обратно легко может быть выполнен в уме.
Перевод десятичного числа A в систему счисления с основанием p тре-
бует 1+[logpA] операций деления. При этом количество цифр числа Ap на
единицу больше целой части logpA. Следовательно, при переводе большо-
го десятичного числа A в шестнадцатеричную систему счисления требует-
ся в четыре раза меньше операций деления, чем при переводе этого же
числа в двоичную систему счисления. При ручном переводе десятичных
чисел в двоичные обычно вначале десятичное число переводят в шестна-
дцатеричное, а затем полученное шестнадцатеричное число переводят в
двоичное.
Алгоритм перевода из шестнадцатеричной системы в двоичную:
1. Вместо каждой шестнадцатеричной цифры пишем ее четырехзнач-
ный код в двоичном виде по табл. 11.1.
Таблица 11.1
0 1 2 3 4 5 6 7
0000 0001 0010 0011 0100 0101 0110 0111
8 9 A B C D E F
1000 1001 1010 1011 1100 1101 1110 1111

2. В полученном двоичном числе убираем ведущие нули, если они


имеются.
Пример. Число 3169789 перевести в двоичную систему счисления.
1) По приведенному выше алгоритму, производя шесть операций де-
ления на 16, получаем шестнадцатеричное число 305dfd16.

129
2) Вместо каждой шестнадцатеричной цифры пишем ее четырехраз-
рядный двоичный код по табл. 11.1:
0011 0000 0101 1101 1111 1101.
3) Убираем два ведущих нуля и получаем искомое двоичное число:
3169789 = 11 0000 0101 1101 1111 11012 .
11.3.1. Написать программу, переводящую шестнадцатеричное число в
двоичное по приведенному выше алгоритму.
Sub ПереводИзШестнадцатеричнойВДвоичную()
Dim sHex As String, i As Long, sBin As String, mHex As Variant
Dim c As String * 1, sHexAlph As String, L As Boolean
' Алфавит шестнадцатеричных цифр
sHexAlph = "0123456789abcdef"
' Таблица четырехзначных двоичных кодов шестнадцатеричных
‘ цифр
mHex = Array("0000", "0001", "0010", "0011", "0100", "0101", "0110", _
"0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111")
sHex = _
Trim(InputBox("Введите число в 16-ричной системе счисления"))
For i = 1 To Len(sHex) 'Обход по всем цифрам числа
' LCase - перевести большие буквы в маленькие A в a, B в b, ... ,
‘ F в f.
' i-тый символ шестнадцатеричного числа
c = LCase(Mid(sHex, i, 1))
' Логическое выражение истинное, если с – шестнадцатеричная
‘ цифра
L = c >= "0" And c <= "9" Or c >= "a" And c <= "f"
If Not L Then ' Контроль правильности i-той цифры
Debug.Print "Ошибка. Цифра "; c; " во введенном числе "; _
sHex; " не восьмеричная."
Exit Sub
End If
'Добавление в sBin четырех двоичных символов,
‘соответствующих шестнадцатеричной цифре
sBin = sBin + mHex(InStr(sHexAlph, c) - 1)
Next i
' убрать ведущие нули. Вернуть правую часть строки sBin длиной
‘ меньшей на количество ведущих нулей
‘InStr(sBin, "1") – номер первого не нулевого бита
sBin = Right(sBin, Len(sBin) - InStr(sBin, "1") + 1)
Debug.Print "Шестнадцатеричное число "; sHex; _
" в Двоичной системе счисления равно "; sBin
End Sub
Алгоритм перевода из восьмеричной системы в двоичную:
1. Вместо каждой шестнадцатеричной цифры пишем ее трехзначный
код в двоичном виде по табл. 11.2.
Таблица 11.2

130
0 1 2 3 4 5 6 7
000 001 010 011 100 101 110 0111

2. В полученном двоичном числе убираем ведущие нули, если они


имеются.
Пример. Число 3169789 перевести в двоичную и восьмеричную
системы счисления.
1) По приведенному выше алгоритму, производя восемь операций
деления на 8, получаем восьмеричное число 140567758.
2) Вместо каждой восьмеричной цифры пишем ее трехразрядный
двоичный код по табл. 11.2:
001 100 000 101 110 111 111 101
3) Убираем два ведущих нуля и получаем искомое двоичное число.
3169789 = 1 100 000 101 110 111 111 1012 .
11.3.2. Написать программу, переводящую восьмеричное число в
двоичное.
Sub ПереводИзВосьмеричнойВДвоичную()
Dim sOct As String, i As Long, sBin As String, Oct As Variant
Dim c As String * 1
Oct = Array("000", "001", "010", "011", "100", "101", "110", "111")
sOct = _
Trim(InputBox("Введите число в восьмеричной системе счисления"))
For i = 1 To Len(sOct) 'Обход по всем восьмеричным символам числа
c = Mid(sOct, i, 1) ' i-тый символ восьмеричного числа
If c < "0" Or c > "7" Then ' Контроль правильности введенных цифр
Debug.Print "Ошибка. Цифра "; c; " во введенном числе "; _
sOct; " не восьмеричная."
Exit Sub
End If
'Добавление в sBin трех двоичных символов
sBin = sBin + Oct(Val(c)) 'Соответствующих восьмеричной цифре
Next i
' Убрать ведущие нули. Вернуть правую часть строки sBin , без
' ведущих нулей. InStr(sBin, "1") - возращает номер первой единицы
sBin = Right(sBin, Len(sBin) - InStr(sBin, "1") + 1)
Debug.Print "Восьмеричное число "; sOct; _
" в двоичной системе счисления равно "; sBin
End Sub
Алгоритм перевода из двоичной системы в шестнадцатеричную:
1. Начиная с младшего (правого) разряда, разбиваем двоичное число на
группы по четыре двоичных цифры. Если в старшей (левой) группе не хва-
тает цифр, добавляем необходимое количество ведущих нулей.
2. Вместо каждой полученной группы пишем одну шестнадцатеричную
цифру согласно табл. 11.1.

131
11.3.3. Написать программу, переводящую двоичное число в шестна-
дцатеричное.
Sub ПереводИзДвоичнойВШестнадцатериричную()
Dim mHex As Variant, sBin As String, i As Long, n As Long, k As Long
Dim sHexc As String, sHex As String, sHexAlph As String
' алфавит шестнадцатеричных цифр
sHexAlph = "0123456789abcdef"
mHex = Array("0000", "0001", "0010", "0011", "0100", "0101", "0110", _
"0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111")
sBin = InputBox("Введите Число в двоичной системе счисления ")
sBin = "000" + Trim(sBin) ' Добавить слева три нуля
' Сделать количество цифр в двоичном числе, кратным 4
sBin = Right(sBin, (Len(sBin) \ 4) * 4) ' Убрать лишние нули слева
n = Len(sBin)
For i = 1 To n \ 4 ' Обход по всем группам из 4 двоичных цифр
sHexc = Mid(sBin, (i - 1) * 4 + 1, 4)
'Поиск соответствующей шестнадцатеричной цифры
For k = 0 To 15
If sHexc = mHex(k) Then ' Нашли символ
sHex = sHex + Mid(sHexAlph, k + 1, 1) ' Накопили в sHex
Exit For ' Выйти из цикла For
End If
Next k
Next i
Debug.Print "Двоичное число "; sBin; _
" в Шестнадцатеричной системе счисления равно "; sHex
End Sub
Алгоритм перевода из двоичной системы в восьмеричную:
1. Начиная с младшего (правого) разряда, разбиваем двоичное число на
группы по три двоичных цифры. Если в старшей (левой) группе не хватает
цифр, добавляем необходимое количество ведущих нулей.
2. Вместо каждой полученной группы пишем одну восьмеричную циф-
ру согласно табл. 11.2.
Программу, реализующую данный алгоритм, предлагается написать
читателям самостоятельно.
Алгоритм перевода из восьмеричной системы счисления в
шестнадцатеричную:
1. Перевести восьмеричное число в двоичное .
2. Полученное двоичное число перевести в шестнадцатеричное.

11.3.4. Написать программу, переводящую восьмеричное число в шест-


надцатеричное по приведенному выше алгоритму.

132
Sub ПереводИзВосьмеричнойВШестнадцатериричную()
Dim mHex As Variant, sHexc As String, sHex As String, _
sHexAlph As String, mOct As Variant, sOct As String, i As Long, _
sBin As String, n As Long, k As Long
sHexAlph = "0123456789abcdef" ' алфавит цифр
mOct = Array("000", "001", "010", "011", "100", "101", "110", "111")
mHex = Array("0000", "0001", "0010", "0011", "0100", "0101", "0110", _
"0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111")
sOct = _
InputBox("Введите число в восьмеричной системе счисления ")
For i = 1 To Len(Trim(sOct)) ' Перевод в двоичную систему
sBin = sBin + mOct(Val(Mid(sOct, i, 1)))
Next i
' Убрать ведущие нули
sBin = Right(sBin, Len(sBin) - InStr(sBin, "1") + 1)
' Перевести с двоичной в шестнадцатеричную
sBin = "000" + Trim(sBin) ' Добавить слева три нуля
sBin = Right(sBin, (Len(sBin) \ 4) * 4) ' Убрать лишние нули слева
n = Len(sBin)
For i = 1 To n \ 4
sHexc = Mid(sBin, (i - 1) * 4 + 1, 4)
For k = 0 To 15
If sHexc = mHex(k) Then sHex = sHex + Mid(sHexAlph, k + 1, 1)
Next k
Next i
Debug.Print "Восьмеричное число "; sOct; _
" в Шестнадцатеричной системе счисления равно "; sHex
End Sub
Алгоритм перевода из шестнадцатеричной системы счисления в
восьмеричную:
1. Перевести шестнадцатеричное число в двоичное .
2. Полученное двоичное число перевести в восьмеричное.

11.4. Перевод целых чисел в двоичный формат


До сих пор мы переводили в различные форматы только положитель-
ные числа. Целые отрицательные числа типа Integer и Long в памяти ЭВМ
хранятся в дополнительном коде. Для того чтобы дать определения допол-
нительного кода числа, необходимо ввести определение обратного кода
целого числа.
Для положительного целого числа типа Integer или Long прямой, об-
ратный и дополнительный код совпадают, при этом первый бит равен 0.
В отрицательном числе A в прямом, обратным и дополнительным ко-
дах первый (знаковый) бит равен 1. В прямом коде числа A все незнако-
вые биты совпадают с соответствующими битами положительного числа
|A|. В обратном коде числа A все незнаковые биты инвертируются по от-

133
ношению к положительному числу | A|. Под инверсией понимается замена
0 на 1, а 1 на 0. Дополнительный код получается прибавлением 1 к млад-
шему биту числа в обратном коде.
В VB целые числа типа Byte бывают только положительными, хранятся
в прямом коде, занимают 1 байт (8 бит) и находятся в диапазоне от 0 =
000000002 до 255 = 111111112 . При этом первый бит не является особым,
т.е. все биты незнаковые.
Числа типа Integer занимают 2 байта (16 бит). При этом первый бит
определяет знак числа.
Рассмотрим примеры представления чисел типа Integer в памяти ЭВМ.
Самое малое число такого типа равно –32768=10000000000000002 =
800016, а самое большое число 32767=01111111111111112=7FFF16.
Примеры. Число -1999 представить в прямом, обратном и дополни-
тельном коде.
Решение. Переводим число 1999 в шестнадцатеричный код.
1999=07CF16. Число занимает 16 бит или четыре шестнадцатеричных циф-
ры, причем первый бит знаковый. Прямой, обратный и дополнительные
коды положительного числа 1999 совпадают и равны 0000 0111 1100
11112. В прямом, обратном и дополнительном кодах отрицательного числа
-1999 первый бит равен 1.
В прямом коде числа –1999 все незнаковые биты совпадают с битами
положительного числа 1999.
Таким образом, –1999 = 1000 0111 1100 11112[п].
В обратном коде числа –1999 все незнаковые биты инвертируются.
-1999 = 1111 1000 0011 00002[о].
Для получения дополнительного кода к двоичному числу в обратном
коде добавляем 1.
-1999 = 1111 1000 0011 00012[д].
Хранение чисел в дополнительном коде удобно тем, что при сложении
чисел любого знака получается число в дополнительном коде.
При суммировании двух чисел в дополнительном коде действуют сле-
дующие правила:
1) Двоичные числа складываются поразрядно справа налево по обыч-
ным правилам арифметики двоичных чисел. При этом 0+0=0;
0+1=1+0=1; 1+1=0, и 1 переносится в старший разряд; 1+1+1 =1, и 1
переносится в старший разряд.
2) Если в разряд левее знакового переносится 1, то она теряется.
3) Если при сложении двух положительных чисел получается отрица-
тельное число или при сложении двух отрицательных чисел получа-
ется положительное число, то происходит ошибка переполнения.
4) Результатом является число в дополнительном коде.
Пример. Сложить два числа A и B, а результат поместить в перемен-
ную C.
1) A=3, B=-2.

134
A=0000 0000 0000 00112[д], B=1000 0000 0000 00102[п] =
= 1111 1111 1111 11012[п] = 1111 1111 1111 11102[д].
0000 0000 0000 0011
+
1111 1111 1111 1110
0000 0000 0000 0001
2) A=-3, B=2.
A=1000 0000 0000 00112[п] = 1111 1111 1111 11012[д].
B=0000 0000 0000 00102[д] .
1111 1111 1111 1101
+
0000 0000 0000 0010
1111 1111 1111 1111
С=1111 1111 1111 10112[д] =1111 1111 1111 11102[о]=
1000 0000 0000 00012[п].
С=-1.
3) A=31773 , B=-15768.
A=7C1D16 , B=-3D9816 .
A=0111 1100 0001 11012[д] . B = 1011 1101 1001 10002[п] =
= 1100 0010 0110 01112[о] = 1100 0010 0110 10002[д].
0111 1100 0001 1101
+
1100 0010 0110 1000
0011 1110 1000 0101
С=3E85=16005.
Для чисел типа Long действуют те же правила, что и для чисел типа
Integer, только для них отводится 32 бита.
При программировании на Visual Basic, для того чтобы извлечь любой
бит, применяются битовые операции над числами.
11.4.1. Написать программу перевода числа A типа Byte в двоичную
систему счисления.
Решение. Возьмем двоичное число b=100000002. Десятичное значение
этого числа равно 27 = 128. Результатом побитовой операции A And b бу-
дет 0, если первый бит числа A равен 0, и число 100000002, если первый
бит равен 1. В текстовую переменную s справа дописываем 0, если резуль-
тат побитовой операции равен 0, и 1 – в противном случае. Затем делим
число b на 2. Получаем число 64=010000002. И опять применяем побито-
вую операцию A And b и дописываем в s второй бит. И так до восьмого
бита. Для удобства чтения результата между каждой четверкой битов
вставляем пробел.
Sub ПереводВДвоичныйФорматНаБитовыеОперацииByte()
Dim a As Byte, b As Byte, i As Integer, s As String
b = &H80 ' первый бит =1, остальные 7 равны 0. b=128
s = ""
a = Val(InputBox("Введите целое число типа Byte"))
For i = 1 To 8
' В числе b i-тый бит = 1, остальные =0

135
If (a And b) = 0 Then s = s + "0" Else s = s + "1"
If (i Mod 4) = 0 Then s = s + " " ' Через 4 бита пробел
b=b/2 'Сдвиг битов числа b на один вправо
Next i
Debug.Print s
End Sub
11.4.2. Написать программу перевода числа A типа Long в двоичную
систему счисления.
Решение. Для чисел типа Long или Integer необходимо вначале опреде-
лить значение первого бита, а затем в цикле определить незнаковые биты.
Это связано с тем, что первый бит определяет знак числа, а при делении
отрицательного числа на 2 получаем отрицательное число, в котором опять
первый бит равен 1.
Sub ПереводВДвоичныйФорматНаБитовыеОперации()
Dim a As Long, b As Long, i As Integer, s As String
' Первый бит =1, остальные 32 равны 0 (1-вый бит знаковый)
b = &H80000000 ' Для определения знака числа (первый бит)
s = "" ‘ В переменной s будем накапливать биты числа a
a =Val(InputBox(“Введите целое число”))
‘Если число a отрицательно, то 1-ый бит =1 и (a And b)≠0
If (a And b) = 0 Then s = s + "0" Else s = s + "1"
b = &H40000000 ' Второй бит =1, остальные 0
For i = 2 To 32 ‘ Обход по всем незнаковым битам от 2-го до 32-го
' В числе b i-тый бит = 1, остальные =0
If (a And b) = 0 Then s = s + "0" Else s = s + "1"
If (i Mod 4) = 0 Then s = s + " " ' Через 4 бита пробел
b = b / 2 'Сдвиг битов на один вправо
Next i
Debug.Print s
End Sub

11.5. Перевод вещественных чисел в двоичный фор-


мат
Запись действительного числа A в p-ичной системе счисления пред-
ставляется в виде последовательности цифр целой части, запятой и цифр
дробной части, после которой на нижнем индексе записывается число p,
указывающее основание системы счисления. A=αnαn-1…α1α0 ,α-1α-2…αm-
1αm p. Где n, m ─ число цифр в целой и дробных частях. Это же число мож-
но представить в виде суммы n+m+1-го слагаемого:
A= pn+αn-1pn-1+…+α1p1+α0p0+α-1p-1 + …+ α-(m-1)p-(m-1) + α-mp-m , (11.3)
где αi – i-тая цифра числа.
Для перевода данного числа в р-ичную систему счисления необходимо
по отдельности перевести целую и дробную части числа, а затем их соеди-

136
нить. Алгоритм перевода целой части числа A рассмотрен в предыду-
щих подразделах. Разработаем алгоритм перевода дробной части
числа A в p-ичную систему. Обозначим дробную часть этого чис-
ла буквой D.
D = α-1p-1 + … + α-(m-1) p-(m-1) + α-mp-m . (11.4)
Чтобы получить первую цифру α-1, необходимо число D умножить
на основание p. pD = α-1 + α-2p-1 + …+ α-(m-1)p-(m-2) + α-mp-(m-1). Целая часть
полученного числа является первой цифрой числа D. Для получения сле-
дующей цифры α-2, опять берем дробную часть числа D1= α-2p-1 + …+ α-(m-
-(m-2)
1)p + α-mp-(m-1) и проделаем те же операции. Такие операции проделыва-
ем до тех пор, пока дробная часть Dm будет положительной или достигнем
необходимой точности.
Теперь рассмотрим метод хранения вещественных чисел. Веществен-
ные числа в памяти компьютера хранятся совсем иначе, чем целые. Суще-
ствовало множество форматов хранения вещественных чисел. Причем на
различных типах компьютеров был свой формат. В последнее время разра-
ботан международный стандарт IEEE 754, который сейчас применяется
практически на компьютерах всех типов.
В данной работе рассмотрим стандарт хранения числа типа Single.
Число типа Double хранится аналогично числам типа Single, только под
порядок и мантиссу отводится больше бит, так как число типа Double за-
нимают в два раза больше памяти. Зная диапазон изменения чисел типа
Double, табл 1.1., читатель самостоятельно может определить количество
бит, отведенных под порядок и мантиссу для чисел типа Double. Число ти-
па Single занимает 4 байта или 32 бита. Следовательно, по логике, это чис-
ло получается из 32 символов 0 или 1. На самом деле число типа Single,
состоит из 33 бит. При этом применяется один скрытый бит. Согласно
этому стандарту вещественное число a представляются в виде трех частей:
1. Знак числа s. Под знак числа отводится один ─ первый бит. При этом
если число не отрицательное, то s=0, а если отрицательное, то s=1.
2. Следующие 8 бит, отводятся под порядок P. На самом деле в этих вось-
ми битах хранится смещенный порядок P′, который получается прибав-
лением к порядку P смещения равное 126.
3. Под мантиссу m отводится 23 бита. Первый бит мантиссы всегда равен
1, поэтому он не хранится в памяти. Таким образом, длину мантиссы
получается 24 бита. Следовательно, число типа Single состоит из 33 бит.
Число 0 имеет особый формат. Если все биты равны 0, то число счита-
ется равным нулю.
Особым случаем является число, в котором все биты порядка равны 1.
В этом случае, код числа равен либо (-1)s∞, если мантисса равна 0, либо
код переполнения (NaN), если мантисса не равна 0.
s P′ m
0 1 8 9 31

137
Алгоритм перевода вещественного числа a, в двоичный формат стан-
дарта IEEE 754.
1. Перевести модуль целой части в двоичное число.
2. Переводим дробную часть в двоичный формат.
3. Объединяем полученные целую и дробную части. Для этого к целой
части справа приписываем дробную часть. При этом предполагаем,
что дробная часть начинается с десятичной запятой.
4. Нормализуем полученное двоичное число. Для этого передвигаем
десятичную запятую (влево или вправо) таким образом, чтобы пер-
вый бит равный 1 был сразу же справа от десятичной запятой. При
этом если запятую передвигали влево, то порядок будет положи-
тельным, а если вправо, то ─ отрицательный. Модуль порядка P ра-
вен величине сдвига десятичной запятой.
5. К порядку P добавляем число 126, получаем смещенный порядок P′.
Число P′ должно быть меньше 255. то Переводим, полученный
смещенный порядок P′ в двоичный код по алгоритму перевода в
двоичный код положительного числа.
6. Записываем в первый бит знак числа s.
7. Со второго по 9 бит, записываем двоичный код смещенного порядка
P′.
8. С 10 по 24 бит записываем 23 бита мантиссы, начиная со второго би-
та. Т.к. первый бит мантиссы всегда равен 1, то подстановка этого
бита осуществляется процессором автоматически.
9. Если число равно нулю, то все 32 бита, заполняем нулями.
10. Если P′>254, то все биты заполняются единицами.
Рассмотрим теперь более подробно второй пункт данного алгоритма.
Алгоритм перевода дробной части действительного числа в двоичный
формат.
1. В строку, назовем ее R, где будем накапливать результат, ставим
десятичную запятую.
.
2. Умножаем число a на 2. a= a 2.
3. Записываем, полученную целую часть справа в строку R.
4. Целую часть полученного числа a, обнуляем.
5. Если a=0, то перейти на пункт 8.
6. Если число разрядов, начиная с первой 1, больше 24, перейти на
пункт 8.
7. Перейти на пункт 2.
8. Выводим результат перевода R.
Пример 1. Перевести число A=0,8125 в двоичный формат.
0,8125 =0,1 0,625 =0,11 0,25 =0,110 0,5 =0,1101
2 2 2 2
1,625 1,25 0,5 1,0
Ответ: 0,8125=0,11012.

138
В данном случае порядок числа P=0. Следовательно, смещенный поря-
док P′=126=7E16=011111102.
В памяти компьютера число 0,8125 хранится в следующем виде:
0 01111110 101 0000 0000 0000 0000 0000.
Для удобства чтения числа, порядок выделен жирным шрифтом, и ман-
тисса разбита на шестнадцатеричные цифры.
Записывать и читать такую длинную последовательности нулей и еди-
ниц достаточно трудоемко. Часто это число представляют в шестнадцате-
ричном виде также как и целое число. При этом все 32 бита, разбиваем на
8 групп по 4 символа и вместо каждой группы из четырех двоичных цифр
записываем одну шестнадцатеричную цифру согласно табл. 11.1.
В шестнадцатеричной системе 0,8125=3FA0000016.
Пример 2. A=0,1.
Такое простое, для десятичной системы счисления, число, в двоичной
системе является бесконечной периодической дробью. При умножении его
на 2, получаем следующую последовательность: 0,2; 0,4; 0,8; 1,6; 3,2, а
дальше последовательность дробной части повторяется.
При ручном переводе дробных чисел, также как и целых, удобнее ис-
пользовать шестнадцатеричную систему. В этом случае умножаем дроб-
ные числи A на 16, запоминая шестнадцатеричные цифры в целый части,
до тех пор, пока дробная часть не превратится в 0, или число шестнадцате-
ричных цифр, начиная с первой ненулевой цифры, будет равно 6, если
первая значащая цифра от 8 до F (содержит 1 в первом двоичном разряде)
или 7, если первая значащая цифра от 1 до 7. Тогда в мантиссе получается
не менее 24 значащих разрядов.
0,1 =0,1 0,6 =0,19 0,6 =0,199 0,6 =0,1999 0,6 =0,19999
16 16 16 16 16
1,6 9,6 9,6 9,6 9,6
0,6 =0,199999 0,6 =0,1999999
16 16
9,6 9,6
0,1=0,199999916 =0,0001 1001 1001 1001 1001 1001 10012 .
Нормализуем полученное число, сдвигая запятую вправо на три разря-
да.
0,1==0,1100 1100 1100 1100 1100 1100*2-32.
Таким образом, P=2. P′=-3+126=123=7B16 =011110112.
В памяти компьютера число 0,1 хранится в следующем виде:
0 01111011 100 1100 1100 1100 1100 1100.
В шестнадцатеричной системе 0, 1=3DCCCCCC16.
Пример 3. A=-23445,23
Переводим число 23445 в шестнадцатеричный формат. Выкладки про-
пускаем. 23445=5B9516. Теперь осталось получить три шестнадцатеричных

139
цифр дробной части числа A. 0,23*16=3,68. 0,68*16=10,88. 0,88*16=14,08.
Следовательно, дробная часть числа A=,3AE16.
Таким образом, A=-5B95,3AE16.
В двоичном виде A=-101 1011 1001 0101,0011 1010 11102.
Нормализуем данное число A=-,1011 0111 0010 1010 0111 01012*215.
P=-15. P′=-15+126=111=6F16=0110 11112.
В памяти компьютера число A=-23445,23 хранится в следующем виде:
1 01101111 011 0111 0010 1010 0111 0101.
В шестнадцатеричной системе A=-23445,23 =B7B72A7516.

Приведем некоторые примеры хранения в памяти компьютера еще не-


скольких вещественных чисел.
Чис Нормализ Смещен- Мантисса Двоичный код Шестна-
ло ованный ный дцате-
вид Порядок ричный
код
0,5 0.1 * 20 126=0111 0.1 0 01111110 000 0000 3F000000
1110 0000 0000 0000 0000
0,25 0.1 * 2-1 125=0111 0.1 001111101 000 0000 3E800000
1101 0000 0000 0000 0000
-5 0.101 * 23 129=1000 0.101 110000001 010 0000 C0A00000
0001 0000 0000 0000 0000
127 0.1111111 133=1000 0.1111111 010000101 111 1110 42FE0000
*27 0101 0000 0000 0000 0000
Максимальном положительным вещественным числом Amax, является
следующее число:
0 11111110 0111 1111 1111 1111 1111 1111.
Максимальный смещенный порядок равен P′=254. Следовательно,
несмещенный порядок P=254 - 126 = 128. Максимальная мантисса равна:
0,1111 1111 1111 1111 1111 1111 = 1-2-24. Т.о., максимальное число равно
Amax = (1-2-24) 2128≈3,4*1038 .
Минимальным положительным вещественным числом Amin, является
следующее число: 0 00000000 000 0000 0000 0000 0000 0001.
P′=0. P=0-126=-126. Мантисса m=,1000 0000 0000 0000 0000 0001.
Amin = (2-1+2-24)*2-126 ≈ 2-127 ≈ 5,8*10-39.
Напишем теперь функции, реализующие перевод чисел типа Single в
двоичный формат, согласно разработанным алгоритмам. Двоичные числа
будем хранить в переменных типа String.
Первая функция ПереводВ2PlusInt необходима для перевода смещен-
ного порядка в двоичный формат. Эта функция переводит любое целое по-
ложительное число в двоичный формат. Количество двоичных символов в
результирующей строке для числа ia равно log 2 ia .
' Перевод Целого положительного числа в двоичный формат
Function ПереводВ2PlusInt(ByVal ia As Long) As String
Dim s As String

140
s = "" ' Здесь накапливаем число в двоичном виде
While ia > 0 'Цикл пока число ia больше 0
' Дописываем слева в строку S остаток от деления числа на 2
s = Trim(str((ia Mod 2))) + s
ia = ia \ 2 ' Делим нацело на 2. Остаток от деления
‘отбрасывается
Wend
ПереводВ2PlusInt = s
End Function
Следующая функция ─ ПереводВ2Дробь переводит в двоичный фор-
мат дробную часть десятичного числа типа Single. При этом выходная
строка s, начинается с символа ”,”, после которой расположен двоичный
код дробного числа d. При этом строка s содержит 24 двоичные цифры,
начиная с первой ненулевой цифры. Это необходимо для получения необ-
ходимого числа знаков мантиссы.
' Это функция для перевода дробной части в двоичный код
Function ПереводВ2Дробь(d As Single) As String
Dim s As String, i As Integer, id As Integer
i = 0: s = ","
' В переменной S получаем 24 знака (после первой 1) мантиссы
While i < 24 And Len(s) < 100
i=i+1 ' Количество знаков дробной части после первой 1
id = Int(d * 2) ' Получаем очередную цифру 0 или 1
s = s + Trim(str(id)) 'Дописываем ее в строку s справа
If InStr(s, "1") = 0 Then i = 0 'Пока не появится первая цифра 1, i=0
'Убираем целую часть. Путем вычитания превращаем ее в 0
d = d * 2 - id
Wend
ПереводВ2Дробь = s
End Function
Теперь пишем основную функцию, которая переводит в двоичный
формат любое число типа Single.
Function ПереводSingleВДвоичныйФормат(a As Single) As String
Dim s As String, BinIntA As String, ia As Long
Dim d As Single, mant As String, p As Integer, s1 As String
If a < 0 Then s = "1" Else s = "0" 'Знак числа. Первый бит
ia = Int(Abs(a)) ' Целая часть аргумента
d = Abs(a) - ia ' Дробная часть аргумента
'BinIntA -- Двоичный код вещественного числа в виде
' целая часть +","+дробная часть
BinIntA = Trim(ПереводВ2PlusInt(ia)) + Trim(ПереводВ2Дробь(d))
p = InStr(BinIntA, ",") - 1 ' Несмещенный порядок числа
' Если p=0, то порядок или = 0, или отрицательный
If p = 0 Then p = 2 - InStr(BinIntA, "1")
' Получение мантиссы
If p > 0 Then

141
'Берем p разрядов целой части и 24-p бита дробной части
mant = Left(BinIntA, p) + Right(BinIntA, Len(BinIntA) - p - 1)
Else
' Порядок <0. Берем 24 бита дробной части, начиная с бита 2-p
mant = Mid(BinIntA, 2 - p, 24)
End If
' Смещенный порядок в двоичном виде
s1 = ПереводВ2PlusInt(p + 126)
' Дополняем слева в порядок нули до 8 символов
s1 = String(8 - Len(s1), "0") + s1 ' Теперь в S1 ровно 8 цифр
' К знаку s добавляем порядок S1 и 23 символа мантиссы mant.
' Со второй по 24. Первый бит мантиссы всегда равен 1, поэтому
' он не храниться
s = s + s1 + Mid(mant, 2, 23)
'Особый случай. Если число равно 0, то по стандарту все
‘биты равны 0
If Abs(a) = 0 Then s = String(32, "0")
ПереводSingleВДвоичныйФормат = s
End Function
Часто приходится решать обратную задачу ─ перевести число из дво-
ичного формата в шестнадцатеричный формат. Напишем и такую функ-
цию.
Function ПереводИз2ВSingle(s As String) As Single
Dim a As Double, p As Integer, b As Integer, m As Double
Dim i As Integer, d As Double
'Определение смещенного порядка числа 2-9 биты
b = 1: p = 0
For i = 9 To 2 Step -1 'Переводим из 2-ой в десятичную
p = p + Val(Mid(s, i, 1)) * b
b=b*2
Next i
p = p - 126 ' Несмещенный порядок
m = 0.5 ' Здесь накапливаем мантиссу
d = 0.5
For i = 10 To 32 ' Цикл по всем разрядам мантиссы
d = d / 2 ' Вес разряда в мантиссе
m = m + Val(Mid(s, i, 1)) * d
Next i
a=m*2^p
' Учет знака числа
If Mid(s, 1, 1) = "1" Then a = -a
' Если все биты числа S были =0, то число =0
If p = -126 And m = 0.5 Then a = 0
ПереводИз2ВSingle = a
End Function

142
Для тестирования предложенных функций напишем основную про-
грамму. В программе необходимо считать числа типа Single из первого
столбца рабочего листа Excel. Перевести в двоичный формат и вывести во
второй столбец. Затем, полученное двоичное число перевести в десятич-
ный формат и вывести в третий столбец.
Решение:
Sub Вариант0Задача24()
Dim i As Integer, a As Single, BinSingleA As String
Sheets("Лист24").Select: i = 0
' Отформатировать столбец B, в который выводится строка
‘ с результатами перевода в двоичный код, как текстовый
Columns("B").NumberFormat = "@"
Do 'Обход по всем элементам последовательности
i=i+1
If Cells(i, 1) = Empty Then Exit Do
'Если ячейка пустая - выйти из цикла
a = Cells(i, 1) ' Переписать в переменную а содержимое ячейки
' Переводим действительное число типа Single в двоичный
‘ формат
BinSingleA = ПереводSingleВДвоичныйФормат(a)
Cells(i, 2) = BinSingleA 'Записываем его во второй столбец
‘ Производим обратный перевод из двоичного кода в десятичный
Cells(i, 3) = ПереводИз2ВSingle(BinSingleA)
Loop
End Sub
В ответе первый и третий столбцы должны совпадать.

11.6. Хранение символьной информации в памяти


компьютера
Как уже отмечалось выше, все виды информации (числовая, символь-
ная, звуковая, видео информация, графическая информация и т.д.) хранят-
ся при помощи всего лишь двух символов: 0 и 1. В данном подразделе рас-
смотрим методы хранения текстовой информации.
Текстовая информация хранится посимвольно. На каждый символ от-
водится по одному байту. Следовательно, в таком формате можно помес-
тить не более 256 различных символов. Каждому возможному символу
присваивается свой код. Первые 32 символа с кодами от 0 до 31, являются
управляющими символами. Для получения кода символа используется
функция Asc.
Пример 1. Написать программу, которая выводит в окно вывода код
символа, введенного с клавиатуры.
Sub КодыСимволов()
Dim i As Integer, Kod As Integer, c As String * 1, Res As String
For i = 1 To 256

143
c = InputBox("Введите любой символ")
Kod = Asc(c) ' Код введеного символа
Res = MsgBox("Символ " + c + " имеет код" + str(Kod) + _
". Продолжать?", vbCritical + vbYesNo + vbDefaultButton1)
If Res = vbNo Then Exit Sub ‘ Выход, если нажали на кнопку No
Next i
End Sub
Вторая функция Chr является обратной по отношению к функции Asc.
Функция Chr(Kod) выводит символ соответствующий его числовому коду.
Пример 2. Написать программу, выводящую в ячейки рабочего листа
таблицу кодов не управляющих символов.
Sub ТаблицаКодовСимволы()
Dim i As Integer, Kod As Integer, Row As Integer, k As Integer
Sheets("Лист1").Select: Cells.Clear
For i = 32 To 255 ‘ Обходим по всем не управляющим символам
k = (i - 32) \ 20 ‘ Выводим по 20 чисел в столбец. K – номер пары
Row = ((i - 32) Mod 20) + 1 ‘ Номер строки для вывода
Cells(Row, 2 * k + 1) = I ' Код числа
Cells(Row, 2 * k + 2) = Chr(i) ‘ Символ
Next i
End Sub
Результаты работы программы, представлены в табл. 11.3. Эту таблицу
можно использовать при написании программ на текстовые переменные.
Коды цифр расположены подряд в порядке возрастания в интервале от 48
до 57. Латинские буквы расположены так же непрерывным участком по
алфавиту в диапазоне от 65 до 90 прописные буквы и от 97 до 122 строч-
ные. Русские буквы расположены также непрерывным участком в диапа-
зоне от 192 до 255 строго по алфавиту, сначала прописные (192─ 223), а
затем строчные (224─255).
Таблица 11.3
32 57 9 82 R 107 k 132 „ 157 ќ 182 ¶ 207 П 232 и
33 ! 58 : 83 S 108 l 133 … 158 ћ 183 · 208 Р 233 й
34 " 59 ; 84 T 109 m 134 † 159 џ 184 ё 209 С 234 к
35 # 60 < 85 U 110 n 135 ‡ 160 185 № 210 Т 235 л
36 $ 61 = 86 V 111 o 136 € 161 Ў 186 є 211 У 236 м
37 % 62 > 87 W 112 p 137 ‰ 162 ў 187 » 212 Ф 237 н
38 & 63 ? 88 X 113 q 138 Љ 163 Ј 188 ј 213 Х 238 о
39 ' 64 @ 89 Y 114 r 139 ‹ 164 ¤ 189 Ѕ 214 Ц 239 п
40 ( 65 A 90 Z 115 s 140 Њ 165 Ґ 190 ѕ 215 Ч 240 р
41 ) 66 B 91 [ 116 t 141 Ќ 166 ¦ 191 ї 216 Ш 241 с
42 * 67 C 92 \ 117 u 142 Ћ 167 § 192 А 217 Щ 242 т
43 + 68 D 93 ] 118 v 143 Џ 168 Ё 193 Б 218 Ъ 243 у
44 , 69 E 94 ^ 119 w 144 ђ 169 © 194 В 219 Ы 244 ф
45 - 70 F 95 _ 120 x 145 ‘ 170 Є 195 Г 220 Ь 245 х

144
46 . 71 G 96 ` 121 y 146 ’ 171 « 196 Д 221 Э 246 ц
47 / 72 H 97 a 122 z 147 “ 172 ¬ 197 Е 222 Ю 247 ч
48 0 73 I 98 b 123 { 148 ” 173 - 198 Ж 223 Я 248 ш
49 1 74 J 99 c 124 | 149 • 174 ® 199 З 224 а 249 щ
50 2 75 K 100 d 125 } 150 – 175 Ї 200 И 225 б 250 ъ
51 3 76 L 101 e 126 ~ 151 — 176 ° 201 Й 226 в 251 ы
52 4 77 M 102 f 127 152 177 ± 202 К 227 г 252 ь
53 5 78 N 103 g 128 Ђ 153 ™ 178 І 203 Л 228 д 253 э
54 6 79 O 104 h 129 Ѓ 154 љ 179 і 204 М 229 е 254 ю
55 7 80 P 105 i 130 ‚ 155 › 180 ґ 205 Н 230 ж 255 я
56 8 81 Q 106 j 131 ѓ 156 њ 181 µ 206 О 231 з

Пример 3. Написать программу, переводящую в двоичный код строку,


введенную с клавиатуры.
Sub ПереводВДвоичныйКодСтроки()
Dim s As String, bin As String, i As Long, kod As Byte, k As Byte
Dim c As String
s = InputBox("Введите строку")
bin = "" ' Здесь будем накапливать двоичный код строки
For i = 1 To Len(s) 'Цикл по всем символам введенной строки
kod = Asc(Mid(s, i, 1)) ' Код i-того символа
c = "" ' Здесь получаем двоичный код символа
For k = 1 To 8 'Получить 8 двоичных цифр кода i-того символа
c = Trim(str((kod Mod 2))) + c 'Слева дописать двоичную цифру
kod = kod \ 2 ' Уменьшить в два раза число
Next k
' В строку bin, cправа дописать код полученного символа
bin = bin + c + " "
Next i
'Вывести в окно отладки двоичный код, введенного текста
Debug.Print bin
End Sub

12. Построение графиков функций


При решении многих задач результаты необходимо отобразить в гра-
фическом виде. Для решения этой задачи идеально подходит мастер диа-
грамм табличного процессора Excel. При этом программа пользователя
должна вывести на рабочий лист данные для графика или диаграммы и вы-
звать соответствующие методы, необходимые для графической иллюстра-
ции результатов работы программы. Методы, соответствующие построе-
нию графиков, можно получить, используя мастер диаграмм в режиме за-
писи макроса.
12.1. Построить график функции y=x4 + x3-2x-2 на отрезке [-2,2].

145
Решение: В цикле for табулируем заданную функцию на отрезке [2,2]
с шагом 0.1 и выводим результаты в первый и второй столбец рабочего
листа Лист5. Для того чтобы записать ту часть программы, которая отвеча-
ет за диаграмму, необходимо зайти на рабочий лист Лист5 и проделать
следующие действия:
1) Выделить произвольную прямоугольную область.
2) Войти в пункт меню Сервис. Выбрать пункт Начать Запись…
3) Запомнить предложенное имя макроса и нажать кнопку OK.
4) Вызвать мастер диаграмм и на первом шаге выбрать тип диаграммы
точечная, со значениями, соединенными отрезками без маркеров.
5) На втором шаге мастера диаграмм нажать кнопку готово.
6) Остановить запись макроса, нажав на кнопку остановить запись
панели инструментов Visual Basic или зайти опять в меню Сер-
вис/Макрос/Остановить макрос.
7) Зайти в записанный на шагах 4-6 макрос и перекопировать тело
макроса в программу после оператора Next x.
8) Найти обращение к свойству Range(“..”) и правильно указать об-
ласть, в которую наша программа записывает данные для графиков.
Свойство PlotBy :=xlColumns, указывающее, что нужно строить
график по столбцам, можно удалить, т.к. по умолчанию графики
строятся по столбцам.
9) Запустить программу.
Результатом работы программы будет график, нарисованный на рабо-
чем листе с именем Лист5. Если последнюю строку, выданную мастером
диаграмм удалить, то график будет выведен не на рабочий лист, а в от-
дельный чистый лист типа диаграмма.
Читатели могут поэкспериментировать с различными типами диа-
грамм, а также включить другие шаги мастера диаграмм.
Sub График111()
Dim x As Double, n As Long
Sheets("Лист5").Select
n = 0 ' Номер строки для вывода координат точек
' Цикл по точкам графика
For x = -2 To 2.00001 Step 0.1
n=n+1
Cells(n, 1) = x
Cells(n, 2) = x ^ 4 + x ^ 3 - 2 * x - 2
Next x
' Эти строки отвечают за построение графика функции
Charts.Add ' Добавить диаграмму
' Задает тип диаграммы. Была выбрана точечная, со значениями,
' соединенными отрезками без маркеров
ActiveChart.ChartType = xlXYScatterLinesNoMarkers
' Задает область в которой находятся данные для построения
‘ графика данные берутся из области "A1:Bn" рабочего

146
‘ листа с именем Лист5
ActiveChart.SetSourceData Source:=Sheets("Лист5").Range("A1:B" _
+ Trim(Str(n)))
'Задает область для построения диаграммы на том же листе
ActiveChart.Location Where:=xlLocationAsObject, Name:="Лист5"
End Sub
12.2. Написать программу для автоматического построения графика
указанной ниже функции и касательной к нему при x0=0.5.

x 3 x 5 x 7 x 9 x11 x13 x15


y= x+ − − + + − − + ... .
3! 5! 7! 9! 11! 13! 15!
Решение. Для вычисления значения функции в произвольной точке на-
пишем подпрограмму-функцию Fun112(x) с действительным аргументом
x. В переменной a вычисляется значение очередного слагаемого. Пере-
менная z отвечает за знак перед слагаемыми. Переменная n равна степени
в которую необходимо возвести x. Тогда целая часть числа n\2+1 будет
равна номеру очередного слагаемого. Знак z меняем, когда целое число
[n/2] четно (через два слагаемых).
Function Fun112(x As Double) As Double
Dim S As Double, a As Double, n As Long, z As Long
a = x: S = a: n = 1: z = 1
While Abs(a) > 0.000000001
n=n+2
a = a * x*x / ((n - 1) * n): S = S + z * a
If (n \ 2 Mod 2) = 0 Then z = -z ' Поменять знак числа
Wend
Fun112 = S
End Function
Для получения координат графика касательной напишем две функции:
FunDiv(x) и FunTang(x,x0). Первая функция вычисляет производную на-
шей функции Fun112 в произвольной точке x, а вторая вычисляет ординату
касательной в точке x.
Для вычисления производной используем ее определение. Производ-
ной называется предел отношения приращения функции на приращения
аргумента при стремлении последнего к 0.
y ( x + Δx ) − y ( x )
y ′ = lim .
Δx → 0 Δx
В качестве ∆x возьмем достаточно малое число 0.000001.

147
Function FunDiv(x As Double) As Double
Dim d As Double: d = 0.0000001
FunDiv = (Fun112(x + d) - Fun112(x)) / d
End Function
Уравнение касательной записывается в виде
Y=f(x0)+f ′(x0)(x-x0).
Согласно этому уравнению пишем функцию FunTang(x,x0).
Function FunTang(x As Double, x0 As Double) As Double
FunTang = Fun112(x0) + FunDiv(x0) * (x - x0)
End Function
Теперь напишем подпрограмму, которая табулирует функции Fun112 и
FunTang, выводя значения абсциссы в первый столбец, а ординаты во вто-
рой и третий столбцы. В эту же подпрограмму перекопируем из задачи
12.1 строки, отвечающие за построение графиков.
Sub Graphics(a As Double, b As Double, h As Double, x0 As Double)
Dim x As Double, n As Long
n=0
For x = a To b + 0.001 * h Step h
n=n+1
Cells(n, 1) = x
Cells(n, 2) = Fun112(x)
Cells(n, 3) = FunTang(x, x0)
Next x
' Эти строки отвечают за построение графика функции
Charts.Add ' Добавить диаграмму
' Задает тип диаграммы. Было выбрано Точечная со значениями,
' соединенными отрезками без маркеров
ActiveChart.ChartType = xlXYScatterLinesNoMarkers
' Задает область, в которой находятся данные для построения
‘ графика теперь уже строим график на базе чисел находящихся в
‘ трех первых 'столбцах A, B и C.
ActiveChart.SetSourceData Source:=Sheets("Лист6").Range("A1:C" _
+ Trim(Str(n)))
' Где строить диаграмму?
ActiveChart.Location Where:=xlLocationAsObject, Name:="Лист6"
End Sub
И наконец напишем основную программу, в которой задаем интервал
[a,b], на котором нужно строить график, шаг между точками на графике h
и абсциссу x0, в которой надо проводить касательную к графику.

148
Sub График112()
Dim a As Double, b As Double, h As Double, x0 As Double
Sheets("Лист6").Select
a = -10: b = 10: h = 0.05: x0 = 0.5
Call Graphics(a, b, h, x0)
End Sub
Все приведенные в данном задании программные единицы (функции,
подпрограммы и основную программу) необходимо поместить в произ-
вольном порядке в один модуль.
Разработанная программа получилась достаточно универсальной. Для
построения графика другой функции необходимо просто заменить тело
функции Fun112.

Список литературы
1. Шмидт В. Visual Basic 5.0. –М. : АБФ, 1997. –688с.
2. Берков Н.А. , Беркова Н.Н. Алгоритмический язык Фортран. –М:
МГИУ,1998. –94с.
3. Справочная информация пакета программ Microsoft Office 97.

149
Введение....................................................................
1. Основные элементы языка .......................................... 5

1.1. Первая программа .................................................................... 5

1.2. Типы данных.............................................................................. 7


1.2.1. Константы ................................................................................ 7
1.2.2. Переменные величины ........................................................... 8

1.3. Операции и выражения ............................................................ 11


1.3.1. Оператор присваивания........................................................ 11
1.3.2. Арифметические операции и выражения ........................... 11
1.3.3. Логические операции и выражения .................................... 13
1.3.4. Битовые операции ................................................................. 15
1.3.5. Текстовые выражения........................................................... 17

1.4. Встроенные функции................................................................. 19


1.4.1. Математические функции .................................................... 19
1.4.2. Символьные функции ........................................................... 21
1.4.3. Функции преобразования .................................................... 23
1.4.4. Функции даты и времени ..................................................... 24
2. Управляющие операторы ............................................25

2.1. Оператор безусловного перехода ............................................ 25

2.2. Логические операторы if .......................................................... 25


2.2.1. Простой укороченный if....................................................... 26
2.2.2. Простой полный if................................................................. 26
2.2.3. Блочные операторы If ........................................................... 27
2.2.4. Укороченный блочный If ..................................................... 27

2.3. Оператор выбора........................................................................ 30

2.4. Операторы цикла ....................................................................... 31


2.4.1. Оператор цикла For …Next .................................................. 31
2.4.2. Оператор цикла While........................................................... 33
2.4.3. Операторы цикла Do............................................................. 34
3. Массивы и пользовательские типы данных........... 36

3.1. Массивы переменных................................................................ 36


3.1.1. Описание массива ................................................................. 36
3.1.2. Задание начальных значений элементам массива ............. 37

3.2. Динамические массивы ............................................................ 40

3.3. Пользовательские типы данных............................................. 42

150
4. Операторы организации функций и подпрограмм 44

4.1. Подпрограммы-функции.......................................................... 44
4.1.1. Оператор FUNCTION ........................................................... 44
4.1.2. Необязательные параметры ................................................. 46
4.1.3. Передача параметров по ссылке и значению ..................... 46
4.1.4. Оператор Exit Function ......................................................... 47
4.1.5. Особенности использования в качестве формальных
параметров массивов ............................................................................ 48

4.2. Подпрограммы............................................................................ 50
4.2.1. Оператор описания подпрограммы SUB ............................ 50
4.2.2. Оператор вызова подпрограммы CALL ............................. 50
4.2.3. Примеры подпрограмм ......................................................... 51
4.2.4. Способы передачи формальных параметров ..................... 53
5. Ввод-вывод данных .........................................................

5.1. Функция MsgBox ..................................................................... 54

5.2. Функция InputBox................................................................... 57

5.3. Вывод результатов в окно отладки ..................................... 58

5.4. Форматирование данных.......................................................... 61


5.4.1. Функция Format..................................................................... 61
5.4.2. Примеры форматов ............................................................... 61
5.4.3. Стандартные форматы .......................................................... 63
5.4.4. Форматы даты и время ......................................................... 64

5.5. Ввод-вывод в ячейки рабочего листа .................................... 65

5.6. Методы форматирования ячеек рабочего листа ................. 67


5.6.1. Методы выделения ячеек цветом ........................................ 67
5.6.2. Методы форматирования и очистки ячеек ......................... 70

5.7. Операции ввода-вывода с файлами данных ........................ 72


6. Отладка программ...........................................................
7. Примеры решения простейших стандартных задач....... 77

7.1. Задачи на линейные алгоритмы ............................................. 77

7.2. Задачи на циклические алгоритмы........................................ 81


7.2.1. Арифметическая прогрессия................................................ 81
7.2.2. Геометрическая прогрессия ................................................. 82
7.2.3. Вычисление суммы арифметической последовательности83
7.2.4. Сумма индуктивных слагаемых .......................................... 85

151
7.3. Задачи на разветвляющиеся алгоритмы .............................. 87
8. Задачи сортировки ..........................................................

8.1. Перестановка элементов в массиве........................................ 90

8.2. Сортировка методом “пузырька”........................................... 93


8.2.1. Метод "пузырька" для массивов.......................................... 93
8.2.2. Метод "пузырька" для структур .......................................... 95

8.3. Сортировка методом выбора................................................... 97

8.4. Сортировка методом вставки.................................................. 98

8.5. Быстрая сортировка .................................................................. 99

8.6. Сравнения быстродействия основных типов сортировок101


9. Задачи на символьные переменные............................... 103

9.1. Задачи обработки текстовой информации.......................... 104

9.2. Задачи шифрования текста.................................................... 109


10. Задачи на массивы ..........................................................

10.1. Одномерные массивы натуральных чисел....................... 112

10.2. Задачи на одномерные массивы действительных чисел115

10.3. Задачи на двухмерные массивы действительных чисел120


11. Хранение чисел в памяти компьютера ..........................125
11.1. Перевод натуральных чисел в различные системы счисления 125

11.2. Программы перевода чисел в p-ичную систему счисления127

11.3. Перевод натуральных чисел в системы счисления, кратные


двоичной.................................................................................................. 129

11.4. Перевод целых чисел в двоичный формат ....................... 133

11.5. Перевод вещественных чисел в двоичный формат ........ 136

11.6. Хранение символьной информации в памяти компьютера143


12. Построение графиков функций ...................................... 145
Список литературы.............................................................

152