FreeBasic: Optimierung

Aus Wikibooks
Zur Navigation springen Zur Suche springen

Theorie[Bearbeiten]

Variabeln sparen[Bearbeiten]

Bevor 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?[Bearbeiten]

Gesucht: 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[Bearbeiten]

Geradzahligkeitsprüfer[Bearbeiten]

Ob 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[Bearbeiten]

Der Preprozessor[Bearbeiten]

Einzeilige 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[Bearbeiten]
dim 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[Bearbeiten]

Farben[Bearbeiten]

Anstelle 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[Bearbeiten]

Freebasic 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[Bearbeiten]

dim 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?[Bearbeiten]

Was 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.