Benutzer:Mstma/gvergleich

Aus C64-Wiki
Zur Navigation springenZur Suche springen

Dieses Dokument beschreibt einen einfachen Geschwindigkeitsvergleich auf dem Commodore 64 in den Sprachen CBM-Basic, G-Pascal, C (cc65) und Assembler.

Als Test dient eine doppelt verschachtelte Schleife, bei deren Durchlaufen die beiden Zählervariablen miteinander multipliziert werden.

Ergebnisse[Bearbeiten | Quelltext bearbeiten]

Der Geschwindigkeitsvergleich wurde mit 50 mal 50 Durchläufen und 2.500 Multiplikationen gemacht (die Variable bzw. Konstante MX hat den Wert 50). Die folgende Tabelle enthält die gemessenen Laufzeiten auf dem C64-Emulator POWER64_Macintosh.

In jeder der Sprachen werden zwei unterschiedliche Schleifen-Typen getestet: einmal mit while [Bedingung] do und einmal mit for [von..nach] do. In Basic gab es einen deutlichen Geschwindigkeitsunterchied zwischen einer mit IF- und GOTO-Befehlen nachgebauten while-Schleife und einer Schleife mit FOR ... NEXT.

Sprache While-Schleife For-Schleife
CBM-Basic 27,3 Sek. 13,2 Sek.
G-Pascal 13,0 Sek. 12,3 Sek.
cc65 1,2 Sek. 1,2 Sek.
Assembler 1,9 Sek. 1,9 Sek.

Quelltexte[Bearbeiten | Quelltext bearbeiten]

CBM-Basic[Bearbeiten | Quelltext bearbeiten]

Variante mit nachgebildeter while-Schleife:

 10 REM BASIC MIT WHILE-SCHLEIFE 
 20 T=TI 
 25 MX=50 
 30 A=1 
 35 IF A>MX THEN 100 
 40 B=1 
 45 IF B>MX THEN 80 
 50 C=A*B 
 60 B=B+1 
 70 GOTO 45 
 80 A=A+1 
 90 GOTO 35 
 100 PRINT (TI-T)/60 
 110 PRINT C 

Variante mit FOR-Schleife:

 10 REM BASIC MIT FOR-SCHLEIFEN 
 20 T=TI 
 25 MX=50 
 30 FOR A=1 TO MX 
 40 FOR B=1 TO MX 
 50 C=A*B 
 60 NEXT B 
 70 NEXT A 
 80 PRINT (TI-T)/60 
 90 PRINT C


G-Pascal[Bearbeiten | Quelltext bearbeiten]

Zum Kompilieren und Ausführen der Pascal-Programme muss zuerst G-Pascal geladen werden.

Variante mit while-Schleife:

 (* Pascal mit While-Schleife *) 
 const mx=50; 
 var a,b,c,t1,t2: integer ; 
  
 (* entspricht variable ti in basic *) 
 function gettime; 
   begin 
   gettime:=memc [$00a0]*65536+memc [$00a1]*256+memc [$00a2] 
   end ; 
  
 (* hauptprogramm *) 
 begin 
 t1:=gettime; 
 a:=1; 
 while a <= mx do 
 begin 
   b:=1; 
   while b <= mx do 
   begin 
     c:=a * b; 
     b:=b + 1; 
   end ; 
   a:=a + 1; 
 end ; 
 t2:=gettime-t1; 
 (* ausgabe in sekunden mit einer dezimalstelle *) 
 write (t2/60,"."); 
 writeln ((t2 mod 60)*10/60); 
 writeln (c); 
 end . 


Variante mit for-Schleife:

 (* Pascal mit For-Schleife *) 
 const mx=50; 
 var a,b,c,t1,t2: integer ; 
  
 (* entspricht variable ti in basic *) 
 function gettime; 
   begin 
   gettime:=memc [$00a0]*65536+memc [$00a1]*256+memc [$00a2] 
   end ; 
  
 (* hauptprogramm *) 
 begin 
 t1:=gettime; 
 for a:=1 to mx do 
 begin 
   for b:=1 to mx do 
     c:=a * b; 
 end ; 
 t2:=gettime-t1; 
 (* ausgabe in sekunden mit einer dezimalstelle *) 
 write (t2/60,"."); 
 writeln ((t2 mod 60)*10/60); 
 writeln (c); 
 end .

C (cc65)[Bearbeiten | Quelltext bearbeiten]

Die Programme müssen zuerst mit cc65 kompiliert werden. Dies geschieht am einfachsten mit dem Aufruf cl65 -O [QUELLDATEI]. Das kompilierte Programm kann auf dem C64 wie ein Basic-Programm geladen und gestartet werden.

Variante mit while-Schleife:

 #include <stdio.h> 
 #include <stdlib.h> 
  
 #define MX 50 
 #define TI ((unsigned char*)0x00A0) 
  
 // entspricht Variable ti in Basic; allerdings nur 16 Bit gross! 
 unsigned int gettime (void) 
 { 
   return (unsigned int)TI[1] * 256 + (unsigned int)TI[2]; 
 } 
  
 int main (void) 
 { 
   unsigned int a = 0; 
   unsigned int b = 0; 
   unsigned int c = 0; 
   unsigned int t1 = 0; 
   unsigned int t2 = 0; 
   t1 = gettime(); 
   a = 1; 
   while (a <= MX) 
   { 
     b = 1; 
     while (b <= MX) 
     { 
       c = a * b; 
       b = b + 1; 
     } 
     a = a + 1; 
   } 
   t2 = gettime()-t1; 
   printf ("%d\n", c); 
   printf ("%d.%d Sek.\n", t2 / 60, (t2 % 60) * 10/60); 
   return EXIT_SUCCESS; 
 } 


