-Музыка

 -Подписка по e-mail

 

 -Поиск по дневнику

Поиск сообщений в xpackpackax

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 09.01.2009
Записей:
Комментариев:
Написано: 1835





Расширенные коды клавиатуры

Понедельник, 05 Октября 2009 г. 23:25 + в цитатник
Нажатие клавиши преобразуется в двухбайтовый код, называемый скан-ASCII-кодом. Этот код помещается в буфер клавиатуры, откуда ваша программа может считать его с помощью прерывания системы BIOS. Старший байт двухбайтового кода называется скан-кодом и является отображением фактически нажатой клавиши. Скан-код не отражает состояние клавиш Shift, Ctrl или Alt и не является уникальным. Помимо скан-кодов нажатия, существуют коды отпускания клавиш, отличающиеся на шестнадцатеричное значение 80 в сторону увеличения. Младший байт полного кода, называемый ASCII-кодом, также не является уникальным, но полная комбинация скан и ASCII-кода уникальна. Некоторые клавиши не имеют ASCII-кода и вместо него возвращается ноль. Такие двухбайтовые коды называются расширенными. При приеме кода нажатой клавиши через DOS последняя отделяет от общего значения скан-код. Кроме того, работающий в системе русификатор может дополнительно транслировать скан-коды буквенных клавиш в ASCII-коды русских букв.

Исходя из сказанного, при использовании стандартной функции readkey, работающей с ASCII-кодами клавиш, в общем случае является правильной следующая схема обработки на Паскале:

ch := readkey; {Чтение символа в байт ch}

if ch = #0 then begin

{Если нет ASCII-кода, прочитать

дополнительно расширенный код}

ch := readkey;

{Обработка расширенного кода}

end

else

{Обработка ASCII-кода}

На Паскале десятичный код может быть записан в виде #N, где N -- число, например, #65 ('A' латинская). ASCII-коды основных печатных символов можно узнать из Приложения 1, остальные нужные коды приводятся в табл. П5, П6.



Таблица П5. ASCII-коды некоторых клавиш
Enter
13
Пробел
32

Esc
27
BackSpace
8

Tab
9






Таблица П6. Расширенные коды некоторых клавиш
Клавиша
Код
Код с Shift
Код с Ctrl
Код с Alt

F1
59
84
94
104

F2
60
85
95
105

F3
61
86
96
106

F4
62
87
97
107

F5
63
88
98
108

F6
64
89
99
109

F7
65
90
100
110

F8
66
91
101
111

F9
67
92
102
112

F10
68
93
103
113

Стрелка вверх
72




Стрелка вниз
80




Стрелка влево
75




Стрелка вправо
77




Insert
82




Delete
83




Home
71

119


End
79

117


Page Up
73

132


Page Down
81

118

Правила хорошего кода

Понедельник, 05 Октября 2009 г. 23:24 + в цитатник
Написание красивого и эффективного программного кода -- целое искусство, во многом, увы, подзабытое в связи со взрывным ростом мощности вычислительных устройств, вызвавшим снижение требований к качеству алгоритмов. Это небольшое приложение не может заменить изучения специализированных дисциплин вроде "Технологии программирования" или "Теории алгоритмов и формальных языков", но следование изложенным здесь принципам позволит начинающему программисту привыкать не просто "решать задачи", а делать это возможно более красивым и экономичным с точки зрения вычислительных затрат способом.

1. Структурируйте и выравнивайте код, по крайней мере, так, как сказано в гл. 5. Во всем пособии я тоже форматировал листинги в привычном для себя стиле. Лучше привыкнуть структурировать текст, сдвигая любые вложения и разветвления кода одним-двумя пробелами вправо. Программа при этом не "разъедется" далеко вправо на сложных блоках, а вид текста, открытого в любом редакторе, не будет зависеть от размера отступа табуляции.

2. Давайте переменным осмысленные имена. Переменная с именем Length, или, в крайнем случае, Dlina, сама напомнит о своем назначении, в отличие от L. С другой стороны, не возбраняется использовать стандартные сокращения -- например, S для площади, P для периметра, a, b и c -- для сторон треугольника. Любые индексы естественно выглядят с именами i, j, k и т. д. Но если индекс обозначает номер месяца в году, куда естественней назвать его month, чем i. Хотя Паскаль и не различает регистр букв в именах переменных и служебных словах -- соблюдайте его везде. Большинство профессиональных языков регистр символов различают.

3. Существует множество соглашений об именах переменных -- можно спорить об их достоинствах и недостатках, но бесспорно одно -- соблюдение единообразного стиля именования намного облегчает понимание и модификацию программы. В сложных проектах осмысленных имен переменных может оказаться недостаточно, тогда на помощь придут префиксы. Так, если все имена всех переменных, относящихся к таблице "Студенты", начинаются на st_, а все динамические указатели имеют в имени префикс ptr_ (от англ. "pointer" -- указатель), читать такую программу будет намного проще.

4. Создавая любую переменную, обратите внимание на следующие моменты:

· какой тип значений может принимать переменная, нельзя ли заменить ее перечислением, множеством или иным "сокращенным" типом данных?

· есть ли ограничения на допустимые значения, если да, где и как они будут учтены?

· что произойдет при переполнении значения или попытке дать переменной недопустимое значение?

5. Закрывайте блоки сразу. Такой блок, как

if условие then begin

end

else begin

end;

или

while условие do begin

end;

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

6. Не оставляйте неработающее приложение "на завтра". Блочно-модульная структура программы позволяет всегда избежать этого. Подпрограмма может быть пустой "заглушкой", вы можете использовать ничего не делающие условия, пустые блоки, комментарии, но текущий код должен компилироваться, если завтра вы не хотите половину рабочего дня затратить на восстановление в памяти недоделанного сегодня.

7. Доводите программу до отсутствия предупреждений компилятора, а не только ошибок. Неизвестно, как скажутся на самом деле эти "невинные" напоминания. В языке Си конструкция вида if a:=0 допустима и вызовет лишь предупреждение "Possibly incorrect assignment" -- хотя в результате переменная a всегда будет получать значение 0 и ветвь алгоритма, привязанная к этому условию, будет всегда выполняться.

8. Выбирайте более короткие типы данных там, где это уместно: часто byte может заменить word или integer, а string[20] -- просто string.

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

10. Выбирайте менее трудоемкие операции. Так, n div k лучше, чем Trunc(n/k), а Inc(i); лучше, чем i:=i+1;. Во всех случаях порядковые операторы и операнды работают быстрее, чем вещественные. Поэтому обходитесь порядковыми данными везде, где это возможно. Особенно избегайте без необходимости деления на вещественные числа.

11. Не забывайте о погрешностях при работе с вещественными числами. Хрестоматийное while x<=2.5 do ... -- плохо, если x -- вещественный. С другой стороны, while abs(x-2.5)n), помещенное в цикл, где n не меняется, выглядит нелепо. Ведь каждое вычисление синуса (как и других стандартных функций) -- это трудоемкое разложение в ряд Фурье, выполняемое машиной.

17. Используйте математику там, где это уместно для сокращения трудоемкости кода и числа сравнений. Проверить, что переменные x и y имеют один знак, можно так:

if (x>0) and (y>0) or (x<0) and (y<0) then ...,

а можно и в виде if (x*y>0) then ....

18. Прекращайте циклы, когда результат уже достигнут. Приоритет средств при этом следующий:

· использование циклов repeat-until или while-do вместо for;

· операторы break или exit;

· в последнюю очередь -- goto, и только в случаях, описанных в п. 16.2.

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

20. Именуйте размерные константы массивов. Никому не нужны несколько циклов с верхними границами-"близнецами". А что, если размерность обрабатываемых данных придется изменить?

21. Передавайте значения подпрограммам преимущественно по адресу, а не по значению. Для матричных и векторных данных старайтесь делать это всегда. Применение векторных данных имеет приоритет перед матричными.

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

23. Не пишите подпрограмм, возвращающих более одного объекта -- скаляра, вектора или матрицы. В крайнем случае, можно отдельным параметром передавать или возвращать размерность векторных данных. Избегайте подпрограмм, которые ничего не возвращают. Разработка сложных подпрограмм облегчается, если их "точка выхода" и возвращаемое значение указаны единственным и последним оператором. Для перехода из тела подпрограммы в точку возврата в этом случае не грешно использовать даже goto:

function Test (a,b:integer):integer;

label end_of_Test;

var error:integer;

begin

error:=0;

if (a<0) or (b<0) then begin

error:=1;

goto end_of_Test;

end;

. . .

end_of_Test:

Test:=error;

end;

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

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

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

27. Если написанная вами программа не работает или работает "криво", ошибка лежит на вашей совести, а компьютер с компилятором ни в чем не виноваты. "Отладка", при которой программист хаотически меняет то одно, то другое место в коде и на которую уходит до 90% времени написания, на самом деле -- свидетельство не слишком качественной работы. Хорошо написанной программе нужна не столько отладка, сколько тестирование на различных допустимых, недопустимых и "пограничных" наборах данных. Кстати, обдумывание и написание тестов до тестируемого кода способствует и улучшению, и большей устойчивости конечного продукта.

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

beauty-cosmetic.org - косметика против целлюлита

Понедельник, 05 Октября 2009 г. 23:01 + в цитатник
Натуральная лечебная косметика на основе водорослей.
На сайте, посвященном этой продукции, все товары удобно разрубрикованы, таким образом вы тратите минимум времени на поиск. В дополнение, на этом же сайте, вы можете узнать технические подробности некоторых косметических процедур, например, обертывания зоны «живот-талия».
Из товаров ознакомьтесь, например, для начала с антицеллюлитным маслом от отеков. В его состав, как и в состав всех других продуктов, входят только натуральные природные компоненты. Если у вас возникнут вопросы по поводу косметики, вы можете задать легко задать их прямо на интернет ресурсе.
beauty-cosmetic.org

Svem.ru - бесплатная юридическая консультация

Понедельник, 05 Октября 2009 г. 22:32 + в цитатник
Svem.ru - бесплатная юридическая консультация.
Онлайн консультация собственных юристов. Вы можете задать свой вопрос и получить ответ от специалиста, а можете почитать статьи экспертов и найти нужную информацию.
Также читайте журнал «Юридический ликбез». Это блог, в котором публикуются полезные статьи на тему различных юридических проблем. Журнал имеет удобную рубрикацию, таким образом вы можете без труда найти нужные для вас публикации. Чтобы следить за обновлениями, вы можете подписаться на рассылку.
юридическая консультация

Чат без регистрации, знакомства без регистрации

