CODINGLISTINGS ★ WÜRFEL (CPC AMSTRAD INTERNATIONAL) ★

Würfel (CPC Amstrad International)Coding Listings
★ Ce texte vous est présenté dans sa version originale ★ 
 ★ This text is presented to you in its original version ★ 
 ★ Este texto se presenta en su versión original ★ 
 ★ Dieser Text wird in seiner Originalfassung präsentiert ★ 

Von Zeit zu Zeit
BASIC, Variablen und das Tempoproblem

Jeder BASIC-Bastler hat es mit Variablen zu tun. Sie verwalten Rechenergebnisse, Adressen, Kennzeichen und vieles andere mehr. Wenn es um das “schlafmützige BASIC” geht, sind sich die Tempo-Freaks in der Regel einig. Aber: Durch überlegten Einsatz der richtigen Variablentypen läßt sich in vielen Fällen einiges an Millisekunden gutmachen. “Programm-Optimierung” ist nicht nur ein Thema für Assembler-Druiden.
Das Locomotive-BASIC des CPC stellt dem Anwender drei Variablentypen zur Verfügung: die Integer-, die Real- und die Stringvariable, dazu noch dimensionierte Arrays (Felder) aus diesen Typen.

Integer: Bereich der ganzen Zahlen (Wertebereich von -32768 bis+32767). Integer-Variablen werden durch ein nachgestelltes gekennzeichnet.
Beispiel: ZAEHLER%= 100 Real: Dezimalbrüche mit einer Genauigkeit von 6 Nachkommastellen (Wertebereich von 2 hoch -129 bis 2 hoch + 127). Real-Variablen finden in BASIC standardmäßig Verwendung; sie werden ohne besonderes Kennzeichen dargestellt.
String: maximal 255 Zeichen, wobei jedes Zeichen 256 verschiedene Symbole darstellen kann. String variablen werden durch ein nachgestelltes “$” gekennzeichnet. Beispiel:

TEXT$=”MOIN-MOIN”

Über die oben genannte Kennzeichnung hinaus gibt es noch die Möglichkeit, Variablen, die mit einem bestimmten Anfangsbuchstaben beginnen, zusammenzufassen. Man legt zum Beispiel mit dem DEFSTR-Befehl fest, daß alle Variablen mit dem angegebenen Anfangsbuchstaben vom Typ “String” sein müssen. Das gleiche geht sinngemäß auch mit Real- und Integervariablen, nur heißen die Befehle dann DEFRFAL und DEFINT.
Wenn der CPC also von “A” bis “C” Integer, bei “D” und “G” Strings und bei “Q” und “Y” bis “Z” Realtypen bereitstellen soll, lauten die zugehörigen Anweisungen:

DEFINT A-C
DEFSTR D, G
DEFREAL Q, Y-Z

Eine Besonderheit bei der Typenauswahl mit dem DEF [Typ]-Befehl ist , daß für hier zugeordnete Integer- und String-Variablen das Kennzeichen (Dollaroder Prozent) wegfällt.

Die Anonymität der Masse

Oft empfiehlt es sich, Variablen nicht “Stück für Stück” mit Werten zu füllen, sondern formelgesteuert ganze Wertegruppen zuzuweisen. Man faßt dann Variablen zu Feldern (Arrays) zusammen.
Ein Feld besteht aus einer Gruppe von Variablen gleichen Typs, die den gleichen Namen tragen und nur durch einen in Klammern angehängten Index voneinander unterscheidbar sind. Die Größe eines Feldes muß dem BASIC mitgeteilt werden. Dies geschieht mit dem DIM-Befehl.
Für die Zahlendarstellung stehen zwei Variablentypen. Real und Integer, zur Verfügung. Integer-Variablen lassen sich deutlich schneller verarbeiten als Real-Variablen. Grund: Sie stehen der systeminternen Darstellung der Zahlenwerte näher.
Ein weiteres Plus für Integer-Variablen ist die Tatsache, daß sie weniger Speicher verbrauchen als ihre Real-Kollegen.