Variante mit for-Schleife:

 #include <stdio.h> 
 #include <stdlib.h> 
  
 #define MX 50 
 #define TI ((unsigned char*)0x00A0) 
  
 // entspricht Variable ti in Basic; allerdings nur 16 Bit gross! 
 unsigned int gettime (void) 
 { 
   return (unsigned int)TI[1] * 256 + (unsigned int)TI[2]; 
 } 
  
 int main (void) 
 { 
   unsigned int a = 0; 
   unsigned int b = 0; 
   unsigned int c = 0; 
   unsigned int t1 = 0; 
   unsigned int t2 = 0; 
   t1 = gettime(); 
   for (a = 1; a <= MX; a ++ ) 
   { 
     for (b = 1; b <= MX; b ++ ) 
     { 
       c = a * b; 
     } 
   } 
   t2 = gettime()-t1; 
   printf ("%d\n", c); 
   printf ("%d.%d Sek.\n", t2 / 60, (t2 % 60) * 10/60); 
   return EXIT_SUCCESS; 
 }


Assembler (acme)[Bearbeiten | Quelltext bearbeiten]

Die Programme müssen zuerst mit ACME übersetzt werden. Dies geschieht mit dem Aufruf acme [QUELLDATEI]. Das übersetzte Programm wird dann auf dem C64 mit LOAD "[DATEI]", 8, 1 geladen. Danach NEW aufrufen und das Basic-Programm zur Zeitmessung laden und starten.

Basic-Programm zum Aufruf und zur Zeitmessung der Assembler-Programme:

 10 REM ZEITMESSUNG FUER ASSEMBLER 
 20 T=TI 
 30 SYS 49152 : PRINT 
 40 PRINT (TI-T)/60 

Variante mit nachgebildeter while-Schleife:

   !to "a-while", cbm 
   *= $c000 
   umult  = $b357 
   axout  = $bdcd 
   fak1   = $28 
   fak2   = $71 
  
 ; a = 1   
   lda #1 
   sta a 
 loop1 
 ; a > mx 
 ; (bcs testet auf groesser gleich, daher muss zuerst 
 ; ein Vergleich mit beq erfolgen) 
   lda a 
   cmp mx 
   beq initb 
   bcs endloop1 
 initb 
 ; b = 1 
   lda #1 
   sta b 
 loop2 
 ; b > mx 
 ; (bcs testet auf groesser gleich, daher muss zuerst 
 ; ein Vergleich mit beq erfolgen) 
   lda b 
   cmp mx 
   beq mult 
   bcs endloop2 
 mult 
 ; zwei 16 Bit Zahlen mit umult multiplizieren 
 ; (s. Abschnitt 43, Bild 29, Seite 50 im Sonderheft) 
   lda #0 
   sta fak1+1 
   sta fak2+1 
   lda a 
   sta fak1 
   lda b 
   sta fak2 
   jsr umult 
   stx c 
   sty c+1 
 ; b = b + 1 
   inc b 
   jmp loop2 
 endloop2 
 ; a = a + 1 
   inc a 
   jmp loop1 
 endloop1 
 ; Ergebnis ausgeben 
 ; (axout gibt 16 Bit Zahl direkt aus) 
   ldx c 
   lda c+1 
   jsr axout 
   rts 
  
 mx 
   !by 50 
 a 
   !by 0 
 b 
   !by 0 
 c 
   !by 0, 0 


Variante mit nachgebildeter for-Schleife:

   !to "a-for", cbm 
   *= $c000 
   umult  = $b357 
   axout  = $bdcd 
   fak1   = $28 
   fak2   = $71 
    
 ; a = 1 
   lda #1 
   sta a 
 loop1 
 ; b = 1 
   lda #1 
   sta b 
 ; zwei 16 Bit Zahlen mit umult multiplizieren 
 ; (s. Abschnitt 43, Bild 29, Seite 50 im Sonderheft) 
 loop2 
   lda #0 
   sta fak1+1 
   sta fak2+1 
   lda a 
   sta fak1 
   lda b 
   sta fak2 
   jsr umult 
   stx c 
   sty c+1 
 ; b = b + 1 
   inc b 
 ; b <= mx 
 ; (bcc testet auf kleiner, beq auf gleich) 
   lda b 
   cmp mx 
   bcc loop2 
   beq loop2 
 ; a = a + 1 
   inc a 
 ; a <= mx 
 ; (bcc testet auf kleiner, beq auf gleich) 
   lda a 
   cmp mx 
   bcc loop1 
   beq loop1 
 ; Ergebnis ausgeben 
 ; (axout gibt 16 Bit Zahl direkt aus) 
   ldx c 
   lda c+1 
   jsr axout 
   rts 
  
 mx 
   !by 50 
 a 
   !by 0 
 b 
   !by 0 
 c 
   !by 0, 0