General > The Laboratory
ascii adder
zedd151:
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.
bugfix
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\masm32rt.inc
asciiadder PROTO :DWORD, :DWORD, :DWORD
.data
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)
.code
start:
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
inkey
exit
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
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
ebxgr:
mov edx, ebx
setdst:
inc edx ; add an extra byte for potential carry
calc:
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
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
end start
--- End code ---
:biggrin:
final version attached
dedndave:
did you consider using the AAA instruction ?
zedd151:
--- Quote from: dedndave on September 26, 2015, 06:37:07 AM ---did you consider using the AAA instruction ?
--- End quote ---
:P
--- Code: ---
add al, byte ptr [ebp+ebx]
@@:
aaa
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.
thinking....
zedd151:
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 ?
thinking....
zedd151:
Okay, I tried different things using all of eax, to try to add 4 bytes at a time.
The results were less than good.
Hmmm.....
Navigation
[0] Message Index
[#] Next page
Go to full version