Podstawy programowania w Pascalu
1. Struktura programu
program <nazwa>;
...
begin
...
end.
Program w Pascalu rozpoczyna się słowem kluczowym program i identyfikatorem oznaczającym
nazwę programu. Jest to pozostałość po wcześniejszych wersjach języka, gdzie instrukcja ta służyła
od wskazywania plików z danymi wejściowymi i wyjściowymi.
Drugim obowiązkowym elementem jest blok składający się z pary słów kluczowych begin i end.
Tutaj wyjątkowo zakończonych kropką (wszystkie pozostałe instrukcje powinny być kończone
średnikiem). Po kropce nie powinno być już żadnych innych instrukcji. Zawartość tego bloku
stanowi treść programu (program główny).
Pomiędzy instrukcją program a blokiem begin-end. można umieszczać pomocnicze sekcje oraz
definicje funkcji i procedur.
2. Definiowanie funkcji i procedur
procedure <nazwa>(<lista parametrów>);
...
begin
...
end;
function <nazwa>(<lista parametrów>) : <typ wyniku>;
...
begin
...
<nazwa> := <wyrażenie>;
end;
Definicję procedury rozpoczynamy słowem kluczowym procedure. Potem należy podać jej
nazwę. Jak każda inna nazwa w Pascalu:
•
nie może ona zawierać spacji,
•
musi się składać z liter, cyfr lub znaku podkreślenia oraz
•
musi zaczynać się od litery.
Po nazwie procedury podajemy w nawiasach okrągłych listę parametrów. Składnia tej listy jest
dokładnie taka sama jak sekcji var opisanej poniżej. Jeżeli procedura nie ma parametrów nawiasy
okrągłe można pominąć.
Po deklaracji procedury musi pojawić się blok Begin-end z jej treścią. Opcjonalnie przed tym
blokiem możemy umieścić sekcje pomocnicze (w szczególności sekcję var) z definicjami lokalnymi
dla danej procedury.
Różnica między funkcją a procedurą polega na tym, że celem funkcji jest obliczenie pewnej
wartości, i w związku z tym ma ona wartość. By wskazać jaka wartość jest wynikiem wykonania
funkcji w jej treści należy przypisać odpowiednie wyrażenie do wirtualnej zmiennej o nazwie takiej
samej jak nazwa funkcji. Nie musi to nastąpić w ostatniej linii, ale należy zadbać by zawsze takie
podstawienie wykonało się podczas wykonania funkcji. Ponieważ w Pascalu przywiązywana jest
bardzo duża uwaga do typów wartości w definicji funkcji należy podać typ wartości zwracanej
przez funkcję.
Przykładowa funkcja:
function pole_trapezu(a, b, h : Real) : Real;
begin
pole_trapezu := h * (a + b) / 2;
end;
3. Zmienne pomocnicze i sekcja var
W celu uproszczenia treści funkcji, obliczenia można podzielić na etapy. Pojawia się wtedy
konieczność przechowania wartości pośrednich. Językach programowania służą do tego zmienne.
W języku Pascal przykładana jest bardzo duża uwaga do typów wartości i dlatego każdą zmienną
należy wcześniej zadeklarować i określić jej typ.
Do deklarowania zmiennych służą sekcje var. Można je umieścić między deklaracją funkcji lub
procedury a stanowiącym jej treść blokiem Begin-end. Wtedy są to zmienne lokalne dla danej
funkcji czy procedury, a więc pojawiają się w momencie jej uruchomienia i znikają po jej
zakończeniu.
Druga możliwość to umieszczenie sekcji var między instrukcją program a blokiem Begin-end.,
wtedy są to zmienne globalne, czyli dostępne we wszystkich procedurach i funkcjach oraz w
programie głównym. Mimo, że jest to możliwe, należy unikać korzystania ze zmiennych
globalnych w procedurach i funkcjach.
Budowa sekcji var:
Var <nazwa1>, <nazwa2> : <typ1>;
<nazwa3>, <nazwa4> : <typ2>;
Przykład:
function dlugosc(x1, y1, x2, y2 : Real) : Real;
var dx, dy : Real;
begin
dx := x2 – x1;
dy := y2 – y1;
dlugosc := Sqrt(dx*dx + dy*dy);
end;
4. Typy zmiennych i parametrów
Przy deklarowaniu zmiennej lub parametru należy określić ich typ. Próba przypisania do zmiennej
wartości niekompatybilnego typu (np. ciągu znaków do liczby całkowitej) spowoduje
wygenerowanie błędu już na etapie kompilacji programu.
Podstawowe typy dostępne w języku Pascal zebrane zostały w poniższej tabeli:
Boolean wartość logiczna (True lub False)
Char
pojedynczy znak
Integer
liczba całkowita
Real
liczba rzeczywista
(zmiennoprzecinkowa)
String
ciąg znaków
Text
plik tekstowy
5. Zmienne tablicowe
Zwykłe zmienne służą do przechowywania pojedynczych wartości. Istnieje także możliwość
zdefiniowania tablicy, a więc zmiennej przechowującej wiele wartości:
var temperatura : array[1..10] of Real;
W powyższym przykładzie zmienna temperatura jest 10-elementową tablicą, której komórki są
liczbami rzeczywistymi. Komórki ponumerowane są od 1 do 10, a dostęp nich odbywa się poprzez
dopisanie do nazwy zmiennej wyrażenia w nawiasach kwadratowych określającego numer
komórki:
temperature[1] := 10.0;
temperatura[i] := 20.0;
temperatura[2*i] := 15.0;
W powyższym przykładzie wartości 1 i 10 oznaczają odpowiednio pierwszy i ostatni numer
komórki. Nie ma obowiązku rozpoczynania numeracji komórek od 1, jednak jest to zwyczajowo
przyjęte w języku Pascal.
Tablice wielowymiarowe definiuje i wykorzystuje się w analogiczny sposób, dodając nowe
wymiary w nawiasach kwadratowych:
var wspolrzedne : array[1..10][1..2] of Real;
...
wspolrzedne[5][1] := x5;
wspolrzedne[5][2] := y5;
Dużym ograniczeniem oryginalnego Pascala była konieczność podania rozmiaru tablicy na etapie
pisania programu, dlatego też został on uzupełniony o tablice dynamiczne. W takim wypadku
rozmiar tablicy musi być ustalony przed pierwszym jej użyciem przy pomocy procedury SetLength:
var wysokosci : array of Real;
...
SetLength(wysokosci, rozmiar);
Elementy tablic dynamicznych numerowane są od zera. Długość takiej tablicy można uzyskać
przekazując ją jako parametr do funkcji Length.
6. Rekordy
Tablica to zbiór wartości tego samego typy, które z jakiegoś powodu traktujemy w programie jako
całość. Do poszczególnych elementów dostajemy się podając numer elementu. Czasami jednak
przydatne jest połączenie w jedną całość wartości różnych typów, które np. opisują cechy jednego
obiektu. Jednym z najprostszych jest punkt. Ma on dwie lub trzy współrzędne i można oczywiście
reprezentować go jako krótką tablicę, ale zawsze istnieje ryzyko pomyłki. Punkt[1] oznacza
współrzędną o indeksie numer 1, ale w zależności od stosowanej konwencji może to być pierwszy
lub drugi element tablicy (w informatyce często numeruje się elementy tablicy od 0, a Pascal jest
jednym z nielicznych wyjątków), a co za tym idzie może to być współrzędna x lub y. Gdybyśmy
chcieli rozszerzyć definicję punktu o inne informacje, na przykład numer lub opis, będące ciągami
znaków, pojedyncza tablica mogłaby już nie wystarczyć. Przekazywanie danych o punktach
parametry procedur i funkcji niepotrzebnie zwiększałoby objętość kodu. Nie wspominając o tym, że
dodanie kolejnego elementu do definicji punktu, wymagałoby poprawienia list argumentów
wszystkich procedur i funkcji.
Rozwiązaniem tego problemu są rekordy, czyli możliwość zdefiniowania zmiennej składającej się z
kilku pól. Każde pole ma swoją nazwę i typ, a dostajemy się do nich wpisując nazwę zmiennej
reprezentującej cały rekord, kropkę i nazwę pola.
Proszę porównać poniższe kawałki kodu:
Źle:
var wspx : array [1..100] of Real;
wspy : array [1..100] of Real;
nr : array [1..100] of String;
wysokosci : array[1..100] of Real;
procedure WypiszPunkt(wspx, wspy : Real;
nr : String;
wysokosc : Real);
begin
WriteLn('Numer: ', nr);
WriteLn('x: ', wspx:10:2, 'y: ', wspy:10:2);
...
end;
...
WypiszPunkt(wspx[i], wspy[i], nr[i], wysokosc[i]);
...
Poprawnie:
type TPunkt = record
nr : String;
x, y, h : Real;
end;
var punkty : array [1..100] of TPunkt;
procedure WypiszPunkt(p : TPunkt);
begin
WriteLn('Numer: ', p.nr);
WriteLn('x: ', p.x, 'y: ', p.y);
end;
...
WypiszPunkt(punkty[i]);
...
7. Sekcje type i const
Definicje zmiennych tablicowych wymagają podania zakresu indeksów i jeżeli chcemy definiować
podobne tablice w kilku miejscach w programie, musimy dokładnie te definicje powtórzyć i wpisać
dokładnie taki sam zakres indeksów. Jeżeli w trakcie prac okaże się, że musimy zmodyfikować
zakres indeksów, zmiany będziemy musieli nanieść w wielu miejscach w programie. Podobny
problem występuje w przypadku stałych. Nie dość, że interpretacja zapisu typu a+42 wymaga
pewnego zastanowienia czym owo 42 jest, to bardzo często się zdarza, że stałe musimy
modyfikować. Wtedy w całym programie trzeba ich szukać i uaktualniać, ale tylko te wystąpienia,
które występują w danym kontekście. W programie ta stałe o tej samej wartości mogą mieć różne
znaczenia, więc nie wystarczy mechaniczna zamiana jednej wartości na drugą.
W celu poprawienia czytelności kodu, skrócenia zapisu długich definicji oraz uniknięcia
problemów w przypadku konieczności zmiany definicji w późniejszych etapach prac, zaleca się
stosowanie sekcji type i const, które pozwalają na wprowadzanie własnych nazw dla odpowiednio
typów i stałych.
Proszę porównać poniższe przykłady:
Źle:
var punkty : array [1..100] of
record
nr : String;
x, y : Integer;
end;
function odleglosc(a, b : record
nr : String;
x, y : Integer
end) : Real;
begin
...
end;
function pole(wielokat : array[1..100] of record
record
nr : String;
x, y : Integer;
end;
n : Integer) : Real;
begin
...
end;
...
xp := Round(x – 42) + 5;
...
Poprawnie:
const
MAX_PKT = 100;
WIDTH = 84;
MARGIN = 5;
type
TPunkt = record
nr : String;
x, y : Integer;
end;
TPunkty = array [1..MAX_PKT] of TPunkt;
var
punkty : TPunkty;
function odleglosc(a, b : TPunkt) : Real;
begin
...
end;
function pole(wielokat : TPunkty; n : Integer) : Real;
begin
...
end;
...
xp := Round(x – WIDTH/2) + MARGIN;
...
8. Instrukcja warunkowa
Często w trakcie obliczeń musimy podejmować decyzje i na przykład wykonać jakieś dodatkowe
kroki w zależności od wartości otrzymanego wyniku. W tym celu przydaje się instrukcja
warunkowa If. Występuje ona w dwóch wariantach:
if <warunek> then
begin
<instrukcje>
end;
if <warunek> then
begin
<instrukcje1>
end
else
begin
<instrukcje2>
end;
Pierwsza postać pozwala na wykonanie zestawu instrukcji, tylko jeżeli spełniony jest pewien
warunek. Jeżeli ten warunek nie jest spełniony, instukcja nie robi nic. Druga postać pozwala na
wybór między dwoma wariantami. Jeżeli spełniony jest warunek, wykonywane są instrukcje po
słowie kluczowym Then. Jeżeli warunek nie jest spełniony, wykonywane są te po słowie
kluczowym Else. Należy zwrócić uwagę na to, że przed else nie stawia się średnika. Jeżeli po then
lub else ma być tylko jedna instrukcja Begin i end można pominąć, ale nie jest to zalecane. Nic nie
stoi na przeszkodzie by po else zaczynała się kolejna instrukcja if.
Warunek jest to dowolne wyrażenie, któremu można przypisać wartość logiczną (prawda albo
fałsz). Konstrukcji warunku możemy wykorzystywać zmienne, stałe, wywołania funkcji oraz
operatory: =, <>, >, >=, <, <=, Or, And, Not.
Przykład:
if (a >= 0) and (b >= 0) then
begin
c: = a + b
end;
9. Instrukcja For
Instrukcja For umożliwia powtarzanie pewnego fragmentu kodu i dlatego nazywana jest także pętlą
For. Jej konstrukcja jest następująca:
var i : Integer;
...
for i := <pocz.> to <koniec> do
begin
<instrukcje>
end;
var i : Integer;
...
for i := <pocz.> down to <koniec> do
begin
<instrukcje>
end;
Zmienna i nazywana jest zmienną kontrolną. Zwyczajowo wykorzystuje się nazwy typu i, j, k, n lub
m. Podobnie do oznaczeń indeksów w matematyce. Zmienna taka musi być typu
całkowitoliczbowego, czyli na przykład Integer. W każdym powtórzeniu pętli zmienna ta będzie
przyjmować kolejne wartości zaczynając od wartości wyrażenia wpisanego w miejscu <pocz.>,
a kończąc na wartości podanej w miejscu <koniec>. W lewym wariancie pętli, zmienna kontrolna
będzie zwiększała swoją wartość o 1. W prawym – zmniejszała.
Poniżej znajduje się przykład funkcji obliczającej silnię z wykorzystaniem instrukcji For:
function silnia(n : Integer) : Integer;
var i, s : Integer;
begin
s := 1;
For i := 2 to n do
begin
s := s * i
end;
silnia := s
end;
W tabeli poniżej zebrane zostały wartości zmiennych w poszczególnych iteracjach (powtórzeniach)
pętli dla n = 5:
i
s
Wartość początkowa
nieokreślona
1
Iteracja 1
2
2
Iteracja 2
3
6
Iteracja 3
4
24
Iteracja 4
5
120
10.Pętle while i repeat-until
Jeżeli ilość powtórzeń pętli nie jest znana z góry, nie będzie możliwe wykorzystanie pętli for.
Dlatego też Pascal oferuje dwie inne instrukcje pętli:
while <warunek> do
begin
<instrukcje>
end;
repeat
<instrukcje>
until <warunek>;
W przypadku pętli while, warunek określa czy powinna się wykonać następna iteracja. W
szczególności czy powinna wykonać się pierwsza iteracja. W przypadku repeat-until zawsze
wykona się co najmniej jedna iteracja, a warunek określa kiedy należy przerwać wykonywanie pętli
(czyli jest dokładnie zaprzeczeniem warunku z pętli while).
11.Operacje wejścia-wyjścia
Do wypisywania danych na ekran w Pascalu wykorzystywane są procedury Write i WriteLn. Mogą
one mieć dowolną liczbę argumentów (w szczególności zero). Różnica między nimi polega na tym,
że ta ostatnia dopisuje na koniec znak nowej linii. Do odczytywania danych służą analogiczne
funkcje, Read i ReadLn, które jako argumenty przyjmują zmienne, które mają być wypełnione
danymi.
Przykład:
Write(‘Podaj x: ‘);
ReadLn(x);
WriteLn(‘Wpisałeś x=’, x);
Liczby zmiennoprzecinkowe (m.in. typu Real) domyślnie wypisywane są w formacie naukowym
(wykładniczym). Zapis ten składa się z cyfr znaczących oraz wykładnika wskazującego przez którą
potęgę 10 należy pomnożyć część z cyframi znaczącymi by otrzymać docelową liczbę. Taki zapis
jest wygodny, gdy zakres wypisywanych wartości jest bardzo duży, ale zazwyczaj potrzebny jest
tradycyjny format (po angielsku zwany fixed) i najczęściej z dokładnie określoną liczbą cyfr po
przecinku. Procedury Write i WriteLn pozwalają w prostu sposób wskazać jaki format jest
potrzebny:
WriteLn('Długość: ', dl:3:2);
Liczba po pierwszym dwukropku oznacza szerokość pola. Ta po drugim --- liczbę miejsc po
przecinku. Jeżeli liczba ma więcej miejsc dziesiętnych zostanie zaokrąglona. Jeżeli nie mieści się w
wyznaczonym polu (np. podaliśmy długość pola równą 3, a chcemy wypisać liczbę 10000),
zostanie ono rozszerzone o brakujące cyfry. Gdy długość pola jest za duża, jest ono wypełniane
spacjami.
Nie ma konieczności wpisywania drugiego dwukropka i liczby cyfr dziesiętnych. Można podać
wyłącznie szerokość pola. Dzięki temu zapis z dwukropkami pozwala właściwie zaokrąglić
wartości, ale również ładnie wyrównać dane wyjściowe.
12. Operacje na plikach
By zapisać lub odczytać dane z pliku tekstowego, konieczne jest zadeklarowanie zmiennej typu
Text, z którą następnie trzeba skojarzyć plik na dysku komputera. W tym celu należy wywołać
procedurę Assign. Jako pierwszy argument przyjmuje ona zmienną plikową. Drugi to ciąg znaków
zawierający ścieżkę do pliku. Kolejnym krokiem jest otwarcie pliku. W zależności od operacji,
które chcemy wykonać na pliku należy wywołać procedurę Rewrite, Reset lub Append.
Po otwarciu pliku można do niego pisać lub z niego czytać (w zależności od tego w jakim trybie go
otworzyliśmy) za pomocą procedur Read, ReadLn, Write oraz WriteLn. Zachowują się one
analogicznie do procedur o tych samych nazwach działających na konsoli, z tym, że jako pierwszy
argument należy podać zmienną plikową.
Po zakończeniu pracy z plikiem należy go zamknąć za pomocą procedury Close. Dzięki temu inne
programy będą mogły go otworzyć. System operacyjny pilnuje by plik był otwarty do zapisu
dokładnie raz, natomiast do czytania plik może być otwarty wielokrotnie, ponieważ nie ma ryzyka
wymieszania się danych.
Praca z plikiem tekstowym odbywa się według następujących schematów:
Czytanie:
var plik : Text;
...
Assign(plik, 'D:\Dane\plik.csv');
Reset(plik);
while not Eof(plik) do
begin
ReadLn(plik, <zmienne>);
...
end;
Close(plik);
Pisanie:
var plik : Text;
...
Assign(plik, 'D:\Dane\plik.csv');
Rewrite(plik);
for i := ... to ... do
begin
WriteLn(plik, <zmienne>);
...
end;
Close(plik);
Najważniejsze procedury i funkcje operujące na plikach zostały zebrane w poniższej tabeli:
Assign(plik, ścieżka)
Wiąże zmienną plikową plik z plikiem na dysku
wskazywanym przez ciąg znaków ścieżka
Append(plik)
Otwiera plik do pisania i ustawia aktualną pozycję w pliku
na jego koniec. Dotychczasowa zawartość pliku pozostaje
bez zmian. Jeżeli plik nie istnieje jest tworzony.
Reset(plik)
Otwiera plik do czytania i ustawia aktualną pozycję w
pliku na jego początek
Rewrite(plik)
Otwiera plik do pisania i ustawia aktualną pozycję w pliku
na jego początek. Dotychczasowa zawartość pliku zostaje
usunięta. Jeżeli plik nie istnieje jest tworzony.
Close(plik)
Zamyka otwarty plik
Eof(plik)
Zwraca wartość True, jeżeli odczytano już wszystkie dane
z pliku (EOF – ang. end of file)
Read(plik, zmienna1, zmienna2, ...)
Wczytuje z pliku reprezentowanego przez zmienną
plikową plik wartości kolejno do zmiennych zmienna1,
zmienna2 itd. Zawartość pliku będzie interpretowana
zgodnie z typami zmiennych. Np. jeżeli zmienna1 jest typu
Integer, Read będzie próbował wczytać tekst
reprezentujący liczbę całkowitą. Białe znaki (spacja,
tabulator, znak końca linii) są pomijane przez procedurę
Read. Wyjątek stanowi wczytywanie ciągów znaków (typ
String) --- wtedy Read czyta do końca linii. W
szczególności, gdy aktualna pozycja w pliku wskazuje na
znak końca linii, wczytany zostanie pusty ciąg znaków.
ReadLn(plik, zmienna1, zmienna2, ...) Działa dokładnie tak samo, jak Read, tylko dodatkowo
spodziewa się że po ciągu wartości wyznaczonym przez
przekazane w wywołaniu zmienne znajdzie się znak końca
linii, który zostanie pominięty. Pozwala to na czytanie
ciągów znaków linia po linii.
Write(plik, wartość1, wartość2, ...)
Zapisuje do pliku kolejno podane wartości. Nie są
wstawiane żadne odstępy między danymi. Formatowanie
zależy od typu wartości. Można stosować formatowanie w
postaci: x:n lub x:n:m, gdzie n to szerokość pola,a m liczba
cyfr dziesiętnych.
WriteLn(plik, wartość1, wartość2, ...)
Działa analogicznie do Write, z tą różnicą że po podanym
ciągu wartości dopisuje również znak końca linii.
Procedurę można wywołać tylko z jednym parametrem
(zmienną plikową) wtedy zapisuje do pliku tylko znak
końca linii.
13. Operacje na ciągach znaków
Ciągi znaków reprezentowane są w Pascalu przez typ String. Jest to nic innego jak tablica znaków o
zmiennej długości (w szczególności może mieć długość zerową). Długość ciągu znaków można
sprawdzic za pomocą funkcji Length. Do poszczególnych znaków można się odwoływać jak do
elementów tablicy. Pierwszy znak ma indeks numer 1.
Wypisywanie i odczytywanie ciągów znaków odbywa się tak samo, jak w przypadku pozostałych
typów prostych (np. Real). Z tą różnicą, że wczytywanie ciągu znaków kończy się na znaku nowej
linii, a nie na np. spacji. Stąd, gdybyśmy chcieli wczytać z pliku wartości oddzielane tabulatorami
lub spacjami, które są ciągami znaków, musielibyśmy wczytać całą linię do zmiennej typu string, a
następnie ją pociąć na poszczególne elementy. W pierwszej kolejności należałoby zlokalizować
separator (spację lub tabulator), po czym wyciąć fragment ciągu i przenieść go do innej zmiennej.
W tym celu konieczne będzie użycie funkcji i procedur Pos, Copy, Delete oraz Length.
Length(str)
Zwraca długość ciągu znaków.
Pos(znak, str)
Zwraca pozycję znaku znak w ciągu str lub 0 jeżeli taki
znak w nim nie występuje.
Copy(str, pos, len)
Zwraca fragment ciągu str o długości len zaczynający się o
znaku na pozycji pos.
Delete(str, pos, len)
Usuwa z ciągu str fragment o długości len zaczynający się
o znaku na pozycji pos.
Przykład:
var plik : Text;
linia, pole : String;
i, p : Integer;
...
ReadLn(plik, linia);
i := 1;
while Length(linia) > do
begin
p := Pos(';', linia);
if p <> 0 then
begin
pole := Copy(linia, 1, p-1);
Delete(linia, 1, p);
end
else
begin
pole := linia;
linia := '';
end;
WriteLn('Pole #', i, ': ', pole);
i := i + 1;
end;
Możliwa jest zamiana ciągu znaków na wartość liczbową i odwrotnie. Tradycyjnie służyły do tego
funkcja Str i procedura Val. Nowsze wersje Pascala uzupełnione zostały o funkcje typu IntToStr i
StrToInt.
Str(wartosc)
Zwraca zwraca wartosc sformatowaną jako ciąg znaków.
Można wykorzystać notację z dwukropkami do określenia
długości pola i ilości miejsc dziesiętnych.
Var(str, zm, err)
Zamienia ciąg znaków str na wartość liczbową, którą
wpisuje do zmiennej zm. Jeżeli operacja się powiodła
zmienna err ustawiana jest na 0. W przeciwnym przypadku
zmienna ta wskazuje na pozycję w ciągu str, gdzie znajduje
się znak, który uniemożliwia dokonania konwersji. To jak
będzie interpretowany ciąg znaków wskazuje typ zmiennej
zm. Jeżeli jest to zmienna typu Integer, procedura Val
spodziewać się będzie, że str zawiera wyłącznie ciąg cyfr
(poprzedzony ewentualnie znakiem + lub -). Jeżeli
zmienna zm ma typ Real, to ciąg str może zawierać
również przecinek.
Przykład:
var s : String;
v : Real;
err : Integer;
...
Write('Wpisz liczbę rzeczywistą: ');
ReadLn(s);
Val(s, v, err);
if err = 0 then
begin
WriteLn('Wpisałeś liczbę rzeczywistą o wartości: ', v:5:2);
end
else
begin
WriteLn('To co wpisałeś nie jest liczbą rzeczywistą!');
end;