присвоювання
Ім’я ліворуч від символу присвоювання := є ім’я змінної, якій присвоюється значення виразу, який стоїть праворуч. Тому поряд зі значенням виразу важливим атрибутом є його тип. Тип виразу у правій частині оператора присвоювання повинен співпадати або бути сумісним з типом змінної з лівої частини. Компілятор на етапі синтаксичного аналізу програми здійснює цю перевірку – так званий контроль типів. Допустиме присвоювання змінних будь-яких типів, за винятком типу File.
Root1 := Pi*(x - y)
Solution := Discriminant >=0
Discriminant := Sqrt(b*b-4*a*c)/2/A
Index := Index + 1
Letter := Succ(Succ(Letter))
4.10. Оператори введення - виведення
Для організації введення - виведення даних у мові Pascal використовуються оператори - процедури Read, Readln, Write, Writeln. За допомогою цих операторів організується введення даних з файлу Input та виведення даних у файл Output.
Текстові файли Input ,Ouтput представляються користувачу як текст, що поділений на рядки і забезпечений ознакою кінця файлу і ознаками кінців рядків. Кожен рядок може містити числа або символьні дані (тобто рядок складається з декількох даних типів Integer, Real, Сhar). Читання / запис здійснюється через так званий буфер файла. В момент звернення до файла його буфер встановлений на деяке дане – елемент файла. Буфер файла може бути переміщений або до наступного даного, або до першого даного наступного рядка.
Оператор Read(х) читає дане з Input у змінну х і переміщує буфер до наступного даного.
Оператор Write(х) пише дане в Output зі змінної х і переміщує буфер у наступну позицію.
Оператор Readln(х) читає дане з файла Input у змінну х та переміщує буфер у наступний рядок.
Оператор Writeln(х) пише дане в Output зі змінної х та переміщує буфер у наступний рядок.
Оператори введення/виведення можуть використовуватись у більш загальній формі:
Read( <список змінних> ),
Readln( <список змінних> )
Write( <список виразів або рядків> )
Writeln( <список виразів або рядків> )
Тепер ми володіємо знаннями, яких достатньо для написання лінійних (які не розгалужуються) програм.
4.11. Приклад лінійної програми
Приклад 4.1. Програма обчислення площі кола, вписаного у трикутник і площі кола, описаного навколо трикутника.
Program Triangle; {програма обчислює площі, вписаного в трикутник і описаного навколо трикутника кіл}
Const
Pi = 3.1415926;
Line = ‘_______________________________’;
Var
a, b, c : Real;
Sint, Sout : Real;
S, p : Real;
Begin
{ введення даних}
Write(‘ введіть сторони трикутника a b c ‘);
Readln(a, b, c);
{обчислення }
p := (a + b + c)/2;
S := Sqrt(p*(p - a)*(p - b)*(p - c));
Sout := Pi*sqrt(a*b*c/4/S);
Sint := Pi*sqrt(2*S/p);
{друк відповіді}
Writeln;
Writeln (Line);
Writeln(‘Sвпис = ‘, Sout);
Writeln(Line);
Writeln(‘Sопис = ‘, Sint);
Writeln(Line)
End .
Оператори Readln і Writeln можуть застосовуватись без параметрів (тобто без дужок та тексту у дужках), для переходу до введення/ виведення з наступного рядка або для пропускання рядка.
Для оформлення введення в операторах Write, Writeln можна використовувати рядок. Наприклад:
writeln(‘***’, ‘ площа вписаного кола = ‘, sint, ‘***’).
Текст програми може містити коментарії. Коментарій – це деякий текст, який стоїть у фігурних дужках. Коментарії використовують для пояснень, необхідних для кращого розуміння програми. Добре прокоментована програма – ознака кваліфікації і сумлінності програміста.
Особливу увагу треба звертати на проектування введення/ виведення. У професіональних програмах це одна з найбільш важливих проблем. Тут треба виділити наступні аспекти:
* Захист програми від помилок користувача при введенні даних;
* Орієнтація на користувача, який не ознайомлений з програмою – введення/ виведення в режимі дружелюбного діалогу.
4.12. Поняття складності виразу. Оптимізація обчислень
Основний критерій якості програми – її правильність. Строге математичне поняття правильності програми виходить за рамки нашого розгляду. Припустимо, що наші програми виконують саме ті дії, яких ми від них чекаємо.
У цьому припущенні критеріями якості програми є, наприклад, її розмір, об’єм пам’яті, що відведений під дані, швидкість виконання, і т.і.
Швидкість виконання програми, що не розгалужується, визначається кількістю обчислень, які необхідні для отримання значень виразів, що містяться в операторах присвоювання і операторах виведення.
Кількість обчислень, необхідних для отримання значення виразу, будемо називати його складністю. Розглянемо приклад:
U := X*Cos(Alfa) + Y*Sin(Alfa) (1)
V := Y*Cos(Alfa) - X*Sin(Alfa) (2)
Для обчислення значення U необхідно виконати два обчислення значення тригонометричної функції, два множення й одне додавання. Це і є мірою складності правої частини оператора (1). Права частина оператора (2) має ту саму складність, що і оператора (1). Зрозуміло, швидкість обчислень значень елементарних функцій, операцій множення і додавання різні і залежать від реалізації мови програмування. Однак реально припускати, що швидкості обчислень всіх елементарних трансцендентних функцій тотожні між собою, швидкості виконання мультиплікативних операцій тотожні, і швидкості виконання адитивних операцій також тотожні.
Хай Tf, Tm і Ta - час обчислення відповідно функцій, множення і додавання, а T(U) - час обчислення значення U. Тоді
T(U) = 2Tf + 2Tm + Ta, T(V) = T(U) (3)
Час обчислення значення виразу і є мірою його складності. Зрозуміло, що програміст повинен турбуватись про зменшення складності виразів, що входять в програму. Для цього використовують:
а)Тотожні перетворення, що зменшують складність;
б) Попередні обчислення спільних підвиразів;
Приклади:
U := 4*Sin(X)*Cos(X) + 3 <==>
U := 2*Sin(2*X) + 3 <==>
U := Sin(X)^2 - 3*Sin(X) + 2 <==>
U := (Sin(X) - 2)*(Sin(X) - 1) <==>
Y := Sin(X); U := (Y - 2)*(Y - 1)
Між величинами Tf, Tm і Ta існують співвідношення
Tf >> Tm > Ta (4)
які при програмуванні обчислень не можна ігнорувати. Тому особливу увагу треба приділяти зменшенню кількості обчислень трансцендентних функцій, кількості множень та ділень.
Наступний приклад визначає оптимальну форму запису полінома для задачі обчислення його значення.
Приклад 4.2 (Схема Горнера)
Обчислити значення Y = a0x3 + a1x2 + a2x + a3;
Оскільки операції піднесення до степеня у мові немає, можна замінити його множеннями:
Y = a0*x*x*x + a1*x*x + a2*x + a3;
У цьому варіанті T(Y) = 6Tm + 3Tа;
Якщо виносити х за дужки там, де це можливо, отримаємо:
Y = ((a0x + a1)x + a2)x + a3;
T(Y) = 3Tm + 3Tа {Схема Горнера}.
Відомо, що схема Горнера обчислення багаточлена є оптимальною.
4.13. Оптимізація лінійних програм
Задача зменшення складності програми, що містить декілька виразів, носить більш складний характер. Тут оптимізації підлягають одночасно декілька виразів, які обчислюються послідовно.
Приклад 4.3. Програма обчислення координат вектора, повернутого на кут Alfa.
Program Vector;
Var
X, Y : Real;
Alfa : Real;
U, V : Real;
Begin
{ Введення X, Y, Alfa }
U := X*Cos(Alfa) + Y*Sin(Alfa);
V := Y*Cos(Alfa) - X*Sin(Alfa);
{ Виведення U, V }
End.
У цьому варіанті складність програми T(U, V) є
T(U, V) = 4Tf + 4Tm + 2Ta
Здійснимо попереднє обчислення функції Sin, Cos:
{ Описати допоміжні змінні Fsin, Fcos }
Begin
{ Введення X, Y, Alfa }
Fsin := Sin(Alfa);
Fcos := Cos(Alfa);
U := X*Fcos + Y*Fsin;
V := Y*Fcos - X*FSin ;
{ Виведення U, V }
End.
Отримаємо: T(U, V) = 2Tf + 4Tm + 2Ta
В результаті перетворення складність зменшилась приблизно вдвічі. Можна ще зменшити складність програми, якщо обчислити U і V наступним способом:
A := (Fcos + Fsin)*(X + Y);
B := X*Fsin;
C := Y*Fcos;
U := A - B - C;
V := C - B;
Тоді T(U, V) = 2Tf + 3Tm + 5Ta
Рішення питання про те, який з двох варіантів перетворень програми кращий за швидкодією, залежить від реалізації множення у комп’ютері.
Менш очевидним є прийом оптимізації, що заключається в використанні співвідношень між виразами – правими частинами операторів. Розглянемо його на наступному прикладі:
Приклад 4.4. Відомо, що рівняння x2 - px + q має два корені . Знайти їх.
Варіант 1:
Discriminant := Sqrt(p*p - 4*q);
Root1 := ( p + Discriminant )/2;
Root2 := ( p - Discriminant )/2;
Варіант 2:
Discriminant := Sqrt(p*p - 4*q);
Root1 := (p + Discriminant)/2;
Root2 := p - Root1;
Обчислення у другому варіанті містять на одне ділення менше. Тут оптимізація досягнута завдяки наявності співвідношення між Root1 і Root2: Root1+ Root2 = p.
Відмітимо на закінчення, що розглянуті прийоми оптимізації має смисл застосовувати тоді, коли обчислення повторюються в програмі достатньо часто і час виконання програми – критичний параметр.
4.14. Задачі і вправи
Скласти програму, що розв’язує задачу.