Понедельник, 05 Октября 2009 г. 22:18 + в цитатник
Этот портал посещают самые разные люди и разных уголков страны или даже мира. Огромное количество людей с самими разными мыслями в голове, стало быть, каждый желающий заведет знакомства на вкус и цвет.
Теперь это ещё проще - регистрация не обязательна. Вы можете просматривать анкеты других пользователей, можете завести свою, а можете просто войти в чат всего лишь введя ник.

Чат без регистрации, Знакомства без регистрации. Хороший чат - Комфортное общение! Общение и знакомства без регистрации и границ.
Чат без регистрации

Стройком - строительство коттеджей

Понедельник, 05 Октября 2009 г. 22:10 + в цитатник
Кредо компании «Комплекс услуг – все «под ключ». Заказчик всегда прав. Работаем на репутацию».
Это, я думаю, лучшая я гарантия работы на совесть. Компания думает о своем завтрашнем дне, и именно поэтому не может не относиться серьезно к заказам и пожеланиям своих клиентов - таким образом, клиент может быть спокоем за свой будущий дом.
Заказчик может смело рассчитывать на высококачественное исполнение заказа в срок.
Посетите сайт компании, чтобы получить всю интересующую вас информацию по поводу строительства коттеджей и всех связанных с этим работ.
строительство коттеджей

производство рекламных вывесок

Четверг, 01 Октября 2009 г. 22:28 + в цитатник
Если кому-то нужна рекламная вывеска (а, быть может, даже СРОЧНО нужна), то я посоветую вам, куда следует обратиться -ЗАО «Призма-рек-лайт».
Бывает, что ждёшь долго, получаешь не то что было обговорено и качества совсем низкого. Тут же всё проверено: заказ будет выполнен быстро и без головной боли. Выйдет качественно и недорого (действуют специальные антикризисные предложения). Не теряйте времени, делайте заказ как можно скорее!
производство рекламных вывесок

Кратные циклы

Четверг, 01 Октября 2009 г. 15:06 + в цитатник
Часть 2 предназначена для углубленного изучения основ программирования на Паскале. Это углубление связано с такими актуальными темами, как применение вложенных циклов и многомерных массивов, написание сложных программ, состоящих из процедур и функций, обработка символьных и строковых величин, обмен данными с текстовыми и бинарными файлами, основы компьютерной графики.
16. Кратные циклы



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



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

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

Поясним сказанное на примере. В конструкции, описанной ниже:

for i:=1 to 5 do begin

{начало внешнего цикла}

j:=-5;

while j<=5Х6 do begin

{начало внутреннего цикла}

{тело двойного цикла}

j:=j+0.5;

end; {конец внутреннего цикла}

end; {конец внешнего цикла}

при i=1 переменная j последовательно принимает значения -5, -4.5, ... , 5, затем процесс повторится при i=2, 3, 4 и 5. Таким образом, за время выполнения каждого шага внешнего цикла for внутренний цикл while выполнится 21 раз.

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

1. Для функции двух переменных f(x,y) = sin 2x + cos 4y построить таблицу ее значений при значениях аргументов x и y, меняющихся от 0 до 2 с шагом, равным 0.25.

Решение задачи возможно, как минимум, в трех вариантах. Они схематично изображены на рис. 16.1.

Варианты 1 и 2 отличаются лишь порядком следования внешнего и внутреннего циклов. Рассмотрим возможное решение для варианта 1.





Рис. 16.1. Таблицы значений функции 2 переменных



var x,y,f:real;

begin

writeln ('x':8,'y':8,'f':8);

x:=0;

while x<=2 do begin

y:=0;

while y<=2 do begin

f:=sin(2*x)+cos(4*y);

writeln (x:8:2,y:8:2,f:8:2);

y:=y+0.25;

end;

x:=x+0.25;

end;

end.

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

Вариант 3 удобен "естественным" представлением таблицы значений функции двух переменных, однако, помешать его реализации может ограниченная ширина окна консоли (80 символов). Ниже приводится одна из возможных реализаций такой программы:

var x,y,f:real;

begin

writeln; write (' ':6);

{оставляем место для печати значений y}

x:=0;

while x<=2 do begin

{ для печати строки значений x

потребовался отдельный цикл }

write (x:6:2);

x:=x+0.25;

end;

y:=0;

while y<=2 do begin

writeln;{перевод строки для очередного y}

write (y:6:2); {печать значения y}

x:=0; {реализация внутреннего цикла по x}

while x<=2 do begin

f:=sin(2*x)+cos(4*y);

write (f:6:2);

x:=x+0.25;

end;

y:=y+0.25;

end;

end.

Как видно из листинга, код несколько усложнился за счет дополнительного цикла формирования строки значений x, для того, чтобы строка таблицы помещалась на строке экрана, пришлось также уменьшить ширину поля вывода с 8 до 6 символов. Однако, выигрыш несомненен -- теперь вся таблица поместилась на одном текстовом экране. Ограничение на ширину экрана консоли не имело бы значения, например, при выводе таблицы значений в текстовый файл.

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

Напечатать на первой строке вывода один символ звездочки, на второй -- два, на строке номер N -- N символов. Значение N вводится с клавиатуры, 1Ai) переставляя A1 и Ai. Таким образом, после выполнения этого цикла на первом месте в массиве гарантированно окажется его наименьший элемент. Для поиска следующего по величине элемента алгоритм можно повторить, сравнивая элемент A2 с остальными и при необходимости выполняя перестановку. Таким образом, приходим к двойному циклу следующего вида:

i=1,2,....,N-1 {до N-1 - так как у

элемента AN нет следующего}

j=i+1,i+2,...,N {будем для Ai перебирать

все следующие элементы}

{в теле двойного цикла сравниваем

Ai и Aj, при необходимости переставляем

их значения}

Реализуем этот алгоритм в виде следующей программы:

const nmax=100; {максимальная размерность}

var a:array [1..nmax] of real;

i,j,n:integer;

b:real; {буферная переменная}

begin

repeat {цикл ввода значения N с проверкой}

writeln ('Введите N от 2 до ',nmax,':');

{$I-}read (n);{$I+}

if (IoResult<>0) or (n<2) or (n>nmax)

then writeln ('Ошибка! Повторите ввод');

until (n>1) and (n<=nmax);

{Цикл ввода и печати исходного массива}

randomize;

{Элементы массива выберем случайными}

writeln ('Исходный массив:');

for i:=1 to n do begin

a[i]:= random(100);

write (a[i]:4:0);

end;

{Двойной цикл сортировки}

for i:=1 to n-1 do

for j:=i+1 to n do

if a[i]>a[j] then begin

b:=a[i]; a[i]:=a[j]; a[j]:=b;

end;

{Цикл вывода измененного массива}

writeln;

writeln ('Отсортированный массив:');

for i:=1 to n do write (a[i]:4:0);

reset (input); readln;

end.

Сортировка массива по убыванию отличается лишь знаком в операторе сравнения элементов Ai и Aj.

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

4. Найти, сколько раз каждый элемент встречается в массиве.

Первое, что приходит в голову при решении этой распространенной задачи -- кроме массива данных ввести "массив частот", элементы которого будут хранить информацию о встречаемости тех или иных значений. Однако решить проблему можно и без столь расточительных трат оперативной памяти (ведь размерность массива частот будет равна размерности исходного массива). Каждый элемент массива ai, кроме последнего, мы будем сравнивать со следующими за ним элементами aj, считая сколько раз выполнилось равенство ai=aj. Для того чтобы исключить повторную обработку уже встречавшихся элементов, учтенные значения нам придется заменять нулями. Поскольку значение ноль само может встретиться в массиве, дополнительный цикл перед обработкой подсчитает количество нулевых элементов.

Константа size носит то же назначение, что nmax в предыдущей задаче, а константа Diap задает диапазон значений, которые могут принимать элементы массива. Элементы массива следует сделать целочисленными, ведь задача сравнения вещественных чисел в общем случае некорректна (см. п. 7.2).

program m_chast;

const size=10;

Diap=10;

var a:array [1..size] of integer;

i,n,k,j:integer;

begin

writeln;

repeat

write('Введите размерность 1 массива ',

'(от 2 до ',size,'):');

read (n);

until (n>1) and (n<=size);

randomize;

a[1]:=random(Diap);

write ('A= ',a[1],' ');

for i:=2 to n do begin

a[i]:=random(Diap);

write (a[i],' ');

end;

writeln;

k:=0;

for i:=1 to n do if a[i]=0 then Inc(k);

if k>0 then writeln ('0: ',k);

for i:=1 to n-1 do if a[i]<>0 then begin

k:=1;

for j:=i+1 to n do if a[i]=a[j] then

begin

a[j]:=0;

Inc(k);

end;

writeln (a[i],': ',k);

end;

end.

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

5. Координаты десяти точек на плоскости заданы двумя массивами xi, yi, i=1, 2, ..., 10. Найти две точки, расстояние между которыми минимально.

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

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

Номера автобусных билетов состоят из 6 цифр. "Счастливыми" называют билеты, в номерах которых сумма трех первых цифр равна сумме трех последних. Определить общее количество "счастливых" билетов.

Каждая из шести цифр может меняться от 0 до 9 включительно. Создав кратные циклы по шести переменным, воспользуемся известным нам алгоритмом организации счетчика:

var i,j,k,l,m,n:integer;

kol:longint;

{типа integer может быть недостаточно}

begin

kol:=0;

for i:=0 to 9 do

for j:=0 to 9 do

for k:=0 to 9 do

for l:=0 to 9 do

for m:=0 to 9 do

for n:=0 to 9 do

if i+j+k = l+m+n then inc(kol);

writeln

('Количество счастливых билетов=',kol);

end.


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



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

goto Метка;

Здесь Метка -- специальным образом указанное место в программе. Действие goto очень просто: независимо от каких-либо условий он осуществляет передачу управления на оператор, следующий за меткой. Каждая метка имеет вид

m:

где m -- имя, построенное по обычным правилам или целочисленная константа от 0 до 9999 включительно. Метку недостаточно поставить перед нужным оператором -- ее нужно еще и объявить в разделе описаний оператором

label m;.

Можно объявить и несколько меток сразу, разделив их имена запятыми. Принято располагать оператор описания меток до оператора var. Таким образом, метки и оператор goto позволяют решить задачу быстрого непосредственного перехода к нужному месту в программе:

label 10,20;

var i,j:integer;

begin

write ('Введите значение I (i>2)');

readln (i);

if i<3 then goto 10;

j:=2;

20:

if i mod j = 0 then write (j,' ');

j:=j+1;

if j

Структура простой программы на Паскале

Четверг, 01 Октября 2009 г. 15:05 + в цитатник
Программа на Паскале не просто состоит из операторов -- порядок следования этих операторов не случаен и образует определенную структуру. Структура простейшей программы описана в табл. 5.1.



Табл. 5.1. Структура простой программы на Паскале
Название раздела
Операторы раздела

Заголовок программы (необязателен)
program ИмяПрограммы;

Раздел описаний - необязателен, но, как правило, присутствует
const список констант;

var список переменных;

Тело программы - обязателен, содержит операторы программы
begin

операторы;

end.




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

Только последний оператор программы завершается точкой: end. , все остальные -- символом ;.

Если в программе нет констант, в ней будет отсутствовать раздел const, если нет и переменных -- раздел var.

При написании текста программы следует соблюдать несложные правила, облегчающие его последующие чтение и модификацию:

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

· на каждой строке обычно пишется один оператор (это облегчает и отладку программы);

· операторы одного уровня вложенности пишутся с одинаковым отступом слева; например, хорошим тоном считается после начала каждого блока (begin) отступать на следующей строке на символ или несколько символов вправо, а закрывать блок так, чтобы соответствующий end; находился под своим begin. Приведем пример неправильного и правильного структурирования:

program p1; var

a,b,c:real; begin

writeln ('Введите значения A и B:');read(a,b);

c:=a+b; writeln ('A+B=',c); c:=a-b;

writeln ('A-B=',c); end.

Текст этой программы структурирован явно неудачно, гораздо лучше он воспринимается так:

program p1;

var a,b,c:real;

begin

writeln ('Введите значения A и B:');

read (a,b);

c:=a+b;

writeln ('A+B=',c);

c:=a-b;

writeln ('A-B=',c);

end.

· основные действия программы комментируются: комментарием в Паскале считается любой текст, ограниченный фигурными скобками { ... } или символами (* ... *). Количество комментариев в программе никак не влияет на объем генерируемого машинного кода, они призваны, прежде всего, облегчить последующее чтение и модификацию исходного текста программы.

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

program Equation;

var a,b,c,d,x1,x2:real; begin

writeln;

writeln ('Введите коэффициенты a,b,c:');

read (a,b,c);

d:=sqr(b)-4*a*c;

x1:=(-b+sqrt(d))/(2*a);

x2:=(-b-sqrt(d))/(2*a);

writeln ('Корни уравнения');

writeln (x1:10:2,x2:10:2);

readln; readln;

end.

В разделе описаний программы всем переменным, требуемым для решения задачи, присвоен тип real, и этот выбор вполне очевиден -- коэффициенты a, b и с -- не обязательно целые значения. "Лишний" оператор writeln; перед приглашением к вводу -- гарантия того, что приглашение будет напечатано с начала пустой строки, ведь мы пока не умеем очищать экран, и, возможно, при запуске нашей программы курсор находится не в начале строки. После вычисления дискриминанта и корней x1, x2 (условие d≥0 мы пока не проверяем), на экран печатается информационное сообщение "Корни уравнения", а затем с новой строки выводятся значения x1 и x2 с соблюдением указанных ширины и точности вывода. Наконец, два оператора readln; в конце программы позволяют ей дождаться, пока пользователь не нажмет клавишу Enter. "Удвоение" оператора здесь связано с тем, что один раз мы уже нажимали Enter после ввода данных, и первый readln; прочитает именно это нажатие, а второй будет ждать еще одного. Будь ввод данных организован в виде a:=1; b:=2; c:=0; или readln(a,b,c);, нам хватило бы и одного readln;. Однако, оператор readln(a,b,c); потребовал бы от пользователя ввести все 3 числа в одной строке, а задание фиксированных значений a, b, c уменьшило бы до нуля ее полезность. В дальнейшем мы узнаем более гибкие способы программирования реакции программы на действия пользователя.

Компилятор и оболочка Turbo Pascal

Четверг, 01 Октября 2009 г. 15:01 + в цитатник
Кратко рассмотрим основные действия с этой программой. После установки программы из папки Паскаля или с помощью ярлыка запускается файл с именем turbo.exe. Основные элементы окна Турбо Паскаля приведены на рис. 6.1.




Рис. 6.1. Окно программы Turbo Pascal



Как видно на рис. 6.1, устройство окна несколько отличается от стандартного окна Windows.

Для входа в верхнее меню следует нажать клавишу F10 или сделать щелчок мышью на нужном пункте. Если ни одно окно не открыто или необходимо окно для новой программы, в меню File выберите пункт New. Для открытия ранее сохраненной программы в этом же меню выберите Open или просто нажмите F3 из основного окна. Выбрать нужную программу можно в появившемся диалоговом окне, возможно, для этого потребуется сменить папку.

Если открыто сразу несколько окон, переключаться между ними можно, нажимая при нажатой левой Alt цифровую клавишу с номером нужного окна (от 1 до 9). Получить список всех окон можно комбинацией клавиш Alt+0, закрыть текущее окно -- Alt+F3

После ввода программы (а лучше несколько раз в процессе ввода) ее следует сохранить на диске. Для этого в меню File достаточно выбрать команду Save или нажать F2 из окна программы. При первом сохранении программе нужно дать имя. Помните, что Паскаль разрабатывался для операционной системы MS-DOS и даваемые файлам имена должны включать в себя только латинские буквы и цифры, а по длине не превышать 8 символов. Тип файла .pas можно не указывать, он добавится к имени автоматически.

Для сохранения файла с программой на дискету или открытия его с дискеты проще всего в окне ввода указать a: и нажать Enter. Аналогично можно перейти к другим сменным носителям, введя их системное имя диска.

После сохранения программы, для ее компиляции и выполнения достаточно нажать комбинацию клавиш Ctrl+F9. Если в процессе компиляции найдена синтаксическая ошибка, компилятор сообщит о ней и установит курсор на строку, содержащую ошибку. После исправления ошибки нажмите Ctrl+F9 еще раз. По завершении программы, если в ней не предусмотрено никакого останова, произойдет автоматический возврат в окно с исходным текстом. Вернуться к окну вывода программы после ее выполнения можно, нажав Alt+F5.

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

Переключение на русский язык и обратно из оболочки Турбо Паскаля зависит от настроек ОС, уточните их у преподавателя или оператора.

Переключение в полноэкранный режим и обратно, как и для других приложений DOS, выполняется сочетанием клавиш Alt+Enter.

По умолчанию программа Turbo Pascal не создает исполняемых файлов *.exe. Чтобы она начала это делать, достаточно в верхнем меню Compile установить пункт-переключатель Destination в значение Disk (значение по умолчанию -- Memory).

Оболочка Паскаля включает удобные средства отладки программ, основные требуемые команды собраны в меню Debug. Для выполнения программы по строкам достаточно нажимать F7 или F8. Разница между назначениями этих клавиш в том, что нажатие F7 пошагово выполняет программу с входом во все возможные подпрограммы, а F8 -- нет. Пока тема "Подпрограммы" не изучена, разницы в действии клавиш не будет заметно. Строка, которая будет выполняться следующей, выделена светло-зеленым цветом. Перейти сразу к нужному месту в программе можно, установив курсор на соответствующую строку и нажав клавишу F4. Выйти из режима пошагового выполнения и прервать работу отладчика позволяет сочетание клавиш Ctrl+F2.

В процессе пошагового выполнения можно посмотреть и даже изменить значения любых переменных. Для этого достаточно установить курсор на имя нужной переменной и нажать сочетание клавиш Ctrl+F4. На экране должно появиться диалоговое окно "Evaluate and Modify". В поле ввода Expression уже показано имя переменной, на которой стоял курсор. Если это не так, здесь можно задать имя любой доступной переменной или ввести произвольное выражение на Паскале. Нажатие Enter или кнопки Evaluate выводит результат в поле Result. В поле New Value можно, не прерывая пошагового выполнения, изменить значение переменной. Если предложенное изменение возможно, после нажатия кнопки Modify оно будет показано в поле Result, в противном случае там выведется сообщение "Cannot be modified". Таким образом, окно "Evaluate and Modify" позволяет гибко тестировать поведение программы при различных входных данных.

Наконец, в Паскаль встроена мощная система помощи. Нажатие клавиши F1 вызывает окно помощи по редактору, а Shift+F1 -- индекс оглавления справочной системы. В тексте помощи ссылки на другие разделы выделены желтым цветом, а переходить по ссылкам можно клавишами Tab и Shift+Tab или клавишами со стрелками. Нажатие Alt+F1 возвращает к чтению предыдущей статьи. Пользуясь выделением с помощью мыши или клавишами со стрелками при нажатой Shift, информацию из окна помощи можно копировать во встроенный буфер обмена и затем вставлять в новый или существующий файл. Соответствующие команды доступны из меню Edit. Дополнительные возможности системы помощи доступны из меню Help.

Подробнее о работе с этой и другими оболочками компании Borland можно узнать в специальной литературе.

Разветвляющийся вычислительный процесс и условный оператор

Четверг, 01 Октября 2009 г. 14:59 + в цитатник
Pers.narod.ru. Обучение. Учебник по Паскалю. Глава 7

7. Разветвляющийся вычислительный процесс и условный оператор



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

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


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



Логические выражения (ЛВ) строятся из АВ, операций отношения, логических операций и круглых скобок.

Результатом вычисления ЛВ является одно из двух значений: true или false.


7.2. Операции отношения



Операции отношения (сравнения) имеют следующий общий вид:

АВ1 ОО АВ2

где АВ -- арифметические выражения, ОО -- один из следующих знаков операций:

< <= > >= = <>

Последний знак обозначает отношение "не равно". Обратите также внимание на запись отношений "меньше или равно", "больше или равно".

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

Приведем примеры ЛВ, включающих одну ОО:

d<0 -- выбор ветви вычислений зависит от значения d;

sqr(x)+sqr(y)<=sqr(r) -- результат будет равен true для точек с координатами (x, y), лежащих внутри круга радиуса R с центром в начале координат;

cos(x)>1 -- результат этого ЛВ всегда равен false.

К вещественным значениям в общем случае неприменима операция = ("равно") из-за неточного представления этих значений в памяти компьютера. Поэтому для вещественных переменных отношение вида a=b часто заменяется на abs(a-b)1) всегда даст значение true.

Операция AND связывает не менее двух логических выражения (является бинарной). Ее результат равен true, если все выражения истинны или false, если хотя бы одно из выражений ложно.

