aribas - Extras Springer

Werbung
DOKUMENTATION zum
ARIBAS Interpreter for Arithmetic, V1.0, Sep. 1996
written by 0. Forster, email [email protected]�
Beilage zum Buch
O. Forster: Algorithmische Zahlentheorie,
Vieweg-Verlag 1996, ISBN 3-528-06580-X
(*-------------------------------------------------------------*)
Inhalt
1)
2)
3)
4)
5)
6)
EINLEITUNG
BEZEICHNER (identifier)
DATENTYPEN
OPERATOREN
KONTROLL-STRUKTUREN
FUNKTIONS-REFERENZ
a) Funktionen fuer Integer-Arithmetik
b) Funktionen fuer Real-Arithmetik und Analysis
c) Random
d) Characters, Strings
e) Byte-Strings
f) Arrays
g) Stacks
h) In-Out
i) System-Funktionen
7) FUNKTIONS-DEFINITIONEN
8) VARIABLEN-DEKLARATIONEN
9) KOMANDOZEILEN-ARGUMENTE
(*-------------------------------------------------------------*)
1) EINLEITUNG
=============
ARIBAS ist ein interaktiver Interpreter, der vorallem fuer
Ganzzahl-Arithmetik grosser Zahlen und Multipraezisions-GleitkommaArithmetik geeignet ist. Nach dem Start zeigt ARIBAS ein Prompt ==>
und erwartet die Eingabe einer oder mehrerer durch ein Semicolon
getrennter Anweisungen oder Ausdruecke. Der Abschluss der Eingabe
erfolgt durch einen Punkt. Die Anweisungen werden dann der Reihe
nach ausgefuehrt und das Ergebnis der letzten Anweisung wird
nach dem Zeichen -: angezeigt. Danach erscheint wieder das
Prompt-Zeichen und es kann eine neue Eingabe erfolgen.
Beispiele:
==> 2*3 + 17.
-: 23
==> 2**1000.
-:
10_71508_60718_62673_20948_42504_90600_01810_56140_48117_05533_60744_3750
3_
88370_35105_11249_36122_49319_83788_15695_85812_75946_72917_55314_68251_8
7145_
28569_23140_43598_45775_74698_57480_39345_67774_82423_09854_21074_60506_2
3711_
41877_95418_21530_46474_98358_19412_67398_76755_91655_43946_07706_29145_7
1196_
47768_65421_67660_42983_16526_24386_83720_56680_69376
Der Operator ** bedeutet (wie z.B. in Fortran) Potenzierung.
Der Unterstrich _ wird zur Gliederung grosser ganzer Zahlen benuetzt.
==> x := 3; y := 4;
z := sqrt(x*x + y*y).
-: 5.00000000
Dies ist ein Beispiel fuer eine Folge von Anweisungen.
==> for k := 2 to 10 do
writeln(k:3,log(k):12:6);
end.
2
0.693147
3
1.098612
4
1.386294
5
1.609438
6
1.791759
7
1.945910
8
2.079442
9
2.197225
10
2.302585
Hier wurden als Nebenwirkung der writeln-Anweisungen (die FormatAngaben wie in Pascal gestatten) die natuerlichen Logarithmen der
Zahlen von 2 bis 10 ausgegeben. Diese Anweisung hat ein leeres
Ergebnis und ist nur wegen der Nebenwirkung interessant.
==> function fac(n: integer): integer;
var
x: integer;
begin
x := 1;
while n > 1 do
x := x*n;
dec(n);
end;
return x;
end.
-: fac
Diese Anweisung ist eine Funktions-Definition. Als Ergebnis erscheint
hier noch einmal der Funktions-Name. Danach steht diese Funktion zur
Benutzung zur Verfuegung:
==> fac(100).
-: 933_26215_44394_41526_81699_23885_62667_00490_71596_82643_81621_46859_
29638_95217_59999_32299_15608_94146_39761_56518_28625_36979_20827_22375_8
2511_
85210_91686_40000_00000_00000_00000_00000
Diese Beispiele dienten nur einer ersten kurzen Vorstellung von
ARIBAS. Fuer eine erste praktische Einfuehrung verweisen wir auf
das Tutorial.
Das folgende ist eine mehr systematische Beschreibung von ARIBAS.
2) BEZEICHNER (identifier)
==========================
Bezeichner (Namen von Variablen und Funktionen) koennen aus den
Buchstaben
a bis z und A bis Z, den Ziffern 0 bis 9 sowie dem Unterstrich _ gebildet
werden, das erste Zeichen muss ein Buchstabe oder der Unterstrich sein.
Beispiele fuer zulaessige Bezeichner:
x
x1
_alfa1
untere_Grenze
Ungueltige Bezeichner sind z.B. 1alpha, beta.2 oder gamma_$3. Ausserdem
duerfen in Bezeichnern keine Umlaute oder das scharfe s enthalten sein
und natuerlich keine eingebetteten Leerzeichen. Bezeichner duerfen
sich nicht ueber mehrere Zeilen erstrecken. Ansonsten ist die Laenge
beliebig. Alle Zeichen, sowie der Unterschied zwischen Gross- und
Kleinbuchstaben sind signifikant.
Die Bezeichner fuer selbstdefinierte Variable und Funktionen muessen
verschieden von den Schluesselwoertern von ARIBAS und den Namen
eingebauter Funktionen und Prozeduren sein. Eine Liste dieser
reservierten
Namen erhaelt man durch den Aufruf
==> symbols(aribas).
-: (ARGV, _, __, ___, abs, alloc, and, arccos, arcsin, arctan, arctan2,
aribas,
array, atof, atoi, begin, binary, bit_and, bit_clear, bit_length,
bit_not,
bit_or, bit_set, bit_shift, bit_test, bit_xor, boolean, break, by,
byte_length,
byte_string, cardinal, cf_factorize, char, chr, close, concat, const,
cos,
create_array, dec, decode_float, div, do, double_float, else, elsif, end,
even,
exit, exp, extended_float, external, factor16, factorial, false, file,
float,
float_ecvt, floor, flush, for, frac, ftoa, function, gc, gcd, gcdx,
get_filepos, get_floatprec, get_key, get_printbase, halt, help, if, inc,
integer, isqrt, itoa, jacobi, length, load, load_edit, log, long_float,
make_unbound, max, mem_and, mem_bclear, mem_bitswap, mem_bset, mem_btest,
mem_byteswap, mem_not, mem_or, mem_shift, mem_xor, memavail, min, mod,
mod_coshmult, mod_inverse, mod_pemult, new, nil, not, odd, of,
open_append,
open_read, open_write, or, ord, pi, pointer, prime32test, procedure,
product,
protocol, rab_primetest, random, random_seed, read_block, read_byte,
readln,
real, record, return, rewind, rho_factorize, round, save_input,
set_filepos,
set_floatprec, set_printbase, short_float, sin, single_float, sort, sqrt,
stack, stack2array, stack_empty, stack_pop, stack_push, stack_reset,
stack_top,
stderr, stdin, stdout, string, string_split, substr_index, sum, symbols,
system, tan, then, timer, to, tolower, toupper, true, trunc, type, user,
var,
while, write, write_block, write_byte, writeln)
Die Zeichen _, __, ___ sind System-Variablen, die jeweils das letzte,
das vorletzte und das drittletzte Ergebnis enthalten.
Beispiel:
==> sqrt(2).
-: 1.41421356
==> sqrt(_).
-: 1.18920711
==> sqrt(_).
-: 1.09050773
==> _ * __ * ___.
-: 1.83400808
==> _ ** (8/7).
-: 2.00000000
Hier wurden der Reihe nach die Quadratwurzel, die vierte Wurzel und
die achte Wurzel aus 2 berechnet und dann miteinander multipliziert.
Das Ergebnis ist 2 hoch 7/8. Dies Resultat hoch 8/7 muss also wieder
2 ergeben. (Der Potenz-Operator in ARIBAS ist **).
Kommentare
---------Text, der zwischen den Zeichen (* und *) eingeschlossen ist, wird von
ARIBAS als Kommentar angesehen und ueberlesen. Kommentare duerfen sich
ueber mehrere Zeilen erstrecken. Ineinander geschachtelte Kommentare
sind nicht zulaessig.
3) DATENTYPEN
=============
In ARIBAS werden folgende Datentypen unterstuetzt:
integer
real
boolean
char
string
byte_string
array
stack
file
function
(*----------------------------------------------------------------*)
integer
Der Datentyp integer umfasst die ganzen Zahlen, die in ARIBAS bis
zu einer Groesse von 2**16 Binaerstellen verarbeitet werden koennen.
Integer-Literale werden gegeben durch ein optionales Vorzeichen
und eine nichtleere Folge von Dezimalziffern. Zur Gliederung laengerer
Zahlen kann der Unterstrich _ verwendet werden. In diesem Fall muss
unmittelbar vor und nach dem Unterstrich eine Ziffer stehen. Beispiele
fuer Integer-Literale:
1
1234567890
-3456_78965_12367
Ausser der Dezimal-Darstellung ist auch die Darstellung mit den
Basen 2, 8 oder 16 moeglich. Fuer die Basis 2 ist vor die Folge der
Binaerziffern (0 und 1) die Zeichenfolge 0y zu setzen, fuer die
Basis 16 vor die Folge der Hexadezimalziffern (0 ... 9, A ... F)
die Zeichenfolge 0x. Die Basis 8 wird durch das Praefix 0o
gekennzeichnet.
Ein eventuelles Vorzeichen steht noch vor 0y, 0o bzw. 0x. Beispiele:
0y111101
0o177
0xFFFFF_FFFFE
-0x123456789ABCDEF
(*----------------------------------------------------------------*)
real
Der Datentyp real umfasst eine Computer-Approximation der reellen Zahlen.
Real-Literale werden gegben durch eine endliche Dezimal-Darstellung
mit einem optionalen Vorzeichen + oder -, anschliessend eine
nichtleere Folge von Dezimalziffern, einem obligatorischen Dezimalpunkt und eine weitere nichtleere Folge von Dezimalziffern sowie
optional eine Exponenten-Angabe, die aus dem Zeichen E und einer
ganzen Zahl (mit optionalem Vorzeichen) in Dezimaldarstellung besteht.
Beispiele fuer real-Literale sind
0.3
+3.1e-45
-0.00007E1000
Unzulaessig sind z.B. die Darstellungen .333 oder 333e-3. (Die damit
gemeinte Zahl kann z.B. durch 0.333 oder 333.0e-3 dargestellt werden.)
Intern werden Zahlen vom Typ real binaer gespeichert (woraus z.B.
folgt, dass selbst eine so einfache Zahl wie 0.1 nicht exakt
dargestellt werden kann). Die Genauigkeit, mit der mit Real-Zahlen
gerechnet wird, haengt von der jeweils eingestellten floatprecision
ab (defaultmaessig wird mit einer Mantisse von 32 Binaerstellen
gearbeitet). Genaueres hierzu findet sich in der Funktions-Referenz
unter set_floatprec und get_floatprec.
(*----------------------------------------------------------------*)
boolean
Der Datentyp boolean umfasst die Wahrheitswerte false und true.
Die logischen Operatoren not, and und or wirken nach den ueblichen
Regeln auf boolesche Variable. Boolesche Werte entstehen z.B. auch
als Ergebnisse von Vergleichs-Operatoren und werden in den
Bedingungen fuer if- und while-Konstruktionen benuetzt.
Ueberall, wo in ARIBAS ein boolescher Wert erwartet wird, kann auch
ein integer-Wert eingegeben werden. Dabei wird (wie in der Programmiersprache C) der Wert 0 als false, und jeder Wert ungleich 0 als true
interpretiert.
(*----------------------------------------------------------------*)
char
Der Datentyp char (Character) umfasst 256 Zeichen, die nach ihrem
Ascii-Code (0 bis 255) geordnet sind. Character-Literale von druckbaren
Zeichen (Ascii-Code >= 32) werden durch Einschluss des Zeichens in
Hochkommata gegeben, z.B. 'A'. Die Funktion chr verwandelt IntegerWerte aus dem Intervall 0 bis 255 in Characters mit dem entsprechenden
Ascii-Code. Dadurch lassen sich auch Characters erzeugen, die nicht zu
druckbaren Zeichen gehoeren.
(*----------------------------------------------------------------*)
string
Der Datentyp string umfasst Folgen von Characters und dient zur
Darstellung von Text. String-Literale werden durch Einschluss der
Zeichenfolge in Anfuehrungszeichen " gegeben, z.B. "ABC".
Auf die einzelnen Zeichen des Strings kann wie folgt zugegriffen
werden:
==> s := "abcdef";
s[3].
-: 'd'
Die Numerierung beginnt bei 0, das letzte Zeichen hat den Index
n-1, wenn n die Laenge des Strings ist.
(*----------------------------------------------------------------*)
byte_string
Der Datentyp byte_string ist ein Array-Typ, der alle endlichen Folgen
von Bytes umfasst (koennte in Pascal etwa als packed array of byte
umschrieben werden). byte_string-Literale werden in der Form
$XXXXXX...XX gegeben, wobei XX fuer die hexadezimale Darstellung
der Bytes (integers zwischen 0 und 255 einschliesslich) steht. Der
Unterstrich _ kann zur Gliederung eingesetzt werden.
Beispielsweise wird durch
==> B := $0080_12FF78.
-: $0080_12FF_78
ein byte_string der Laenge 6 definiert. Auf die einzelnen Komponenten
kann wie bei Strings zugegriffen werden:
==> B[1].
-: 128
==> B[3].
-: 255
byte_strings koennen in Binaer-Dateien geschrieben und aus solchen
gelesen werden (Funktionen write_block und read_block, siehe weiter
unten) und dienen so dem Daten-Austausch von ARIBAS mit der Aussenwelt.
Es existieren Umwandlungs-Funktionen von integers in byte_strings
und umgekehrt.
(*----------------------------------------------------------------*)
array of Type
Beim allgemeinen Array-Typ koennen die Komponenten einen
beliebigen Datentyp Type haben, z.B. selbst wieder Arrays oder
Strings sein. Array-Literale werden durch Aufzaehlung der
Komponenten zwischen runden Klammern wie im folgenden Beispiel
gegeben.
vec := (37, 41, -9).
Bei Arrays der Laenge 1 sind statt der runden Klammern geschweifte
Klammern zu verwenden.
vec1 := {37}.
Der Ausdruck (37) wuerde einfach als die Zahl 37 interpretiert.
Auch bei Arrays der Laenge > 1 duerfen geschweifte Klammern
verwendet werden.
(*----------------------------------------------------------------*)
stack
In ARIBAS gibt es einen vordefinierten Datentyp stack mit den
Funktionen stack_push, stack_pop, stack_top, stack_rest, stack_empty
stack2array und length (siehe weiter unten in der Funktions-Referenz).
Ein stack kann z.B. guenstig eingesetzt werden zur Zwischenspeicherung
von Objekten (beliebigen Datentyps), deren Anzahl a priori noch unbekannt
ist (etwa die Primfaktoren einer ganzen Zahl).
(*----------------------------------------------------------------*)
file
Datentyp file: ARIBAS unterstuetzt Text-Files und Binaer-Files.
Siehe Funktions-Referenz unter In-Out.
(*----------------------------------------------------------------*)
function
Datentyp function: Benutzerdefinierte und eingebaute Funktionen
(ausser write und writeln) koennen Variablen zugewiesen werden
und als Argumente anderen Funktionen uebergeben werden.
Beispiel:
==> F := (cos,sin,tan).
-: (cos, sin, tan)
==> for i := 0 to length(F)-1 do
fun := F[i];
writeln(fun(pi/6));
end.
0.866025404
0.500000000
0.577350269
(*----------------------------------------------------------------*)
Selbstdefinierte Datentypen: Ausser den eingebauten Datentypen
koennen in ARIBAS neue Datentypen definiert werden. Dazu stehen
records und pointer zur Verfuegung (noch undokumentiert).
(*----------------------------------------------------------------*)
4) OPERATOREN
=============
Der Zuweisungs-Operator :=
-------------------------Eine Zuweisung hat die Gestalt
<variable> := <expression>
Dabei wird der Ausdruck <expression> berechnet. Das Resultat wird
der Variablen <variable> zugewiesen. Im allgemeinen ist <variable>
ein einfacher Bezeichner, kann aber auch ein Array-Element oder ein
Subarray sein. Der Datentyp von <expression> muss zuweisungskompatibel
zum Datentyp von <variable> sein. Auf dem Top-Level (d.h. ausserhalb
von Funktionsdefinitionen) kann <variable> auch ein noch nicht
deklarierter ungebundener Bezeichner sein. Durch die Zuweisung wird
der Bezeichner dann implizit als Variable des passenden Datentyps
deklariert.
Die Zuweisung als Ganzes ist ein Ausdruck, dessen Wert gleich dem
Wert von <expression> ist. Der Zuweisungs-Operator ist (wie in C)
rechts-assoziativ, so dass Mehrfach-Zuweisungen moeglich sind, wie
<variable1> := <variable2> := <expression>
Bei Zuweisungen von Arrays (etwa vec1 := vec2) wird stets eine
neue Kopie (hier von vec2) gefertigt (es handelt sich nicht, wie
etwa in C, um eine Zuweisung von Pointern). Arrays verschiedener
Laenge sind zuweisungs-kompatibel. Beispiel:
==> vec1 := (1,2,3).
-: (1, 2, 3)
==> vec2 := (4,5,6,7).
-: (4, 5, 6, 7).
Jetzt ist die Zuweisung vec1 := vec2 moeglich:
==> vec1 := vec2.
-: (4, 5, 6, 7).
Wird danach vec2 veraendert,
==> vec2[2] := -1.
-: -1
so bleibt vec1 davon unberuehrt.
==> vec2.
-: (4, 5, -1, 7)
==> vec1.
-: (4, 5, 6, 7)
Arithmetische Operatoren
-----------------------+, -, *, **, /, div, mod
+ und - sind sowohl unaere Operatoren (als Praefix) als auch binaere
Operatoren (Infix). Als binaere Operatoren sind sie links-assoziativ.
Die Operanden duerfen integers oder reals sein. Ist einer der Operanden
ein integer, der andere ein real, so erfolgt eine implizite Umwandlung
des integers in den Typ real.
* bezeichnet die Multiplikation und ist ein binaerer links-assoziativer
Infix-Operator, der ebenfalls auf integers und reals anwendbar ist.
** ist der Potenzierungs-Operator. Er ist binaer und rechts-assoziativ.
Die Operanden koennen integers oder reals sein. Ist in dem Ausdruck
x ** y die Basis x ein integer und der Exponent y eine nicht-negative
ganze Zahl, so ist das Resultat wieder ein integer; in allen anderen
Faellen ein real. Ist der Exponent negativ, so muss die Basis ungleich
0 sein. Ist der Exponent ein real, so muss die Basis positiv sein.
Der binaere, links-assoziative Operator / bezeichnet die Division.
Die Operanden koennen integers oder reals sein; das Resultat ist
stets ein real. Division durch 0 ist nicht zugelassen.
div und mod sind binaere, links-assoziative Operatoren, die nur auf
integers anwendbar sind und als Resultat einen integer liefern.
x div y ist die groesste ganze Zahl kleiner-gleich x/y. Der Operator
mod ist durch die Gleichung
x = (x div y) * y + (x mod y)
definiert. Der Divisor y muss ungleich 0 sein.
Vergleichs-Operatoren
--------------------=, /= oder <>, <, <=, >, >=
Alle Vergleichs-Operatoren sind binaere Infix-Operatoren und liefern
einen Booleschen Wert (true oder false) als Ergebnis.
Die Operatoren = (gleich) und /=, <> (zwei Synonyme fuer ungleich)
koennen auf Operanden beliebigen Typs angewendet werden.
Mit den Operatoren < (keiner), <= (kleiner-gleich), > (groesser),
>= (groesser-gleich) koennen Zahlen (integer oder real) miteinander
verglichen werden, ausserdem Characters und Strings. In den letzten
beiden Faellen erfolgt der Vergleich anhand des Ascii-Codes.
Boolesche Operatoren
-------------------not, and, or
not ist ein unaerer Praefix-Operator, and und or sind binaere InfixOperatoren, die auf Boolesche Ausdruecke anwendbar sind. Die Auswertung
der Argumente von and und or erfolgt von links nach rechts und wird
abgebrochen, sobald das Resultat feststeht.
Damit ist dann ein Ausdruck wie
u > 0 and v/u < 1
zulaessig, der einen Fehler erzeugen wuerde, falls u = 0 ist und
immer beide Argumente des and-Operators ausgewertet wuerden.
Vorrang von Operatoren
---------------------Bei der Bildung von zusammengesetzten Ausdruecken koennen Klammern
eingespart werden, wenn man den Vorrang von Operatoren beruecksichtigt.
Sie sind wie folgt nach absteigender Bindungskraft in Klassen eingeteilt:
1.
2.
3.
4.
5.
6.
7.
8.
Potenz-Operator
Unaeres Minus und Plus
Multiplikations- und Divisions-Operatoren *, /, div, mod
Binaeres Plus und Minus
Vergleichs-Operatoren
Boolescher Operator not
Boolesche Operatoren and und or
Zuweisungs-Operator
Beispiel:
bvar := not x < y and y < z
bedeutet dasselbe wie
bvar := ((not (x < y)) and (y < z))
(*-----------------------------------------------------------*)
5) KONTROLL-STRUKTUREN
======================
if then elsif else end
while do end
for to by do end
break
(*-----------------------------------------------------------------*)
if <bool expr> then
<statement-list>
elsif <bool expr> then
<statement-list>
else
<statement-list>
end;
Es koennen auch mehrere (oder null) elsif-Teile vorkommen.
Der else-Teil kann auch fehlen.
Beispiel:
function sign(x: real): integer;
begin
if x > 0 then
return 1;
elsif x < 0 then
return -1;
else
return 0;
end;
end;
*-----------------------------------------------------------------*)
while <boolean expr> do
<statement-list>
end;
Ist der Boolesche Ausdruck <boolean expr> wahr, wird die
Anweisungsfolge <statement-list> ausgefuehrt (diese kann den
Wert von <boolean expr> aendern). Ist danach <boolean expr>
immer noch wahr, wird <statement-list> erneut ausgefuehrt.
Dies wird solange wiederholt, bis <boolean expr> falsch wird,
oder die while-Schleife durch ein return-statement oder
break-statement verlassen wird.
*-----------------------------------------------------------------*)
for Laufvar := Start to End do
<statement-list>
end;
Laufvar muss eine Integer-Variable sein, Start und End
Integer-Ausdruecke. Diese werden beim 1. Betreten der for-Schleife
ausgewertet. Dann wird die <statement-list> der Reihe nach
fuer die Start, Start+1, ..., End ausgefuehrt. Falls End < Start,
wird die <statement-list> ueberhaupt nicht ausgefuehrt.
for Laufvar := Start to End by Incr do
<statement-list>
end;
Hier ist zusaetzlich ein Integer-Ausdruck Incr gegeben, der
ebenfalls zu Beginn ausgewertet wird und einen Wert /= 0
ergeben muss. Ist Incr > 0 und End >= Start, wird die
<statement-list> fuer Start + k*Incr, k=0,1,..., ausgefuehrt,
solange Start + k*Incr <= End.
Ist Incr < 0 und End, wird die <statement-list> ausgefuehrt
fuer Start + k*Incr, k=0,1,..., ausgefuehrt, solange
Start + k*Incr >= End.
Beispiel:
==> for k := 11 to 0 by -2 do
write(k,"; ");
end.
erzeugt die Ausgbabe
11; 9; 7; 5; 3; 1;
*-----------------------------------------------------------------*)
break
Der Befehl break bewirkt (wie in der Programmiersprache C)
ein unmittelbares Verlassen einer while- oder for-Schleife.
Beispiel:
==> for x := 10**7+1 to 10**8 by 2 do
if factor16(x) = 0 then break; end;
end;
x.
-: 10000019
*-----------------------------------------------------------------*)
Es gibt in ARIBAS kein repeat .. until
Diese Kontrollstruktur kann man immer durch geeignete
while-Konstruktionen ersetzen.
*-----------------------------------------------------------------*)
6) FUNKTIONS-REFERENZ
=====================
a) Funktionen fuer Integer-Arithmetik
=====================================
set_printbase
get_printbase
sum
product
odd
even
abs
max
min
inc
dec
gcd
gcdx
isqrt
factorial
mod_coshmult
mod_pemult
mod_inverse
jacobi
factor16
prime32test
rab_primetest
rho_factorize
cf_factorize
(*----------------------------------------------------------------*)
set_printbase(b: integer): integer;
b muss eine der Zahlen 2, 8, 10, 16 sein.
Die Funktion bewirkt, dass nachfolgende Ausgaben von Integern in der
Basis b erfolgen.
Das Funktionsergebnis ist die neu eingestellte printbase.
(Falls b nicht zulaessig ist, bleibt die bisherige Einstellung
unveraendert.)
(*----------------------------------------------------------------*)
get_printbase(): integer;
Liefert als Funktions-Ergebnis die derzeit gueltige printbase.
(*----------------------------------------------------------------*)
sum(vec: array of integer): integer;
sum(vec: array of real): real;
product(vec: array of integer): integer;
product(vec: array of real): real;
Liefert die Summe bzw. das Produkt aller Komponenten von vec.
(*----------------------------------------------------------------*)
even(x: integer): boolean;
odd(x: integer): boolean;
Stellt fest, ob x gerade bzw. ungerade ist.
(*----------------------------------------------------------------*)
max(x1,...,xn: integer): integer;
max(x1,...,xn: real): real;
min(x1,...,xn: integer): integer;
min(x1,...,xn: real): real;
Ergibt das Maximum (Minimum) der Argumente x1,...,xn.
(*----------------------------------------------------------------*)
max(vec: array of integer): integer;
max(vec: array of real): real;
Ergibt das Maximum (Minimum) der Komponenten von vec.
(*----------------------------------------------------------------*)
inc(var x: integer [; delta: integer]): integer;
Erhoeht die Integer-Variable x um delta (Defaultwert delta = 1).
Rueckgabewert ist der neue Wert von x.
(*----------------------------------------------------------*)
dec(var x: integer [; delta: integer]): integer;
Vermindert die Integer-Variable x um delta (Defaultwert delta = 1).
Rueckgabewert ist der neue Wert von x.
(*----------------------------------------------------------*)
gcd(x1,...,xn: integer): integer;
Liefert den groessten gemeinsamen Teiler der Zahlen x1,x2,...,xn.
Fuer n = 1 ist gcd(x) = x; fuer n = 0 ergibt sich gcd() = 0.
(*----------------------------------------------------------*)
gcdx(x,y: integer; var u,v: integer): integer;
Liefert den groessten gemeinsamen Teiler d von x und y.
Gleichzeitig werden in den Variablen u und v Werte abgelegt,
so dass
d = u*x + v*y
(*----------------------------------------------------------*)
mod_inverse(x, mm: integer): integer;
Liefert das Inverse von x modulo mm, falls x zu mm teilerfremd ist.
Andernfalls wird 0 zurueckgegeben; Beispiele:
==> mod_inverse(17,100).
-: 53
==> mod_inverse(18,100).
-: 0
(*----------------------------------------------------------*)
isqrt(x: integer): integer;
Liefert fuer eine ganze Zahl x >= 0 die groesste ganze Zahl y
mit y*y <= x.
(*----------------------------------------------------------*)
factorial(n: integer): integer;
Das Argument n muss eine nicht-negative ganze Zahl sein.
Berechnet n! (n Fakultaet). Beispiel:
==> factorial(8).
-: 40320
(*----------------------------------------------------------*)
mod_coshmult(x,s,mm: integer): integer;
Ist x eine ganze Zahl und xi so gewaehlt, dass cosh(xi) = x,
so ist fuer jede natuerliche Zahl s auch cosh(s*xi) eine
ganze Zahl. Diese Zahl modulo mm ist das Funktions-Ergebnis.
Das Funktions-Ergebnis kann auch durch folgende rekursiv
definierte (Lucas-)Folge ermittelt werden:
a(0) = 1;
a(1) = x;
a(k+2) = 2*x*a(k+1) - a(k);
Dann ist a(s) mod mm das Funktions-Ergebnis.
(*----------------------------------------------------------*)
mod_pemult(x,s,a,mm: integer): array[2] of integer;
Sei pe die Weierstrasssche pe-Funktion zur elliptischen Kurve E(a)
y*y = x*x*x + a*x*x + x
Sei xi ein Punkt der Kurve mit pe(xi) = x. Dann ist s*xi wieder
ein Kurvenpunkt von E(a) (bzgl. der Struktur von E(a) als abelsche
Gruppe), so dass entweder s*xi eine Polstelle von pe ist oder
pe(s*xi) = u/v eine rationale Zahl ist. (Es werden u und v als
teilerfremd angenommen.) Ist im zweiten Fall v teilerfremd zu mm,
so ist das Funktions-Ergebnis (z,1), wobei z = u/v mod mm.
Haben v und mm einen gemeinsamen Teiler d > 1, so ist das
Funktions-Ergebnis (d,0). Ist schliesslich s*xi ein Pol von pe,
so ist das Funktions-Ergebnis (mm,0).
Diese Funktion ist nuetzlich fuer die Faktorisierung ganzer Zahlen
mittels elliptischer Kurven.
(*----------------------------------------------------------*)
factor16(x [,x0 [,x1]]: integer): integer;
Stellt fest, ob die Zahl x einen Primteiler < min(2**16,x) hat.
Das Funktionsergebnis von factor16(x) ist der kleinste solche
Primteiler, falls es ihn gibt, sonst 0. Sind die optionalen
Argumente x0 bzw. x0 und x1 angegeben, so werden nur Primteiler p
mit p >= x0 bzw. x0 <= p <= x1 gesucht.
(*----------------------------------------------------------*)
prime32test(x: integer): integer;
Testet, ob x eine Primzahl < 2**32 ist. (Ein eventuelles Vorzeichen von x wird ignoriert.) Ist dies der Fall, wird 1 zurueckgegeben. Ist abs(x) < 2**32, aber keine Primzahl, ist
das Resultat 0. Falls abs(x) >= 2**32, wird -1 zurueckgegeben.
(*----------------------------------------------------------*)
rab_primetest(x: integer): boolean;
Fuehrt den Rabinschen Pseudo-Primzahltest fuer die Zahl x aus.
Ist das Ergebnis false, so ist x sicher keine Primzahl.
Eine Zahl x, fuer die factor16(x) = 0 und rab_primetest(x) = true,
ist mit grosser Wahrscheinlichkeit eine Primzahl. Zur Erhoehung
der Wahrscheinlichkeit kann der Test wiederholt werden.
(*----------------------------------------------------------*)
jacobi(a,m: integer): integer;
Liefert das Jacobi-Symbol von a ueber m. Der Modul m muss
eine ungerade Zahl sein; a kann eine beliebige ganze Zahl sein,
der Wert der Jacobi-Funktion haengt aber nur von a mod m ab.
Sind a und m nicht teilerfremd, ist das Resultat 0, sonst +1 oder -1.
Ist p eine Primzahl und a mod p /= 0, so ist jacobi(a,p) genau
dann gleich +1, falls a quadratischer Rest modulo p ist.
(*----------------------------------------------------------*)
rho_factorize(x:integer [; b: integer]): integer;
Versucht, die Zahl x nach dem Pollardschen rho-Algorithmus zu
faktorisieren. Das optionale Argument b ist eine Schranke fuer
die maximale Anzahl der Schritte; wird es nicht angegeben, so
wird defaultmaessig b = 2**16 - 1 gesetzt. Findet der Algorithmus
einen Faktor, so wird dieser zurueckgegeben; bei Misserfolg
ist das Ergebnis 0. Unter unguenstigen Umstaenden kann das FunktionsErgebnis auch x sein. Damit das Verfahren gut funktioniert,
sollte x frei von kleinen Primfaktoren (z.B. < 1000) sein.
Hat x dann einen Primfaktor p, so wird dieser im allgemeinen
gefunden, wenn b > sqrt(p) ist. Ist das Funktions-Ergebnis y > 1
und < x, so ist y sicher ein Faktor von x, aber nicht notwendig
prim.
(*----------------------------------------------------------*)
cf_factorize(x: integer [; m: integer]): integer;
Versucht, x nach dem Kettenbruch-Algorithmus von Brillhart-Morrison
zu faktorisieren. Die Laufzeit haengt nicht von der Groesse der
Primfaktoren von x ab. (Ist also bekannt, dass x kleine Primfaktoren
besitzt, sollte besser ein anderes Faktorisierungs-Verfahren
benutzt werden.) Unter unguenstigen Umstaenden (z.B. wenn die
Kettenbruch-Entwicklung von sqrt(x) eine zu kurze Periode hat),
scheitert das Verfahren. Fuer diesen Fall kann man cf_factorize
mit einem 2. Argument m, das eine ganze Zahl 1 <= m < 1024 sein
muss, aufrufen. Es wird dann die Kettenbruch-Enwicklung von
sqrt(m*x) benutzt.
(*----------------------------------------------------------*)
Bit-Operationen fuer ganze Zahlen
bit_test
bit_set
bit_clear
bit_shift
bit_not
bit_and
bit_or
bit_xor
bit_length
byte_length
Die Bit-Operationen koennen auf alle Integers, positiv oder
negativ angewendet werden. Dabei werden die negativen Integers
in Zweier-Komplement-Darstellung gedacht, wobei sich das Vorzeichen-Bit
links nach unendlich erstreckt. Beispielsweise hat die Zahl -1 das
Bit-Muster
......11111111111111111111111111111111
(*----------------------------------------------------------------*)
bit_test(x,n: integer): integer;
Liefert 1, wenn in x das Bit an Position n gesetzt ist, sonst 0.
Die Position wird von 0 an gezaehlt.
Beispielsweise gilt bit_test(x,0) = 1 genau dann, wenn x ungerade ist.
(*----------------------------------------------------------------*)
bit_set(x,n: integer): integer;
Setzt in x das Bit in Position n auf 1.
(*----------------------------------------------------------------*)
bit_clear(x,n: integer): integer;
Setzt in x das Bit in Position n auf 0.
(*----------------------------------------------------------------*)
bit_shift(x,n: integer): integer;
Die Zahl n kann positiv oder negativ sein. Fuer n >= 0 bedeutet
bit_shift(x,n) einen Shift der Bit-Darstellung von x um n Stellen
nach links; dies ist gleichbedeutend mit einer Multiplikation
mit 2**n. Fuer n < 0 ist ein Shift um abs(n) Stellen nach rechts;
gleichbedeutend mit x div 2**abs(n).
(*----------------------------------------------------------------*)
bit_not(x: integer): integer;
Invertiert alle Bits von x. Gleichbedeutend mit -x-1.
(*----------------------------------------------------------------*)
bit_and(x,y: integer): integer;
bit_or(x,y: integer): integer;
bit_xor(x,y: integer): integer;
Bitweises und, oder bzw. exklusives oder von x und y.
Beispielsweise ist bit_and(x,3) aequivalent mit x mod 4.
(*----------------------------------------------------------------*)
bit_length(x: integer): integer;
Liefert die kleinste natuerliche Zahl n, so dass abs(x) < 2**n
(*----------------------------------------------------------------*)
byte_length(x: integer): integer;
Liefert die kleinste natuerliche Zahl n, so dass abs(x) < (2**8)**n,
d.h. die Anzahl der Bytes, die zur binaeren Darstellung von abs(x)
noetig sind.
(*----------------------------------------------------------------*)
b) Funktionen fuer Real-Arithmetik und Analysis
===============================================
round
floor
trunc
frac
set_floatprec
get_floatprec
decode_float
float
sqrt
exp
log
sin
cos
tan
arctan
arctan2
arcsin
arccos
pi
(*----------------------------------------------------------------*)
floor(x: real): integer;
Ergibt die groesste ganze Zahl <= x. Beispiele:
==> floor(pi).
-: 3
==> floor(-pi).
-: -4
(*----------------------------------------------------------------*)
trunc(x: real): integer;
Fuer x >= 0 identisch mit floor(x).
Falls x < 0, wird die kleinste ganze Zahl n >= x zurueckgegeben.
Beispiele:
==> trunc(pi).
-: 3
==> trunc(-pi).
-: -3
(*----------------------------------------------------------------*)
frac(x: real): real;
Definiert durch die Gleichung
x = trunc(x) + frac(x)
Beispiel:
==> frac(1.23).
-: 0.230000000
==> frac(-1.23).
-: -0.230000000
(*----------------------------------------------------------------*)
round(x: real): integer;
Rundet x auf die naechste ganze Zahl n.
Ist x genau in der Mitte zwischen zwei ganzen Zahlen,
wird zur geraden Zahl gerundet. Beispiele:
==> round(pi).
-: 3
==> round(3.5).
-: 4
(*----------------------------------------------------------------*)
set_floatprec(bb: integer): integer;
set_floatprec(Floattype): integer;
Diese Funktion dient zum Einstellen der Genauigkeit (in bits) mit
der anschliessend mit reals gerechnet wird. Es stehen folgende
Moeglichkeiten fuer Floattype zur Verfuegung:
short_float:
17 bits
single_float:
32 bits
double_float:
64 bits
long_float:
128 bits
extended_float: 192 bits
Als Argument ist entweder das entsprechende Symbol oder ein Integer bb
einzugeben. Falls die Zahl bb nicht unter den zur Verfuegung stehenden
Zahlen vorkommt, wird auf die naechst groessere gerundet. Rueckgabewert ist die neu eingestellte Genauigkeit.
Beispiel:
==> set_floatprec(long_float).
-: 128
==> exp(pi*sqrt(163)).
-: 262537412640768743.999999999999250073
==> 2**0.5.
-: 1.41421356237309504880168872420969808
(*----------------------------------------------------------------*)
get_floatprec(): integer;
get_floatprec(x: real): integer;
In der ersten Form (ohne Argument) liefert die Funktion die derzeit
eingestellte Genauigkeit fuer Float-Berechnungen (in bits, also
eine der Zahlen 17, 32, 64, 128, 192). Ist das Argument eine Real-Zahl
x, so wird die Genauigkeit, mit der diese Zahl gespeichert ist,
zurueckgegeben.
Beispiel:
==> set_floatprec(50).
-: 64
==> get_floatprec(pi).
-: 192
==> get_floatprec(1/3).
-: 64
(*----------------------------------------------------------------*)
decode_float(x: real): array[2] of integer;
Fuer eine Real-Zahl x liefert decode_float(x) einen Vektor
(mant, expo), der die interne Darstellung von x wiedergibt.
Dabei sind mant und expo ganze Zahlen, so dass
x = mant * 2**expo
Beispiel:
==> set_printbase(16).
-: 0x10
==> decode_float(-1/3).
-: (-0xAAAA_AAAA, -0x21)
(*----------------------------------------------------------------*)
float(n: integer): real;
Verwandelt den Integer n in eine real-Zahl (mit der aktuellen
float precision).
x := float(n) ist gleichbedeutend mit x := n + 0.0.
(*----------------------------------------------------------------*)
pi
Die Konstante pi ist auf 192 Binaerstellen genau gespeichert.
Ein Ausdruck wie pi/3 wird jedoch i.a. nicht mit dieser Genauigkeit,
sondern mit der gerade eingestellten Float-Genauigkeit (Default-Wert
32 Binaerstellen). Diese kann mit der Funktion set_floatprec
veraendert werden.
(*----------------------------------------------------------------*)
Die Funktionen sqrt (Quadratwurzel), exp, log (natuerlicher Logarithmus),
sin, cos, tan, arctan, arcsin, arccos sind Funktionen, die jeweils
ein real-Argument erwarten und einen real-Wert als Ergebnis haben.
Wird als Argument ein integer uebergeben, wird dieser automatisch
in einen real-Wert verwandelt.
Beispiel:
==> log(2).
-: 0.693147180
==> set_floatprec(extended_float).
-: 192
==> log(2).
-: 0.693147180559945309417232121458176568075500134360255254
(*----------------------------------------------------------------*)
arctan2(y,x: real): real;
Die Zahlen x,y duerfen nicht gleichzeitig 0 sein. Das Ergebnis ist
ein Winkel phi mit -pi < phi <= pi, fuer den gilt
x = r * cos(phi);
y = r * sin(phi);
wobei r = sqrt(x*x + y*y).
Fuer x > 0 gilt arctan2(y,x) = arctan(y/x).
(*----------------------------------------------------------------*)
c) Random
=========
random
random_seed
(*----------------------------------------------------------*)
random(n: integer): integer;
Erzeugt eine (Pseudo-) Zufallszahl z mit 0 <= z < n.
(*----------------------------------------------------------*)
random(x: real): real;
Erzeugt eine reelle (Pseudo-) Zufallszahl z mit 0 <= z < x.
(*----------------------------------------------------------*)
random_seed([s: integer]): integer;
random_seed ohne Argument liefert den gegenwaertigen Zustand
des Zufalls-Generators (eine ganze Zahl z mit 2**48 <= z < 2**49).
Mit einem ganzzahligen Wert s als Argument kann der Zufalls-Generator
auf einen bestimmten Wert gesetzt werden (das Argument s wird
modulo 2**48 auf eine Zahl im Intervall 2**48 <= z < 2**49 normiert.)
Dadurch lassen sich fuer Test-Zwecke reproduzierbare Werte
der random-Funktion erzeugen.
(*----------------------------------------------------------*)
d) Characters, Strings
======================
chr
ord
length
concat
toupper
tolower
string_split
substr_index
itoa
ftoa
float_ecvt
atoi
atof
(*----------------------------------------------------------*)
chr(n: integer): char;
ord(ch: char): integer;
Die Funktion chr erzeugt den Character mit Ascii-Code n; ord ist
die Umkehrfunktion von chr.
(*----------------------------------------------------------*)
length(s: string): integer;
Ergibt Laenge des Strings s. (Die Funktion length ist auch auf
Byte-Strings, Arrays, Stacks und Files anwendbar.)
(*----------------------------------------------------------*)
concat(arg0, arg1, ... , argn): string;
Die Funktion concat erwartet ein oder mehr Argumente, die Strings
oder Characters sein koennen. Es wird ein String erzeugt, der
durch Hintereinanderschreiben der Argumente entsteht.
Beispiel:
==> concat("create",'_',"string").
-: "create_string"
(*----------------------------------------------------------*)
toupper(str: string): string;
toupper(ch: character): character;
Verwandelt einen String bzw. einen Character in Grossbuchstaben.
Dabei werden nur Characters zwischen 'A' und 'Z' betroffen;
alle andern (z.B. auch Umlaute) bleiben unveraendert.
(*----------------------------------------------------------*)
tolower(str: string): string;
tolower(ch: character): character;
Verwandelt einen String bzw. einen Character in Kleinbuchstaben.
Dabei werden nur Characters zwischen 'A' und 'Z' betroffen;
alle andern bleiben unveraendert.
(*----------------------------------------------------------*)
string_split(str: string [; sep: string]): array of string;
Spaltet den String str auf und gibt einen Vektor der
Bestandteile zurueck. Als Trenner werden die im String
sep enthaltenen Characters angesehen. Defaultmaessig
sind Trenner SPACE, TAB und NEWLINE
Beispiele:
==> string_split("abc def").
-: ("abc", "def")
==> string_split("abc def;xxx=yyy",";= ").
-: ("abc", "def", "xxx", "yyy")
(*----------------------------------------------------------*)
substr_index(str, str1: string): integer;
Untersucht, ob der String str1 in str als Teilstring enthalten
ist und gibt die Position zurueck (Zaehlung beginnt bei 0).
Ist str1 nicht in str enthalten, wird -1 zurueckgegeben.
(*----------------------------------------------------------*)
itoa(x: integer [; base: integer]): string;
Verwandelt die ganze Zahl x in einen String. Optional kann noch
die Basis base vorgeschrieben werden, die einen der Werte 2,8,10,16
annehmen darf.
(*----------------------------------------------------------*)
ftoa(x: real): string;
Verwandelt eine reelle Zahl in einen String.
Beispiele:
==> ftoa(1/239).
-: "0.00418410042"
==> ftoa(pi*10**100).
-: "3.14122626E100"
(*----------------------------------------------------------*)
atoi(s: string [; var code: integer]): integer;
Verwandelt einen String, der eine ganze Zahl darstellt, in eine
ganze Zahl. Wird die Funktion mit einem zweiten variable-Parameter
code aufgerufen, so wird in code eine ganze Zahl abgelegt, welche
i.a. die Laenge von s ist. Ist code < length(s), so stellt nur
der vom Anfang an gerechnete Teilstring der Laenge code eine
ganze Zahl dar. Insbesondere bedeutet code = 0 einen unzulaessigen
String.
Beispiele:
==> atoi("1234").
-: 1234
==> atoi("0x1234").
-: 4660
==> atoi("-1234 5678",len).
-: -1234
==> len.
-: 5
==> atoi("_1234",len).
-: 0
==> len.
-: 0
(*----------------------------------------------------------*)
atof(s: string [; var code: integer]): real;
Verwandelt einen String, der eine reelle Zahl darstellt, in eine
reelle Zahl. Ein zweiter, optionaler variable-Parameter code hat
eine analoge Bedeutung wie bei der Funktion atoi.
(*----------------------------------------------------------*)
float_ecvt(x: real; ndig: integer; var decpos, sign: integer): string;
Verwandelt die Zahl x in einen String mit ndig Ziffern. Der String
enthaelt ausschliesslich Ziffern. Die Position des Dezimalpunkts
relativ zum String-Anfang wird im Variablen-Paramater decpos
zurueckgegeben (negative Werte bedeuten: Dezimalpunkt links vom
String-Anfang), das Vorzeichen im Variablen-Parameter sign (sign = 0
bedeutet x >= 0, sign < 0 bedeutet x < 0).
float_ecvt ist analog zur unter Unix verfuegbaren C-Funktion ecvt.
Beispiel:
==> float_ecvt(pi,10,decpos,sign).
-: "3141592654"
==> decpos.
-: 1
==> sign.
-: 0
(*----------------------------------------------------------*)
e) Byte-Strings
===============
length
byte_string
cardinal
integer
hex_string
text_string
(*----------------------------------------------------------*)
length(b: byte_string): integer;
Laenge des Byte-Strings b.
(*----------------------------------------------------------*)
cardinal(b: byte_string): integer;
Verwandelt einen byte_string in einen (nicht-negativen) integer.
Die Komponenten des byte_strings werden dabei als Ziffern der
ganzen Zahl bzgl. der Basis 256 interpretiert (low byte first).
Der Wert der Funktion ist also gleich
sum(b[i] * 256**i: 0 <= i < length(b)).
(*----------------------------------------------------------*)
integer(b: byte_string): integer;
Verwandelt einen byte_string in einen integer. Die Komponenten
des byte_strings werden dabei als Ziffern der ganzen Zahl bzgl.
der Basis 256 in Zweier-Komplement-Darstellung interpretiert.
Ist len = length(b) und das hoechstwertige Bit von b[len-1] nicht
gesetzt, so gilt integer(b) = cardinal(b). Ist dagegen das hoechstwertige Bit von b[len-1] gesetzt, so ist das Funktions-Ergebnis
eine negative Zahl mit
integer(b) = cardinal(b) - 256**len.
(*----------------------------------------------------------*)
byte_string(x: integer [; len: integer]): byte_string;
Verwandelt die ganze Zahl x in einen byte_string und ist die
Umkehrfunktion von integer(). Wird das Argument len nicht angegeben,
so wird als Default-Wert len = byte_length(x) angenommen. Ist
len > byte_length(x), so werden die ueberzaehligen Bytes fuer x >= 0
mit 0, fuer x < 0 mit 0xFF gefuellt. Falls len < byte_length(x) ist,
wird der entstehende byte_string entsprechend gekuerzt.
Beispiele:
==> set_printbase(16).
-: 0x10
==> x := 65111.
-: 0xFE57
==> byte_string(x).
-: $57FE
==> byte_string(-x).
-: $A901
==> byte_string(x,4).
-: $57FE_0000
==> byte_string(-x,4).
-: $A901_FFFF
==> byte_string(x,1).
-: $57
(*----------------------------------------------------------*)
byte_string(s: string): byte_string;
Verwandelt einen gewoehnlichen String in einen byte_string.
Die Komponenten des resultierenden byte_strings sind die Ascii-Codes
der Characters von s.
Beispiel:
==> byte_string("string").
-: $7374_7269_6E67
(*----------------------------------------------------------*)
string(b: byte_string): string;
Verwandelt einen byte_string in einen gewoehnlichen String; Umkehrfunktion von hex_string. Der byte_string darf keine Nullen als
Komponenten enthalten. Vorsicht ist ausserdem geboten, wenn Komponenten
des byte_strings Codes von nicht-druckbaren Zeichen sind, die bei der
Ausgabe auf den Bildschirm als Steuerzeichen interpretiert werden
koennen.
(*----------------------------------------------------------*)
Bit-Operationen fuer Byte-Strings
--------------------------------mem_btest
mem_bset
mem_bclear
mem_not
mem_and
mem_or
mem_xor
mem_shift
mem_bitswap
mem_byteswap
Alle diese Bit-Operationen, mit Ausnahme von mem_btest,
veraendern das als Variablen-Parameter uebergebene erste
Byte-String-Argument und geben den modifizierten Byte-String
zurueck. Der Rueckgabewert ist nur im interaktiven Modus
interessant.
(*----------------------------------------------------------*)
mem_btest(var b: byte_string; n: integer): integer;
Liefert 1 oder 0, je nach dem das Bit an Position n (Zaehlung
beginnt bei 0) des Byte-Strings b gesetzt ist oder nicht.
(*----------------------------------------------------------*)
mem_bset(var b: byte_string; n: integer): byte_string;
Setzt das Bit an Position n im Byte-String b und gibt das
modifizierte b zurueck.
(*----------------------------------------------------------*)
mem_bclear(var b: byte_string; n: integer): byte_string;
Loescht das Bit an Position n im Byte-String b und gibt das
modifizierte b zurueck.
(*----------------------------------------------------------*)
mem_not(var b: byte_string): byte_string;
Bildet das bitweise not des Byte-Strings b und gibt das
modifizierte b zurueck.
(*----------------------------------------------------------*)
mem_and(var b1,b2: byte_string): byte_string;
mem_or(var b1,b2: byte_string): byte_string;
mem_xor(var b1,b2: byte_string): byte_string;
Das erste Byte-String-Argument b1 wird durch das bitweise and
(bzw. or, bzw. xor) von b1 und b2 ersetzt. Der so modifizierte
Byte-String b1 wird zurueckgegeben. Die Byte-Strings b1 und b2
sollen dieselbe Laenge haben.
(*----------------------------------------------------------*)
mem_shift(var b: byte_string; n: integer): byte_string;
Fuehrt in b einen Bit-Shift um abs(n) Stellen durch. Ist n > 0,
in Richtung least-significant --> most-significant, fuer n < 0
in umgekehrter Richtung. n Bits gehen verloren, die frei werdenden
Stellen werden mit Nullen besetzt. Beispiel:
==> bb := $ABCD;
mem_shift(bb,4).
-: $B0DA
(*----------------------------------------------------------*)
mem_bitswap(var b: byte_string): byte_string;
Vertauscht die Bits innerhalb aller Bytes von b (most significant
--> least significant) und gibt den modifizierten Byte-String zurueck.
(*----------------------------------------------------------*)
mem_byteswap(var b: byte_string; wordlen: integer): byte_string;
Der Byte-String b wird in Gruppen von je wordlen Bytes unterteilt.
Innerhalb jeder Gruppe werden die Bytes vertauscht (most significant
--> least significant). Rueckgabewert: Der modifizierte Byte-String.
(*----------------------------------------------------------*)
f) Arrays
=========
length
sort
sum
product
alloc
create_array
(*----------------------------------------------------------*)
length(vec: array): integer;
Liefert die Laenge des Arrays vec.
(*----------------------------------------------------------*)
Die Komponenten eines Arrays vec sind als
vec[i]
wobei 0 <= i <= length(vec), zugaenglich.
Es gibt nicht nur die Moeglichkeit, auf einzelne Komponenten
eines Arrays zuzugreifen, sondern auch auf Subarrays.
Ist etwa vec ein Array, so bezeichnet vec[n1..n2] den Teil von vec,
der aus allen Komponenten vec[i] mit n1 <= i <= n2 besteht.
Beispiel:
==> vec := (1,2,3,4,5,6,7,8,9,10).
-: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
==> vec[2..6].
-: (3, 4, 5, 6, 7)
Die obere Grenze kann auch weggelassen werden;
vec[n1..] bedeutet dasselbe wie vec[n1..length(vec)-1].
Subarrays koennen auch auf der linken Seite von Zuweisungen
stehen und erlauben so die simultane Modifikation von mehreren
Komponenten. Setzt man etwa mit dem obigen Array vec
==> vec[2..6] := (0,-1,-2,-3,-4).
-: (0,-1,-2,-3,-4)
so wird
==> vec.
-: (1, 2, 0, -1, -2, -3, -4, 8, 9, 10)
(*----------------------------------------------------------*)
sum(vec: array of integer): integer;
sum(vec: array of real): real;
product(vec: array of integer): integer;
product(vec: array of real): real;
Liefert die Summe bzw. das Produkt aller Komponenten von vec.
(*----------------------------------------------------------------*)
alloc(Arraytype, Len [,Ele]): Arraytype;
Arraytype ist eines der Symbole array, string, byte_string.
Die Funktion erzeugt ein Array (bzw. einen String, Byte-String)
der Laenge Len, wobei alle Komponenten gleich Ele sind.
Wird das Argument Ele nicht angegeben, so ist defaultmaessig
Ele = 0, falls Arraytype = array, Ele = ' ', falls Arraytype = string
und Ele = 0, falls Arraytype = byte_string.
Beispiele:
==> alloc(array,10).
-: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
==> alloc(string,5,'A').
-: "AAAAA"
==> alloc(byte_string,5,127).
-: $7F7F_7F7F_7F
EINSCHRAENKUNG: Die Laengen von Arrays in ARIBAS koennen
hoechstens 16-Bit-Zahlen sein. Meistens, insbesondere unter
DOS, ist die Maximallaenge aus Speicherplatz-Gruenden viel
kleiner. Es erscheint dann eine Fehlermeldung
==> alloc(array,20000).
too large piece of memory requested
** RESET **
(*----------------------------------------------------------*)
create_array(len: integer [; Ele: Type]): array of Type;
Erzeugt ein Array der Laenge len, wobei alle Komponenten
gleich Ele sind (Defaultwert fuer Ele ist 0).
Aequivalent mit alloc(array,len,Ele).
Nur zur Kompatibilitaet mit aelteren Versionen von ARIBAS,
kuenftig wegfallend.
(*----------------------------------------------------------*)
sort(var vec: array of integer): array of integer;
sort(var vec: array of real): array of real;
sort(var vec: array of string): array of string;
Das als variable-Parameter uebergebene Array von Zahlen bzw. Strings
wird in aufsteigender Ordnung sortiert (bei Strings erfolgt die
Ordnung nach den Ascii-Codes). Das sortierte Array wird zurueckgegeben.
sort(var vec: array of Type; compfun: function): array of Type;
Der Funktion sort kann als optionales zweites Argument eine
Funktion uebergeben werden. Das erste Argument ist ein Array von
Elementen eines beliebigen Datentyps Type. Die Funktion
compfun muss eine Funktion mit zwei Argumenten des Typs Type
sein und integer-Werte liefern. Es wird compfun(x,y) <= 0 als
x <= y interpretiert.
Beispiel: Sei etwa ein Array von Paaren ganzer Zahlen gegeben.
Hierfuer definieren wir eine Vergleichsfunktion
==> function compare2(x,y: array[2]): integer;
begin
return y[1] - x[1];
end.
-: compare2
==> vec := ((1,7), (2,3), (3,4), (4,-1), (5,2));
sort(vec,compare2).
-: ((4, -1), (5, 2), (2, 3), (3, 4), (1, 7))
(*----------------------------------------------------------*)
g) Stacks
=========
length
stack_push
stack_pop
stack_top
stack_reset
stack_empty
stack2array
(*-----------------------------------------------------------------*)
Es gibt keine Stack-Literale. Stacks werden initialisiert
durch ein Variablen-Deklaration. Z.B. erzeugt die folgende
Top-Level-Deklaration
var
st: stack;
end.
einen (leeren) Stack, auf den anschliessend mit stack_push
Elemente gelegt werden koennen.
(*-----------------------------------------------------------------*)
length(st: stack): integer;
Ergibt die Laenge des Stacks st, d.h. die Anzahl der Elemente (beliebigen
Datentyps), die auf dem Stack abgelegt sind.
(*-----------------------------------------------------------------*)
stack_push(st: stack; ele: Type): Type;
Legt ein Element ele des Datentyps Type (der beliebig sein kann) auf
den Stack st. Rueckgabewert ist ele. Die Laenge des Stacks vergroessert
sich um 1.
(*-----------------------------------------------------------------*)
stack_pop(st: stack): Type;
Entfernt das oberste Element vom Stack st und gibt es zurueck.
Es wird vorausgesetzt, dass der Stack nicht leer ist.
Die Laenge des Stacks vermindert sich um 1.
(*-----------------------------------------------------------------*)
stack_top(st: stack): Type;
Gibt das oberste Element des Stacks st zurueck; der Stack selbst
bleibt aber unveraendert.
(*-----------------------------------------------------------------*)
stack_reset(st: stack): integer;
Entfernt alle Elemente vom Stack st. Uebrig bleibt ein leerer Stack.
Rueckgabewert 0.
(*-----------------------------------------------------------------*)
stack_empty(st: stack): boolean;
Stellt fest, ob der Stack st leer ist.
(*-----------------------------------------------------------------*)
stack2array(st: stack): array of Type;
Erzeugt ein Array der Laenge length(st) aus den Elementen, die auf
dem Stack liegen. Das Element, das zuunterst auf dem Stack liegt,
bekommt den Index 0. Uebrig bleibt ein leerer Stack. Der Programmierer
ist selbst verantwortlich dafuer, dass alle Elemente des Stacks
den richtigen Datentyp haben.
(*-----------------------------------------------------------------*)
h) In-Out
=========
write
writeln
flush
readln
load
open_read
open_write
open_append
rewind
close
set_filepos
get_filepos
length
read_byte
read_block
write_byte
write_block
Vordefinierte Files:
stdin
stdout
stderr
(*--------------------------------------------------------------------*)
open_write(var f: file; name: string): boolean;
Oeffnet eine Datei namens name zum Schreiben.
Rueckgabewert: true bei erfolgreicher Oeffnung, sonst false.
VORSICHT: Schon existierende Dateien werden ueberschrieben.
(*--------------------------------------------------------------------*)
open_append(var f: file; name: string): boolean;
Oeffnet eine Datei namens name zum Schreiben. Falls die Datei
schon vorhanden ist, bleibt ihr Inhalt erhalten; Schreib-Operationen
erfolgen an das Ende der Datei. Ist die Datei noch nicht vorhanden,
wird eine neue erzeugt.
Rueckgabewert: true bei erfolgreicher Oeffnung, sonst false.
(*--------------------------------------------------------------------*)
open_read(var f: file; name: string): boolean;
Oeffnet eine vorhandene Datei namens name zum sequentiellen
Lesen mittels readln.
Rueckgabewert: true bei erfolgreicher Oeffnung, sonst false.
(*--------------------------------------------------------------------*)
rewind(var f: file): boolean;
Eine zum Lesen geoeffnete Datei, aus der schon einige Daten
gelesen worden sind, kann mit rewind an den Anfang zurueckgesetzt
werden.
Rueckgabewert: true bei erfolgreicher Ausfuehrung.
(*--------------------------------------------------------------------*)
close(f: file): boolean;
Schliesst das (vorher geoeffnete) File f.
(*--------------------------------------------------------------------*)
length(f: file): integer;
Das File f muss zum Lesen geoeffnet sein. Dann liefert die Funktion
length die Laenge der Datei in Bytes.
(*--------------------------------------------------------------------*)
Lese- und Schreib-Operationen fuer Text-Dateien
readln, write, writeln
readln([f: file;] var arg1,...,argn): integer;
Liest aus der zum Lesen geoeffneten Datei f (falls dies Argument
nicht angegeben wird, wird stdin angenommen, also von der Console
gelesen) eine Zeile. Die Argumente muessen Variable vom Typ
integer, real, char oder string sein. Rueckgabewert ist die Anzahl
der erfolgreich gelesenen Argumente. Ist vor der Ausfuehrung von readln
bereits das Datei-Ende erreicht, wird -1 zurueckgegeben.
(*--------------------------------------------------------------------*)
write([f: file;] arg1,...,argn): integer;
writeln([f: file;] arg1,...,argn): integer;
Schreibt die Argumente arg1,...,argn in eine zum Schreiben geoeffnete
Text-Datei f. Die Argumente argi koennen von beliebigem Datentyp sein.
Die Funktion writeln schliesst die Schreib-Operationen mit einem
Zeilen-Vorschub ab.
Wird das file-Argument f nicht angegeben, so wird default-maessig
stdout (Terminal) angenommen.
Rueckgabewert ist die Anzahl der geschriebenen Argumente.
FORMAT-OPTIONEN fuer die Funktionen write und writeln.
Wie in Pascal koennen Argumente bestimmter Datentypen noch mit
Formatangaben versehen werden. Die Formatangaben, die im folgenden
naeher beschrieben werden, sind vom jeweiligen Argument durch
einen Doppelpunkt getrennt.
a) String, Character
Ist str ein String- oder Character-Ausdruck und width ein
Integer-Ausdruck, so wird durch ein Argument der Form
str: width
die Breite der Ausgabe bestimmt. Ist der Wert von width eine ganze
Zahl, die groesser als die Laenge von str ist, so wird durch
Voranstellen von Leerzeichen die Ausgabe von str rechtsbuendig
auf die Gesamtbreite width gebracht. Ist der Wert von width negativ
und abs(width) groesser als die Laenge von str, so erfolgt die
Ausgabe linksbuendig durch das Nachstellen von Leerzeichen mit
einer Gesamtbreite von abs(width). Ist abs(width) kleinergleich
der Laenge von str, so wird die Formatangabe ignoriert, ebenso
wenn abs(width) groesser als die Zeilenlaenge ist.
Beispiel:
==> writeln("abc":10,'X':10,"###");
writeln("def":-10,'Y':-10,"###").
abc
X###
def
Y
###
-: 3
b) Integer
Ein Integer-Argument mit Formatangabe der Gestalt
x: width
wobei x und width Integer-Ausdruecke sind, bestimmt analog zum
Fall der Strings rechts- bzw. linksbuendige Ausgabe des Integers x.
Beispiel:
==> writeln(3**30:20,'|'); writeln(3**30:-20,'|').
20589_11320_94649|
20589_11320_94649
|
-: 2
In Erweiterung der Moeglichkeiten gegenueber Pascal sind bei Integern
jedoch noch andere Formatangaben moeglich. Diese werden ebenfalls
durch einen Doppelpunkt getrennt und haben die Gestalt
base(n)
group(n)
digits(n)
mit einem Integer-Ausdruck n.
Die Formatangabe base(n), wobei n einen der Werte 2,8,10,16 annehmen
darf, bestimmt die Basis der Ausgabe.
Beispiel:
==> x := 3**9; writeln(x:10, x:20:base(2), x:10:base(8), x:10:base(16)).
19683
1001100_11100011
46343
4CE3
-: 4
ARIBAS gliedert die Ausgabe von grossen ganzen Zahlen durch den
Unterstrich. Dies kann durch die Formatangabe group(n) gesteuert
werden. Dabei kann der Wert von n entweder 0 oder eine ganze Zahl
groessergleich 2 und kleiner als die Zeilenlaenge sein. Bei der
Formatangabe group(0) erfolgt keine Gliederung; sonst werden
jeweils n Ziffern zu einer Gruppe zusammengefasst, die durch einen
Unterstrich von den anderen Gruppen getrennt werden.
Beispiel:
==> x := 3**100; writeln(x); writeln(x: group(0)); writeln(x: group(10)).
515_37752_07320_11331_03646_11297_65621_27270_21075_22001
515377520732011331036461129765621272702107522001
51537752_0732011331_0364611297_6562127270_2107522001
-: 1
(Defaultmaessig verwendet ARIBAS bei Zahlen >= 2**32 im Dezimalsystem
eine Gliederung zu je 5 Ziffern.)
Durch die Formatangabe digits(n) kann die Ausgabe fuehrender Nullen
erzwungen werden. Ist n groesser als die Stellenzahl einer
ganzen Zahl x in einer bestimmten Basis, so werden entsprechend viele
fuehrende Nullen ergaenzt, so dass die Gesamtzahl der ausgegebenen
Ziffern gleich n ist. Ist n kleinergleich der Stellenzahl, so hat die
Formatangabe digits(n) keine Wirkung.
Beispiel:
==> for k := 3 to 10 do
writeln(k: 10: base(2): digits(4): group(2));
end.
00_11
01_00
01_01
01_10
01_11
10_00
10_01
10_10
-:
Die Formatanweisungen base, digits, group duerfen in beliebiger
Reihenfolge stehen.
c) Real
==> writeln(pi:15).
3.141593E+0000
-: 1
==> writeln(pi:15:10).
3.1415926536
-: 1
==> writeln(pi:12:10).
3.1415926536
-: 1
(*--------------------------------------------------------------------*)
flush([f: file]);
Bewirkt nach einer write-Operation in das File f (default = stdout),
dass die zu schreibenden Daten, die sich moeglicherweise noch
in einem Puffer befinden, sofort hinausgeschrieben werden.
(*--------------------------------------------------------------------*)
load(fnam: string): boolean;
fnam muss der Name einer Text-Datei mit ARIBAS-Source-Code sein.
Die Extension .ari kann weggelassen werden.
Durch load wird diese Datei eingelesen und es werden die darin
befindlichen Befehle und Funktions-Definitionen ausgefuehrt,
so als ob sie direkt eingegeben worden waeren.
Rueckgabewert bei erfolgreichem Laden ist true.
(*--------------------------------------------------------------------*)
BINAERDATEIEN:
Der Default-Typ einer Datei in ARIBAS ist die Text-Datei.
Es koennen jedoch auch Binaerdateien zum Schreiben oder zum
Lesen geoeffnet werden. Dazu ist in den Funktionen open_write,
open_read, open_append als drittes Argument das Symbol binary
anzugeben; Beispiel:
==> open_read(f,"BIN.DAT",binary).
Dies oeffnet die Datei mit dem Namen "BIN.DAT", die als existent
vorausgesetzt wird, zum Lesen. Fuer Binaerdateien gibt es die
Schreib-Operationen write_byte und write_block sowie die
Lese-Operationen read_byte und read_block.
Die Funktionen rewind und length koennen auch auf Binaerdateien, die
zum Lesen geoeffnet sind, angewendet werden.
(*--------------------------------------------------------------------*)
set_filepos(f: file; pos: integer): integer;
f muss ein zum Lesen geoeffnetes binaeres File und pos eine Zahl mit
0 <= pos < length(f) sein. Dann setzt set_filepos die Position fuer
die naechste Lese-Operation auf pos. Rueckgabewert ist dann ebenfalls
pos. Liegt pos nicht im zulaessigen Bereich, so erfolgt keine Aktion
und die aktuelle File-Position wird zurueckgegeben.
(*--------------------------------------------------------------------*)
get_filepos(f: file): integer;
f muss ein zum Lesen geoeffnetes binaeres File sein. Es wird die
aktuelle File-Position zurueckgegeben.
(*--------------------------------------------------------------------*)
read_byte(f: file): integer;
Liest aus einer zum Lesen geoeffneten Binaer-Datei f das naechste Byte,
das als integer 0 <= b <= 255 zurueckgegeben wird und erhoeht die
File-Position um eins. Falls aber beim Aufruf von read_byte die
File-Position bereits das Datei-Ende ist, wird -1 zurueckgegeben und
die File-Position nicht veraendert.
(*--------------------------------------------------------------------*)
read_block(f: file; var block: byte_string; len: integer): integer;
f muss eine zum Lesen geoeffnete Binaer-Datei sein und block eine
byte_string-Variable mit einer aktuellen Laenge >= len oder ein
Subarray eines byte_strings mit einer Laenge >= len sein. Dann liest
read_block aus dem File f die naechsten len Bytes und schreibt sie
in die ersten len Komponenten von block. Wenn vorzeitig das Datei-Ende
erreicht wird, wird die Lese-Operation abgebrochen. Der RueckgabeWert der Funktion ist die Anzahl der erfolgreich gelesenen Bytes, im
Normalfall also gleich len.
(*--------------------------------------------------------------------*)
write_byte(f: file; x: integer): integer:
Schreibt in eine (mittels open_write oder open_append) zum Schreiben
geoeffnete Binaer-Datei f das durch einen integer-Wert x mit 0 <= x <=
255
gegebene Byte. Statt eines Integers kann x auch ein Character sein.
Rueckgabewert ist bei erfolgreicher Schreibaktion das geschriebene Byte,
im Fehlerfall -1.
(*--------------------------------------------------------------------*)
write_block(f: file; var block: byte_string; len: integer): integer;
f muss eine zum Schreiben geoeffnete Binaer-Datei sein und block eine
byte_string-Variable mit einer aktuellen Laenge >= len oder ein
Subarray eines byte_strings mit einer Laenge >= len sein.
write_block schreibt die ersten len Bytes von block in das File f.
Der Rueckgabe-Wert der Funktion ist die Anzahl der erfolgreich
geschriebenen Bytes, bei fehlerfreier Ausfuehrung also gleich len.
(*-----------------------------------------------------------------*)
i) System-Funktionen
====================
memavail
gc
timer
exit
halt
make_unbound
symbols
help
system
protocol
save_input
load_edit
(*-----------------------------------------------------------------*)
halt([retcode: integer]): integer;
Wird die Funktion halt aufgerufen, so wird die laufende ProgrammAusfuehrung gestoppt und sofort zum Top-Level zurueckgekehrt
(auch wenn der halt-Aufruf innerhalb eines geschachtelten FunktionsAufrufs erfolgte). Als Ergebnis wird das optionale Argument retcode
(ein 16-Bit integer) geliefert, defaultmaessig 0.
Die Funktion halt ist vorallem zum Abfangen schwerer Fehler geeignet.
(*-----------------------------------------------------------------*)
memavail(): integer;
Ergibt den derzeit freien Speicherplatz auf dem ARIBAS-heap in
Kilobytes und schreibt zusaetzliche Informationen.
Beispiel:
==> memavail().
total number of garbage collections: 1
96000 Bytes reserved; 96000 Bytes active (54780 used, 41220 free)
11417 Bytes free for user defined symbols and symbol names
-: 40
Da ARIBAS einen garbage collector besitzt, der nach dem HalbraumVerfahren arbeitet, ist der ARIBAS-heap ist in zwei gleich grosse Teile
aufgeteilt (in diesem Beispiel zu je 96000 Bytes). Davon ist ein Teil
aktiv, aus ihm werden Speicherplatz-Anforderungen fuer ARIBAS-Objekte
(z.B. grosse Integers) erfuellt. Im obigen Beispiel sind noch 41220
Bytes davon frei, das sind gerundet 40 KB. (Die andere Haelfte
liegt nicht brach, sondern wird z.B. als Zwischenspeicher fuer
Rechnungen genutzt.) Ist der Speicherplatz des aktiven Halbraums
erschoepft, so erfolgt automatisch eine garbage collection.
Die Gesamtzahl der seit Beginn der laufenden ARIBAS-Sitzung
durchgefuehrten garbage collections wird ebenfalls gemeldet.
Namen von benutzer-definierten Variablen und Funktionen werden von
ARIBAS in einer Symboltabelle eingetragen. Der hier noch freie
Platz wird ebenfalls gemeldet.
Man kann alle Meldungen ausschalten, indem man memavail mit dem
zusaetzlichen Argument 0 aufruft.
==> memavail(0).
-: 40
(*-----------------------------------------------------------------*)
gc(): integer;
Erzwingt eine garbage collection und liefert als Ergebnis den
danach freien Speicherplatz fuer ARIBAS-Objekte in Kilobytes.
Es werden dieselben Meldungen wie bei memavail ausgegeben.
Eine stumme Version ist gc(0). Diese ist z.B. nuetzlich, wenn man
die Ausfuehrung einer bestimmten Prozedur davon abhaengig machen will,
dass ein gewisses Mindestmass von Speicher frei ist, etwa
if gc(0) < 64 then
writeln("not enough memory for procedure foo");
else
foo(...);
...
end;
(*-----------------------------------------------------------------*)
timer(): integer;
Liefert die Zeit in Millisekunden, die seit einem von der jeweiligen
Computer-Sitzung abhaengigen Anfangspunkt vergangen ist. (Die Genauigkeit der Zeitmessung ist systemabhaengig.) Damit kann man z.B. die Zeit
stoppen, die fuer die Ausfuehrung gewisser Funktionen gebraucht wird.
==> t := timer();
x := isqrt(2*10**2000);
timer() - t.
-: 216
Im obigen Beispiel, das mit einem 80486-Prozessor mit 33 MHz Taktfrequenz
durchgefuehrt wurde, wurde die Quadratwurzel aus 2 mit 1000 DezimalStellen Genauigkeit in 216 Millisekunden berechnet.
(*-----------------------------------------------------------------*)
symbols(aribas)
Ergibt eine Liste der ARIBAS-Schluesselworte und eingebauten
Funktionen.
Das Symbol aribas muss so wie es steht eingegeben werden.
symbols(user)
Ergibt eine Liste der derzeit benutzer-definierten Variablen
und Funktionen.
(*-----------------------------------------------------------------*)
help(Topic)
Gibt eine kurze Online-Hilfe ueber Topic. Als Topic kommen
die meisten Symbole in Frage, die man mit dem Befehl
symbols(aribas) erhaelt, z.B. liefert
==> help(factor16).
eine kurze Beschreibung der eingebauten Funktion factor16.
Damit das help-Kommando funktioniert, muss sich die Datei
aribas.hlp mit den Hilfe-Texten im selben Directory
wie aribas.exe befinden (dies gilt fuer die DOS-Version).
(*-----------------------------------------------------------------*)
system(command: string): integer;
Der String command wird an den Kommando-Interpreter des
Systems zur Ausfuehrung uebergeben. Rueckgabewert ist
meistens 0, oder ein Fehler-Code.
Beispielsweise erzeugt
==> system("dir").
unter DOS die Ausgabe des Inhalts-Verzeichnis des
aktuellen Directory's
(*-----------------------------------------------------------------*)
7) FUNKTIONS-DEFINITIONEN
=========================
function
procedure
external
const
var
begin
end
return
(*--------------------------------------------------------------------*)
Funktionen werden in ARIBAS (wie in C) alle auf gleicher Ebene
definiert; geschachtelte Funktions-Definitionen sind nicht
zulaessig.
In Funktions-Definitionen darf auf andere Funktionen Bezug
genommen werden, auch wenn diese noch nicht definiert sind.
Es sind keine FORWARD-Deklarationen wie in Pascal noetig.
Es liegt in der Verantwortung des Programmierers, dafuer zu
sorgen, dass alle benoetigen Funktionen definiert sind, wenn
der tatsaechliche Funktions-Aufruf erfolgt.
(*--------------------------------------------------------------------*)
Eine Funktions-Definition hat folgende Gestalt
function Funame(<formale Parameterliste>): Resulttype;
<external Deklaration>
<const Deklaration>
<var Deklaration>
begin
<statemement list>
end.
Statt function darf man auch procedure schreiben
(zur Kompatibilitaet mit Modula-2).
Dabei muss Funame ein zulaessiger Identifier sein, der nicht
mit einem Schluesselwort oder dem Namen einer eingebauten Funktion
zusammenfaellt. Die formale Parameterliste kann wie in Pascal
oder Modula-2 Wert- und Variablen-Parameter enthalten. Sie kann
auch leer sein (man darf aber das Klammerpaar nicht weglassen).
Die external-, const- und var-Deklarationen, die wir spaeter
besprechen, koennen auch fehlen. Im Hauptteil der Funktions-Definition
zwischen begin und end koennen Return-Statements der Form
return Retval;
vorkommen, wobei Retval den Datentyp Resulttype haben muss.
In ARIBAS koennen auch zusammengesetzte Typen wie Arrays
als Funktions-Ergebnisse verwendet werden.
Beispiele:
(*--------------------------------------------*)
function mersenne(n: integer): integer;
begin
return 2**n - 1;
end.
(*--------------------------------------------*)
Diese Funktion berechnet die n-te Mersenne-Zahl
==> mersenne(59).
-: 576_46075_23034_23487
Bemerkung: Der Punkt am Ende der Funktions-Definition
ist nur noetig, wenn man die Funktion interaktiv am
ARIBAS-Prompt eingibt. Falls die Funktions-Definition
in einer Datei steht, die mittels load von ARIBAS geladen
wird, kann man auch ein Semicolon setzen.
Das folgende ist eine rekursive Funktion zur Berechnung
der Fakultaet
(*---------------------------------------------------------*)
function fac_rec(n: integer): integer;
begin
if n <= 2 then
return n;
else
return fac(n-1)*n;
end
end.
(*---------------------------------------------------------*)
Falls die Funktion lokale Variable benoetigt, muessen
diese deklariert werden, wie im folgenden Beispiel, das eine
iterative Version des vorhergehenden Beispiels darstellt.
function fac_it(n: integer): integer;
var
i,x: integer;
begin
x := 1;
for i := 2 to n do
x := x*i;
end;
return x;
end.
(*---------------------------------------------------------*)
Im Gegensatz zu Pascal braucht bei der Variablen-Deklaration
von Arrays die Laenge keine Konstante zu sein.
Beispiel:
(*---------------------------------------------------------*)
function squarelist(n: integer): array;
var
k: integer;
vec: array[n];
begin
for k := 1 to n do
vec[k-1] := k*k;
end;
return vec;
end.
(*---------------------------------------------------------*)
Diese Funktion stellt ein Array der Laenge n mit den
Quadratzahlen von 1 bis n**2 her.
==> squarelist(5).
-: (1, 4, 9, 16, 25)
(*---------------------------------------------------------*)
Auf benutzer-definierte globale Variable kann innerhalb
von Funktionen nur zugegriffen werden, wenn sie explizit
als external deklariert werden.
Dies ist eine Vorsichts-Massnahme, da globale Variable
einfach durch Zuweisungen entstehen koennen.
(Das Gleiche gilt fuer globale benutzer-definierte Konstanten.)
Beispiel:
(*---------------------------------------------------------*)
function count(): integer;
external
Counter: integer;
begin
return inc(Counter);
end;
(*---------------------------------------------------------*)
Dies ist gleichzeitig ein Beispiel fuer eine Funktion ohne
Argumente. Es wird vorausgesetzt, dass die Integer-Variable
Counter existiert, wenn count aufgerufen wird.
==> Counter := 7;
count().
-: 8
Gleichzeitig ist die Variable Counter um 1 erhoeht worden.
==> Counter.
-: 8
Dieselbe Wirkung kann man erzielen, wenn man Counter als
Variablen-Argument uebergibt.
(*---------------------------------------------------------*)
function count1(var Counter: integer): integer;
begin
return inc(Counter);
end;
(*------------------------------------------------------------*)
Falls Konstanten-Deklarationen vorkommen, stehen sie nach
den External-Deklarationen und vor den Variablen-Deklaration.
Sie haben eine Syntax aehnlich wie in Pascal und Modula-2.
In ARIBAS koennen jedoch z.B. auch Array-Konstanten definiert
werden.
Beispiel:
(*------------------------------------------------------------*)
function dayofweek(n: integer): string;
const
Week = ("SU", "MO", "TU", "WE", "TH", "FR", "SA");
begin
return Week[n mod 7];
end;
(*------------------------------------------------------------*)
==> dayofweek(4).
-: "TH"
(*------------------------------------------------------------*)
Optionale Argumente von Funktionen
---------------------------------Man kann in ARIBAS auch Funktionen mit optionalen
Argumenten definieren. Dazu muessen am Ende der formalen
Parameterliste statt der Typ-Vereinbarungen von Wert-Parametern
Zuweisungen der Form <identifier> := Value stehen. Wird beim
Funktions-Aufruf das Argument weggelassen, verwendet die
Funktion den Wert Value. Wird das Argument beim FunktionsAufruf angegeben, darf es einen beliebigen Wert vom gleichen
Datentyp wie Value haben.
Beispiel
(*------------------------------------------------------------*)
function ranvec(len: integer; bound := 1000): array;
var
vec: array[len];
i: integer;
begin
for i := 0 to len-1 do
vec[i] := random(bound);
end;
return vec;
end;
(*------------------------------------------------------------*)
Diese Funktion liefert ein Array der Laenge len aus Zufallszahlen.
Wird die Funktion nur mit dem Argument len aufgerufen, wreden
die Zufallszahlen dem Intervall 0 <= x < 1000 entnommen; mit
zwei Argumenten len und bound stammen die Zufallszahlen aus
dem Intervall 0 <= x < bound.
==> ranvec(12).
-: (923, 23, 510, 475, 970, 974, 5, 553, 175, 700, 891, 411)
==> ranvec(12,100).
-: (15, 95, 55, 99, 17, 63, 7, 82, 24, 62, 49, 10)
(*------------------------------------------------------------*)
8) VARIABLEN-DEKLARATIONEN
==========================
Es gibt globale Variablen-Deklarationen und lokale VariablenDeklarationen
(d.h. innerhalb von Funktions-Definitionen).
Eine globale Variablen-Deklaration (auf dem Top-Level) hat folgende
Gestalt:
var
<identifier_list1>: <type1>;
...
<identifier_listn>: <typen>;
end
Eine Variablen-Deklaration innerhalb einer Funktions-Definition
sieht aehnlich aus, nur steht statt des Symbols end das Symbol
begin, das den Anfang des Funktionskoerpers bezeichnet.
Dabei ist <identifier_listk> eine durch Kommata getrennte Folge von
Variablen-Namen. <typek> ist eine der Typ-Bezeichnungen integer, real,
char, boolean, stack, file oder ein String- oder Array-Typ, zu denen
spaeter noch mehr zu sagen ist. Beispiel:
==> var
n,m: integer;
x: real;
c1,c2: char;
st: stack;
end.
-: var
Nach dieser Variablen-Deklaration existieren Integer-Variablen n und m,
eine Real-Variable x, zwei Character-Variable c1 und c2, sowie eine
Stack-Variable st. Durch eine Variablen-Deklaration werden die
Variablen durch ARIBAS auch initialisiert, und zwar Integers durch 0,
Reals durch 0.0, boolesche Variablen durch false, Characters durch ' '
(d.h. das Space-Zeichen) und Stack-Variable durch den leeren Stack.
Arrays und Strings koennen mit und ohne Laengenangabe deklariert werden.
Die Deklaration mit Laengenangabe geht wie in folgendem Beispiel:
==> var
str: string[4];
vec: array[10] of real;
end.
-: var
Hiermit wird ein String der Laenge 4, der mit Leerzeichen initialisiert
ist, sowie ein real-Array der Laenge 10, initialisiert mit den Elementen
0.0, erzeugt. Man beachte jedoch, dass in ARIBAS Strings und Arrays
verschiedener Laenge zuweisungs-kompatibel sind, somit anschliessend
etwa eine Zuweisung
==> str := concat(str,"___").
-: "
___"
zulaessig ist.
Wird die Laengenangabe weggelassen, so werden Strings oder Arrays der
Laenge 0 erzeugt:
==> var
str: string;
vec: array;
end.
-: var
==> str.
-: ""
==> vec.
-: ()
Jedoch koennen auch hier den Variablen str bzw. vec anschliessend
Strings bzw. Arrays positiver Laenge zugewiesen werden.
Die Laengenangaben von Arrays (sowie Strings und Byte-Strings)
brauchen keine Konstanten zu sein, sondern koennen
auch integer-Ausdruecke sein, wie in folgendem Beispiel:
==> n := 5.
-: 5
==> var
vec: array[2*n+1];
end.
-: var
==> vec.
-: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
(Wird der Datentyp der Elemente eines Arrays nicht spezifiziert, so
wird der Default-Datentyp integer angenommen.)
Kontanten-Deklarationen
=======================
Konstanten-Deklarationen gibt es (wie Variablen-Deklarationen)
sowohl innerhalb von Funktions-Definitionen als auch auf
globaler Ebene. Eine Top-Level-Konstanten-Deklaration
hat die Gestalt
const
Identifier1 = Value_1;
....
Identifiern = Value_n;
end.
(Innerhalb von Funktionen entfaellt end; die Konstanten-Definition
endet mit dem Beginn der Variablen-Deklaration (var) oder, falls
eine solche fehlt, mit dem Funktions-Koerper (begin).)
Die Werte Value_k duerfen sowohl Literale, als auch
arithmetische Ausdruecke oder Funktions-Ausdruecke mit
vorher definierten oder eingebauten Funktionen sein.
Beispiel:
==> const
Bound1 = 2**16 - 1;
Bound2 = round(exp(10));
end.
-: const
(*----------------------------------------------------------*)
9) KOMANDOZEILEN-ARGUMENTE
==========================
Beim Aufruf von ARIBAS koennen in der Kommandozeile Optionen und
der Name einer .ari-Datei als Argumente uebergeben werden:
Moegliche Optionen:
-q
(quiet) Unterdrueckt die Meldungen beim Start von ARIBAS
-cXX
Hierbei steht XX fuer eine Zahl (in Dezimaldarstellung) zwischen 40
und 160. Dadurch wird festgelegt, wieviele Spalten in der BildschirmAusgabe benutzt werden. Defaultwert ist 80.
-mXXX
Hierbei steht XXX fuer eine Zahl (in Dezimaldarstellung) zwischen 64
und 4096. Sie gibt an, wieviel tausend Bytes ARIBAS maximal fuer den
ARIBAS-heap bereitstellen soll. (Siehe dazu die Funktion memavail.)
Als weiteres Kommandozeilen-Argument kann der Name einer Datei mit
ARIBAS-Quellcode angegeben werden, die dann geladen wird. Die
Extension .ari kann weggelassen werden.
Beispiel:
aribas -c72 -m200 factor
Dieser Aufruf von ARIBAS stellt die Ausgabeweite auf 72 Spalten ein,
reserviert 200000 Bytes fuer den ARIBAS-heap in zwei Halbraeumen zu
100000 Bytes (falls moeglich) und laedt die Datei factor.ari aus dem
aktuellen Directory (falls dort vorhanden).
Will man mehrere Dateien beim Programmstart laden, kann man
z.B. eine Datei startup.ari anlegen, in der mehrere load-Anweisungen
stehen und dann aribas startup aufrufen.
Folgen dem Namen der zu ladenden Datei noch weitere Argumente,
stehen diese als Strings innerhalb von ARIBAS zur Verfuegung.
In ARIBAS gibt es eine globale Variable ARGV, die ein Array von
Strings ist. Die nullte Komponente ist der Name der geladenen Datei,
die weiteren Komponenten sind die zusaetzlichen Kommandozeilen-Argumente.
Beispiel: Nach dem Aufruf
aribas -q startup 4536 eisenstein
hat der Vektor ARGV die Form
==> ARGV.
-: ("startup", "4536", "eisenstein")
Braucht man einige der Argumente als Zahlen und nicht als Strings,
kann man die entsprechenden Komponenten von ARGV durch atoi (oder
atof) umwandeln; in unserem Beispiel etwa
==> atoi(ARGV[1]).
-: 4536
Alle Kommandozeilen-Argumente sind optional.
(*************************** EOF ******************************)
Herunterladen