General > The Laboratory

ascii adder

(1/14) > >>

Just for fun, I once made a procedure that adds two unsigned ascii decimal numbers.

I couldn't find the original version, so I rewrote it today. I wanted to find a better way
but still using only registers (no external calls, SSE, MMX, etc)

I'm sure the coding gurus here can find a better method.


This is the only version that works 100% regardless of input string size. one string could be 1 byte and the other 1,000's of bytes and will work properly. (The console input version also works AFAIK 100% also.)

During the optimizations however that accuracy was lost, and the new 'optimised' algo would
only work on input strings of the same length.

--- Code: ---

        include \masm32\include\

        asciiadder PROTO :DWORD, :DWORD, :DWORD

       align 4
       asciinumber1 db 1024 dup (39h)
       dd 0
       align 4
       asciinumber2 db 1024 dup (39h)
       db 3 dup (0)
       align 4
       asciidest    db 1024 dup (0)
       db 4 dup (0)



        print offset asciinumber1, 13, 10, 13, 10
        print chr$("plus"), 13, 10, 13, 10
        print offset asciinumber2, 13, 10, 13, 10
        print chr$("equals"), 13, 10, 13, 10

        invoke asciiadder, addr asciinumber1, addr asciinumber2, addr asciidest
        print offset asciidest, 13, 10


    align 16
    nops 13
    asciiadder proc src1:dword, src2:dword, dst:dword
        push ebp
        push ebx
        push esi
        push edi
        mov esi, [esp+14h]
        mov ebp, [esp+18h]
        mov edi, [esp+1Ch]
        invoke StrLen, ebp
        mov ebx, eax
        invoke StrLen, esi
        mov ecx, eax
        cmp ecx, ebx ;  effectively right aligning all strings - then work our way left
        jl ebxgr
        mov edx, ecx
        jmp setdst
        mov edx, ebx

        inc edx                         ; add an extra byte for potential carry

        mov al, 0
        cmp ecx, -1
        js @f
        mov al, byte ptr [esi+ecx]
        cmp ebx, -1
        js @f
        add al, byte ptr [ebp+ebx]
        sub al, 30h
        cmp al, 0Fh
        jl @f
        sub al, 30h
        cmp al, 0Ah
        jl @f
        sub al, 0Ah
        inc byte ptr [edi+edx-1]

        add al, 30h
        add al, byte ptr [edi+edx]

        cmp al, 39h
        jng @f
        sub al, 0Ah
        inc byte ptr [edi+edx-1]
        mov byte ptr [edi+edx], al

        dec ebx
        dec ecx
        dec edx
    jnz calc
        cmp byte ptr [edi+edx], 30h     ; test to see if first byte in dest is the carry byte
        jg @f
        add byte ptr [edi], 30h         ; if so, convert to ascii
        pop edi
        pop esi
        pop ebx
        pop ebp
        ret 12
    asciiadder endp

    end start
--- End code ---

final version attached

did you consider using the AAA instruction ?


--- Quote from: dedndave on September 26, 2015, 06:37:07 AM ---did you consider using the AAA instruction ?

--- End quote ---


--- Code: ---
        add al, byte ptr [ebp+ebx]
        add al, 30h
        mov byte ptr [edi+edx], al
        mov byte ptr [edi+edx-1], ah

--- End code ---

something like that?

Nope that's not right.
The first result looked ok (using AAA), but tried other input values.....
And the result wasn't right, my implementation was somehow wrong.

Okay, thats ok, but I know there has to be a fool-proof way to do it 4 bytes at a time.
But the endian-ness also gets in the way. (don't want to use bswap for obvious reasons)

lemme think on it...

trouble is the way I'm doing it, I'm using up all the registers.
I don't really want to use local variables.

and eax, 30303030h ?


Okay, I tried different things using all of eax, to try to add 4 bytes at a time.
The results were less than good.



[0] Message Index

[#] Next page

Go to full version