В качестве примера распишем выражение . Т. к. операции принадлежности в Паскале нет, используем операцию AND и операции отношения: (x>=a) and (x<=b).

Математическое выражение a,b,c>0 (одновременно) будет иметь вид (a>0) and (b>0) and (c>0).

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

Распишем выражение . На Паскале оно будет иметь вид(xb). Другой способ связан с применением операции NOT: not ((x>=a) and (x<=b)).

Условие "хотя бы одно из значений a,b,c положительно" может быть записано в виде (a>0) or (b>0) or (c>0) .

Условие "только одно из значений a,b,c положительно" потребует объединения возможностей операций AND и OR:

(a>0) and (b<=0) and (c<=0) or

(a<=0) and (b>0) and (c<=0) or

(a<=0) and (b<=0) and (c>0).

Операция XOR, в отличие от OR, возвращает значение "ложь" (false) и в том случае, когда все связанные ей логические выражения истинны. Чтобы лучше уяснить это отличие, составим так называемую таблицу истинности двух логических операций (табл. 7.2). Для краткости значение false обозначим нулем, а true -- единицей. Для двух логических аргументов возможно всего 4 комбинации значений 0 и 1.



Табл. 7.2. Таблица истинности операций OR и XOR
Аргумент A
Аргумент B
A or B
A xor B

0
0
0
0

0
1
1
1

1
0
1
1

1
1
1
0




В качестве примера использования операции XOR запишем условие "только одно из значений a,b положительно":

(a>0) xor (b>0).

К сожалению, записать условие "только одно из значений a,b,c положительно" в напрашивающемся виде (a>0) xor (b>0) xor (c>0) нельзя -- результат этого выражения будет равен true и в случае, когда все три значения положительны. Связано это с тем, что при последовательном расчете логических выражений слева направо (1 xor 1) xor 1 будет равно 0 xor 1 = 1.

С помощью xor удобно организовывать различного рода переключатели, которые последовательно должны принимать одно из двух состояний:

x := x xor true; writeln ('x=', x);

x := x xor true; writeln ('x=', x);

Независимо от начального значения логической переменной x, второе выведенное на экран значение будет логическим отрицанием первого. В реальной практике конструкции подобные x := x xor true; не дублируются в коде многократно, а применяются внутри цикла (см. гл. 9).

Приоритет логических операций следующий: самая старшая операция -- not, затем and, следующие по приоритету -- or и xor (равноправны между собой), самый низкий приоритет имеют операции отношения. Последнее служит причиной того, что в составных условиях отдельные отношения необходимо заключать в круглые скобки, как и сделано во всех примерах раздела.


7.4. Короткий условный оператор



Это первый вид условного оператора, позволяющий программе выполнить или пропустить некоторый блок вычислений. Общий вид короткого условного оператора следующий:

if логическое_выражение then оператор1;

Сначала вычисляется логическое выражение, если оно имеет значение true, то выполняется оператор1, иначе оператор1 игнорируется. Блок-схема соответствующего вычислительного процесса представлена на рис. 7.1.



Рис. 7.1. Блок-схема короткого условного оператора



Если по условию требуется выполнить несколько операторов, их необходимо заключить в операторные скобки begin...end;, образуя единый составной оператор:

if d>0 then begin

x1:=(-b+sqrt(d))/(2*a);

x2:=(-b-sqrt(d))/(2*a);

writeln (x1:8:3,x2:8:3);

end;

Здесь по условию d>0 выполняется 3 оператора, первые два из которых вычисляют корни x1 и x2 квадратного уравнения, а последний выводит на экран найденные значения корней.

Следующий пример иллюстрирует поиск значения y=max(a,b,c). Поскольку стандартной функции для нахождения максимума в Паскале нет, применим 2 коротких условных оператора:

y:=a;

if b>y then y:=b;

if c>y then y:=c;

Вообще, для условной обработки N значений требуется N-1 короткий условный оператор.


7.5. Полный условный оператор



Эта форма условного оператора позволяет запрограммировать 2 ветви вычислений. Общий вид полного условного оператора следующий:

if логическое_выражение then оператор1

else оператор2;

Оператор работает следующим образом: если логическое выражение имеет значение true, то выполняется оператор1, иначе выполняется оператор2. Всегда выполняется только один из двух операторов. Перед ключевым словом else ("иначе") точка с запятой не ставится, т.к. if-then-else -- единый оператор.

Вычислим значение m=min(x,y) с помощью полного условного оператора:

if x0 then c:=a*b

else begin

a:=0; b:=0;

end;

Из примера видно, что к ветви алгоритма после ключевого слова else, состоящей более чем из одного оператора, также применяются операторные скобки.


7.6. Составной условный оператор



Эта форма условного оператора применяется, когда есть более 2 вариантов расчета. Общий вид составного оператора может включать произвольное число условий и ветвей расчета:

if логическое_выражение1 then оператор1

else if логическое_выражение2 then оператор2

...

else if логическое_выражениеN then операторN

else оператор0;

При использовании оператора последовательно проверяются логические выражения 1, 2, ... ,N, если некоторое выражение истинно, то выполняется соответствующий оператор и управление передается на оператор, следующий за условным. Если все условия ложны, выполняется оператор0 (если он задан). Число ветвей N неограниченно, ветви else оператор0; может и не быть.

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

var x:real;

begin

write ('Введите x:'); readln (x);

if x<0 then writeln ('Отрицательный')

else if x=0 then writeln ('Ноль')

else if abs(x)<1 then

writeln ('По модулю меньше 1')

else writeln ('Больше 1');

end.

Условие x<0 сработает, например, для значения x=-0.5, что не позволит программе проверить условие abs(x)<1.

Еще одну распространенную ошибку работы с составным условным оператором показывает произведенный ниже расчет знака n переменной a:

if a<0 then n:=-1;

if a=0 then n:=0

else n:=1;

Применение одного короткого и одного полного условных операторов является здесь грубой ошибкой -- ведь после завершения короткого условного оператора для всех ненулевых значений a будет выполнено присваивание n:=1. Правильных вариантов этого расчета, по меньше мере, два:

if a<0 then n:=-1;

if a=0 then n:=0;

if a>0 then n:=1;

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

if a<0 then n:=-1;

else if a<0 then n:=1;

else n:=0;

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

Можно сделать вывод, что при программировании многовариантных расчетов следует соблюдать осторожность, чтобы не допустить "потерянных" или неверно срабатывающих ветвей алгоритма.

В качестве еще одного примера рассчитаем значение функции, заданной графически (рис. 7.2).



Рис. 7.2. Функция, заданная графически



Перепишем функцию в аналитическом виде:



Одним из вариантов запрограммировать вычисление y(x) мог бы быть следующий:

if abs(x)>1 then y:=0

else if x<0 then y:=x+1

else y:=1-x;

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

if x<-1 then y:=0

else if x<0 then y:=x+1

else if x<1 then y:=1-x

else y:=0;
7.7. Вложенные условные операторы



Когда после ключевых слов then или else вновь используются условные операторы, они называются вложенными. Число вложений может быть произвольно, при этом действует правило: else всегда относится к ближайшему then. Часто вложением условных операторов можно заменить использование составного.

В качестве примера рассмотрим программу для определения номера координатной четверти p, в которой находится точка с координатами (x,y). Для простоты примем, что точка не лежит на осях координат. Без использования вложений основная часть программы может иметь следующий вид:

if (x>0) and (y>0) then p:=1

else if (x<0) and (y>0) then p:=2

else if (x<0) and (y<0) then p:=3

else p:=4;

Однако использование такого количества условий представляется явно избыточным. Перепишем программу, используя тот факт, что по каждое из условий x>0, x<0 оставляет в качестве значения p только по 2 возможных четверти из 4:

if x>0 then begin

if y>0 then p:=1

else p:=4;

end

else begin

if y>0 then p:=2

else p:=3;

end;

В первом фрагменте программе проверяется от 2 до 6 условий, во втором -- всегда только 2 условия. Здесь использование вложений дало существенный выигрыш в производительности.

Рассмотренный в п. 7.6 пример с определением знака числа может быть переписан и с использованием вложения:

if a>0 then n:=1

else begin

if a<0 then n:=-1

else n:=0;

end;

Однако, как эти операторы, так и составной условный оператор из п. 7.6 проверяют не более 2 условий, так что способы примерно равноценны.


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



Для случаев, когда требуется выбор одного значения из конечного набора вариантов, оператор if удобнее заменять оператором выбора (переключателем) case:

case выражение of

список1: оператор1;

список2: оператор2;

. . .

списокN: операторN;

else оператор0;

end;

Оператор выполняется так же, как составной условный оператор.

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

Мин.значение .. Макс.значение

Оператор диапазона записывается как два рядом стоящих символа точки. В диапазон входят все значения от минимального до максимального включительно.

В качестве примера по номеру месяца m определим число дней d в нем:

case m of

1,3,5,7..8,10,12: d:=31;

2: d:=28;

4,6,9,11: d:=30;

end;

Следующий оператор по заданному символу c определяет, к какой группе символов он относится:

case c of

'A'..'Z','a'..'z':

writeln ('Латинская буква');

'А'..'Я','а'..'п','р'..'я':

writeln ('Русская буква');

'0'..'9':

writeln ('Цифра');

else writeln ('Другой символ');

end;

Здесь отдельные диапазоны для русских букв от "а" до "п" и от "р" до "я" связаны с тем, что между "п" и "р" в кодовой таблице DOS находится ряд не-буквенных символов (см. Приложение 1).

Если по ветви оператора case нужно выполнить несколько операторов, действует то же правило, что для оператора if, т. е. ветвь алгоритма заключается в операторные скобки begin ... end;.
7.9. Примеры программ с условным оператором



Приведем несколько примеров законченных программ, использующих РВП.

1. Проверить, может ли быть построен прямоугольный треугольник по длинам сторон a, b, c.

Проблема с решением этой задачи -- не в проверке условия теоремы Пифагора, а в том, что в условии не сказано, какая из сторон может быть гипотенузой. Подходов возможно несколько -- запрашивать у пользователя ввод данных по возрастанию длины сторон, проверять все три возможных условия теоремы Пифагора и т. п. Используем наиболее естественное решение -- перед проверкой условия теоремы Пифагора упорядочим величины a, b, c так, чтобы выполнялись соотношения a≤b≤c. Для этого применим прием с обменом значений переменных из п. 4.1.

var a,b,c, {Длины сторон}

s:real;{Буферная переменная для обмена}

begin

{ Секция ввода данных }

writeln;

write ('Введите длину 1 стороны:');

