Suurin yhteinen tekijä assemblerilla

Ztane 14.05.07 22:50

Etsii annettujen 32-bittisten kokonaislukujen suurimman yhteisen tekijän (NASM, cdecl, 386+).

 Tekstiversio  Arvo: 6 (8 ääntä)  Äänestä: +  -
        ; 32-bit x86 assembly
        BITS 32


        ; function entry
        global gcd
gcd:
        ; load arguments to eax (a) and edx (b).
        mov  eax, [esp + 4]
        mov  edx, [esp + 8]
        ; cdecl, must save ebx
        push ebx
        xor  ecx, ecx
        xor  ebx, ebx
        inc  ebx        ; 1

        ; check that eax and edx are non-zero
        test eax, eax
        jz   bail_out

        test edx, edx
        jz   bail_out

        ; main loop
do_loop:
        test edx, edx
        jz   end

        test edx, ebx
        jnz  edx_odd

        ; edx (b) ==  even
        shr  edx, 1

        test eax, ebx

        ; eax odd - shr eax (gcd(a, b) = gcd(a, b/2)
        jnz  do_loop

        ; eax is even as well - gcd(a, b) = 2gcd(a/2, b/2)
        shr  eax, 1
        inc  ecx        ; shift ++
        jmp  do_loop

        ; edx odd...
edx_odd:
        test eax, ebx
        jnz  eax_odd

        ; eax even - shr eax (gcd(a, b) = gcd(a/2, b)
        shr  eax, 1
        jmp  do_loop

eax_odd:
        ;  both are odd... swap a, b (eax, edx) if b (edx) < a (eax)!
        cmp  edx, eax
        jae  do_sub
        xchg edx, eax

do_sub:
        ; gcd(a, b) = gcd(a, (b - a) / 2)
        sub  edx, eax
        shr  edx, 1
        jmp do_loop

bail_out:
        ; returns 0
        xor  eax, eax

end:
        ; edx = 0, eax contains gcd / 2^(ecx)
        ; now we have to shift left by ecx bits...
        shl  eax, cl

        pop  ebx
        ; result in eax, return
        ret
 

Ztane 22:53 14.5.07 
esittelee syt-algoritmin 32-bittisille luvuille asm-funktiona jota voidaan kutsua C:stä, prototyypillä

C
uint32_t gcd(uint32_t a, uint32_t b);
 
Ztane 23:01 14.5.07 
algoritmi siis sama kuin tässä: http://mureakuha.com/koodikirjasto/1010
kikka7 01:17 15.5.07 
Annan miinusta koska oon niin kännissä.
Ztane 08:27 15.5.07 
haha xP
Akheron 09:48 15.5.07 
Pakko oli testata tämän tehokkuutta ja Python-version tehokkuutta. 8 sekunnissa assemblyversio jaksoi omalla koneellani laskea funktion 3e7 kertaa, kun samassa ajassa Python-versio jaksoi 2e5 kertaa. Laskenta suoritettiin joka kerta samoilla luvuilla, jotta mittaus olisi mahdollisimman reilu eikä lukujen arvonnasta tulisi overheadia.
Ztane 11:34 15.5.07 
itse asiassa huomasin tuossa, että tuota voi optimoida rankastikin, eli siirtää kokonaan pois noi kakkosella jakamiset eri silmukkaan - 2^n yhteisenä tekijänä voidaan todeta heti alkuun.
editoitu: 16:47 15.5.07
glaas 16:24 15.5.07 
Hieman herätti mielenkiintoa tuossa alussa ollut kommentti ettei ebx/ebp ole käytössä. Käsittääkseni jotta tuota voisi käytellä C:n kautta, ainoat 'vapaat' kokonaislukurekisterit ovat eax, ecx, edx. Muiden arvot olisi tallennettava alussa ja palautettava lopussa. Pikavilasulla tuo näyttäisi pätevän 32-bit win/linux/bsd/mac käyttiksiin.
64 bittisissä linux/bsd nuo vapaat ovatkin sitten rax,rcx,rdx,rsi,rdi,r8-r11 (mahtaisiko sekoittua näihin ;))
editoitu: 17:15 15.5.07
Ztane 17:10 15.5.07 
hmm... eiks edi ja esi ollu muka...

EDIT: argh: EBX, ESI, EDI, EBP, DS, ES, and SS pitää tallettaa...
Akiro 11:36 16.5.07 
kikka7 kirjoitti:
Annan miinusta koska oon niin kännissä.

Kaikki kommenttisi tuntuvat olevan yhtä rakentavia kuin tämä. Vaihda asiallisemmalle linjalle kiitos, eli ei tarvitse postata joka paikkaan jos ei ole mitään asiaa.