Hi allerseits,
bevor ich jetzt mit der Tür ins Haus falle, will ich eben mal die Rahmengeschichte zum Besten geben. Ich habe dieses Jahr mein Informatik-Studium begonnen. Im Modul OOP haben wir neulich im Praktikum einen einfachen Algorithmus zum Berechnen von Pi behandelt (die Leibniz-Reihe). Ein paar anderen erfahreneren Kommilitonen und mir war die reine Implementierung in Java ein bisschen zu fad, daher kamen noch ein paar andere Sprachen hinzu. Irgendwann wurde dann aus der reinen Implementierung ein kleiner Wettkampf um Performance/Geschwindigkeit. Gut, die Implementierungen in PHP oder JavaScript waren dann nicht mehr wirklich konkurrenzfähig. Auch Lua und Python waren nicht die besten Kandidaten. Tatsächlich war die Java-Variante zunächst die schnellste - bis mein C-Programm fertig war. Das war dann dezent schneller. Ein Kommilitone konnte das nicht auf sich sitzen lassen und hat eine eher unbekannte, ungewöhnliche Sprache verwendet: Pony. Auf meinem Netbook (Intel Celeron) braucht die Pony-Variante bei 10.000.000 Schleifendurchläufen mitsamt Ergebnisausgabe knapp 230 ms. Knapp doppelt so schnell wie mein C-Code...
Also musste jetzt das letzte Register gezogen werden (haha, Register...): Assembler.
Ich bin bei weitem kein Assembler-Profi. Ich kann zwar damit programmieren, aber die meisten Tricks kenne ich vermutlich nicht. Da das drumherum um den Algorithmus relativ kurz ist, habe ich direkt alles in Assembler geschrieben. Für knappe 20 ms schneller hat es auch gereicht, auf meinem Rechner also ~210 ms im Schnitt. Ich glaube nicht, dass das noch jemand schlägt. Aber ich bin mir fast sicher, dass es da noch Optimierungsmöglichkeiten gibt. Da sich hier auch einige Leute schon ausführlich mit Assembler auseinandergesetzt haben, dachte ich, ich frage mal, ob jemandem noch etwas einfällt. Kompiliert wurde das Ganze bei mir mit nasm, gelinkt mit gcc unter Debian 8. Die Zeiten wurden einfach im Terminal mit time gemessen.
global main
extern printf
section .data
stepc: dd 0
pi: dq 0.0
sign: dd 0
store: dd 1
four: dq 4.0
msg: db "Pi: %f",10,0
section .text
main:
xor edx, edx
loop:
fld qword [pi]
;Bruch 4/... berechnen
fld qword [four]
fild dword [store]
fdiv
;Vorzeichenwechsel und Addition
cmp dword [sign], 0
jnz sub
fadd
jmp afteradd
sub:
fsub
;Speichern Variable
afteradd:
not dword [sign] ;Flag für VZW
fstp qword [pi]
;Schleifenkopf
add dword [store], 2
inc edx
cmp edx, 10000000
jnz loop
;Ausgabe (printf)
push dword [pi+4]
push dword [pi]
push dword msg
call printf
add esp, 12
mov eax, 0
ret
Alles anzeigen
Ich denke mal, so ein paar ASM-Kniffe zu kennen, schadet keinem. Hat auf jeden Fall das Potential, sich zu einer spannenden Diskussion zu entwickeln.
Grüße!