readln (a);

write ('Введите длину 2 стороны:');

readln (b);

write ('Введите длину 3 стороны:');

readln (c);

{ Сортируем стороны по неубыванию }

if (a>b) then begin

s:=a; a:=b; b:=s;

end;

if (a>c) then begin

s:=a; a:=c; c:=s;

end;

if (b>c) then begin

s:=b; b:=c; c:=s;

end;

{ Проверка и вывод }

if abs(a*a+b*b-c*c)<1e-8 then writeln

('Прямоугольный треугольник ',

'может быть построен!')

else writeln('Прямоугольный треугольник ',

'не может быть построен!')

end.



2. Определить, попадает ли точка плоскости, заданная координатами (a, b) в прямоугольник, заданный координатами двух углов (x1, y1) и (x2, y2).

Как и в предыдущей задаче, было бы не совсем корректно требовать от пользователя вводить данные в определенном порядке -- гораздо лучше при необходимости поменять x- и y-координаты прямоугольника так, чтобы пара переменных (x1, y1) содержала координаты левого нижнего угла прямоугольника, а (x2, y2) -- правого верхнего.

var x1,y1,x2,y2,a,b:real;

begin

writeln ('Введите координаты 1 угла:');

read (x1,y1);

writeln ('Введите координаты 2 угла:');

read (x2,y2);

if x1>x2 then begin

a:=x1; x1:=x2; x2:=a;

end;

if y1>y2 then begin

a:=y1; y1:=y2; y2:=a;

end;

writeln ('Введите координаты точки:');

read (a,b);

if (x1<=a) and (a<=x2)

and (y1<=b) and (b<=y2) then writeln

('Точка попадает в прямоугольник')

else writeln

('Точка не попадает в прямоугольник');

end.



3. Вводится денежная сумма в рублях и копейках. Программа печатает введенную сумму с правильной формой слов "рубли" и "копейки", например, "123 рубля 15 копеек".

Окончание, используемое для слов "рубли" и "копейки", зависит от последней цифры суммы, которую можно получить, взяв остаток от деления на 10 (1058 рублей, 38 рублей и т.д.). Исключения -- суммы с последними двумя цифрами от 11 до 19 включительно, которые всегда произносятся "рублей" и "копеек" (511 рублей, но 51 рубль). Используя эту информацию, составим программу.

var r,k,o10,o100:integer;

begin

writeln;

write ('Введите количество рублей, ',

'затем пробел и количество копеек:');

read (r,k);

writeln;

o10:=r mod 10; {Взяли последнюю цифру}

o100:=r mod 100; {...и 2 последних цифры}

write ('Правильно сказать: ',r,' ');

{Печатаем число рублей, затем пробел}

if (o100>10) and (o100<20)

or (o10>4) or (o10=0) then

write ('рублей')

else if (o10>1) and (o10<5) then

write ('рубля')

else

write ('рубль');

{аналогично для копеек:}

o10:=k mod 10;

o100:=k mod 100;

write (' ',k,' ');

{печатаем число копеек с пробелами}

if (o100>10) and (o100<20) or

(o10>4) or (o10=0) then

write ('копеек')

else if (o10>1) and (o10<5) then

write ('копейки')

else write ('копейка');

end.

http://pers.narod.ru/study/pascal/07.html; Fri, 27 Feb 2009 18:44:37 GMT; гостевая; E-mail

















Яндекс.Словари

Директивы компилятора и обработка ошибок ввода

Четверг, 01 Октября 2009 г. 14:56 + в цитатник
Компилятор Паскаля -- сложное приложение, имеющее множество настроек. При написании учебных программ большинство этих настроек не имеют значения, но некоторые из них окажутся нам полезны. Для управления компилятором существует 2 основных возможности: настройка режимов работы с помощью верхнего меню Options оболочки Turbo Pascal и настройка конкретной программы с помощью директив компилятора, которую мы кратко рассмотрим. В общем виде директива компилятора представляет собой конструкцию вида {$X+} или {$X-}, где X -- латинская буква. Вариант со знаком "+" включает некоторый режим работы компилятора (например, строгий контроль программой соответствия типов данных, вывод системных диагностических сообщений и т. д.), а вариант со знаком "-" выключает его. Расположение директив, в общем, произвольно, однако, директивы, влияющие на всю программу, принято располагать в самом начале файла с исходным текстом. Фигурные скобки комментария { ... } необходимы как часть синтаксиса директивы.

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

Наиболее полезной для нас выглядит директива {$I-}/{$I+}, соответственно, выключающая и включающая автоматический контроль программой результатов операций ввода/вывода (в/в). К операциям в/в относятся, в числе прочего, ввод данных пользователем, вывод строки на принтер, открытие файла для получения или вывода данных и т. п. Понятно, что даже несложная учебная программа выглядит лучше, если она умеет реагировать на неправильные действия пользователя или возникающие ошибки не просто выводом маловразумительного системного сообщения на английском языке, а доступным неискушенному пользователю текстом. По умолчанию контроль в/в включен и системные сообщения об ошибках генерируются автоматически. Все они кратко приведены в Приложении 3. Для замены системной диагностики своей собственной следует, во-первых, отключить директиву контроля оператором {$I-}, а во-вторых, сразу же после оператора, который мог породить ошибку, проверить значение, возвращаемое системной функцией IoResult. Эта функция возвращает ноль, если последняя операция в/в прошла успешно, в противном случае возвращается ненулевое значение. После завершения "критического" оператора директиву следует включить снова, чтобы не создавать потенциально опасных ситуаций в коде, который будет писаться далее. Приведем пример, написав "расширенную" программу решения квадратного уравнения, корректно реагирующую на возникающие ошибки:

uses printer;

var a,b,c,d,x1,x2:real;

begin

writeln;

writeln ('Введите коэффициенты a,b,c:');

{$I-} read (a,b,c); {$I+}

if IoResult<>0 then begin

{Возникла ошибка!}

writeln ('Вы не ввели 3 числа, ',

'это что-то другое!');

reset (input); {очищаем стандартный

поток ввода перед ожиданием нажатия Enter}

readln;

halt; {а этим оператором можно

аварийно завершить программу}

end;

d:=sqr(b)-4*a*c;

if d<0 then begin

writeln ('Ошибка - дискриминант<0');

reset (input); readln; halt;

end;

x1:=(-b+sqrt(d))/(2*a);

x2:=(-b-sqrt(d))/(2*a);

{$I-}

writeln (lst,'x1=',x1:8:2,' x2=',x2:8:2);

{$I+}

if IoResult<>0 then

writeln ('Не удалось напечатать')

else writeln ('Результаты напечатаны');

reset (input); readln; halt;

end.

Специальной директивы для контроля математических ошибок в Паскале не предусмотрено, но это почти всегда можно сделать обычными проверками корректности данных. Обратите внимание на альтернативное решение проблемы "двух readln" в этом коде, а также на новый оператор halt и способ контроля того, удалось ли вывести строку на принтер.

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

Для работы с вещественными числами с двойной точностью (тип double) может также понадобиться указать перед программой директиву {$N+}, позволяющую сгенерировать код для аппаратной обработки таких чисел.

Оператор цикла. Циклы с предусловием и постусловием

Четверг, 01 Октября 2009 г. 14:54 + в цитатник
Циклический вычислительный процесс (ЦВП) характеризуется повторением одних и тех же вычислений над некоторым набором данных. Числом повторений цикла управляет специальная переменная, называемая его счетчиком или управляющей переменной цикла. На счетчик накладывается условие, определяющее, до каких пор следует выполнять цикл.

Повторяемый блок вычислений называют телом цикла. В теле цикла должно быть обеспечено изменение значения счетчика, чтобы он мог завершиться. Если тело цикла состоит более чем из одного оператора, оно заключается в операторные скобки begin ... end;. Однократное выполнение тела цикла называют его шагом.

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

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





Рис. 9.1. Блок-схемы циклов с предусловием и постусловием



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

Исходя из приведенных блок-схем, очевидно основное различие двух циклов: цикл с постусловием гарантированно выполняется хотя бы раз, а цикл с предусловием может не выполняться ни разу, если условие сразу же окажется ложным.

В языке Паскаль реализованы оба вида циклов. Цикл с предусловием имеет следующий общий вид:

while логическое_выражение do begin

{операторы тела цикла}

end;

Работу цикла можно описать словами: "пока логическое выражение истинно, повторяется тело цикла".

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

Общая запись цикла с постусловием следующая:

repeat

{операторы тела цикла}

until логическое_выражение;

Работает цикл с постусловием следующим образом: "тело цикла повторяется до тех пор, пока логическое выражение не станет истинным". Обратите внимание, что, в отличие от while, цикл repeat в Паскале работает, пока условие ложно. Это отличие подчеркивается использованием ключевого слова until ("до тех пор, пока не") вместо while ("до тех пор, пока"). Кроме того, в виде исключения, тело цикла repeat, даже если оно состоит из нескольких операторов, можно не заключать в операторные скобки.

Довольно часто циклы взаимозаменяемы. Представим, например, что для каждого из значений переменной x=1, 2, ... ,20, нужно выполнить некоторый расчет (математически этот закон изменения x можно записать как или ). Это можно сделать как в цикле while:

x:=1;

while x<=20 do begin

{операторы расчета}

x:=x+1;

end;

так и с помощью repeat:

x:=1;

repeat

{операторы расчета}

x:=x+1;

until x>20;

Как видно из листинга, управляющей переменной x в обоих случаях присвоено начальное значение 1, оба цикла изменяют значение x и, соответственно, условие цикла, оператором x:=x+1;, но для цикла repeat условие "перевернуто" ("пока x не станет больше 20"), а тело не заключено в операторные скобки.

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

Цикл со счетчиком и досрочное завершение циклов

Четверг, 01 Октября 2009 г. 14:53 + в цитатник
Прежде, чем перейти к примерам, обсудим еще ряд проблем, связанных с циклами. Как для while, так и для repeat, во-первых, нигде в явном виде не задается число шагов цикла (хотя его обычно можно вычислить), во-вторых, при использовании обоих циклов программист должен заботиться об изменении управляющей переменной. Между тем, весьма распространены задачи, где объем последовательно обрабатываемых данных известен заранее (а значит, известно и требуемое число шагов цикла), а управляющая переменная меняется с шагом, равным единице. Рассмотренный выше пример с двадцатью значениями x относится именно к таким задачам. Поэтому для обработки заранее известного объема данных с шагом по управляющей переменной, равным единице, вместо цикла while используется цикл со счетчиком (цикл for). Его общий вид следующий:

