Benutzer:Mstma/gvergleich
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