C++ suger

”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!

 

Annonser

Kommentera

Fyll i dina uppgifter nedan eller klicka på en ikon för att logga in:

WordPress.com Logo

Du kommenterar med ditt WordPress.com-konto. Logga ut / Ändra )

Twitter-bild

Du kommenterar med ditt Twitter-konto. Logga ut / Ändra )

Facebook-foto

Du kommenterar med ditt Facebook-konto. Logga ut / Ändra )

Google+ photo

Du kommenterar med ditt Google+-konto. Logga ut / Ändra )

Ansluter till %s