for счетчик := НЗ to КЗ do begin

{операторы тела цикла}

end;

Здесь счетчик -- целочисленная переменная, НЗ (начальное) и КЗ (конечное) значения -- целочисленные выражения или константы. Тело цикла образовано не менее чем одним оператором, если этот оператор единственный, операторные скобки можно не писать. Работает цикл for следующим образом: счетчик автоматически меняется от начального значения до конечного включительно, для каждого значения счетчика повторяется тело цикла. После каждого шага цикла значение счетчика автоматически увеличивается на единицу. Если требуется, чтобы значение счетчика уменьшалось, а не увеличивалось, вместо ключевого слова to используется downto.

Подобно while, цикл for может не выполниться и ни разу -- если начальное значение управляющей переменной сразу же больше конечного (при использовании to) или меньше (при использовании downto).

Запишем рассмотренный выше цикл по переменной x с помощью оператора for:

for x:=1 to 20 do begin

{операторы тела цикла}

end;

Удобства очевидны -- границы изменения x заданы сразу же при входе в цикл, а выполнять шаг по x отдельным оператором не требуется. Понятны и ограничения -- x должен быть описан с типом данных integer, а в случае изменения значения x с шагом, не равным единице, использовать for вместо while не удалось бы.

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

x:=1;

while x<10 do begin

y:=ln(x);

if y>2 then x:=10;

{При y>2 цикл нужно завершить}

x:=x+0.5;

end;

Однако, во избежание трудноуловимых ошибок, управляющую переменную не принято менять иначе, чем для выполнения шага цикла. Например, после оператора if y>2 then x:=10; в нашем листинге выполнение текущего шага продолжится, что чревато лишними или неправильными вычислениями. Кроме того, текст такой программы воспринимается нелегко.

Поэтому для досрочного выхода из цикла существует оператор break (от англ. "to break" -- прервать), немедленно прекращающий его выполнение:

x:=1;

while x<10 do begin

y:=ln(x);

if y>2 then break;

x:=x+0.5;

end;

Указание break здесь передаст управление на оператор, следующий непосредственно за циклом. В отличие от предыдущего примера, здесь не будет выполняться часть тела цикла, следующая за break;.

Для немедленного продолжения цикла со следующего шага используется оператор continue (от англ. "to continue" -- продолжить):

var n:integer;

begin

repeat

writeln ('Введите положительное число:');

read (n);

if n<1 then continue;

{Если введено n<1, снова запросить число}

{Операторы обработки числа}

break; {Выход из цикла обработки}

until false;

end.

В этом примере оператор continue использован для повторного перехода к вводу n, если введено n<1. Так как цикл обработки здесь -- бесконечный, для выхода из него необходим break;. Кроме того, пример показывает одну из возможностей контроля правильности ввода данных. Указав директиву {$I-}, изученную в гл. 8, мы могли бы защитить программу и от ввода пользователем нечисловых значений в качестве n.

В теме "Кратные циклы" второй части курса будет рассмотрен оператор goto, также способный решить проблему аварийного завершения циклов.

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

Четверг, 01 Октября 2009 г. 14:51 + в цитатник
Типовые алгоритмы табулирования функций, вычисления количества, суммы и произведения



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

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


11.1. Алгоритм табулирования



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

В общем виде алгоритм можно описать так:

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

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

3. в конце шага цикла значение управляющей переменной (обозначим ее x) изменяется оператором вида x:=x+d;, где d -- заданный шаг по управляющей переменной.

В качестве примера составим таблицу синусов в пределах от 0 до π с шагом по аргументу 0.25. Обозначим аргумент как x, значение синуса от x обозначим как y. В простейшем случае программа табулирования может выглядеть так:

var x,y:real;

begin

writeln('x':10,'sin(x)':10);

{печать заголовка таблицы до цикла}

x:=0; {начальное значение аргумента}

while x<=piХ6 do begin

y:=sin(x); {вычисление функции}

writeln (x:10:2, y:10:2);

{печать строки таблицы}

x:=x+0.25; {шаг по x}

end;

end.

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

, значения a, b вводятся пользователем.

Напишем текст программы, сопроводив его соответствующими комментариями.

var x,f,a,b,dx:real;

n:integer; {счетчик выведенных строк}

begin

repeat {Цикл ввода с контролем

правильности значений: a,dx,b должны быть

числами, dx>0, a+dx должно быть меньше b}

writeln ('Введите a,dx,b:');

{$I-}read (a,dx,b);{$I+}

if IoResult <> 0 then begin

writeln ('Вы не ввели 3 числовых ',

'значения, попробуем еще раз');

continue;

end;

if (dx<=0) or (a+dx>=b) then begin

writeln ('Вы не ввели допустимые ',

'данные, попробуем еще раз');

continue;

end

else break;

until false;

{Печать заголовка таблицы}

writeln;

writeln ('x':10,'f(x)':10);

x:=a;

n:=2; {2 строки уже использованы}

while x<=bХ6 do begin

{в условии цикла учитываем возможную

погрешность работы с real!}

if x<=0 then f:=sqr(x)*x

else f:=exp(1/3*ln(abs(x)));

{корень 3 степени взяли через exp и ln}

writeln (x:10:2,f:10:2);

n:=n+1;

if n=24 then begin

{На экране консоли по умолчанию 25 строк}

write ('Нажмите Enter...');

reset (input); readln;

n:=1;

end;

x:=x+dx;

end;

writeln ('Таблица выведена');

reset (input); readln;

end.

Как видно из примера, основной порядок действий -- такой же, как в предыдущей задаче. Так как экран консоли по умолчанию содержит всего 25 строк, с помощью переменной n мы дополнительно контролируем число уже выведенных строк и делаем по заполнении экрана паузу до нажатия пользователем клавиши Enter.

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

Известна стоимость единицы товара. Составить таблицу стоимости 1, 2, ..., K единиц товара, значение K вводится.

Так как число единиц товара -- заведомо целое, при программировании задачи будет удобен цикл for:

var t:real;

i,k:integer;

begin

writeln;

writeln ('Стоимость единицы товара:');

read (t);

writeln ('Количество единиц товара:');

read (k);

writeln ('Единиц':10,'Стоимость':10);

for i:=1 to k do

writeln (i:10,(i*t):10:2);

end.

Здесь для простоты мы исключили сделанные в предыдущем примере проверки. Стоимость единицы товара обозначена t, переменная i необходима для перебора возможных значений единиц товара в цикле for. Поскольку счетчик цикла for автоматически меняется с шагом 1, а оператором writeln можно выводить не только значения переменных, но и выражения, основной цикл программы состоит из одного оператора и не нуждается в операторных скобках.


11.2. Алгоритм организации счетчика



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

1. в разделе var описать переменную целочисленного типа, с помощью которой будет вестись подсчет;

2. до цикла присвоить ей начальное значение 0;

3. в теле цикла, если очередной элемент данных отвечает условию подсчета, увеличить эту переменную на 1 оператором вида k:=k+1;.

Необходимость присваивания начальных значений на шаге 2 этого и последующих алгоритмов связана с тем, что после описания в разделе var значение переменной еще не определено. "Пока мы не начали подсчитывать количество, оно равно нулю" -- этот очевидный для человека факт не очевиден для компьютера! Поэтому любой переменной, которая может изменяться в теле цикла, необходимо присвоить до цикла начальное значение, что и делает оператор вида k:=0;.

Рассматриваемый нами алгоритм очень часто встречается в самых различных задачах, поэтому для "быстрой" записи операции по увеличению счетчика (она называется инкремент) или его уменьшению (декремент) существуют специальные стандартные процедуры:

Inc(X,N); -- увеличивает значение переменной.

Здесь параметр X -- переменная порядкового типа, а N -- переменная или выражение целочисленного типа. Значение X увеличивается на 1, если параметр N не определен, или на N, если параметр N определен, то есть Inc(X); соответствует X:=X+1;, а Inc(X,N); соответствует X:=X+N;.

Dec(X,N); -- уменьшает значение переменной.

Параметр X -- также переменная порядкового типа, N -- целочисленное значение или выражение. Значение X уменьшается на 1, если параметр N не определен, или на N, если параметр N определен, то есть Dec(X); соответствует X:=X-1;, а Dec(X,N); соответствует X:=X-N;.

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

В качестве примера реализации алгоритма рассмотрим следующую задачу.

Последовательность z(i) задана соотношениями , i=1,2,...,100. Найти количество элементов последовательности, больших значения 0.5.

Обозначив искомое количество за k, составим программу:

var z:real;

i,k:integer;

begin

k:=0;

for i:=1 to 100 do begin

if i mod 2 = 0 then z:=sqr(i)*cos(i)

else z:=sin(i/2);

if z>0.5 then inc(k);

end;

writeln ('Количество=',k);

end.

Так как шаг по переменной i равен 1, в программе использован цикл for, для проверки того, является ли значение i четным, использована операция mod.

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

Известны оценки за экзамен по информатике для группы из n студентов, 2≤n≤25. Оценить количественную и качественную успеваемость группы по формулам:

, , где k1 -- количество "троек", "четверок" и "пятерок", k2 -- количество только "четверок" и "пятерок".

Для ввода текущей оценки используем целочисленную переменную a, в качестве счетчика цикла for введем переменную i ("номер студента"), остальные величины описаны в условии задачи. При вводе значения n и очередного значения a для простоты не будем контролировать корректность вводимых данных.

var a,i,n,k1,k2:integer;

ykol,ykach:real;

begin

writeln;

writeln ('Введите количество студентов:');

read (n);

k1:=0;

k2:=0;

for i:=1 to n do begin

write ('Введите оценку ',i,' студента:');

read (a);

if a>2 then begin

inc(k1);

if a>3 then inc(k2);

end;

end;

ykol:=k1/n*100;

ykach:=k2/n*100;

writeln

('Количественная успеваемость=',ykol:6:2);

writeln

('Качественная успеваемость =',ykach:6:2);

reset (input); readln;

end.


11.3. Алгоритмы накопления суммы и произведения



Данные алгоритмы применяются, когда требуется сложить или перемножить выбранные данные. В общем виде эти широко применяемые алгоритмы можно описать так:

1. для подсчета каждой суммы или произведения описать по одной переменной того же типа, что суммируемые или перемножаемые данные;

2. до цикла переменной-сумме присвоить начальное значение 0, а произведению -- значение 1;

3. в теле цикла, если очередной элемент данных t отвечает условию суммирования или перемножения, сумма накапливается оператором вида s:=s+t;, а произведение -- оператором вида p:=p*t;

