Štruktúra programu
Program sa skladá zo štyroch súborov. Každý z nich využíva ako unity súbory napísané nad ním:
- Globals.pas
Unit starajúci sa o globálne štruktúry a premenné a o výpis chýb. - PolyMath.pas
Unit obsahujúci funkcie na základné operácie s polynómami (sčítanie, násobenie, vyčíslenie...). - FindRoot.pas
Unit s algoritmami na hľadanie koreňov polynómov. Definuje globálnu štruktúruKorene
. - Zapoctak.pas
Hlavný súbor programu. Obsahuje funkcie na parsovanie vstupu a vykonáva jednotlivé príkazy.
V kóde je samozrejme pred každou funkciou komentár čo robí, takže táto dokumentácia je vlastne duplikát.
Napriek tomu som sa snažil, aby bola narozdiel od komentárov detailnejšia, najmä
čo sa týka algoritmov a programovacích techník (napr. "prečo je potrebná premenná errout
").
Aj preto je v mnohých prípadoch vhodné ju čítať spolu so samotným kódom.
Pri čítaní tejto dokumentácie predpokladám, že už verne poznáte príkazy programu a spôsob práce s chybami.
Globals.pas
MAXDEG | REGLAST | ERRREAL | Polynom | fin, fout | usingstdin, usingstdout | errout | register | Error(integer; string); | GlobalsExit; | inicializáciaUnit Globals;
Interface
const MAXDEG
const MAXDEG
Integer
ova konštanta určujúca maximálnu dĺžku polynómu. Znamená to, že najvyšší stupeň
polynómu môže byť MAXDEG-1
.
const REGLAST
const REGLAST
Index posledného registra.
const ERRREAL
const ERRREAL
V mnohých prípadoch som potreboval nejako identifikovať, či funkcia vracajúca real
neskončila chybou.
Presne na to slúži táto konštanta.
type Polynom = array[-1..MAXDEG] of Real
type Polynom = array[-1..MAXDEG] of Real
Kľúčová štruktúra programu na uloženie polynómu. V trunc(Polynom[-1])
je uložená jeho dĺžka,
čo je stupeň+1. Potom v prvkoch poľa Polynom[0]
až Polynom[dĺžka-1]
sú uložené koeficienty
polynómu a to tak, že v prvku Polynom[i]
je uložený koeficient pri xi. Nemusí nutne platiť, že
koeficient pri člene najvyššieho stupňa nie je 0; ale tam, kde to je nutné, polynóm normalizujem.
Príklad uloženia polynómu 4x2+7x-5:
[-1] [0] [1] [2] 3 -5 7 4
Maximálny stupeň polynómu je MAXDEG-1
. Tým pádom by stačilo spraviť pole o 1 kratšie, ale ten prvok navyše
je tam pre pohodlie programovania (napr. je jedno, či v podmienke testujem najprv koniec polynómu alebo čítam koeficient).
Napriek tomu by sa tam nemalo nič zapisovať alebo očakávať nejakú konkrétnu hodnotu.
Poznámka: Pri zisťovaní dĺžky polynómu je nutné používať funkciu trunc
(dolná celá časť), pretože prvky
polynómu sú typu real
. Preto na niektorých miestach programu pre istotu pridávam k ukladanej dĺžke 0,1.
Poznámka: Nulový polynóm P(x) = 0 je správne uložený tak, že v Polynom[-1]
je uložené číslo 0, čo znamená,
že polynóm má nulovú dĺžku. My totiž nechceme, aby koeficient pri najvyššom stupni bol nula, preto nemôže byť stupeň polynómu 0
(= dĺžka 1).
var fin, fout : text
var fin, fout : text
Globálne premenné na prácu so vstupným súborom resp. konzolou (fin
) a výstupným súborom resp. konzolou
(fout
).
var usingstdin, usingstdout : boolean
var usingstdin, usingstdout : boolean
usingstdin
je true
, pokiaľ sa číta zo štandartného vstupu (z konzoly). V opačnom prípade je false
a číta sa zo súboru. Podobne, usingstdout
je true
, pokiaľ sa zapisuje na štandartný výstup (do konzoly) a pri
zápise do súboru je false
. Tieto premenné sú potrebné z dvoch dôvodov. Po prvé, testovať koniec súboru nemá zmysel
(a robí to blbosti) pri čítaní z konzoly; a za druhé, rozdielne sa vypisuje do konzoly a do súboru.
var errout : boolean
var errout : boolean
Má hodnotu true
, pokiaľ sa nemajú vypisovať chybové hlášky. Používam to pri riešení polynómu.
var register : array[chr(ord('A')-2)..REGLAST] of Polynom
var register : array[chr(ord('A')-2)..REGLAST] of Polynom
Globálne pole registrov. Použiteľné sú registre register['A']
až
register['REGLAST']
vrátane. Sú ešte vyhradené ďalšie dva registre "pred": register[pred('A')]
a register[pred(pred('A'))]
na účely načítavania. (V znakoch sú ich indexy '@' a '?'.)
Procedure Error(err : integer; s : string)
Procedure Error(err : integer; s : string)
Procedúra vypisujúca chybové hlášky. Prvý parameter je číslo chyby. Ak je nula alebo ak errout = true
,
nič sa nevypíše. V opačnom prípade sa vypíše ERR
alebo WAR
a číslo chyby (podľa toho, či to je chyba alebo
varovanie). Je to navrhnuté tak, že chyby sú do čísla 20 (vrátane), ďalej sú varovania. Pokiaľ sa vypisuje na štandartný výstup,
vypíše sa ešte popis chyby a za ním text v druhom parametri (s
). To je užitočné vtedy, ak text výpisu závisí od toho,
čo užívateľ zadal. (Napr. pri chybe 1.)
Procedure GlobalsExit
Procedure GlobalsExit
Procedúra má za úlohu "poupratovať" globálne premenné. V tomto prípade zavrie fin a fout (vstupný a výstupný súbor).
Implementation
inicializácia
inicializácia
Inicializujú sa globálne premenné popísané vyššie, najmä nulujú sa registre a otvárajú súbory.
PolyMath.pas
EvalPoly(Polynom; real) : real; | PlusPoly(Polynom; Polynom; Polynom); | MinusPoly(Polynom; Polynom; Polynom); | TimesPoly(Polynom; Poly; Polynom) : boolean; | DivPoly(Poly; Polynom; Polynom) : boolean; | ModPoly(Poly; Polynom; Polynom) : boolean; | DerivePoly(Polynom; Polynom); | DerivePolyX(Polynom; real) : real; | NormalizePoly(Polynom);Unit PolyMath;
Interface
uses Globals;
uses Globals;
Function EvalPoly(var p : Polynom; x: real) : real
Function EvalPoly(var p : Polynom; x: real) : real
Funkcia vráti hodnotu polynómu p
v bode x
.
Procedure PlusPoly(var a, b, res: Polynom)
Procedure PlusPoly(var a, b, res: Polynom)
Funkcia sčíta polynómy a
a b
a výsledok uloží do res
. Ten istý polynóm sa
môže v argumentoch opakovať.
Procedure MinusPoly(var a, b, res: Polynom)
Procedure MinusPoly(var a, b, res: Polynom)
Funkcia spočíta rozdiel polynómov a - b
a výsledok uloží do res
. Ten istý polynóm sa
môže v argumentoch opakovať.
Function TimesPoly(var a, b, res: Polynom) : boolean
Function TimesPoly(var a, b, res: Polynom) : boolean
Funkcia vynásobí polynómy a
a b
a výsledok uloží do res
. Ten istý polynóm sa
môže v argumentoch opakovať. Pokiaľ nastane pretečenie polynómu (keď je výsledný polynóm väčší než MAXDEG
),
vygeneruje sa chyba a program vráti true
. Ak chyba nenastane, vráti false
.
Využívam to pri ukladaní polynómu.
Function DivPoly(a: Polynom; var b: Polynom; var res: Polynom) : boolean
Function DivPoly(a: Polynom; var b: Polynom; var res: Polynom) : boolean
Do polynómu res
uloží podiel a/b
. V prípade, že b
je nulový, vypíše chybu a vráti
true
. Následne skontroluje, či nie je b
väčšieho stupňa ako a
; ak áno, výsledok je 0.
Následne delí klasickým štýlom - zistí, koľkokrát sa najvyšší stupeň b
nachádza v najvyššom stupni a
,
uloží sa to do výsledku a od a
-čka sa odčíta ten násobok b
-čka. Napokon vráti false
(viď priradenie). Ako argument sa môže ten istý polynóm opakovať.
Function ModPoly(var a : Polynom; b : Polynom; var res: Polynom) : boolean
Function ModPoly(var a : Polynom; b : Polynom; var res: Polynom) : boolean
Funkcia počíta zvyšok po delení a/b
. Ak b
je nulový polynóm, vyhlási chybu a vráti true
.
Algoritmus je podobný ako pri delení - zistí, koľkokrát sa najvyšší stupeň b
nachádza v najvyššom stupni a
a od a
-čka sa odčíta ten násobok b
-čka. Nakoniec narozdiel od delenia vráti v res
to, čo zostalo
v a
-čku a vráti false
. Ten istý polynóm sa môže v argumentoch opakovať.
Procedure DerivePoly(var a, res: Polynom)
Procedure DerivePoly(var a, res: Polynom)
Zderivuje polynóm a
a výsledok uloží do res
. Derivácia nulového polynómu je nulový polynóm,
ináč sa zmenší stupeň a vypočítajú koeficienty derivácie. V argumentoch sa môže ten istý polynóm opakovať.
Function DerivePolyX(var a: Polynom; x: real) : real
Function DerivePolyX(var a: Polynom; x: real) : real
Vráti deriváciu polynómu a
v bode x
.
Procedure NormalizePoly(var p : Polynom)
Procedure NormalizePoly(var p : Polynom)
Zmenší stupeň polynómu tak, aby nezačínal nulou.
FindRoot.pas
Korene | SetPrecision(real); | GetPrecision : Real; | MtdBisection(Polynom; Real; Real) : Real; | MtdSecant(Polynom; Real; Real) : Real; | MtdNewton(Polynom; Real; Real) : Real; | SolvePoly(Polynom; integer; Korene); | MINPREC | precision | inicializáciaUnit FindRoot;
Interface
uses Globals;
uses Globals;
type Korene = array[-1..MAXDEG+2] of Real
type Korene = array[-1..MAXDEG+2] of Real
Štruktúra vracaná funkciou SolvePoly. V trunc(Korene[-1])
je uložený počet koreňov polynómu a samotné korene sú uložené v indexoch 1 až trunc(Korene[-1])-1
vrátane. Špeciálne môže mať trunc(Korene[-1])
hodnotu -1, čo znamená, že koreňov je nekonečno;
t.j. príslušný polynóm bol nulový.
Na korene je vyhradených 0..MAXDEG+2
pozícii. Aký je dôvod, keď polynóm má maximálne stupeň-1 koreňov?
Odpoveď je vo funkcii SolvePoly. V nej potrebujem uložiť ešte jednu hodnotu pred prvý a jednu za posledný koreň. Na to by
stačil a rozsah do MAXDEG
, pre istotu však nechávam rezervu.
Procedure SetPrecision(prec : real)
Procedure SetPrecision(prec : real)
Nastaví presnosť výpočtu pre ostatné funkcie na prec
. Pokiaľ je
prec
menšia než MINPREC
, nastaví sa presnosť na MINPREC
.
Function GetPrecision : Real
Function GetPrecision : Real
Vráti aktuálnu presnosť. Je to užitočné v prípade, ak chce funkcia zmeniť presnosť a po jej skončení vrátiť pôvodný stav. (viď napr. Solve)
Function MtdBisection(var p : Polynom; left, right : Real) : Real
Function MtdBisection(var p : Polynom; left, right : Real) : Real
Vráti koreň polynómu p
v intervale [left, right)
. Zaručuje, že nájdený bod sa nebude líšiť
od skutočného koreňa o viac než precision
a taktiež hodnota v nájdenom bode od nuly.
Funkcia vyžaduje, aby hodnota polynómu na jednom konci intervalu bola kladná a na druhom záporná (alebo na ľavom konci nulová),
pretože potom vďaka spojitosti musí existovať koreň. Ak to tak nie je, vyhlási chybu a vráti
ERRREAL
.
Pokiaľ test prejde, funkcia nastaví premennú sign
na 1 alebo -1 podľa toho, či je hodnota polynómu
v ľavom kraji intervalu záporná a v pravom kladná alebo naopak. Vďaka tejto premennej nemusím neskôr špeciálne rozlišovať ktorý
prípad nastal, len v príslušných podmienkach vynásobím správnu stranu nerovnosti týmto číslom.
Samotný algoritmus funguje nasledovne. Pokiaľ
- je veľkosť intervalu väčšia ako dvakrát
precision
- alebo hodnota v ľavom alebo pravom konci intervalu je ďalej od nuly než
precision
- a ak sa nezacyklil (dvakrát za sebou vyšla tá istá hodnota),
tak vyráta stredný bod a zistí v ňom funkčnú hodnotu. Ak je to presne koreň tak skončí, ináč zmenší interval na polovicu tým, že v závislosti od hodnoty v tomto bode prestaví pravý alebo ľavý kraj na tento bod.
Po skončení cyklu program vráti nájdený bod.
Poznámka: Interval, v ktorom sa hľadá, je polootvorený preto, aby pri naväzujúcich intervaloch nebol nájdený viackrát ten istý koreň.
Function MtdSecant(var p : Polynom; left, right : Real) : Real
Function MtdSecant(var p : Polynom; left, right : Real) : Real
Táto funkcia je podobná MtdBisection.
Vráti koreň polynómu p
v intervale [left, right)
. Zaručuje, že hodnota v nájdenom bode sa nebude líšiť
od nuly o viac než precision
.
Funkcia vyžaduje, aby hodnota polynómu na jednom konci intervalu bola kladná a na druhom záporná (alebo na ľavom konci nulová),
pretože potom vďaka spojitosti musí existovať koreň. Ak to tak nie je, vyhlási chybu a vráti
ERRREAL
.
Pokiaľ test prejde, funkcia nastaví premennú sign
na 1 alebo -1 podľa toho, či je hodnota polynómu
v ľavom kraji intervalu záporná a v pravom kladná alebo naopak. Vďaka tejto premennej nemusím neskôr špeciálne rozlišovať ktorý
prípad nastal, len v príslušných podmienkach vynásobím správnu stranu nerovnosti týmto číslom.
Samotný algoritmus funguje nasledovne. Pokiaľ
- hodnota v ľavom alebo pravom konci intervalu je ďalej od nuly než
precision
- a ak sa nezacyklil (dvakrát za sebou vyšla tá istá hodnota),
tak vyráta bod niekde v intervale a zistí v ňom funkčnú hodnotu. Ak je to presne koreň tak skončí, ináč zmenší interval tým, že v závislosti od hodnoty v tomto bode prestaví pravý alebo ľavý kraj na tento bod.
Ten "bod niekde v intervale" hľadá nasledovne. Vie, že v bode left
je hodnota lval
a v bode
right
rval
. Tak odhadne polynóm lineárnou funkciou f(x) = ax+b tak, že f(left
)
= lval
a f(right
) = rval
. Následne vypočíta, kde táto funkcia pretína x-ovú os
a to bude hľadaný bod.
Po skončení cyklu program vráti nájdený bod.
Poznámka: Interval, v ktorom sa hľadá, je polootvorený preto, aby pri naväzujúcich intervaloch nebol nájdený viackrát ten istý koreň.
Function MtdNewton(var p : Polynom; left, right : Real) : Real
Function MtdNewton(var p : Polynom; left, right : Real) : Real
Vráti koreň polynómu p
v intervale [left, right)
. Zaručuje, že hodnota v nájdenom bode sa nebude líšiť
od nuly o viac než precision
.
Funkcia vyžaduje, aby hodnota polynómu na jednom konci intervalu bola kladná a na druhom záporná (alebo na ľavom konci nulová),
pretože potom vďaka spojitosti musí existovať koreň. Ak to tak nie je, vyhlási chybu a vráti
ERRREAL
.
Pokiaľ test prejde, funkcia nastaví premennú sign
na 1 alebo -1 podľa toho, či je hodnota polynómu
v ľavom kraji intervalu záporná a v pravom kladná alebo naopak. Vďaka tejto premennej nemusím neskôr špeciálne rozlišovať ktorý
prípad nastal, len v príslušných podmienkach vynásobím správnu stranu nerovnosti týmto číslom.
Samotný algoritmus funguje nasledovne. Ako počiatočný bod zvolí stred intervalu. Potom kým
- je hodnota ďalej od nuly než
precision
- a ak sa nie je zacyklený (dvakrát za sebou nevyšla tá istá hodnota),
zderivuje polynóm v aktuálnom bode. Ak derivácia vyšla nula, vypíše varovanie a predá úlohu funkcii MtdSecant s tým, že oreže interval podľa poslednej nájdenej hodnoty. Potom z derivácie vypočíta, kde dotyčnica v aktuálnom bode pretína x-ovú os. Ak priesečník vyjde mimo počiatočného intervalu, rovnakým spôsobom predá úlohu MtdSecant. Ináč je nájdený bod nový bod iterácie.
Stojí za zmienku porozmýšľať nad tým, kedy cyklus skončí kvôli tomu, že sa zacyklil, t.j. kedy oldx = x
. To ľahko
zistíme z priradenia x := x - xval/der
. Aby sa x
nezmenilo, musí zrejme platiť xval/der = 0
,
čo môže platiť v dvoch prípadoch. Prvý je, že xval = 0
, čo je dobre, pretože ak je hodnota v x
nula,
chceme skončiť. Druhý prípad je, keď der
(derivácia) v danom bode je absolútne veľmi veľká a počítač vďaka zaokrúhľovaniu
vyhodnotí výraz ako nulu. Vtedy nemôžme urobiť nič lepšie než skončiť, pretože koreň je tak blízko tomuto bodu
(hoci xval
je väčšie než precision
), že presnosť počítača na to nestačí.
Poznámka: Interval, v ktorom sa hľadá, je polootvorený preto, aby pri naväzujúcich intervaloch nebol nájdený viackrát ten istý koreň.
Procedure SolvePoly(var p : Polynom; mtd : integer; var kor : Korene)
Procedure SolvePoly(var p : Polynom; mtd : integer; var kor : Korene)
Nájde podľa možností všetky korene polynómu p
používajúc metódu mtd
a uloží ich do štruktúry
kor
, pričom 0 je metóda polením, 1 je sečnicová metóda a 2 je Newtonova metóda. Pritom zaručuje, že korene
sú uložené vo vzostupnom poradí.
Vnútorne funguje nasledovne. Najprv si zistí stupeň polynómu a ak je -1 (nulový polynóm), 0 (konštanta), 1 (lineárna funkcia)
alebo 2 (kvadratický), vypočíta korene podľa vzorca resp. uloží príslušné hodnoty do kor
a skončí.
Ináč nájde extrémy polynómu, čo sú korene derivácie. Tým sú určené intervaly, kde je polynóm monotónny, teda v každom z týchto intervalov môže byť maximálne jeden koreň. Ďalšie dva korene však ešte môžu byť jeden pred prvým a druhý za posledným extrémom. Preto program nájde také body "vľavo" a "vpravo", odkiaľ bude polynóm zaručene kladný/záporný a uloží ich do poľa s extrémami.
Potom už len stačí nájsť zvolenou metódou koreň na všetkých nájdených intervaloch. Môže sa stať, že v danom intervale koreň
nie je, preto jednak treba korene počítať a tiež vypnúť chybové výpisy nastavením premenej errout
.
Poznámka: Body "vľavo" a "vpravo" od extrémov hľadám pomocou vlastnosti, že najvyššia mocnina v polynóme určite raz prevýši absolútny súčet všetkých ostatných. Preto stačí položiť za x absolútne maximálny koeficient, upraviť vzhľadom na koeficient pri najvyššej mocnine a vynásobiť počtom členov (čiže stupňom). Totiž ak x = am (maximálny koeficient, n je stupeň), tak xn = amn >= aiami = aixi, z čoho vyplýva n.xn >= an-1xn-1 + an-2xn-2 + ... + a0. V skutočnosti používam slabší odhad, a síce dosadzujem n.am (čo potom spôsobí násobenie nn) a ešte prirátavam jednotku. Nakoniec ešte musím ošetriť prípad, keď an < 0, kedy x vydelím priamo an.
Implementation
uses PolyMath;
uses PolyMath;
const MINPREC
const MINPREC
Minimálna dovolená presnosť. Konštantu používa funkcia SetPrecision.
var precision : Real
var precision : Real
Presnosť výpočtov pri hľadaní koreňa. Čím je číslo menšie, tým je výpočet presnejší.
inicializácia
inicializácia
Nastaví východziu presnosť.
Zapoctak.pas
line | linepos | Exist(string) : boolean; | RegOut(char; integer); | ExtractArg(string); | IsNum(char) : boolean; | ReadReal : real; | ReadPoly(char) : char; | Priradenie(char); | RegManager(char); | Root; | Solve; | InputHandler : boolean; | mainProgram PolynomSolver;
uses Globals, PolyMath, FindRoot;
uses Globals, PolyMath, FindRoot;
var line : string
var line : string
Globálna premenná uchovavajúca práve spracúvaný riadok zo vstupu. Premenná linepos
určuje aktuálnu pozíciu kurzora v ňom.
var linepos : integer
var linepos : integer
Globálna premenná, ktorá si pamätá aktuálnu pozíciu kurzoru v line
, čiže miesto,
pokiaľ je vstupný riadok spracovaný. Funkcie spracuvávajúce vstup zanechávajú kurzor tak, aby line[linepos]
bol prvý nenačítaný znak.
function Exist(FN : String) : boolean
function Exist(FN : String) : boolean
Vráti true
, pokiaľ súbor s názvom FN
existuje.
Procedure RegOut(c: char; prec: integer)
Procedure RegOut(c: char; prec: integer)
Vypíše polynóm v registri c
s presnosťou na prec
desatinných miest.
Poznámka: Pôvodne mala byť dvojka v x2 vypísana v exponente, ale kvôli problémom s kódovaním to je x2.
Procedure ExtractArg(var arg: string)
Procedure ExtractArg(var arg: string)
Do arg
uloží prvú nemedzerovú postupnosť za kurzorom
(z line
). Najprv prečíta všetky medzery a potom kým nie je ďalšia medzera,
načítava znaky do arg
. Pokiaľ nič neprečítal (napr. ak už bol koniec riadku), tak arg
vráti prázdny.
Function IsNum(c: char) : boolean
Function IsNum(c: char) : boolean
Vráti true
, pokiaľ je c
číslica.
Function ReadReal : real
Function ReadReal : real
Funkcia načíta reálne číslo z line
a vráti ho. Pokiaľ nejde načítať, vráti
ERRREAL
. Požadovaný formát čísla vyplýva zo spôsobu načítavania.
Najprv prečíta všetky počiatočné nečíselné znaky a ak narazí na koniec súboru, vráti ERRREAL
. Následne skontroluje,
či predošlý znak nebol '-'
a ak áno, zapamätá si to a na konci vynásobi výsledok -1. Ďalej číta čísla a postupne
ich pomocou mocnín 10 ukladá do premennej ret
. Keď ich dočíta, pozrie, či ďalší znak nie je desatinná bodka '.'
.
Ak je, podobným spôsobom načíta desatinnú časť. Nakoniec vráti prečítanú hodnotu.
Function ReadPoly(memreg: char) : char
Function ReadPoly(memreg: char) : char
Načíta polynóm z line
. Pokiaľ je zadaný ručne, uloží ho do registra memreg
a vráti memreg
, ináč musí byť zadaný odkazom na iný register a v tom prípade vráti
index toho registra. Ak sa mu polynóm nepodarí načítať, vráti chr(1)
.
Najprv funkcia prečíta počiatočné medzery. Ak je ďalší znak veľké písmeno od 'A'
do
REGLAST
, je to identifikátor iného registra a funkcia vráti jeho index. Ináč polynóm musí byť zadaný "ručne".
Vtedy funkcia prečíta ľavú zátvorku a číta a ukladá reálne čísla, pokiaľ nie je buď koniec riadku, nenarazí na pravú zátvorku alebo
zadaný polynóm nie je príliš veľkého stupňa. Pokiaľ niečo zlyhalo vyhlási buď chybu 3 alebo
chybu 5. Nakoniec polynóm obráti, pretože je zadávaný v opačnom poradí ako je ukladaný
a zmaže počiatočné nuly (NormalizePoly).
Procedure Priradenie(reg: char)
Procedure Priradenie(reg: char)
Funkcia spracuváva príkazy = a := zo vstupu. V čase spustenia funkcie je už načítaný
register reg
, do ktorého sa zapisuje, a tiež aj znak priradenia (=/:=). Na pravej strane sa má vyskytovať
register alebo ručne zadaný polynóm, tak ho načíta pomocou ReadPoly do registra s indexom "'A'-1"
,
ktorý je na to vyhradený (prípadne nenačíta ak bol zadaný cez register). Následne načíta operátor medzi polynómami.
Ak žiaden nie je, je to obyčajné priradenie a registre prosto skopíruje. Ak je operátor "'"
, čiže derivácia,
polynóm zderivuje do zadaného registra. V ostatných prípadoch načíta operátor ('+', '-', '*', '/', '%') a tiež polynóm
na druhej strane (ak je zadaný ručne, uloží ho do vyhradeného registra "'A'-2"
). Prevedie s nimi danú
operáciu a ošetrí prípadné chyby. Nakoniec polynóm normalizuje a vypíše.
Procedure RegManager(reg : char)
Procedure RegManager(reg : char)
Je to rozcestník pre príkazy, ktoré manipulujú s registrami. To sú také, ktoré začínajú písmenom registra
(napr. A = ..., A (4.1)
).
Procedúra načíta ďalší argument z riadku. Ak žiaden nie je, polynóm vypíše; prípadne ešte načíta presnosť. Ak je argument '=' alebo ':=', spustí Priradenie. Pokiaľ argument začína '(', môže ísť o vyčíslenie polynómu. Tak nastaví kurzor na zátvorku a skúsi načítať reálne číslo a pravú zátvorku. Ak sa to podarí, polynóm vyčísli a vypíše s najväčšou presnosťou. V ostatných prípadoch vyhlási chybu 1 a vypíše nerozpoznaný argument.
Procedure Root
Procedure Root
Spracuváva príkazy root resp. koren na nájdenie koreňa v zadanom intervale.
Najprv načíta polynóm a interval. Na načítanie intervalu nie je špeciálna funkcia, takže to robí nasledovne. Najprv prečíta nadbytočné medzery a načíta ľavú zátvorku. Potom prečíta dve reálne čísla, zbaví sa medzier a nakoniec pravú zátvorku. Pokiaľ to niekde zlyhalo alebo je pravý koniec intervalu menší než ľavý, vyhlási chybu 8 a skončí.
Po intervale môžu nasledovať dva nepovinné parametre. Najskôr skúsi pomocou ExtractArg načítať metódu. Ak to nejde, použije Newtonovu a nastaví kurzor naspäť. Potom pomocou ReadReal skúsi načítať presnosť výpočtu. Ak to nejde, použije presnosť 10-10.
Nakoniec už len vypíše používanú metódu (ak sa nevypisuje do súboru) a použije ju. Ak nevznikla chyba, vypíše nájdený koreň. Posledný príkaz nastaví znova pôvodnú presnosť.
Procedure Solve
Procedure Solve
Spracuváva príkazy solve resp. vyries na nájdenie koreňov zadaného polynómu.
Ako prvé funkcia načíta polynóm. Potom rovnakým spôsobom ako pri procedúre Root skontroluje, či nie sú uvedené nepovinné parametre na zvolenie metódy a presnosti výpočtu a uloží ich. Ak nie sú uvedené, použije rovnaké východzie hodnoty ako v prípade Root.
Následne v prípade vypisovania na konzolu oznámi používanú metódu. Polynóm normalizuje, pretože je to nutné v zápätí pre použitie funkcie SolvePoly. Napokon v závislosti od počtu koreňov ich vypíše.
Poznámka: Normalizovanie polynómu by nemalo byť nutné, pretože všetky volané funkcie meniace polynóm ho normalizujú. Ale je dobrým zvykom, aby sa funkcia nespoliehala na ostatné funkcie a "upratala si na vlastnom piesočku".
Function InputHandler : boolean
Function InputHandler : boolean
Funkcia "programovej slučky". Jedno spustenie funkcie spracuje jeden riadok vstupu, t.j. rozpozná príkazy a vykoná ich
(resp. predá ich vykonanie iným funkciám). V prípade, že načíta príkaz "ukonči program", vráti false
.
Na začiatku funkcia načíta do line
vstupný riadok a pomocou ExtractArg
načíta príkaz. Potom nasleduje dlhá konštrukcia if - else if - else if ...
rozpoznávajúca jednotlivé príkazy
a predávajúca ich vykonanie ďalej.
Predsa len niektoré jednoduché príkazy spracúva funkcia sama. Sú to ukončenie programu, prázdny príkaz s komentárom a presmerovanie vstupu a výstupu. Pri posledných dvoch musí dbať na správne nastavenie globálnych premenných usingstdin a usingstdout.
Pokiaľ príkaz nerozozná, vypíše chybu 1.
main - zavádzacia funkcia
main - zavádzacia funkcia
Funkcia vypíše správu o zapnutí programu a spustí programovú slučku. Keď skončí, spustí GlobalsExit na zatvorenie premenných z unitu Globals a vypíše informáciu o úspešnom ukončení programu.