Beiträge von JeeK im Thema „3D-Grafik in V2 BASIC“


    Diese Wertebereichsumrechnung von von 512 <-> 2*PI macht da den Tabellenvorteil irgendwie zunichte. Ich hätte mir da mehr Potential in dieser Optimierung versprochen. Das gesamte Mapping (schon "r") könnte sich da an 0-511 orientieren ...

    Jetzt solltest Du die "Zeitersparnis" durch deine "Optimierungen" nur noch ins Verhältnis setzen zu der Zeit, die Du benötigt hast, um diese Änderungen ins Programm einzubringen. Und dann fällt die Bilanz durchgehend negativ aus, wenn man davon ausgeht, daß das Programm nur einmal laufen gelassen wird.

    Macht ja nix, zu diesem Zweck alleine war es auch nicht gedacht. Die Neugier nach dem konkreten Verhalten war hier völlig ausreichend. Wenn es danach ginge, sollte man vielleicht generell die Finger vom C64 lassen. ;)

    Weiterhin leidet die Einsichtigkeit durch die Verwendung von Variablen anstelle von numerischen Konstanten ganz erheblich. Gerade der Ersatz von einstelligen Konstanten durch Variable lohnt sich (mit Ausnahme von - etwa - E=1 und E direkt als erste Variable definiert) fast überhaupt nicht, Null kann aber problemlos überall durch den Dezimalpunkt ersetzt werden. Ersatz von mehrstelligen und 'gängigen' Konstanten wie etwa mit V=53248 ist aber in Ordnung.

    Das kommt darauf an, an welcher Stelle die Variablen definiert bzw. in der Variablen-Liste aufzufinden sind.
    Ich hatte das bislang nicht im Detail untersucht bzw. in allen Varianten verglichen, aber wenn ich mir das jetzt so ansehe, dann ist "." für 0 in der Tat nicht zu unterbieten. Aber dann sind einstellige Konstanten erst dann schneller (manche brauchen länger) erst wenn die Variable an 10. Stelle definiert ist. Ok, da müsste man schon recht aufpassen. Bei 2-stelligen Konstanten (da haben wir ja schon ein Fließkommamultiplikation drinnen), sind ca. die ersten 28 Variablen (da muss man schon 2-stellige nehmen, die aber geringfügig die Suche verlangsamen) schneller als die Konstante.

    Klar, das Gefummle mit den Variablen will man sich freilich nicht antun und wie du schon sagst kann man jedenfalls guten Gewissens alles was mind. 3-stellig auf jeden Fall in eine Variable packen und muss dabei nicht mal an die Reihenfolge achten, um auf jeden Fall einen Geschwindigkeitsvorteil zu erhalten.

    Die "Deklaration" von häufig genutzten Variablen hingegen bringt durchaus etwas, wenn es um eine enge Schleife geht und im wesentlichen nur die Grundrechenarten im Spiel sind. Wovon man im aktuellen Beispiel aufgrund der SQR() und COS() Funktionen leider auch nicht sprechen kann. Ich hab' aber mal in einem anderen Programm (Apfelmännchen) die innere Schleife so erheblich beschleunigt:

    Das hab ich ja nicht verschwiegen bzw. es explizit erwähnt. ;)

    Zusammen mit dem restlichen Programm *) brauchte das für das Ausgangsbild (die "Grundmenge") zunächst mal 195 Minuten. Als ich dann die Variablen X, Y, X2, Y2, XY, R und J (in dieser Reihenfolge) als erste Variablen deklariert hatte, fiel die Rechenzeit auf 156 Minuten! Dabei war es nicht nötig, die Laufvariable I und den Endwert N früh zu deklarieren, da FOR einen Zeiger auf seine Laufvariable ermittelt und so immer schnellen Zugriff hat, und der Endwert auch nur einmal ausgewertet wird und dann mit auf den Stapel geht. Aber als ich dann die Konstante 4 auch noch durch eine Variable ersetzt hatte, wurde das Programm schon wieder langsamer!

    Die FOR-NEXT-Schleifen hab ich ja deswegen auch nicht optimiert, außer die Werte lagen sonst schon in Variablen.
    Wegen der "4", siehe oben. ;)

    Letztenendes war aber genau diese Schleife dann der Knackpunkt und genau die hatte ich dann später mal in Maschinencode übersetzt, wo dann die Arithmetikroutinen des Interpreters direkt aufgerufen wurden. In der Folge wurde dann diese Schleife um den Faktor 3 beschleunigt, zusammen mit dem restlichen Programm lag dann beim Ausgangsbild die Zeit bei ca. 90 Minuten. Ein anderer Koordinatensatz (mit 254 als maximale Rechentiefe) wurde z.B. von 2360 auf 840 Minuten beschleunigt.

    Auch beachtlich. So ein Compiler ist nicht zu verachten.

    Um noch mal zum Hut-3D-Plotter zurückgekommen: mein Originalprogramm war ja auch schon nicht ganz ohne Optimierungen. Zum Beispiel muß man den Bitwert zum Einmaskieren ja nicht unbedingt mit angezogener Handbremse (sprich: mit 2^(7-(XPAND7))) berechnen. Auch die Adreßberechnung arbeitet ja bereits mit einer Tabelle, anstatt ständig den vollen Ausdruck 'AD=8192+320*INT( YP/8 )+8*INT( XP/8 )+(YPAND7)' auszuwerten (mit 'XPAND504' geb' ich dir aber Recht... hab' ich auch schon mal verwendet... )

    Der "^"-Operator ist freilich ein ziemlicher Klotz am Bein. So eine Polynom-Auswertung für die Exponentiation ist freilich dahingehend echt massiv.

    Ansonsten gilt nach wie vor: Experimentieren macht Spaß!

    Das ist das Motto!

    LG, speziell allen Experimentierern
    JeeK

    Zitat von »Tale-X«

    Rest des Programms wird diese Schleife nicht fortgesetzt, und darum - richtig beobachtet - 'hängt' die Schleife zunächst, wenn die IF-Anweisung nicht (mehr) ausgeführt wird. Das ist aber weiter kein Problem, wenn man dann bei der nächst äußeren Schleife die Laufvariable explizit angibt. In diesem Fall sucht NEXT den Stapel nach der FOR-Anweisung mit der passenden Laufvariable ab und entfernt sauber alle 'hängenden', nicht abgeschlossenen Schleifen dazwischen.

    Oder wenn ein FOR die gleiche Laufvariable verwendet, werden etwaige bereits offenen FOR-NEXT-Schleifen (und alle darin verschachtelten) vom BASIC-Stack entfernt. Schaut mitunter wild aus - im Forum war in jüngerer Zeit eh so ein Listing nur mit gleicher Schleifenvariable mit an allen Ecken und Enden offenen Schleifen ...

    Oder Bitte melde dich an, um diesen Link zu sehen.: Wenn das in einem Unterprogramm ist, dann räumt das RETURN auch alle im Unterprogramm offen gebliebenen FOR-NEXT-Stack-Frames weg. ;)

    Als Nachtrag, die Herumspielerei hat bisserl gedauert. :)

    Sehr interessant und nett zum rumspielen, die reine Basic-Implementierung. Vor allem, man braucht einfach sonst nix dazu. ;) Deswegen hab ich dann auch noch so einfache "Erweiterungen" mal außen vor gelassen.

    Wenn ich mir das Listing so anschaue, ist gleich mein interner Optimierer angesprungen und ich wollte wissen, ob diese da
    wirklich was bringen ... Gleich vorab: Wegen der massiven Nutzung der trigonometrischen Funktionen (also wenn man das nicht durch vorberechnete Felder ersetzt), kann man in diesem Fall "nur" so um 5 % bei der Laufzeit rausholen.


    Das ist auch noch die Zeitmessung mit TI$ drinnen (und die Tastenabfrage am Schluss fällt durch). Ist auch angehängt.

    Praktisch sind freilich für die Grafikprogrammierung folgende einfache Optimierungen:

    Statt Zeile 17:

    Code
    3 DIMF%(8000):CLR

    Löscht den im Basic-RAM liegen Hires-Speicher BIF- äh blitzschnell, da Basic Felder initialisiert. Solle auch mit Fließkommafelder gehen, aber mit 2 Byte pro Element rechnet es sich leichter. ;)

    Die Zeile 29 ersetzt durch:

    Code
    29 AD=LI(YP/8)+(XPAND504)+(YPAND7):POKEAD,PEEK(AD)ORBI(XPAND7):RETURN

    Ersetzt die Modulo-8-Rechnung durch ein simples AND.

    Dazu kann man freilich dann noch mehr mit Variablen herausholen, wo Konstanten, die aufwändig vom Interpreter immer jedes Mal in die Fleißkommadarstellung umgerechnet werden müssen, durch Variablen ersetzt werden. Die häufigen Variablen werden damit mittels DIM
    zuerst in der Variablenliste angelegt (ohne sie gleich mit einem Wert belegen zu müssen), entsprechend der Häufung in der Nutzung.

    Zeitmessungen: (hmm als Quellcode, wegen der Formatierung)

    Code
    Variante                Dauer   Verbesserung    in %------------------------------------------------------Original                56:23Adressberechnung        56:11   00:12           <0.4Grafiklöschen+Adressb.  55:46   00:37           1Gra.löschen+Adress+Var. 53:40   02:43           <5