Очевидно, почему начальное значение произведения -- 1, а не 0. После оператора p:=0; оператор p:=p*t;, расположенный в теле цикла, будет возвращать только нули.

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

Для поиска арифметического среднего необходимо сначала найти сумму s и количество k положительных значений функции. Составим следующую программу:

var x,f,s,p:real;

k:integer;

begin

s:=0; k:=0; p:=1;

x:=-5;

while x<=5Х6 do begin

if x<0 then f:=sqr(ln(abs(x)))

else if x>0 then f:=sin(sqr(x))

else f:=0;

if f>0 then begin

s:=s+f;

k:=k+1;

end;

if f<>0 then p:=p*f;

x:=x+0.5;

end;

s:=s/k; {теперь в s - искомое среднее}

writeln

('Среднее положительных =',s:10:6);

writeln

('Произведение ненулевых=',p:10:6);

reset (input); readln;

end.

В следующей задаче также применяется алгоритм накопления суммы.

Требуется написать программу, имитирующую работу кассового аппарата: пользователь в цикле вводит цену очередного товара или 0 для завершения ввода, программа суммирует цены. По завершении цикла ввода программа начисляет скидку с общей стоимости товара по правилам: скидки нет, если общая стоимость покупки -- менее 10000 руб.; скидка равна 5%, если общая стоимость -- от 10000 до 20000 руб.; скидка равна 7%, если общая стоимость -- свыше 20000 руб. После начисления скидки выводится окончательная стоимость покупки.

Обозначив общую стоимость покупки s, а цену очередного товара -- t, напишем следующую программу:

var s,t:real;

begin

writeln;

s:=0; {начальное значение суммы!}

repeat

writeln ('Введите стоимость товара или '

'0 для завершения ввода:');

{$I-}read(t);{$I+}

if (IoResult<>0) or (t<0) then begin

writeln ('Ошибка! Повторите ввод');

continue;

end;

if t=0 then break;

{Округляем t до 2 знаков после запятой -

на случай, если есть копейки}

t:=round (t*100) / 100;

s:=s+t; {накопление суммы}

until false;

{Начисление скидки и вывод ответа}

writeln ('Стоимость без скидки:',s:8:2);

if s>20000 then s:=s-s*0.07

else if s>10000 then s:=s-s*0.05;

writeln ('Стоимость со скидкой:',s:8:2);

writeln ('Спасибо за покупку!');

reset (input); readln;

end.

Тип данных real выбран для s и t не случайно -- выбор integer ограничил бы диапазон обрабатываемых значений и не позволил в удобном виде ввести копейки. Проверки корректности ввода, делаемые программой, знакомы по предыдущим примерам и поэтому не закомментированы.

Типовые алгоритмы поиска максимума и минимума

Четверг, 01 Октября 2009 г. 14:50 + в цитатник
В этой главе мы изучим простейшие статистические алгоритмы, главный из которых -- определение максимального и минимального значений на множестве данных.

Рассмотрим алгоритм в общем виде:

1. описать для каждого максимума и минимума по одной переменной того же типа, что анализируемые данные;

2. до цикла максимуму присваивается либо заведомо малое для анализируемых данных значение, либо первый элемент данных; минимуму присваивается либо заведомо большое для анализируемых данных значение, либо первый элемент данных;

3. в теле цикла каждый подходящий для поиска элемент данных t обрабатывается операторами вида:
if t>max then max:=t; -- для максимума;
if tmax не выполнится ни разу и ответом будет max, равное нулю, что неправильно. Выбор заведомо малого начального значения max (например, значение -1E30, т. е., -1030, вряд ли встретится в любых реальных данных) гарантирует, что условие t>max выполнится хотя бы раз и максимум будет найден. Альтернативный способ -- присвоить переменной max значение отдельно вычисленного первого элемента последовательности данных. В этом случае ответ либо уже найден, если первый элемент и есть максимальный, либо будет найден в цикле.

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

Перейдем к примерам. Для функции y(x)=sin2(x), найти минимальное среди положительных и максимальное значения.

Обозначив искомые значения min и max соответственно, напишем следующую программу:

var x,y,max,min:real;

begin

x:=-pi/3;

max:=-2;

min:=2; {эти начальные значения

- заведомо малое и большое для синуса}

while x<=pi/3Х6 do begin

y:=sqr(sin(x));

if y>0 then

{ищем min только среди положительных!}

if ymax then max:=y;

x:=x+pi/24;

end;

writeln ('Минимум =',min:8:2);

writeln ('Максимум=',max:8:2);

reset (input); readln;

end.

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

Последовательность T(k) задана соотношениями T(k)=max(sin k, cos k), k=1, 2, ... ,31. Найти номера максимального и минимального элементов последовательности.

Поиск номеров не избавит нас от необходимости поиска значений. Поэтому, кроме переменных min и max, нам понадобятся две целочисленные переменные для хранения номеров минимального и максимального значений, обозначим их kmin и kmax соответственно. Обратите также внимание, что на каждом шаге цикла дополнительно потребуется находить максимальное из значений sin(k) и cos(k), для занесения его в переменную t.

var t,max,min:real;

k,kmin,kmax:integer;

begin

min:=1e30;

max:=-1e30;

{задаем "надежные" значения,

близкие к плюс и минус бесконечности}

for k:=1 to 31 do begin

if sin(k)>cos(k) then t:=sin(k)

else t:=cos(k);

if tmax then begin

max:=t; kmax:=k;

end;

end;

writeln ('Номер мин. элемента =',kmin);

writeln ('Номер макс. элемента=',kmax);

reset (input); readln;

end.

Решение учебных задач на циклы

Четверг, 01 Октября 2009 г. 14:48 + в цитатник
Применяя полученные навыки работы с типовыми алгоритмами, рассмотрим несколько учебных задач различных типов.

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

Задана функция и ее разложение в ряд:

n=0, 1, 2, ... (здесь n! обозначает факториал числа n, равный 1*2*3*...*n; при этом 0!=1). Найти число элементов ряда k, требуемое для достижения заданной точности ε.

Перед нами -- типичная задача на ряды. С ростом величины n слагаемые становятся все меньше, равно как и модуль разности между двумя соседними слагаемыми. Поэтому под достижением заданной точности будем понимать выполнение условия где sn, sn-1 -- суммы ряда, вычисленные на текущем и предыдущем шагах цикла, а значение ε задается малым числом, от 10-6 и ниже. Для вычисления x2n введем переменную xn, которую на каждом шаге цикла будем домножать на x2, аналогично, для вычисления текущего значения факториала используем переменную nf. Иной подход потребовал бы большого количества повторных вычислений на каждом шаге цикла, плюс был бы чреват большими потерями точности. Для вычисления (-1)n было бы странно использовать формулу ax=exln a -- вполне достаточно завести целочисленную переменную znak, равную 1, которая на каждом шаге цикла будет менять свое значение на противоположное оператором znak:=-znak;. Кроме того, так как требуемое число шагов заранее неизвестно, используем для всех основных переменных более точный тип double вместо real.

Реализуем все сказанное в следующей программе:

{$N+} {Совместимость с процессором 80287 -

для использования double}

var x,sn,sn1,xn,nf,eps:double;

k,n:longint;

znak:integer;

begin

writeln ('Введите значение x:');

read (x);

writeln ('Введите требуемую точность:');

read (eps);

sn1:=0;

sn:=0;

k:=0;

n:=0;

xn:=1;

nf:=1;

znak:=1;

repeat

sn1:=sn; {Текущая сумма стала

предыдущей для следующего шага}

sn:=sn+znak*xn/nf; {Выполняем шаг цикла}

{Меняем переменные для следующего шага:}

znak:=-znak;

xn:=xn*sqr(x);

nf:=nf*(n+1)*(n+2);

n:=n+2;

k:=k+1;

until abs(sn1-sn)

Одномерные массивы. Описание, ввод, вывод и обработка массивов на Паскале

Четверг, 01 Октября 2009 г. 14:47 + в цитатник
Массивом называют упорядоченный набор однотипных переменных (элементов). Каждый элемент имеет целочисленный порядковый номер, называемый индексом. Число элементов в массиве называют его размерностью. Массивы используются там, где нужно обработать сразу несколько переменных одного типа -- например, оценки всех 20 студентов группы или координаты 10 точек на плоскости. Строку текста можно рассматривать как массив символов, а текст на странице -- как массив строк.

Массив описывается в разделе var оператором следующего вида:

var ИмяМассива: array [НИ .. ВИ] of Тип;

Здесь

НИ (нижний индекс) -- целочисленный номер 1-го элемента массива;

.. -- оператор диапазона Паскаля (см. п. 7.8);

ВИ (верхний индекс) -- целочисленный номер последнего элемента;

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

Опишем несколько массивов разного назначения.

var a: array [1..20] of integer;

Здесь мы описали массив с именем A, состоящий из 20 целочисленных элементов;

var x,y : array [1..10] of real;

Описаны 2 массива с именами x и y, содержащие по 10 вещественных элементов;

var t : array [0..9] of string;

Массив t состоит из 10 строк, которые занумерованы с нуля.

Легко увидеть, что размерность (число элементов) массива вычисляется как ВИ - НИ + 1.

Для обращения к отдельному элементу массива используется оператор вида ИмяМассива [Индекс].

Здесь Индекс -- целочисленный номер элемента (может быть целочисленным выражением или константой). Индекс не должен быть меньше значения нижнего или больше верхнего индекса массива, иначе возникнет ошибка "Constant out of range". Отдельный элемент массива можно использовать так же, как переменную соответствующего типа, например:

A[1]:=1;

x[1]:=1.5; y[1]:=x[1]+1;

t[0]:='Hello';

В этой главе мы изучаем одномерные массивы, в которых каждый элемент имеет один номер (индекс), характеризующий его положение в массиве. В математике понятию одномерного массива из n элементов соответствует понятие вектора из n компонент: A = {Ai}, i=1, 2 ,..., n.

Как правило, ввод, обработка и вывод массива осуществляются поэлементно, с использованием цикла for.

Простейший способ ввода -- ввод массива с клавиатуры:

const n = 10;

var a: array [1..n] of real;

i:integer;

begin

writeln ('Введите элементы массива');

for i:=1 to n do read (A[i]);

Размерность массива определена константой n, элементы вводятся по одному в цикле for -- при запуске этой программы пользователю придется ввести 10 числовых значений. При решении учебных задач вводить массивы "вручную", особенно если их размерность велика, не всегда удобно. Существуют, как минимум, два альтернативных решения.