Keine unnötigen Bremsklötze

Um sich nun im Detail über die Geschwindigkeitsunterschiede klar zu werden, braucht man ein Programm, das die Zeit mißt, die für die Ausführung einer Programmzeile benötigt wird. Für diese Aufgabe bietet sich die Funktion “TIME” an. Sie zählt fortlaufend die Zeit, die seit dem Einschalten des Computers vergangen ist, in Schritten von einer Dreihundertstelsekunde.
Das folgende Programm merkt sich den Stand dieser laufenden Systemzeit
vor und nach einer Programmzeile und berechet dann die Differenz aus beiden Werten:

10 ALTEZEIT = TIME
20 REM Hier Test zeile
30 NEUEZEIT = TIME
40 PRINT "Die Ausfuehrung hat "; (NEUEZEIT-ALTEZEIT)/0.3;" Millisekunden gedauert."

Lassen wir beim ersten Testlauf Zeile 20 weg, gibt der Rechner eine Zeit von 3,333... Millisekunden aus. So lange braucht er für den “Weg” zwischen den beiden TIME-Zuweisungen? - Niemals!...

Des Rätsels Lösung: Der CPC stellt seine Uhr nur jede Dreihundertstelsekunde weiter. Das entspricht unseren 3.33333 Millisekunden. Er kann also Ereignisse, die unterhalb dieses Zeitintervalls passieren, nicht stoppen. Wir können Abhilfe schaffen, indem wir die bewußten Zuweisungen ausreichend oft wiederholen - dann addieren sich die Ausführungszeiten zu Werten, die über 1/3 Sekunde liegen. Wir schieben also die folgenden beiden Zeilen ein:

15 For Zaehler%=1 to 1000
25 NEXT Zaehler%

Fast gut, das Ganze! Jetzt gilt es noch, den “Eigenbedarf" der Schleifenkonstruktion wegzufiltern, um einen Nullstand zu bekommen. Und dann muß ja noch der Faktor 1000 berücksichtigt werden. Durch den müssen wir das Endergebnis teilen, um den Zeitbedarf einer einzigen Operation herauszubekommen. Schließlich und endlich ist uns auch mit einer übertriebenen Genauigkeit (die nur Restfehler herausfordert) nicht gedient; drei Nachkommastellen sind mehr als genug. Die endgültige Version von Zeile 40 sieht dann nach einiger Probiererei folgendermaßen aus:

40 PRINT "Die Ausfuehrung hat";INT((NEUEZEIT-ALTEZEIT-1) /0.3-479)/1000;" Millisekunden gedauert."

Nach dem zweiten Durchlauf des Programms ohne Zeile 20 müßte sich der ausgegebene Werl bei 0 Millisekunden eingepèndelt haben. Der Korrekturwert 479, der in Zeile 40 erscheint, trifft für unseren Redaktions-6128er zu. Sollte Ihr CPC hierein von Null abweichendes Ergebnis bringen, setzen Sie den Korrekturwert 479 für einen Fehler von je 0,001 um eins herauf, beziehungsweise für-0,001 um eins herunter.

Wem die Millisekunde schlägt

Jetzt kann es endlich losgehen! Wir messen an einigen Beispielen, welche Zeit für verschiedene Anweisungen benötigt wird und brauchen dazu nur das jeweilige Statement als Zeile 20 ins Programm einzufügen. Eine simple REM-Zeile

20 REM Hier Zeile

bringt es auf bescheidene 0,147 Millisekunden. Nun zu den begehrten Wertezuweisungen. Wirsetzen zunächst eine Integervariable auf den Wert Null:

20 Variable%=0

Nach dem Programmstart gibt der CPC die Zeit 0.607 Millisekunden aus. Wenn wir dasselbe mit

20 Variable=0

probieren, kommen wir auf 0.837 Millisekunden. Aha! Der Unterschied ist jetzt deutlich meßbar. Wie sieht es mit der String-Variable aus?

