FreeBasic: Optimierung
Theorie
BearbeitenVariabeln sparen
BearbeitenBevor man mit irgendwelchen aufwändigen Aktionen beginnt, kann man ganz banal prüfen, ob unnötige Variabeln deklariert sind.
Hier hilft diese Direktive:
OPTION EXPLICIT
Seit 0.17 ist Deklarieren obligatorisch und "OPTION EXPLICIT" wird nicht mehr akzeptiert.
Damit muss man jede einzelne Variable deklarieren. Ihr werdet staunen, wie viele temporäre Variablen ihr angelegt habt.
Als nächstes könnt ihr die Dimensionerung der Felder prüfen. Ist irgendeines zu groß?
In ähnlicher Art könnt ihr Strings prüfen. Speichert ein String z.B. nur das Resultat des INKEY-Befehls, reicht ein 2 Byte langer String aus. Vorsicht ist bei anderen Strings angebracht, die der Benutzer direkt beeinflusst.
Was lohnt sicht?
BearbeitenGesucht: Besserer Titel
Es lohnt sich nicht, eine Subroutine zu optimieren, die nur einmal aufgerufen wird.
Messt bei jedem größeren Block aus, wie oft er aufgerufen wird und wie lange er braucht.
Die Zeitmessung dient dann auch gleich der Erfolgskontrolle.
Muster suchen und erkennen
BearbeitenGeradzahligkeitsprüfer
BearbeitenOb eine Zahl gerade ist oder nicht, kann man auf verschiedene Arten prüfen:
Dim a as integer
do
input a
if a=1 or a=3 or a=5 or a=7 or a=9 then
? "Ungerade"
else
? "Gerade"
End if
loop
Diese Lösung ist sowohl mühsam zum Programmieren, als auch unnötig langsam (und prüft zudem nur Ziffern).
Dim a as integer
do
input a
if a MOD 2 then
? "Ungerade"
else
? "Gerade"
End if
loop
Schon viel besser.
Auch gut:
Dim a as integer
do
input a
if a AND 1 then
? "Ungerade"
else
? "Gerade"
End if
loop
2 Lösungen also; nun ergibt sich die Frage, was besser ist.
Dim t as double
Dim a as integer
Dim i as integer
Dim res as integer
t=timer
for i=0 to 20000
for a= 0 to 10000
if a MOD 2 then
res=1
else
res=0
End if
next a
Next i
? timer-t
t=timer
for i=0 to 20000
for a= 0 to 10000
if a AND 1 then
res=1
else
res=0
End if
next a
Next i
? timer-t
sleep
Der Print-Befehl wurde entfernt, weil er bekanntermassen langsam ist und damit die Messung verfälschen würde.
Da die Methode mit AND um den Faktor 5 bis 10 schneller ist, ist diese zu empfehlen.
Funktionen und Subroutinen
BearbeitenDer Preprozessor
BearbeitenEinzeilige Funktionen lohnen sich in der Regel als Makro zu verfassen.
Begründung: Wie ihr im Kapitel Preprozessor gelernt habt, fügt der Compiler den Code direkt ein.
Das heisst, der vorallem bei kleinen Funktionen grosse Zeitverlust bei Aufrufen der Subroutine beziehungsweisse Funktion, tritt nicht auf.
Beispiel 1
Bearbeitendim i as single
Declare function flaeche(SeiteA as single) as single
for i=0 to 10 step 0.5
? flaeche(i)
next i
sleep
function flaeche(SeiteA as single) as single
flaeche=SeiteA^2
End function
Besser:
#Define flaeche(SeiteA) SeiteA^2
dim i as single
for i=0 to 10 step 0.5
? flaeche(i)
next i
sleep
Aus der Praxis
BearbeitenFarben
BearbeitenAnstelle von solchen Sachen:
FUNCTION Farbe(R AS INTEGER,G AS INTEGER,B AS INTEGER)
Farbe = (B+G*256+R*256*256)
END FUNCTION
Kann man gleich das FreeBasic Interne Macro RGB nehmen. (Syntax dokumentieren oder auf entsprechendes Kapitel verweissen)
Einzelne Zeichen eines Strings bearbeiten
BearbeitenFreebasic hat erstaunlich viele Methoden im Angebot.
Wir gehen ihr nicht genau darauf ein, wieso funktionieren sondern vergleichen sie ganz einfach mit einander.
Zuerst mal der Beweis, das sie das gleiche Resultat liefern:
Dim a as string
Dim i as integer
a="Hallo Welt! ABCDEFGHIJKLMNOPQRSTUVVWXYYZ"
for i=1 to len(a)
? a[i-1]; " ";asc(a,i); " ";asc(mid$(a,i,1))
next i
sleep
Alle drei Methoden liefern das gleiche Resultat, aber was ist nun schneller?
Dim a as string
Dim b as ubyte
Dim c as double
dim i as integer
dim i2 as integer
a="Hallo Welt! ABCDEFGHIJKLMNOPQRSTUVVWXYYZ"
c=timer
for i2=0 to 100000
for i=0 to len(a)-1
b=a[i]
next i
next i2
? timer-c
c=timer
for i2=0 to 100000
for i=1 to len(a)
b=asc(a,i)
next i
next i2
? timer-c
c=timer
for i2=0 to 100000
for i=1 to len(a)
b=asc(mid$(a,i,1))
next i
next i2
? timer-c
sleep
b=a[i] (Erklärung im Kapitel Pointer) ist mit Abstand die schnellste Methode.
In der Praxis sollte die Wahl aber genau durchdacht werden, weil Pointer auch ein Risiko darstellen (siehe Kapitel Pointer).
prüfen und dann einbauen
Bearbeitendim a as double
Dim i as integer
dim i2 as integer
dim b as integer
dim temp as integer
?
? "Beispiel zum Thema Rechnungen optimieren"
? "Thema Hochrechnen"
?
? "Zeit Bedarf fuer Erste Formel:"
a=timer
for i2=0 to 1000000
for i=0 to 20
'Erste Formel
b=2^i
'Erste Formel
next i
next i2
? timer-a
?
? "Zeit Bedarf fuer Zweite Formel:"
a=timer
for i2=0 to 1000000
for i=0 to 20
'Zweite Formel
if i = 0 then
b=1
else
b = 2 shl (i-1)
end if
'Zweite Formel
next i
next i2
? timer-a
?
? "Zeit Bedarf fuer Dritte Fromel:"
a=timer
for i2=0 to 1000000
for i=0 to 20
'Dritte Formel
b=1
for temp=1 to i
b=b*2
next temp
'Dritte Formel
next i
next i2
? timer-a
?
? "Wie ihr seht, ist die zweite Formel viel schneler, ist aber aber auch richtig?"
? "(weiter mit Tastendruck)"
?
sleep
for i=0 to 20
b=2^i
? b
if i = 0 then
b=1
else
b = 2 shl (i-1)
end if
? b
b=1
for temp=1 to i
b=b*2
next temp
? b
?
next i
?
? "Keine Abweichung, also ist sie Richtig."
? "(beenden mit Tastendruck)"
?
sleep
Byvar oder Byref?
BearbeitenWas ist schneller Byref oder Byval? Das kommt auf das an, was als Parameter übergeben wird. Wird eine komplexe Struktur übergeben auf jeden Fall Byref. Wenn es sich um Integers handelt würde dies keinen Sinn ergeben, da eine Referenz 4 Byte groß ist und ein Integer auch. Bei Strings lohnt es sich auch alle mal und bei Byte und Short wäre Byref sogar negativ.