”Vilket programmeringsspråk är bäst?” Ofta ser man denna fråga dyka upp i olika programmeringsforum på nätet. Sen följer med stor sannolikhet en hätsk debatt utan några gråskalor. Varje debattör framhåller ofta ett enda språk som det i särklass bästa: ”Ska man programmera på riktigt så är det bara X som gäller. Allt annat är skräp”. Inte sällan ser man en tendens att betrakta krånglig lågnivåprogrammering som ”finare” är enklare högnivåprogrammering.
Själv gillar jag att tänka på olika programmeringsspråk ungefär som olika konstformer: olja, akryl, akvarell, tusch, blyerts, torrnål, etsning, keramik, glas, skulptur… Vilken konstform är bäst? Ingen konstform är naturligtvis bäst. Men sen när vi kommer till den funktionella aspekten på specifika programmeringsuppdrag så finns det givetvis viktiga faktorer att ta i beaktande. Där kan man lätt ställa upp vissa tumregler. En sådan tumregel skulle kunna vara:
Eftersom tid är pengar – välj ett språk på så hög nivå som möjligt men som ändå på ett adekvat sätt löser uppgiften.
Ibland kanske den bästa lösningen är att göra den övergripande strukturen i ett högnivåspråk och sen programmera vissa resurskritiska procedurer i nåt lågnivåspråk. Det allra bästa är förstås om man kan utnyttja att någon annan redan har gjort den tidsödande lågnivåprogrammeringen tidigare. Om nån annan reda gjort jobbet förrut – varför uppfinna hjulet en gång till?
Om man på ett smart och kostnadseffektivt sätt vill bygga ett hus – varför först sätta sig ner och i minsta detalj designa alla spikar och skruvar?
Nu ska vi jämföra tre olika språk hur de kan lösa en konkret programmeringsuppgift – att räkna ut fakulteten av en miljard.
För de som inte är så matematiskt bevandrade kan jag säga att fakulteten av ett tal x är produkten av alla hela tal från ett upp till talet x. Fakulteten av 8 är alltså 1*2*3*4*5*6*7*8. Fakulteten sticker snabbt iväg och blir ruskigt stor för större tal. Fakulteten av 63 är ett tal som är större än det beräknade antalet partiklar i universum. Min TI-83 räknare kan nätt och jämt räkna ut fakulteten av 69. Det blir ungefär 1,7112 * 10^98. Högre än så klarar den inte.
Själv har på senaste tiden kommit att bli ganska förtjust i språket C# (C sharp). Det är ett språk som ligger på en slags mellannivå och har fördelar som vanligtvis tillkommer både hög- och lågnivåspråk. Här nedan är mitt C#-program för att räkna ut fakulteten på en miljard.
double ax = 1;
double ay = 0;
double x;
double NumberToDivideByPower = 0;
double NumberToDivideBy = 1;
DateTime t1 = DateTime.Now;
for (double b = 2; b <= 1000000000; b++)
{
x = b / NumberToDivideBy;
if (x == 10)
{
NumberToDivideBy *= 10;
NumberToDivideByPower++;
x = 1;
}
ay += NumberToDivideByPower;
ax *= x;
if (ax >= 10)
{
ax /= 10;
ay++;
}
}
TimeSpan tt = DateTime.Now – t1;
MessageBox.Show(”(1*10^9)! = ” + ax.ToString() + ” * 10 ^ ” + ay.ToString()
+ ”\r\n\r\n” + ”Tidsåtgång:” + tt.ToString());
På min 1,2 GHz laptop tar denna beräkning c:a 48 sekunder. Jag var emellertid inte nöjd. Jag tänkte att det borde gå att göra ett snabbare program med ett annat språk. Valet föll på C++.
Jag gjorde alltså en C++-version av ovanstående program men programmet ser i princip identiskt ut bortsett från att jag valt att ändra vissa variabeltyper för att uppnå bättre prestanda. I slutänden visar det sig ändå att C++ och C#-programmen i princip är lika snabba. Finns det ändå en chans att göra programmet snabbare? Svaret är förstås Assembler. Assemblerversionen jobbar lite annorlunda än C#/C++-versionerna. Mycket av matematiken sker på bit-nivå.
TITLE BillionFactorial (BillionFactorial.asm)
; This program calculates the factorial of 1 billion very fast
; with four significant hexadecimal digits
; Last update: 2008-05-17
; by Gustav Bonds
.code
main PROC
mov eax,1 ; mantissa of factorial
mov ebx,1 ; counter from 1 to 1 billion
mov esi,0 ; power of two (LO DWORD)
mov edi,1000000000 ; 1 billion loop limit
mov ebp,0 ; power of two (HI DWORD)
startloop:
inc ebx
mul ebx
jnc K4 ; You don’t need to do shrd at all
bsr ecx,edx ; Bit scan right put result in cl (ecx)
bt eax,ecx ; Check highest bit among the trimmed away ones
jc K2 ; Jump to the procedure where we increase EAX
inc cl
shrd eax,edx,cl ; Shift right cl number of bits from EDX to EDA
jmp K3
K2:
inc cl
shrd eax,edx,cl
inc eax
K3:
add esi,ecx
jnc K4
inc ebp
K4:
cmp ebx,edi ; do we have 1 billion yet?
jne startloop ; jump if not equal to startloop
exit
main ENDP
END main
På bara 16,9 sekunder får vi svaret i hexadecimal form: A59E8867 * 2 ^ 6A0079F06 vilket decimalt motsvarar ungefär 9,904 * 10 ^ 8 565 705 522. Visserligen har de båda andra programmen större precision men vill man prioritera rå snabbhet så kan man säga att C# och C++ suger. Assembler äger!