20 Text$="A"

Mit 0,864 “Millis” nicht gerade ein Rennpferd. Wie flott das Dimensionieren eines Feldes vonstatten geht, können wir so leider nicht messen. Bereits beim zweiten Durchlauf der Meßschleife gibt es einen “Already dimensioned”-Error. Klar: Ein Feld läßt sich halt nur einmal einrichten. Echte Schnecken scheinen sich bei den mathematischen Funktionen zu verbergen. Probieren Sie einmal:

20 Variable=sqr(3)

Bei den über 26 Millisekunden, die sich hier ergeben, wird langsam deutlich, warum rechenintensive BASIC-Programme so langsam sind.

Machen Sie sich ruhig den Spaß und testen Sie einige Anweisungen Ihrer Wahl auf ihre Ausführungszeit hin. Nach so viel Zeitmessung ist es an der Zeit, sich zu fragen, warum überhaupt solch immense Unterschiede in puncto Verarbeitungszeit bestehen. Der Grund liegt in der internen Verarbeitung der Variablen.

Wenn man sich mit Variablen beschäftigt, stößt man unvermittelt auf einen innigen Zusammenhang von Zeit und Raum im Rechner. Nein, nein - weder Philosophie noch Grundlagenphysik, die Rede ist von Ausführungszeit und Speicherplatz. Man muß wissen, daß der Computer in seinem Inneren mit verschieden “Ur”-Variablen rechnet. Diese heißen “Byte'*, “Word” und “Longword” Sie unterscheiden sich nur durch ihren Wertebereich. Beim Byte umfaßt er 256 Werte, beim Word 65536 und beim Longword 4294967296. Man braucht diese Daten natürlich nicht auswendig zu wissen, es ist aber gut, wenn man eine Vorstellung von den Größenordnungen hat.

Was sich in diese Variablen hineinpacken läßt, wissen wir jetzt. Aber wieviel Speicherplatz sie benötigen, ist ja auch interessant. Ein Byte braucht acht Bit Speicherplatz. Das Word benötigt zwei Byte im Speicher, und das Longword sogar vier.

Jedem Byte seinen Platz

Wie kann man diese Erkenntnisse nun auf BASIC an wenden? Eine Integer-Variable ist zum Beispiel auch zwei Byte lang, entspricht also einem Word. Sie umfaßt den Wertebereich von - 32768 bis 32767. Zusammengezählt ergeben sich hier wie bei einem Word 65536 verschiedene Werte, wobei das höchstwertige Bit als Vorzeichen benutzt wird. Der Aufbau einer Real-Variablen ist sehr viel komplizierter. Der 5 Byte lange Wert besteht aus Vorzeichen, Mantisse und Exponent. Anschließend fehlt nur noch der Dritte im Bunde, der String. Er wird etwas anders behandelt als die beiden anderen Variablentypen. Immerhin hat er ja nicht nur “Wert”, sondern auch “Länge” - und die ist beim BASIC des CPC zu allem Überfluß auch noch veränderbar. Deshalb speichert das BASIC für jede Stringvariable die Länge und die Speicheradresse, ab der die Buchstaben abgelegt sind. Ein Variableneintrag hat im Speicher des CPC folgenden Aufbau:

  • 2 Byte: Adresse der nächsten Variablen mit dem gleichen Anfangsbuchstaben relativ zum Anfang des Variablenspeichers
  • 1 -40 Bytes: Variablenname (im letzten Zeichen ist Bit7 gesetzt)
  • 1 Byte: Variablentyp (1 =lnteger;2=String;4=Real)
  • 2,3 oder 5 Bytes: Zahlenwertoder Stringdeskriptor

Der Stringdeskriptor besteht aus einem Byte für die Länge und zwei daran anschließenden Bytes mit der Adresse des Strings im Speicher.

