Contributor: MARTIN PREISHUBER { From: Martin Preishubermycalc.pas that is a unit with mathematical function. the numbers are based on 65536, so you can calculate with really huge numbers. rabin.pas it's a demo program for mycalc. you can test large number,s whether it is a prime or not both programs are documented in german, so i guess that documentation won't help much :-( } (* ----------------------------------------------------------------------- *) (* RabinTest pr’t, ob eine Zahl eine Primzahl ist *) (* ----------------------------------------------------------------------- *) {$M 65000, 0, 655360} (* Stack auf maximale Gr批e *) PROGRAM RabinTest; USES Crt, (* Ein/Ausgabefunktionen *) Extend, (* erweiterte I/O - Funktionen *) MyCalc; (* Funktionen f〉 das Rechnen mit gro疇n Zahlen *) (* ----------------------------------------------------------------------- *) FUNCTION Expt(zahl : Real; hoch : INTEGER) : Real; (* Berechnung des Exponenten einer Realzahl (einfach, weil nur f〉 die *) (* Berechnung von AnzahlTests n杯ig *) VAR i : INTEGER; (* Z?hlvariable *) hilfe : Real; (* Hilfsvariable f〉 das Ergebnis *) BEGIN IF hoch = 0 THEN (* Hochzahl = 0 *) Expt := 1 (* => Ergebnis = 1 *) ELSE BEGIN hilfe := 1; (* Ergebnis mit 1 initialisieren *) FOR i := 1 TO hoch DO hilfe := hilfe * zahl; (* Zahl hoch mal mit sich selbst multiplizieren *) Expt := hilfe; (* Ergebnis zur...kliefern *) END; END; (* ----------------------------------------------------------------------- *) FUNCTION AnzahlTests(wahrscheinlichkeit : Real) : INTEGER; (* ermittelt die Anzahl Tests, welche n杯ig sind um die gew]schte *) (* Wahrscheinlichkeit zu erreichen *) VAR anzahl : INTEGER; (* Anzahl der n杯igen Tests *) BEGIN anzahl := 0; (* Anzahl mit 0 initialisieren *) REPEAT INC(anzahl); (* Anzahl um 1 erh派en *) UNTIL ((1/(Expt(4,anzahl))) < wahrscheinlichkeit); (* solange wiederholen, bis W> (1/4)^x *) AnzahlTests := anzahl; (* Anzahl Tests zur...kgeben *) END; (* ----------------------------------------------------------------------- *) FUNCTION EvenString(zahl : STRING) : BOOLEAN; (* pr’t, on ein String gerade ist *) BEGIN EvenString := NOT Odd(Ord(zahl[Length(zahl)]) - 48); END; (* pr’t, ob die letzte Stelle des Strings gerade ist *) (* ----------------------------------------------------------------------- *) FUNCTION Div5(zahl : STRING) : BOOLEAN; (* pr’t, ob ein String durch 5 dividierbar ist *) VAR last : BYTE; (* letzte Stelle von zahl *) BEGIN last := Ord(zahl[Length(zahl)]) - 48; (* letzte Stelle ermitteln *) IF (last = 0) OR (last = 5) THEN (* Falls letzte Stelle 0 oder 5 ist *) Div5 := TRUE (* ist die Zahl durch 5 dividierbar *) ELSE Div5 := FALSE; (* sonst nicht *) END; (* pr’t, ob die letzte Stelle des Strings gerade ist *) (* ----------------------------------------------------------------------- *) FUNCTION Div3(zahl : STRING) : BOOLEAN; (* pr’t, ob ein String durch 5 dividierbar ist *) VAR ziffernSumme : WORD; (* Ziffernsumme des Strings *) laenge : BYTE; (* Laenge des Strings *) i : BYTE; (* Z?hlvariable *) BEGIN ziffernSumme := 0; (* Ziffernsumme initialisieren *) laenge := Length(zahl); (* L?nge des Strings ermitteln *) FOR i := 1 TO laenge DO (* ZiffernSumme ermitteln *) BEGIN ziffernSumme := ziffernSumme + (Ord(zahl[i]) - 48); (* aktuelle Zahl zur Ziffernsumme addieren *) END; IF (ZiffernSumme MOD 3) = 0 THEN (* Ziffernsumme durch 3 teilbar *) Div3 := TRUE (* => Zahl durch 3 teilbar *) ELSE Div3 := FALSE; (* sonst ist Zahl nicht durch 3 teilbar *) END; (* ----------------------------------------------------------------------- *) (* Bedingung 1 beim Rabintest: b^v?1 mod p *) FUNCTION Bedingung1(b, v, p, pMinus1, EINS : CalcStr) : BOOLEAN; VAR hilfe : CalcStr; (* HilfsCalcString *) BEGIN ExptModCalcStr(b, v, p, hilfe); (* b^v mod p berechnen *) Write('b^v mod p = '); PrintCalcStr(hilfe); IF EqualCalcStr(hilfe, EINS) THEN (* Falls Ergebnis = 1 *) Bedingung1 := TRUE (* Bedingung 1 erf〕lt *) ELSE IF EqualCalcStr(hilfe, pMinus1) THEN Bedingung1 := TRUE (* Bedingung 2 mit r=0 erf〕lt *) ELSE Bedingung1 := FALSE; (* sonst ist Bedingung 1 nicht erf〕lt *) END; (* ----------------------------------------------------------------------- *) (* Bedingung 2 beim Rabintest: b^(v^(2r)) ? -1 mod p *) FUNCTION Bedingung2(VAR b, v, u, p, pMinus1, EINS : CalcStr) : BOOLEAN; VAR r : CalcStr; (* zu durchlaufende Hochzahlen *) ZWEI : CalcStr; (* konstante CalcString-Darstellung f〉 2 *) hilfe1 : CalcStr; (* HilfsCalcString *) hilfe2 : CalcStr; (* HilfsCalcString *) BEGIN InitCalcStr(r); (* r initialisieren *) r.stellen := 1; (* r hat 1 Stelle, diese ist zu Beginn 0 *) r.zahl[1] := 1; (* r lеft von 1 weg, weil Bedingung mit r=0 schon in *) (* Bedingung 1 gepr’t wird *) WordToCalcStr(2, ZWEI); (* Zahl zwei in CalcString ermitteln *) WHILE LessCalcStr(r, u) DO (* solange r < u *) BEGIN Write('r = '); PrintCalcStr(r); ExptCalcStr(ZWEI, r, hilfe1); (* 2^r ermitteln *) MulCalcStr(hilfe1, v, hilfe2); (* 2^r mit v multiplizieren *) ExptModCalcStr(b, hilfe2, p, hilfe1); (* b^(v2^r) MOD p berechnen *) Write('b^(v2^r) mod p = '); PrintCalcStr(hilfe1); IF EqualCalcStr(hilfe1, pMinus1) THEN (* Falls Ergebnis = -1 *) BEGIN Bedingung2 := TRUE; (* Bedingung 2 erf〕lt *) EXIT; END; AddCalcStr(r, EINS, hilfe2); (* r um 1 erh派en *) r := hilfe2; (* r wieder zuweisen *) END; Bedingung2 := FALSE; (* 2. Bedingung nicht erf〕lt *) END; (* ----------------------------------------------------------------------- *) (* Rabin pr’t eine Zahl mit Hilfe des RabinTests *) FUNCTION Rabin(primzahl : STRING; anzahl : INTEGER) : BOOLEAN; VAR p : CalcStr; (* zu untersuchende Primzahl *) pMinus1 : CalcStr; (* Primzahl - 1 *) EINS : CalcStr; (* konstanter Wert f〉 1 *) u : CalcStr; (* p-1 = 2^u*v (v ungerade) *) v : CalcStr; (* p-1 = 2^u*v (v ungerade) *) b : CalcStr; (* Basis bei Primzahltest *) hilfe : CalcStr; (* HilfsCalcString *) i : BYTE; (* Z?hlvariable *) BEGIN StrToCalcStr(primzahl, p); (* Primzahl ins 65536-System umwandeln *) WordToCalcStr(1, EINS); (* CalcStringdarstellung von 1 *) SubCalcStr(p, EINS, pMinus1); (* vom pMinus1 = p - 1 *) InitCalcStr(u); (* u initialisieren *) u.stellen := 1; (* u besitzt 1 Stellen, diese ist 0 *) v := pMinus1; (* v ist zu Beginn p-1 *) REPEAT AddCalcStr(u, EINS, hilfe); (* 2^u, Potenz um 1 erh派en *) u := hilfe; (* und wieder u zuweisen *) Div2CalcStr(v); (* v durch 2 dividieren *) UNTIL OddCalcStr(v); (* solange, bis v ungerade ist *) Write('p = '); PrintCalcStr(p); Write('u = '); PrintCalcStr(u); Write('v = '); PrintCalcStr(v); FOR i := 1 TO anzahl DO (* Anzahl Tests durchf"ren *) BEGIN RandomCalcStr(p, b); (* zuf?llige Basis ermitteln *) Write('b = '); PrintCalcStr(b); IF (Bedingung1(b, v, p, pMinus1, EINS) = FALSE) THEN (* 1. Bedingung pr’en *) IF (Bedingung2(b, v, u, p, pMinus1, EINS) = FALSE) THEN BEGIN (* 2. Bedingung pr’en *) Rabin := FALSE; EXIT; (* beide Bedingungen nicht erf〕lt => keine Primzahl *) END; END; Rabin := TRUE; (* Rabintest bestanden *) END; (* ----------------------------------------------------------------------- *) (* PrimeTest pr’t, ob Zahl eine Primzahl ist *) FUNCTION PrimeTest(zahl : STRING; anzahlTests : INTEGER; VAR meldung : STRING) : BOOLEAN; BEGIN IF EvenString(zahl) THEN (* Zahl ist durch 2 dividierbar *) BEGIN PrimeTest := FALSE; (* => keine Primzahl *) meldung := 'gerade Zahl'; (* Meldung zur...kgeben *) END ELSE IF Div5(zahl) THEN (* Falls Zahl durch 5 dividierbar ist *) BEGIN PrimeTest := FALSE; (* => keine Primzahl *) meldung := 'Zahl durch 5 dividierbar'; (* Meldung zur...kgeben *) END ELSE IF Div3(zahl) THEN (* Zahl durch 3 dividierbar *) BEGIN PrimeTest := FALSE; (* => keine Primzahl *) meldung := 'Zahl durch 3 dividierbar'; (* Meldung zur...kgeben *) END ELSE BEGIN IF NOT Rabin(zahl, anzahlTests) THEN (* Falls Rabintest negativ *) BEGIN PrimeTest := FALSE; (* keine Primzahl *) meldung := 'Rabintest'; (* Meldung zur...kgeben *) END ELSE PrimeTest := TRUE; (* sonst ist Zahl Primzahl *) END; END; (* ----------------------------------------------------------------------- *) (* Hauptprogramm erledigt die Ein/Ausgabe *) PROCEDURE Hauptprogramm; (* Hauptprogramm des Primzahltests *) VAR anzahl : INTEGER; (* Anzahl notwendiger Tests *) wahrscheinlichkeit : Real; (* Fehlerwahrscheinlichkeit *) primzahl : STRING; (* zu untersuchende Zahl *) meldung : STRING; (* Meldung, warum keine Primzahl *) prim : BOOLEAN; (* ist sie Primzahl oder nicht *) BEGIN ClrScr; (* Bildschirm l敗chen *) Frame(27, 1, 53, 3, 1, '', TRUE); (* Rahmen ausgeben *) WriteXY(29, 2, 'Primzahltest nach Rabin'); GotoXY(1, 6); WriteLn('1. Test: gerade Zahl'); (* Tests anzeigen *) WriteLn('2. Test: Zahl durch 5 dividierbar'); WriteLn('3. Test: Ziffernsumme durch 3 dividerbar'); WriteLn('4. Test: RabinTest'); WriteLn; Write('Primzahl (p): '); ReadLn(primzahl); (* Primzahl eingeben *) Write('Fehlerwahrscheinlichkeit: '); ReadLn(wahrscheinlichkeit); (* Fehlerwahrscheinlichkeit eingeben *) anzahl := AnzahlTests(wahrscheinlichkeit); (* Testanzahl ermitteln *) WriteLn; WriteLn('Anzahl Tests: ', anzahl); WriteLn; prim := PrimeTest(primzahl, anzahl, meldung); (* auf Primzahl testen *) Write(primzahl, ' ist '); IF NOT prim THEN WriteLn('keine Primzahl (',meldung,')') (* Meldung ausgeben *) ELSE WriteLn('Primzahl'); END; (* ----------------------------------------------------------------------- *) BEGIN Hauptprogramm; (* Hauptprogramm aufrufen *) END. (* ----------------------------------------------------------------------- *) (* ----------------------------------------------------------------------- *) (* MyCalc stellt eine LongInteger-Arithmetik zur Verfuegung *) (* ----------------------------------------------------------------------- *) {$M 65000, 0, 655360} (* Stack auf maximale Groesse *) UNIT MyCalc; INTERFACE CONST MAXCALCSTR = 500; (* maximal 500 Word-Zahlen *) TYPE CalcStr = RECORD stellen : WORD; (* Anzahl der belegten Stellen *) zahl : ARRAY[1..MAXCALCSTR] OF WORD; (* gro疇 Zahl *) END; PROCEDURE InitCalcStr(VAR calcZahl : CalcStr); PROCEDURE ReverseCalcStr(VAR ergebnis : CalcStr); PROCEDURE SwapCalcStr(VAR zahl1, zahl2 : CalcStr); PROCEDURE PrintCalcStr(VAR calcZahl : CalcStr); PROCEDURE StrToCalcStr(zeichenkette : STRING; VAR ergebnis : CalcStr); PROCEDURE WordToCalcStr(zahl : WORD; VAR ergebnis : CalcStr); PROCEDURE AddCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr); PROCEDURE SubCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr); PROCEDURE Mul2CalcStr(VAR calcZahl : CalcStr); PROCEDURE Div2CalcStr(VAR calcZahl : CalcStr); PROCEDURE MulCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr); PROCEDURE ExptCalcStr(VAR basis, exponent: CalcStr; VAR ergebnis : CalcStr); PROCEDURE RandomCalcStr(VAR calcZahl: CalcStr; VAR ergebnis : CalcStr); PROCEDURE MulModCalcStr(VAR zahl1, zahl2, modul : CalcStr; VAR ergebnis : CalcStr); PROCEDURE ExptModCalcStr(VAR basis, exponent, modul : CalcStr; VAR ergebnis : CalcStr); FUNCTION CalcStrLength(VAR calcZahl : CalcStr) : WORD; FUNCTION CalcStrToStr(VAR calcZahl : CalcStr; VAR ergebnis : STRING) : BOOLEAN; FUNCTION CalcStrToWord(VAR calcZahl : CalcStr; VAR ergebnis : WORD) : BOOLEAN; FUNCTION EqualCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; FUNCTION GreaterCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; FUNCTION GreaterEqual(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; FUNCTION LessCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; FUNCTION LessEqual(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; FUNCTION EvenCalcStr(VAR calcZahl : CalcStr) : BOOLEAN; FUNCTION OddCalcStr(VAR calcZahl : CalcStr) : BOOLEAN; FUNCTION DivCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr) : BOOLEAN; FUNCTION ModCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr) : BOOLEAN; IMPLEMENTATION USES Crt; (* Ein/Ausgabefunktionen *) VAR EMPTYCALCSTR : CalcStr; (* leerer CalcString *) i : WORD; (* Z?hlvariable zur Initialisierung von EMPTYCALCSTR *) (* ======================================================================= *) (* Bitmanipulationen *) (* ----------------------------------------------------------------------- *) (* SetBit setzt das BitNr.te Bit in Zahl *) FUNCTION SetBit(zahl : WORD; bitNr : BYTE): WORD; BEGIN SetBit := zahl OR (1 SHL bitNr) (* BitNr Stellen nach links shiften und mit oder verkn}fen *) END; (* ----------------------------------------------------------------------- *) (* TestBit pr’t, ob das BitNr.te Bit in Zahl gesetzt ist *) FUNCTION TestBit(zahl : WORD; bitNr: BYTE): BOOLEAN; BEGIN TestBit := (((zahl SHR bitNr) AND 1) = 1) (* Bit ist dann gesetzt, falls an der BitNr. Stelle bei einer *) (* Und-Verkn}fung wieder 1 das Ergebnis ist *) END; (* ======================================================================= *) (* Hilfsfunktionen f〉 Strings *) (* ----------------------------------------------------------------------- *) (* TestString pr’t, ob im String eine g〕tige Zahl enthalten ist *) FUNCTION TestString(zeichenkette : STRING) : BOOLEAN; VAR laenge : BYTE; (* L?nge der Zeichenkette *) i : BYTE; (* Z?hlvariable *) BEGIN laenge := Length(zeichenkette); (* L?nge der Zeichenkette ermitteln *) FOR i := 1 TO laenge DO IF (NOT (zeichenkette[i] IN ['0'..'9'])) THEN (* keine Zahl *) BEGIN TestString := FALSE; (* String ist ung〕tig *) EXIT; (* Funktion verlassen *) END; TestString := TRUE; END; (* ----------------------------------------------------------------------- *) (* OddString pr’t, ob ein String ungerade ist *) FUNCTION OddString(zeichenkette : STRING) : BOOLEAN; VAR zahl : BYTE; (* Bytedarstellung von Zeichen *) dummy : INTEGER; (* dient zur 喘erpr’ung von zeichen bei Umwandlung *) last : CHAR; (* letztes Zeichen in zeichenkette *) laenge : BYTE; (* L?nge der Zeichenkette *) BEGIN laenge := Length(zeichenkette); (* L?nge mu? neu ermittelt werden *) last := zeichenkette[laenge]; (* letztes Zeichen *) Val(last, zahl, dummy); (* letztes Zeichen in zahl umwandeln *) oddString := Odd(zahl); (* pr’en, ob zahl ungerade ist *) END; (* ----------------------------------------------------------------------- *) (* StrDiv2 dividiert einen String durch 2 *) FUNCTION StrDiv2(zeichenkette : STRING) : STRING; VAR hilfe : STRING; (* Hilfsstring f〉 das Ergebnis *) index : BYTE; (* Index f〉 Position in zeichenkette *) laenge : BYTE; (* L?nge der Zeichenkette *) zahl : BYTE; (* zu dividierender Faktor *) zeichen : CHAR; (* Zeichendarstellung von Zahl *) dummy : INTEGER; (* dient zur 喘erpr’ung von zeichen bei Umwandlung *) uebertrag : BOOLEAN; (* ist ein 喘ertrag aufgetreten *) BEGIN hilfe := ''; (* hilfe initialisieren *) laenge := Length(zeichenkette); (* L?nge der zeichenkette *) IF oddString(zeichenkette) THEN (* falls die Zahl ungerade ist *) DEC(zeichenkette[laenge]); (* Zahl um 1 dekrementieren *) uebertrag := FALSE; (* kein 喘ertrag *) IF zeichenkette[1] = '1' THEN (* falls an 1.Stelle ein 1er *) BEGIN index := 2; (* an 2.Stelle weitermachen *) zahl := 10; (* 喘ertrag an 1.Stelle => zahl = 10 *) END ELSE BEGIN index := 1; (* beginne bei 1.Stelle *) zahl := 0; (* => zahl = 0 *) END; REPEAT zahl := zahl + Ord(zeichenkette[index]) - 48; (* Zahl ermitteln *) IF (zahl AND 1) = 1 THEN uebertrag := TRUE; (* ungerade zahl => 喘ertrag *) zahl := zahl SHR 1; (* zahl durch 2 dividieren *) zeichen := Chr(zahl + 48); (* Zahl wieder in ASCII-Zeichen umwandeln *) hilfe := hilfe + zeichen; (* und an hilfe anh?ngen *) INC(index); (* Index um 1 erh派en *) IF uebertrag THEN (* 喘ertrag *) zahl := 10 (* 喘ertrag in zahl sichern *) ELSE zahl := 0; (* sonst zahl = 0 *) uebertrag := FALSE; (* Annahme: kein 喘ertrag *) UNTIL index> laenge; (* keine Zeichen mehr zum dividieren *) StrDiv2 := hilfe; (* Ergebnis steht in Hilfe *) END; (* ----------------------------------------------------------------------- *) (* StrMul2 multipliziert einen String mit 2 *) FUNCTION StrMul2(zeichenkette : STRING) : STRING; VAR laenge : BYTE; (* Laenge der zeichenkette *) i : BYTE; (* Z?hlvariable *) hilfe : STRING; (* Hilfsstring f〉 Ergebnis *) dummyStr : STRING; (* dient zur Umwandlung Zahl -> Zeichen *) uebertrag : BOOLEAN; (* 喘ertrag ja/nein *) zeichen : CHAR; (* aktuelles Zeichen *) zahl : BYTE; (* Byte-Darstellung von zeichen *) dummy : INTEGER; (* dient zur Pr’ung von zeichen bei Umwandlung *) BEGIN laenge := Length(zeichenkette); (* L?nge ermitteln *) uebertrag := FALSE; (* Annahme: kein 喘ertrag *) hilfe := ''; (* Hilfsstring initialisieren *) FOR i := laenge DOWNTO 1 DO (* zeichenkette r...kwвts durchlaufen *) BEGIN zeichen := zeichenkette[i]; (* aktuelles Zeichen ermitteln *) zahl := Ord(zeichen) - 48; (* in eine Zahl umwandeln *) zahl := zahl SHL 1; (* Zahl mit 2 multiplizieren *) IF uebertrag THEN INC(zahl); (* bei 喘ertrag 1 addieren *) IF (zahl>= 10) THEN (* falls Zahl>= 10 *) BEGIN uebertrag := TRUE; (* 喘ertrag aufgetreten *) zahl := zahl - 10; (* 喘ertrag wegschneiden *) END ELSE uebertrag := FALSE; (* sonst kein 喘ertrag *) zeichen := Chr(zahl + 48); (* zahl in Zeichen umwandeln *) hilfe := zeichen + hilfe; (* und an Hilfe anh?ngen *) END; IF uebertrag THEN hilfe := '1' + hilfe; (* restlichen 喘ertrag noch ber...ksichtigen *) StrMul2 := hilfe; (* Ergebnis zuweisen *) END; (* ======================================================================= *) (* Operationen auf den Datentyp CalcString *) (* ----------------------------------------------------------------------- *) (* InitCalcStr initialisiert einen CalcString: *) PROCEDURE InitCalcStr(VAR calcZahl : CalcStr); BEGIN calcZahl := EMPTYCALCSTR; (* leeren CalcStr zuweisen *) END; (* ----------------------------------------------------------------------- *) (* CalcStrLength liefert die L?nge des CalcStrings zur...k *) FUNCTION CalcStrLength(VAR calcZahl : CalcStr) : WORD; BEGIN CalcStrLength := calcZahl.stellen; (* L?nge ist in stellen gespeichert *) END; (* ----------------------------------------------------------------------- *) (* ReverseCalcStr dreht einen CalcString um *) PROCEDURE ReverseCalcStr(VAR ergebnis : CalcStr); VAR laenge : WORD; (* Anzahl Stellen im CalcString *) i : WORD; (* Z?hlvariable *) anzahl : WORD; (* ben杯igte Schrittzahl *) hilfe : WORD; (* Zwischenspeicher *) BEGIN laenge := CalcStrLength(ergebnis); (* L?nge des CalcStrings ermitteln *) anzahl := laenge DIV 2; (* man ben杯igt nur laenge/2 Schritte *) WITH ergebnis DO (* Record abarbeiten *) BEGIN FOR i := 1 TO anzahl DO BEGIN hilfe := zahl[i]; (* i. Zahl merken *) zahl[i] := zahl[laenge - (i - 1)]; (* i. Zahl wird zur entsprechenden Zahl von hinten *) zahl[laenge - (i - 1)] := hilfe; (* hintere Zahl wird i.te Zahl *) END; END; END; (* ----------------------------------------------------------------------- *) (* SwapCalcStr vertauscht zwei CalcStrings *) PROCEDURE SwapCalcStr(VAR zahl1, zahl2 : CalcStr); VAR hilfe : CalcStr; (* HilfsString f〉 Vertauschung *) BEGIN hilfe := zahl1; (* Hilfe auf Zahl1 setzen *) zahl1 := zahl2; (* Zahl1 auf Zahl2 setzen *) zahl2 := hilfe; (* Zahl2 auf Hilfe setzen *) END; (* ----------------------------------------------------------------------- *) (* PrintCalcStr gibt einen CalcString als Vektor auf dem Bildschirm aus *) PROCEDURE PrintCalcStr(VAR calcZahl : CalcStr); VAR i : WORD; (* Z?hlvariable *) BEGIN ReverseCalcStr(calcZahl); (* calcZahl mu? umgedreht werden *) WITH calcZahl DO (* Recordtyp als Grundlage *) BEGIN IF stellen> 0 THEN (* Zahl darf nicht 0 sein *) BEGIN Write('('); (* positives Vorzeichen *) FOR i := 1 TO (stellen - 1) DO (* alle Stellen abarbeiten *) BEGIN Write(zahl[i]); (* Zahl ausgeben *) Write(','); (* durch Beistrich trennen *) END; Write(zahl[stellen]); (* letzte Zahl ausgeben *) WriteLn(')'); (* Klammer des Vektors schlie疇n *) END ELSE WriteLn('(0)'); (* sonst 0 ausgeben *) END; ReverseCalcStr(calcZahl); (* calcZahl mu? wieder umgedreht werden *) END; (* ----------------------------------------------------------------------- *) (* StrToCalcStr wandelt einen String in einen CalcString um *) PROCEDURE StrToCalcStr(zeichenkette : STRING; VAR ergebnis : CalcStr); VAR index : WORD; (* Index im ErgebnisCalcString *) bitnr : BYTE; (* Nummer des zu setzenden Bit's *) laenge : BYTE; (* L?nge der Zeichenkette *) BEGIN ergebnis := EMPTYCALCSTR; (* ErgebnisString initialisieren *) index := 1; (* erstes Element im CalcString *) ergebnis.stellen := 1; (* L?nge des CalcStrings wird auf 1 gesetzt *) bitnr := 0; (* zu Beginn wird Bit 0 gesetzt/nicht gesetzt *) laenge := Length(zeichenkette); (* L?nge der Zeichenkette ermitteln *) IF TestString(zeichenkette) THEN (* ist zeichenkette eine g〕tige Zahl *) WITH ergebnis DO (* Record als Grundlage *) BEGIN REPEAT IF oddString(zeichenkette) THEN (* ist zeichenkette ungerade ? *) zahl[index] := SetBit(zahl[index], bitnr); (* Bit setzen *) zeichenkette := StrDiv2(zeichenkette); (* Zeichenkette / 2 *) IF zeichenkette '0' THEN (* falls noch nicht fertig *) BEGIN INC(bitnr); (* BitNr um 1 erh派en *) IF bitnr>= 16 THEN (* falls 1 Word voll ist *) BEGIN bitnr := 0; (* BitNr wird wieder 0 *) INC(index); (* ein Element im CalcString weiter *) INC(stellen); (* L?nge des CalcStrings wird um 1 erh派t *) END; END; UNTIL zeichenkette = '0'; (* bis zeichenkette auf 0 reduziert *) END; END; (* ----------------------------------------------------------------------- *) (* CalcStrToStr wandelt eine CalcString um, falls er sich als String *) (* darstellen l?疸 *) FUNCTION CalcStrToStr(VAR calcZahl : CalcStr; VAR ergebnis : STRING) : BOOLEAN; VAR i : WORD; (* Z?hlvariable *) BitNr : BYTE; (* Nummer des aktuellen Bits *) anzahl : WORD; (* Anzahl Stellen im CalcString *) laenge : BYTE; (* L?nge des Ergebnisstrings *) BEGIN IF calcZahl.Stellen> 50 THEN (* Stringl?nge w〉de |erschritten *) CalcStrToStr := FALSE (* String|erlauf *) ELSE BEGIN (* Zahl pa疸 in einen String *) ergebnis := '0'; (* Ergebnisstring ist zu Beginn 0 *) anzahl := CalcStrLength(calcZahl); (* L?nge des CalcStrings *) FOR i := anzahl DOWNTO 1 DO (* alle Element des CalcStrings durchlaufen *) FOR BitNr := 15 DOWNTO 0 DO (* alle Bits pr’en *) BEGIN ergebnis := StrMul2(ergebnis); (* ErgebnisString mit 2 mult. *) IF TestBit(calcZahl.zahl[i], BitNr) THEN (* Ist das Bit gesetzt ? *) BEGIN laenge := Length(ergebnis); (* L?nge ermitteln *) INC(ergebnis[laenge]); (* letztes Zeichen um 1 erh派en *) END; END; CalcStrToStr := TRUE; (* Umwandlung gegl...kt *) END; END; (* ----------------------------------------------------------------------- *) (* WordToCalcStr wandelt eine Wordzahl in einen CalcString um *) PROCEDURE WordToCalcStr(zahl : WORD; VAR ergebnis : CalcStr); BEGIN ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *) ergebnis.stellen := 1; (* 1 Stelle wird belegt *) ergebnis.zahl[1] := zahl; (* Zahl in CalcZahl sichern *) END; (* ----------------------------------------------------------------------- *) (* CalcStrToWord wandelt einen CalcString in eine Wordzahl um *) FUNCTION CalcStrToWord(VAR calcZahl : CalcStr; VAR ergebnis : WORD) : BOOLEAN; BEGIN IF (calcZahl.Stellen> 1) THEN (* Zahl mit mehr als 1 Stelle k馬nen nicht umgewandelt werden *) CalcStrToWord := FALSE (* keine Umwandlung *) ELSE BEGIN ergebnis := calcZahl.zahl[1]; (* Ergebnis zur...kgeben *) CalcStrToWord := TRUE; (* Umwandlung gegl...kt *) END; END; (* ----------------------------------------------------------------------- *) (* EqualCalcStr pr’t, ob ein CalcStr1 = CalcStr2 *) FUNCTION EqualCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; VAR i : WORD; (* Z?hlvariable *) BEGIN IF (zahl1.stellen zahl2.stellen) THEN EqualCalcStr := FALSE (* unterschiedliche Anzahl Stellen *) ELSE (* Stellenzahl gleich *) BEGIN FOR i := 1 TO zahl1.stellen DO (* alle Stellen abarbeiten *) IF zahl1.zahl[i] zahl2.zahl[i] THEN (* Zahlen verschieden *) BEGIN EqualCalcStr := FALSE; (* Zahlen sind verschieden *) EXIT; (* Schleife verlassen *) END; EqualCalcStr := TRUE; (* Zahlen sind gleich *) END; END; (* ----------------------------------------------------------------------- *) (* GreaterCalcStr pr’t, ob ein CalcStr1> CalcStr2 *) FUNCTION GreaterCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; VAR i : WORD; (* Z?hlvariable *) hilfe : BOOLEAN; (* Hilfsvariable *) BEGIN IF (zahl1.stellen> zahl2.stellen) THEN (* Zahl1 besitzt mehr Stellen *) GreaterCalcStr := TRUE (* => Zahl1> Zahl2 *) ELSE IF (zahl1.stellen < zahl2.stellen) THEN (* Zahl1 besitzt weniger Stellen *) GreaterCalcStr := FALSE (* => Zahl1 nicht> Zahl2 *) ELSE (* Stellenzahl gleich *) BEGIN FOR i := zahl1.stellen DOWNTO 1 DO (* alle Stellen abarbeiten *) IF zahl1.zahl[i]> zahl2.zahl[i] THEN (* i.Stelle von Zahl1> i.te Stelle von Zahl2 *) BEGIN GreaterCalcStr := TRUE; (* Zahl1> Zahl2 *) EXIT; (* Schleife verlassen *) END ELSE IF zahl1.zahl[i] < zahl2.zahl[i] THEN (* i.Stelle von Zahl1 < i.te Stelle von Zahl2 *) BEGIN GreaterCalcStr := FALSE; (* Zahl1 nicht> Zahl2 *) EXIT; (* Schleife verlassen *) END; GreaterCalcStr := FALSE; (* alle Stellen sind gleich *) END; END; (* ----------------------------------------------------------------------- *) (* GreaterEqual pr’t, ob Zahl1>= Zahl2 *) FUNCTION GreaterEqual(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; BEGIN GreaterEqual := NOT LessCalcStr(zahl1, zahl2); (* Zahl1>= Zahl2, wenn Zahl1 nicht kleiner als Zahl2 ist *) END; (* ----------------------------------------------------------------------- *) (* LessCalcStr pr’t, on Zahl1 < Zahl2 *) FUNCTION LessCalcStr(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; VAR i : WORD; (* Z?hlvariable *) hilfe : BOOLEAN; (* Hilfsvariable *) BEGIN IF (zahl1.stellen < zahl2.stellen) THEN (* Zahl1 besitzt weniger Stellen *) LessCalcStr := TRUE (* => Zahl1 < Zahl2 *) ELSE IF (zahl1.stellen> zahl2.stellen) THEN (* Zahl1 besitzt mehr Stellen *) LessCalcStr := FALSE (* => Zahl1 nicht < Zahl2 *) ELSE (* Stellenzahl gleich *) BEGIN FOR i := zahl1.stellen DOWNTO 1 DO (* alle Stellen abarbeiten *) IF zahl1.zahl[i] < zahl2.zahl[i] THEN (* i.Stelle von Zahl1 < i.te Stelle von Zahl2 *) BEGIN LessCalcStr := TRUE; (* Zahl1 < Zahl2 *) EXIT; (* Schleife verlassen *) END ELSE IF zahl1.zahl[i]> zahl2.zahl[i] THEN (* i.Stelle von Zahl1> i.te Stelle von Zahl2 *) BEGIN LessCalcStr := FALSE; (* Zahl1 nicht < Zahl2 *) EXIT; (* Schleife verlassen *) END; LessCalcStr := FALSE; (* alle Stellen sind gleich *) END; END; (* ----------------------------------------------------------------------- *) (* LessEqual pr’t, ob Zahl1 <= Zahl2 *) FUNCTION LessEqual(VAR zahl1, zahl2 : CalcStr) : BOOLEAN; BEGIN LessEqual := NOT GreaterCalcStr(zahl1, zahl2); (* Zahl1 <= Zahl2, wenn Zahl1 nicht gr批er als Zahl2 ist *) END; (* ----------------------------------------------------------------------- *) (* EvenCalcStr pr’t, ob ein CalcString gerade ist *) FUNCTION EvenCalcStr(VAR calcZahl : CalcStr) : BOOLEAN; BEGIN EvenCalcStr := NOT Odd(calcZahl.zahl[1]); (* CalcZahl ist gerade, falls die letzte Stelle nicht ungerade ist *) END; (* ----------------------------------------------------------------------- *) (* OddCalcStr pr’t, ob ein CalcString ungerade ist *) FUNCTION OddCalcStr(VAR calcZahl : CalcStr) : BOOLEAN; BEGIN OddCalcStr := Odd(calcZahl.zahl[1]); (* CalcZahl ist ungerade, falls die letzte Stelle ungerade ist *) END; (* ----------------------------------------------------------------------- *) (* AddCalcStr addiert zwei CalcStrings *) PROCEDURE AddCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr); VAR anzahl : WORD; (* Anzahl Stellen f〉 Addition *) i : WORD; (* Z?hlvariable *) summe : LongInt; (* Hilfsvariable zur Pr’ung eines 喘ertrags *) ueberlauf : BYTE; (* 喘erlauf = 1, kein 喘erlauf = 0 *) addition : BOOLEAN; (* k馬nen Zahlen addiert werden oder nicht *) BEGIN {$Q-} (* 喘erlaufpr’ung ausschalten *) ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *) anzahl := zahl1.stellen; (* Annahme: Zahl 1 ist gr批er *) IF zahl2.stellen> anzahl THEN (* Falls doch 2. Zahl gr批er ist *) anzahl := zahl2.stellen; (* so viele Stellen m《sen addiert werden *) ueberlauf := 0; (* zu Beginn kein 喘erlauf *) FOR i := 1 TO anzahl DO (* anzahl Stellen abarbeiten *) BEGIN ergebnis.zahl[i] := zahl1.zahl[i] + zahl2.zahl[i] + ueberlauf; (* ergebnis ist die Summe der beiden Zahlen (kann einfach *) (* addiert werden, weil 喘erlaufpr’ung ausgeschaltet ist *) summe := LongInt(zahl1.zahl[i]) + LongInt(zahl2.zahl[i]) + ueberlauf; (* Summe ohne 喘erlauf *) IF (summe> ergebnis.zahl[i]) THEN (* ist ein 喘erlauf aufgetreten *) ueberlauf := 1 (* ja -> 喘erlauf auf 1 setzen *) ELSE ueberlauf := 0; (* nein -> 喘erlauf ist 0 *) END; IF (ueberlauf = 1) THEN (* letzter 喘erlauf mu? gepr’t werden *) BEGIN ergebnis.stellen := anzahl + 1; (* letzter 喘erlauf belegt 1 Feld *) ergebnis.zahl[anzahl + 1] := 1; (* Zahl 1 steht im letzten Feld *) END ELSE ergebnis.stellen := anzahl; (* gleich viele Stellen wie die l?ngere Zahl *) {$Q+} (* 喘erlaufpr’ung wieder einschalten *) END; (* ----------------------------------------------------------------------- *) (* SubCalcStr subtrahiert zahl2 von zahl1 *) PROCEDURE SubCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr); VAR swapped : BOOLEAN; (* wurden Zahl1 und Zahl2 vertauscht ? *) i : WORD; (* Z?hlvariable *) uebertrag : BYTE; (* 喘ertrag: 1, kein 喘ertrag: 0 *) BEGIN ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *) swapped := FALSE; (* Zahlen wurden nicht vertauscht *) uebertrag := 0; (* kein 喘ertrag *) IF GreaterCalcStr(zahl2, zahl1) THEN EXIT; (* Zahl2> Zahl1 *) FOR i := 1 TO zahl1.stellen DO (* alle Stellen abarbeiten *) BEGIN IF (zahl1.zahl[i]>= (zahl2.zahl[i] + uebertrag)) THEN (* Zahl1[i]>= Zahl2[i] mit Ber...ksichtigung des 喘ertrags *) BEGIN ergebnis.zahl[i] := zahl1.zahl[i] - (zahl2.zahl[i] + uebertrag); (* Differenz der Zahlen ermitteln *) uebertrag := 0; (* kein 喘ertrag *) END ELSE BEGIN ergebnis.zahl[i] := LongInt(zahl1.zahl[i] + 65536) - (zahl2.zahl[i] + uebertrag); uebertrag := 1; END; END; ergebnis.stellen := zahl1.stellen; (* Annahme: gleich viel Stellen wie Zahl1 *) WHILE (ergebnis.zahl[ergebnis.stellen] = 0) AND (ergebnis.stellen> 0) DO DEC(ergebnis.stellen); (* richtige Stellenzahl ermitteln *) END; (* ----------------------------------------------------------------------- *) (* Mul2CalcStr multipliziert einen CalcString mit 2 *) PROCEDURE Mul2CalcStr(VAR calcZahl : CalcStr); VAR i : WORD; (* Z?hlvariable *) BEGIN WITH calcZahl DO (* Record als Grundlage *) IF ((stellen = 1) AND (zahl[1] = 0)) OR (stellen = 0) THEN ELSE (* CalcZahl ist 0 => Ergebnis ist 0 *) BEGIN (* Sonst ist Ergebnis 0 *) IF (zahl[stellen] AND 32768)> 0 THEN BEGIN (* Ist 16.Bit der letzten Stelle gesetzt ? *) INC(stellen); (* Stellenzahl um 1 erh派en *) zahl[stellen] := 0; (* und mit 0 initialisieren *) END; FOR i := (stellen - 1) DOWNTO 1 DO (* Zahl abarbeiten *) BEGIN zahl[i + 1] := zahl[i + 1] SHL 1; (* Zahl[i + 1] * 2 *) IF (zahl[i] AND 32768)> 0 THEN INC(zahl[i + 1]); END; (* Bei 喘erlauf bei Zahl[i] => Zahl[i + 1] erh派en *) zahl[1] := zahl[1] SHL 1; (* 1. Zahl mit 2 multiplizieren *) END; END; (* ----------------------------------------------------------------------- *) (* Div2CalcStr dividiert einen CalcString durch 2 *) PROCEDURE Div2CalcStr(VAR calcZahl : CalcStr); VAR i : WORD; (* Z?hlvariable *) BEGIN WITH calcZahl DO IF ((stellen = 1) AND (zahl[1] = 0)) OR (stellen = 0) THEN ELSE (* calcZahl = 0 => calcZahl * 2 = 0 *) BEGIN FOR i := 1 TO (stellen - 1) DO (* Zahl abarbeiten *) BEGIN zahl[i] := zahl[i] SHR 1; (* Zahl[i] DIV 2 *) IF (zahl[i + 1] AND 1)> 0 THEN (* Falls bei Zahl[i + 1] ein Unterlauf auftritt *) zahl[i] := zahl[i] OR 32768; (* Bit 16 bei Zahl[i] setzen *) END; zahl[stellen] := zahl[stellen] SHR 1; (* letzte Stelle DIV 2 *) IF (zahl[stellen] = 0) THEN DEC(stellen); (* Falls letzte Stelle 0 ist => Stellen um 1 erniedrigen *) END; END; (* ----------------------------------------------------------------------- *) (* MulCalcStr multiplizier2 zahl1 mit zahl2 *) PROCEDURE MulCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr); VAR hilfe : CalcStr; (* HilfsCalcString *) hilfe1 : CalcStr; (* HilfsCalcString *) hilfe2 : CalcStr; (* HilfsCalcString *) i, j : WORD; (* Z?hlvariablen *) wert : WORD; (* Wert von Zahl an der i.ten Stelle *) BEGIN IF LessCalcStr(zahl1, zahl2) THEN (* Falls zahl1 < zahl2 *) BEGIN hilfe1 := zahl1; (* Hilfe1 wird Zahl1 zugewiesen *) hilfe2 := zahl2; (* Hilfe2 wird Zahl2 zugewiesen *) END ELSE BEGIN hilfe2 := zahl1; (* Hilfe2 wird Zahl1 zugewiesen *) hilfe1 := zahl2; (* Hilfe1 wird Zahl2 zugewiesen *) END; ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *) IF ((hilfe1.stellen = 1) AND (hilfe1.zahl[1] = 0)) OR (hilfe1.stellen = 0) THEN ELSE (* Ergebnis=0, weil X * 0 = 0 *) BEGIN i := 1; (* i mit 1 initialisieren *) WHILE (i <= (hilfe1.stellen - 1)) DO (* Hilfe 1 abarbeiten *) BEGIN wert := hilfe1.zahl[i]; (* Wert = i.Zahl *) j := 1; (* j mit 1 initialisieren *) WHILE (j <= 16) DO (* alle Bits abarbeiten *) BEGIN IF (wert AND 1)> 0 THEN (* Falls 1.Bit gesetzt *) BEGIN AddCalcStr(ergebnis, hilfe2, hilfe); (* Ergebnis und Hilfe2 addieren *) ergebnis := hilfe; (* Ergebnis aus Addition *) END; wert := wert SHR 1; (* Wert DIV 2 *) Mul2CalcStr(hilfe2); (* Hilfe2 * 2 *) INC(j); (* j um 1 erh派en *) END; INC(i); (* i um 1 erh派en *) END; wert := hilfe1.zahl[hilfe1.stellen]; (* letzte Stelle behandeln *) WHILE wert> 0 DO (* Solange noch 1 Bit gesetzt ist *) BEGIN IF (wert AND 1)> 0 THEN (* Falls Bit 1 gesetzt ist *) BEGIN AddCalcStr(ergebnis, hilfe2, hilfe); (* Ergebnis und Hilfe2 addieren *) ergebnis := hilfe; (* Ergebnis aus Addition *) END; wert := wert SHR 1; (* Wert DIV 2 *) Mul2CalcStr(hilfe2); (* Hilfe2 * 2 *) END; END; END; (* ----------------------------------------------------------------------- *) (* DivCalcStr dividiert einen CalcString durch einen anderen *) FUNCTION DivCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr) : BOOLEAN; VAR hilfe : CalcStr; (* HilfsCalcString *) hilfe1 : CalcStr; (* HilfsCalcString *) hilfe2 : CalcStr; (* HilfsCalcString *) EINS : CalcStr; (* konstanter HilfsString f〉 1 *) BEGIN IF ((zahl2.stellen = 1) AND (zahl2.zahl[1] = 0)) OR (zahl2.stellen = 0) THEN DivCalcStr := FALSE (* Division durch 0 nicht m波lich *) ELSE BEGIN EINS := EMPTYCALCSTR; (* Eins initialisieren *) EINS.stellen := 1; (* Eins besitzt 1 Stelle *) EINS.zahl[1] := 1; (* diese wird mit 1 belegt *) ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *) hilfe1 := zahl1; (* Hilfe1 wird Zahl1 zugewiesen *) hilfe2 := zahl2; (* Hilfe2 wird Zahl2 zugewiesen *) WHILE NOT (GreaterCalcStr(hilfe2, hilfe1)) DO Mul2CalcStr(hilfe2); (* schiebe hilfe2 solange nach links, bis dividiert werden kann *) WHILE NOT (EqualCalcStr(hilfe2, zahl2)) DO (* Abbruchbedingung *) BEGIN Mul2CalcStr(ergebnis); (* Ergebnis mit 2 multiplizieren *) Div2CalcStr(hilfe2); (* Hilfe2 durch 2 dividieren *) IF NOT (GreaterCalcStr(hilfe2, hilfe1)) THEN (* falls hilfe2 nicht> hilfe1 *) BEGIN SubCalcStr(hilfe1, hilfe2, hilfe); (* Hilfe1 - Hilfe2 *) hilfe1 := hilfe; (* Hilfe1 wird Hilfe zugewiesen *) AddCalcStr(ergebnis, EINS, hilfe);(* zum Ergebnis 1 addieren *) ergebnis := hilfe; (* Ergebnis wird hilfe zugewiesen *) END; END; DivCalcStr := TRUE; (* Division erfolgreich *) END; END; (* ----------------------------------------------------------------------- *) (* ModCalcStr berechnet den Rest bei Division von Zahl1 durch Zahl2 *) FUNCTION ModCalcStr(VAR zahl1, zahl2 : CalcStr; VAR ergebnis : CalcStr) : BOOLEAN; VAR hilfe : CalcStr; (* HilfsCalcString *) hilfe1 : CalcStr; (* HilfsCalcString *) hilfe2 : CalcStr; (* HilfsCalcString *) EINS : CalcStr; (* konstanter HilfsString f〉 1 *) BEGIN IF ((zahl2.stellen = 1) AND (zahl2.zahl[1] = 0)) OR (zahl2.stellen = 0) THEN ModCalcStr := FALSE (* Division durch 0 nicht m波lich *) ELSE BEGIN EINS := EMPTYCALCSTR; (* Eins initialisieren *) EINS.stellen := 1; (* Eins besitzt 1 Stelle *) EINS.zahl[1] := 1; (* diese wird mit 1 belegt *) ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *) IF GreaterCalcStr(zahl2, zahl1) THEN (* falls Zahl2> Zahl1 *) ergebnis := zahl1 (* Ergebnis ist Zahl1 *) ELSE BEGIN hilfe1 := zahl1; (* Hilfe1 wird Zahl1 zugewiesen *) hilfe2 := zahl2; (* Hilfe2 wird Zahl2 zugewiesen *) WHILE NOT (GreaterCalcStr(hilfe2, hilfe1)) DO Mul2CalcStr(hilfe2); (* schiebe hilfe2 solange nach links, bis dividiert werden kann *) WHILE NOT (EqualCalcStr(hilfe2, zahl2)) DO (* Abbruchbedingung *) BEGIN Mul2CalcStr(ergebnis); (* Ergebnis mit 2 multiplizieren *) Div2CalcStr(hilfe2); (* Hilfe2 durch 2 dividieren *) IF NOT (GreaterCalcStr(hilfe2, hilfe1)) THEN (* falls hilfe2 nicht> hilfe1 *) BEGIN SubCalcStr(hilfe1, hilfe2, hilfe); (* Hilfe1 - Hilfe2 *) hilfe1 := hilfe; (* Hilfe1 wird Hilfe zugewiesen *) AddCalcStr(ergebnis, EINS, hilfe); (* zum Ergebnis 1 addieren *) ergebnis := hilfe; (* Ergebnis wird hilfe zugewiesen *) END; END; ModCalcStr := TRUE; (* Division erfolgreich *) END; END; END; (* ----------------------------------------------------------------------- *) (* ExptCalcStr berechnet Basis^Exponent *) PROCEDURE ExptCalcStr(VAR basis, exponent: CalcStr; VAR ergebnis : CalcStr); VAR hilfe : CalcStr; (* HilfsCalcString *) hilfe1 : CalcStr; (* HilfsCalcString *) i, j : WORD; (* Z?hlvariablen *) wert : WORD; (* Wert des Exponenten an der i.ten Stelle *) BEGIN ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *) ergebnis.stellen := 1; (* Ergebnis hat min. 1 Stelle *) ergebnis.zahl[1] := 1; (* Ergebnis>= 1 *) IF ((exponent.stellen = 1) AND (exponent.zahl[1] = 0)) OR (exponent.stellen = 0) THEN ELSE (* Exponent = 0 => Ergebnis = 1 *) BEGIN hilfe1 := basis; (* Hilfe1 wird Basis zugewiesen *) i := 1; (* i wird mit 1 initialisiert *) WHILE (i <= (exponent.stellen - 1)) DO (* Exponenten abarbeiten *) BEGIN wert := exponent.zahl[i]; (* i.te Stelle des Exponenten *) INC(i); (* i um 1 erh派en *) j := 1; (* j wird mit 1 initialisiert *) WHILE (j <= 16) DO (* alle Bits abarbeiten *) BEGIN IF (wert AND 1) = 1 THEN (* falls 1. Bit gesetzt ist *) MulCalcStr(ergebnis, hilfe1, ergebnis); (* Ergebnis mit Hilfe1 multiplizieren *) MulCalcStr(hilfe1, hilfe1, hilfe1); (* Hilfe1 quadrieren *) wert := wert SHR 1; (* Wert DIV 2 *) INC(j); (* 1 Bit weitergehen *) END; END; wert := exponent.zahl[exponent.stellen]; (* letzte Stelle behandeln *) WHILE (wert 0) DO (* solange noch 1 Bit gesetzt *) BEGIN IF (wert AND 1) = 1 THEN (* falls 1. Bit gesetzt ist *) MulCalcStr(ergebnis, hilfe1, ergebnis); (* Ergebnis mit Hilfe1 multiplizieren *) MulCalcStr(hilfe1, hilfe1, hilfe1); (* Hilfe1 quadrieren *) wert := wert SHR 1; (* Wert DIV 2 *) END; END; END; (* ----------------------------------------------------------------------- *) (* RandomCalcStr liefert eine Zufallszahl < calcZahl *) PROCEDURE RandomCalcStr(VAR calcZahl: CalcStr; VAR ergebnis : CalcStr); VAR i : WORD; (* Z?hlvariable *) BEGIN ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *) ergebnis.stellen := calcZahl.stellen; (* Annahme: Stellenzahl ist gleich *) FOR i := 1 TO (calcZahl.stellen - 1) DO ergebnis.zahl[i] := Random(65535); (* zuf?llige Zahl < 65535 *) ergebnis.zahl[ergebnis.stellen] := Random(calcZahl.zahl[calcZahl.stellen]); (* letzte Zahl mu? kleiner Ausgangszahl sein *) WHILE (ergebnis.zahl[ergebnis.stellen] = 0) AND (ergebnis.stellen> 1) DO DEC(ergebnis.stellen); (* f"rende Nullen abschneiden *) IF ((ergebnis.stellen = 1) AND (ergebnis.zahl[1] = 0)) OR (ergebnis.stellen = 0) THEN BEGIN (* Ergebnis darf nicht 0 sein *) ergebnis.stellen := 1; (* min. 1 Stelle *) ergebnis.zahl[1] := 1; (* diese mit 1 besetzen *) END; END; (* ----------------------------------------------------------------------- *) (* MulModCalcStr multipliziert ein Zahl modulo modul *) PROCEDURE MulModCalcStr(VAR zahl1, zahl2, modul : CalcStr; VAR ergebnis : CalcStr); VAR i, j : WORD; (* Z?hlvariablen *) wert : WORD; (* Wert von Zahl an i.ter Stelle *) hilfe : CalcStr; (* HilfsCalcString *) hilfe1 : CalcStr; (* HilfsCalcString *) hilfe2 : CalcStr; (* HilfsCalcString *) BEGIN IF LessCalcStr(zahl1, zahl2) THEN (* Falls Zahl1 < Zahl2 *) BEGIN ModCalcStr(zahl1, modul, hilfe1); (* Divisionsrest Zahl1/Modul *) ModCalcStr(zahl2, modul, hilfe2); (* Divisionsrest Zahl2/Modul *) END ELSE BEGIN ModCalcStr(zahl1, modul, hilfe2); (* Divisionsrest Zahl1/Modul *) ModCalcStr(zahl2, modul, hilfe1); (* Divisionsrest Zahl2/Modul *) END; ergebnis := EMPTYCALCSTR; (* ErgebnisCalcString initialisieren *) IF ((hilfe1.stellen = 1) AND (hilfe1.zahl[1] = 0)) OR (hilfe1.stellen = 0) THEN (* Hilfe1 mu? ungleich 0 sein *) ELSE BEGIN i := 1; (* i mit 1 initialisieren *) WHILE (i <= (hilfe1.stellen - 1)) DO (* alle Stellen von Hilfe1 abarbeiten *) BEGIN wert := hilfe1.zahl[i]; (* aktuellen Wert ermitteln *) j := 1; (* j mit 1 initialisieren *) WHILE (j <= 16) DO (* alle Bits abarbeiten *) BEGIN IF (wert AND 1)> 0 THEN (* Falls Bit 1 gesetzt ist *) BEGIN AddCalcStr(ergebnis, hilfe2, hilfe); (* Hilfe2 zum Ergebnis addieren *) ergebnis := hilfe; (* und dem Ergebnis zuweisen *) END; wert := wert SHR 1; (* Wert durch 2 dividieren *) Mul2CalcStr(hilfe2); (* Hilfe2 mit 2 multiplizieren *) INC(j); (* j um 1 erh派en *) END; INC(i); (* i um 1 erh派en *) END; wert := hilfe1.zahl[hilfe1.stellen]; (* letzte Zahl gesondert behandeln *) WHILE (wert> 0) DO (* solange noch ein Bit gesetzt *) BEGIN IF (wert AND 1)> 0 THEN (* Falls 1. Bit gesetzt ist *) BEGIN AddCalcStr(ergebnis, hilfe2, hilfe); (* Hilfe2 zum Ergebnis addieren *) ergebnis := hilfe; (* und dem Ergebnis zuweisen *) END; wert := wert SHR 1; (* Wert durch 2 dividieren *) Mul2CalcStr(hilfe2); (* Hilfe2 mit 2 multiplizieren *) END; END; hilfe1 := ergebnis; (* Hilfe1 wird Ergebnis zugewiesen *) ModCalcStr(hilfe1, modul, ergebnis); (* Divisionsrest hilfe1/Modul *) END; (* ----------------------------------------------------------------------- *) (* ExptModCalcStr berechnet basis^exponent MOD modul *) PROCEDURE ExptModCalcStr(VAR basis, exponent, modul : CalcStr; VAR ergebnis : CalcStr); VAR i, j : WORD; (* Z?hlvariablen *) wert : WORD; (* Wert von Zahl an i.ter Stelle *) hilfe : CalcStr; (* HilfsCalcString *) hilfe1 : CalcStr; (* HilfsCalcString *) BEGIN ergebnis := EMPTYCALCSTR; (* Ergebnis initialisieren *) ergebnis.stellen := 1; (* Ergebnis besitzt min. 1 Stelle *) ergebnis.zahl[1] := 1; (* Ergebnis hat mind. Wert 1 *) IF ((exponent.stellen = 1) AND (exponent.zahl[1] = 0)) OR (exponent.stellen = 0) THEN (* Exponent = 0 => Ergebnis = 1*) ELSE BEGIN ModCalcStr(basis, modul, hilfe1); (* Divisionsrest Basis/Modul *) i := 1; (* i mit 1 initialisieren *) WHILE (i <= (exponent.stellen - 1)) DO BEGIN wert := exponent.zahl[i]; (* Wert = i.te Stelle von Exponent *) j := 1; (* j mit 1 initialisieren *) WHILE (j <= 16) DO (* alle Bits abarbeiten *) BEGIN IF (wert AND 1)> 0 THEN (* Falls Bit 1 gesetzt ist *) BEGIN MulModCalcStr(ergebnis, hilfe1, modul, hilfe); (* Ergebnis * Hilfe1 MOD Modul *) ergebnis := hilfe; (* und dem Ergebnis zuweisen *) END; wert := wert SHR 1; (* Wert durch 2 dividieren *) MulModCalcStr(hilfe1, hilfe1, modul, hilfe); (* Hilfe1*Hilfe1 MOD Modul *) hilfe1 := hilfe; (* und wieder Hilfe1 zuweisen *) INC(j); (* j um 1 erh派en *) END; INC(i); (* 1 um 1 erh派en *) END; wert := exponent.zahl[exponent.stellen]; (* letzte Zahl gesondert behandeln *) WHILE (wert> 0) DO (* solange noch ein Bit gesetzt *) BEGIN IF (wert AND 1)> 0 THEN (* Falls 1. Bit gesetzt ist *) BEGIN MulModCalcStr(ergebnis, hilfe1, modul, hilfe); (* Hilfe1*Ergebnis MOD Modul *) ergebnis := hilfe; (* und dem Ergebnis zuweisen *) END; wert := wert SHR 1; (* Wert durch 2 dividieren *) MulModCalcStr(hilfe1, hilfe1, modul, hilfe); (* Hilfe1*Hilfe1 MOD Modul *) hilfe1 := hilfe; (* und wieder hilfe1 zuweisen *) END; END; END; (* ----------------------------------------------------------------------- *) BEGIN Randomize; (* Zufallsgenerator einschalten *) (* Initialiseren eines globalen Leerstrings *) WITH EMPTYCALCSTR DO (* Recordtyp abarbeiten *) BEGIN stellen := 0; (* L?nge ist 0 *) FOR i := 1 TO MAXCALCSTR DO zahl[i] := 0; (* zahl initialisieren *) END; (* Ende der Initialisierung *) END.