Описание массива констант удобно, если элементы массива не должны изменяться в процессе выполнения программы. Как и другие константы, массивы констант описываются в разделе const. Приведем пример такого описания:

const a:array [1..5] of real=(

3.5, 2, -5, 4, 11.7

);

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

Формирование массива из случайных значений уместно, если при решении задачи массив служит лишь для иллюстрации того или иного алгоритма, а конкретные значения элементов несущественны. Для того чтобы получить очередное случайное значение, используется стандартная функция random(N), где параметром N передается значение порядкового типа. Она вернет случайное число того же типа, что тип аргумента и лежащее в диапазоне от 0 до N-1 включительно. Например, оператор вида a[1]:=random(100); запишет в a[1] случайное число из диапазона [0,99].

Для того чтобы при каждом запуске программы цепочка случайных чисел была новой, перед первым вызовом random следует вызвать стандартную процедуру randomize;, запускающую генератор случайных чисел. Приведем пример заполнения массива из 20 элементов случайными числами, лежащими в диапазоне от -10 до 10:

var a:array [1..20] of integer;

i:integer;

begin

randomize;

for i:=1 to 20 do begin

a[i]:=random(21)-10;

write (a[i]:4);

end;

end.

Еще более удобный путь -- чтение элементов массива из текстового или двоичного файла. Об этом рассказывается в гл. 21 и 22.

К массивам применимы все типовые алгоритмы, изученные в теме "Циклы". Приведем один пример, в котором вычисляется сумма s положительных элементов массива.

var b:array [1..5] of real;

s:real; i:integer;

begin

writeln ('Введите 5 элементов массива');

for i:=1 to 5 do read (b[i]);

s:=0;

for i:=1 to 5 do if b[i]>0 then s:=s+b[i];

Вывод массива на экран также делается с помощью цикла for.

for i:=1 to 5 do write (b[i]:6:2);

Здесь 5 элементов массива b напечатаны в одну строку. Для вывода одного элемента на одной строке можно было бы использовать оператор writeln вместо write.

Существенно то, что если обработка массива осуществляется последовательно, по 1 элементу, циклы ввода и обработки зачастую можно объединить, как в следующем примере.

Найти арифметическое среднее элементов вещественного массива t размерностью 6 и значение его минимального элемента.

var b:array [1..6] of real;

s, min:real;

i:integer;

begin

s:=0; min:=1e30;

writeln ('Ввод B[6]');

for i:=1 to 6 do begin

read (b[i]);

s:=s+b[i];

if b[i] max then begin

max:=dist; {запомнили новое расстояние}

Num:=i; {и номер точки}

end;

end;

writeln ('Номер точки=',num,

' расстояние=',dist:8:2);

Len:=0;{длина ломаной - сумма длин сторон}

for i:=1 to 9 do begin

{у 10-й точки нет следующей!}

r:= sqrt (sqr(x[i]-x[i+1])+

sqr(y[i]-y[i+1]));

Len:=Len+r;

end;

writeln ('Длина ломаной=',len:8:2);

end.

Приведем пример задачи формирования массива по правилу.

Задан массив x из 8 элементов. Сформировать массив y по правилу



и найти количество его положительных элементов.

var x,y: array [1..8] of real;

i,k:integer;

begin

writeln ('Введите массив x из 8 эл.');

for i:=1 to 8 do begin

read (x[i]);

if i mod 2 =0 then y[i]:=4*x[i]

else y[i]:=cos(2*x[i]);

end;

K:=0;

writeln ('Массив y');

for i:=1 to 8 do begin

if y[i]>0 then k:=k+1;

write (y[i]:8:2);

end;

writeln;

writeln ('K=',k);

end.

15. Решение типовых задач на массивы

Четверг, 01 Октября 2009 г. 14:46 + в цитатник
В гл. 14 мы подчеркивали, что типовые алгоритмы, изученные в теме "Циклы", в полной мере применимы и к массивам. Занимая определенный объем оперативной памяти, однажды полученные элементы массива остаются доступными весь сеанс работы программы и не требуют повторного вычисления или чтения из файла. Это порождает круг приложений, связанных с типовой обработкой наборов данных -- вычисление математических и статистических характеристик векторов, объединение массивов или поиск нужных значений в них и т. д. Другие интересные примеры, такие как подсчет частоты встречаемости элементов в массиве, задача сортировки (упорядочения) данных, будут рассмотрены в гл. 16.

1. Найти сумму, скалярное произведение и длину двух векторов произвольно заданной размерности. Размерность не может превышать значения 100.

Предельную размерность массивов зададим константой size=100. Размерность реальных векторов a и b, с которыми работает программа, не обязательно столь велика, обозначим ее n и позаботимся о том, чтоб при вводе значения n соблюдалось соотношение 2≤n≤size. Введем вектор a с клавиатуры, а вектор b сгенерируем из случайных вещественных чисел, принадлежащих диапазону от 0 до 10. Для этого достаточно умножить на 10 значение, возвращаемое стандартной функцией random, если она вызвана без параметров: b[i]:=random*10;.

При написании кода мы применим изученный в гл. 8 прием контроля правильности вводимых данных с помощью директивы компилятора и стандартной функции IoResult.

Как известно из математики, сумма векторов a и b ищется поэлементно по правилу ci=ai+bi, скалярное произведение может быть вычислено по формуле , а длина вектора a из n элементов ищется по формуле .

const size=100;

var a,b,c:array [1..size] of real;

n,i:integer;

la,lb,s:real;

begin

repeat

writeln;

write ('Введите размерность A и B, ',

'значение от 2 до ',size,':');

{$I-}readln (n);{$I+}

if (IoResult<>0) or (n<2) or (n>size)

then

writeln ('Неверный ввод, повторите')

else break;

until false;

writeln ('Введите вектор A из ',

n,' элементов:');

for i:=1 to n do begin

repeat

write ('A[',i,']=');

{$I-}readln (a[i]);{$I+}

if IoResult=0 then break;

until false;

end;

writeln ('Генерируется вектор B из ',

n,' элементов:');

randomize;

for i:=1 to n do begin

b[i]:=random*10;

write (b[i]:8:2);

end;

la:=0;

lb:=0;

s:=0;

writeln;

writeln ('Вектор c=A+B:');

for i:=1 to n do begin

c[i]:=a[i]+b[i];

write (c[i]:8:2);

la:=la+sqr(a[i]);

lb:=lb+sqr(b[i]);

s:=s+a[i]*b[i];

end;

writeln;

writeln ('Длина вектора A: ',

sqrt(la):8:2);

writeln ('Длина вектора B: ',

sqrt(lb):8:2);

writeln ('Скалярное произведение:',s:8:2);

reset (input); readln;

end.

Думаю, при анализе листинга вы обратили внимание еще на одну особенность программы -- на каждом шаге цикла ввода вектора a дополнительно выполняется цикл repeat...until, предназначенный для контроля правильности ввода элементов массива. Подробнее такие конструкции, называемые кратными циклами, будут изучены в гл. 16.

2. Задана выборка из n случайных чисел. Для n=100 определить математическое ожидание mx и дисперсию dx выборки по формулам: , .

Две подсчитываемые величины -- самые распространенные статистические характеристики набора случайных данных. Фактически, математические ожидание характеризует арифметическое среднее данных выборки, а дисперсия -- среднеквадратичное отклонение данных от среднего значения. Для хранения данных используем массив x из 100 элементов, сами данные сгенерируем из случайных чисел, находящихся в диапазоне от -1 до 1 включительно. Поскольку алгоритм накопления суммы предполагает последовательное и однократное использование каждого элемента массива, в цикле генерации элементов массива могут быть подсчитаны значения и , которые затем позволят найти mx и dx.

const n=100;

var x:array [1..100] of real;

s,d:real;

i:integer;



begin

writeln;

writeln ('Массив x[100]:');

randomize;

s:=0; d:=0;

for i:=1 to n do begin

x[i]:=random*2-1;

write (x[i]:8:3);

s:=s+x[i];

d:=d+sqr(x[i]);

end;

s:=s/n; {теперь в s - мат. ожидание,}

d:=d/(n-1)-sqr(s)/(n*(n-1));

{а в d - дисперсия}

writeln;

writeln ('s=',s:8:4);

writeln ('D=',d:8:4);

reset (input); readln;

end.

3. Объединить 2 упорядоченных по возрастанию массива A и B в массив C.

Для решения этой задачи тоже достаточно одного прохода по массивам. Действительно, заведя для каждого из массивов a, b и c по собственному счетчику (обозначим их ia, ib и i соответственно), мы можем, в зависимости от истинности или ложности соотношения aia≤bib переписывать в элемент ci значение aia или bib. Остается проконтролировать, чтобы ни один из счетчиков не вышел за границу размерности своего массива. Увидеть детали вам поможет внимательный анализ листинга.

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

program m_concat;

const size=10;

step=5;

var a,b:array [1..size] of integer;

c:array [1..2*size] of integer;

i,n1,n2,ia,ib,ic:integer;

begin

writeln;

repeat

write('Размерность 1 массива ',

'(от 2 до ',size,'):');

read (n1);

until (n1>1) and (n1<=size);

randomize;

a[1]:=random(step);

write ('A= ',a[1],' ');

for i:=2 to n1 do begin

a[i]:=a[i-1]+random(step);

write (a[i],' ');

end;

writeln;

repeat

write('Размерность 2 массива ',

'(от 2 до ',size,'):');

read (n2);

until (n2>1) and (n2<=size);

b[1]:=random(step);

write ('B= ',b[1],' ');

for i:=2 to n2 do begin

b[i]:=b[i-1]+random(step);

write (b[i],' ');

end;

writeln;

ia:=1; ib:=1;

write ('c= ');

for i:=1 to n1+n2 do begin

if a[ia]<=b[ib] then begin

c[i]:=a[ia];

if ia

Стальные двери

Четверг, 01 Октября 2009 г. 13:52 + в цитатник
«Компания Завод Спецоборудование» - Клинское производство стальных дверей.
Надежные изделия, предназначенные для первоклассной защиты, но при этом изготовитель не забывает и о этической стороне вопроса - о дизайне.
Изготовление дверей любой сложности с учетом пожеланий заказчика и технических особенности помещения. Вы можете ознакомиться с общими принципами изготовления стальных дверей прямо на главной странице сайта производителя.
Специальное предложение на время непростой экономической ситуации - скидка на всю продукцию!
стальные двери


Поиск сообщений в xpackpackax
Страницы: 25 ... 21 20 [19] 18 17 ..
.. 1 Календарь