Das ganze eben erlangte Wissen würde uns nicht viel nützen, wenn das BASIC des CPC nicht den Adreßoperator zur Verfügung stellen würde. Er wird einfach dem Variablennamen vorangestellt. Als Ergebnis erhält man die Speicheradresse der Variable. Auch hierfür wiederein Beispiel:

10 REM Integer zahl
20 A%=3304
30 PRINT "Speicheradresse von A% = ";@A%

An der durch @A% bestimmten Adresse liegt die Variable A%. Deren Werterhält man mit folgender Formel:

IntegerWert=PEEK(@Var%)+256*PEEK(@Var%+1)

Ein Beispiel für die Stringanwendung:

10 REM String-Variable
20 A$="Zaphod Beeblebrox"
30 PRINT "Speicheradresse von A$ = "; @A$
40 PRINT "Die Laenge betraegt =";PEEK (@A$)
50 PRINT "Die Adresse des Texts ist =";PEEK(@A$+1)+256*PEEK(@A$+2)

Damit läßt sich schon einiges anfangen. Eine Möglichkeit wäre beispielsweise die Beschränkung der Stringlänge. Um etwa einen String auf die Länge 5 zu beschränken, kann man statt “A$=MID$(A$, 1,5)” auch “POKE @A$,5” schreiben. Auf was man bei diesem etwas unsauberen Trick achten sollte: Strings lassen sich auf diese Art nur kürzen, nie verlängern. Die jeweils nachfolgenden Variablen hätten nämlich etwas gegen das “illegale” Aufblasen einer Stringlänge.

Als kleines Bonbon und praktischen Anschauungsunterricht in Sachen Tempogewinn haben wir im Anschluß an diesen Artikel noch ein kleines Programm abgedruckt, mit dem sich ein dreidimensionaler Würfel anzeigen und drehen läßt. Das Hauptproblem dabei sind die zeitaufwendigen Sinus und Cosinusberechnungen, die für die Drehung notwendig sind. Deshalb verwendet das Programm eine Tabelle, in der diese Werte für alle ganzen Gradschritte abgelegt sind.

Weil die abzuspeichernden Werte zwischen 0 und 1 liegen, scheint auf den ersten Blick nur ein Real-Feld sinnvoll. Es geht aber auch anders: Man kann sehr viel Geschwindigkeit erreichen und Platz sparen, wenn man diese Zahlen mit 256 multipliziert. Das Ergebnis liegt dann immer zwischen 0 und 256 und läßt sich somit, wenn man einen kleinen Rundungsfehler in Kauf nimmt, in einer Integervariable unterbringen.

Wenn Sie das Programm starten, zeichnet es zunächst den Würfel in seiner Grundstellung. Mit den Cursortasten, der “7” und der “8” läßt sich der Würfel um drei Achsen drehen. Ein Druck auf [Q] beendet das Programm.

Wir hoffen, daß es Sie jetzt in den Fingern juckt, auf Entdeckungsreise im Dschungel des Variablendickichts zu gehen. Wir wünschen Ihnen dabei viel Spaß!

Markus Kräutner/jg , CPCAI

★ PUBLISHER: CPC Amstrad International
★ YEAR: 1992
★ CONFIG: 64K + AMSDOS
★ LANGUAGE:
★ LiCENCE: LISTING
★ AUTHOR: Markus Kräutner
 

★ AMSTRAD CPC ★ DOWNLOAD ★

Type-in/Listings:
» WUERFELSPASS    GERMANDATE: 2012-12-23
DL: 422
TYPE: ZIP
SiZE: 14Ko
NOTE: 40 Cyls
.HFE: Χ

» Wuerfel    (CPC  Amstrad  International)    GERMANDATE: 2020-04-26
DL: 173
TYPE: ZIP
SiZE: 5Ko
NOTE: 40 Cyls
.HFE: Χ

★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
Je participe au site:
» Vous avez des infos personnel, des fichiers que nous ne possédons pas concernent ce programme ?
» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop/c
Page créée en 388 millisecondes et consultée 815 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.