Langzahlen mit der Unit LZahl80
Der Zahlentyp Comp erfasst zwar die ganzen Zahlen in einem 18-stelligen Bereich lückenlos, stellt jedoch keine ganzzahlige Division mit Rest bereit. Eine solche steht in Delphi nur für Zahlen im Bereich von LongInt zur Verfügung.
Der Bereich der ganzen Zahlen des Typs LongInt reicht jedoch manchmal nicht aus. Er soll daher durch einen Typ LZahl erweitert werden. Von dem wir fordern:
1. Der Typ soll beliebig weit ausdehnbar sein,
2. Delphis Integertypen und Strings mit ganzen Zahlen sollen sich in Langzahlen wandeln lassen,
3. Langzahlen sollen sich als Dezimalzahlstrings ausgeben lassen,
4. Langzahlen sollen sich vergleichen lassen,
5. Eine Arithmetik mit Addition, Subtraktion, Multiplikation und ganzzahliger Division mit Rest
6. Ein reeller Quotient zweier Langzahlen soll gebildet werden können.
Naheliegend ist zunächst die Realisierung als Dualzahl in 2er-Komponentdarstellung, gespeichert in einem Array von Doppelworten. Dazu gibt Delphi jedoch kaum Unterstützung. Es fehlt schon ein vorzeichenloser Typ mit 32bit Breite, da Cardinal die Vorzeichenstelle von Integer nicht nutzt! Die
Unit wäre fast vollständig in Assembler zu schreiben, vom Debugger ist dann kaum noch eine brauchbare Unterstützung zu erwarten.
Die
Unit LZahl80 geht daher einen anderen Weg und definiert den Langzahlen Typ mit
Delphi-Quellcode:
const
N = 20; // für Stellenzahl 4*N = 80
type
LZahl = record // Zahlentyp Langzahl
s : boolean; // Vorzeichen
w : array[1..N] of word end; // Betrag, 4 Stellen/Word
Jedes Wort im Arrays enthält eine Langzahl-Stelle mit einem Stellenwert 0..9999, der 4 Dezimalstellen entspricht. Damit wird erreicht:
alle Operationen mit den Langzahl-Stellen können in Pascal geschrieben werden,
die Anzeige einer Langzahl im Debugger erscheint nahezu als Dezimalzahl, es fehlen in den Stellen nur die führenden Nullen.
Die Verbindung zwischen den Langzahlen und der übrigen Welt wird über Strings hergestellt mit
Delphi-Quellcode:
function LVal(s: string; var z: LZahl): integer; // String in Langzahl
procedure LStr(const z: LZahl; var s: string); // String aus Langzahl
Für Vergleiche von Langzahlen stehen zur Verfügung:
Delphi-Quellcode:
function LCompAbs(x, y : LZahl): integer; // Vergleich Betrag Langzahl
function LComp(x, y: LZahl): integer; // Vergleich von Langzahlen
Die Arithmetik von Langzahlen ist implementiert mit:
Delphi-Quellcode:
procedure LAbs(var z: LZahl); // Betrag einer Langzahl
procedure LNeg(var z: LZahl); // Negation einer Langzahl
function LAdd(var z: LZahl; x, y: LZahl): integer; // Addition
function LSub(var z: LZahl; x, y: LZahl): integer; // Subtraktion
function LMul(var z: LZahl; x, y: LZahl): integer; // Multiplikation
function LDiv(var z, Rest: LZahl; x, y: LZahl): integer; // Division mit Rest
function LQuotStr(var Q: string; x, y: LZahl; d: integer): integer; // Quotient
Die Funktionen geben einen Fehlercode 0 zurück, wenn sie fehlerfrei ausgeführt wurden. Man Beachte, dass das Ergebniss z in die Variablen x bzw. y der Operatoren eingeschrieben werden kann.
Zum Quotient zweier Langzahlen:
Es existiert kein Zahlentyp, der den Quotienten zweier Langzahlen mit durch die Operanden gegebenen Bereich und Genauigkeit aufnehmen kann. Daher stellt die Funktion LQuotStr diesen nur als String dar.
d ist die gewünschte Stellenzahl hinter dem Dezimalpunkt. Mit d=0 wird die durch die Operanden signifikante Anzahl von Stellen ausgegeben.
Anmerkung: Mit veränderter Konstanten N kann die
Unit für beliebige Stellenzahlen 4*N compiliert werden.
procedure LStr(const z: LZahl; var s: string); // String aus Langzahl
Überarbeitet, gibt jetzt immer einen String der Länge 4*N zurück, in dem die Zahl rechtsbündig steht.
Wieder zur Übernahme der Parameter über den Stack zurückgekehrt. Habe die Übernahme per const nicht gepackt.
Im Attachment der Code mit einem Testproramm.