i've just been converting some of my procedures from masm syntax and though i'd post this:) last time i timed this routine is was about 8 times faster than the comparable C function
ps i've updated this code on 13th April 2011, due to a slight bug:) its now been tested across the full 32-bit range
;-----------------------------------------------------------------
;very fast signed dword to ascii string conversion
;input: EAX=number to convert, EBX=buffer to hold the string
;returns: EAX points to the ascii string which contains the number
;-----------------------------------------------------------------
GLOBAL dwtoa
SECTION .text
dwtoa:
push ebx ;this push is popped into EAX for the return value
push esi
push ecx
push edx
mov esi, 0CCCCCCCDh ;magic number that eliminates the need for div by 10 (see agner fogs optimisation tips)
test eax, eax ;test if the number is negative or positive
jns .CalcNumOfDigits ;jump forward if number is positive
mov byte[ebx], '-' ;number is negative, add '-' to the start of the string
inc ebx ;and increment the string pointer
neg eax ;get the absolute value of the negative number, ready for the conversion
.CalcNumOfDigits:
;optimisation that eliminates the need for string reversal
cmp eax, 9 ;does the number have 1 digit?
ja .lbl2 ;jump if the number has more than 1 digit
inc ebx ;else make space for 1 digit in the string
jmp .TerminateStr ;and then add the null terminator to the string
.lbl2:
cmp eax, 99 ;does the string have 2 digits?
ja .lbl3 ;jump if the number has more than 2 digits
add ebx, 2 ;else make space for 2 digits in the string
jmp .TerminateStr ;and then add the null terminator
.lbl3:
cmp eax, 999 ;does the string have 3 digits?
ja .lbl4
add ebx, 3
jmp .TerminateStr
.lbl4:
cmp eax, 9999 ;4
ja .lbl5
add ebx, 4
jmp .TerminateStr
.lbl5:
cmp eax, 99999 ;5
ja .lbl6
add ebx, 5
jmp .TerminateStr
.lbl6:
cmp eax, 999999 ;6
ja .lbl7
add ebx, 6
jmp .TerminateStr
.lbl7:
cmp eax, 9999999 ;7
ja .lbl8
add ebx, 7
jmp .TerminateStr
.lbl8:
cmp eax, 99999999 ;8
ja .lbl9
add ebx, 8
jmp .TerminateStr
.lbl9:
cmp eax, 999999999 ;9
ja .lbl10
add ebx, 9
jmp .TerminateStr
.lbl10:
add ebx, 10 ;10
.TerminateStr:
mov byte[ebx], 0 ;add null terminator to the string
dec ebx ;ebx now points to the place where the first number will be inserted into the string
.DoConversion:
mov ecx, eax ;store eax's value as we'll need this to calculate the remainder
;the following two instructions divide eax by 10 and store the result in edx (see agner fogs optimisation tips)
mul esi
shr edx, 3
mov eax, edx ;store the result of the division back in eax ready for the next division
;the following three instructions multiply edx by 10, subtract edx from the original value to get the remainder (which
;is the digit we need) then adds '0' to convert the digit to ascii
lea edx, [edx+edx*4]
lea edx, [edx+edx-'0']
sub ecx, edx
mov [ebx], cl ;place the ascii digit in the string
sub ebx, 1 ;adjust string pointer, ready for the next character to be inserted
test eax, eax ;if eax=0 then we have finished the conversion
jz .Finished
;loop unrolled twice for extra speed
mov ecx, eax
mul esi
shr edx, 3
mov eax, edx
lea edx, [edx+edx*4]
lea edx, [edx+edx-'0']
sub ecx, edx
mov [ebx], cl
sub ebx, 1
test eax, eax
jnz .DoConversion
.Finished:
pop edx
pop ecx
pop esi
pop eax
ret