This algo was originally designed by Paul Dixon in PowerBASIC, I have converted it to MASM notation and removed the stack frame and it is testing up fine. It will handle both signed and unsigned 32 bit integers and long ago I did exhaustive testing on the algo and it works correctly over the full range. I have in mind eventually replacing the dwtoa() used in the str$() macro with this algo. It is probably the fastest I have seen that does a conventional integer to ascii conversion writing to a pre-allocated buffer.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
comment * -----------------------------------------------------
Build this template with
"CONSOLE ASSEMBLE AND LINK"
----------------------------------------------------- *
ntoa$ MACRO variable
LOCAL buffer
.data?
align 16
buffer db 32 dup (?)
.code
push OFFSET buffer
push variable
call numtostr
mov eax, OFFSET buffer
EXITM <eax>
ENDM
; ShowESP MACRO
; IFNDEF esp_reg
; .data
; esp_reg dd (0)
; .code
; ENDIF
; mov esp_reg, esp
; print ustr$(esp_reg)," = ESP stack address",13,10
; ENDM
ShowESP MACRO
IFNDEF esp_reg
.data?
esp_reg dd ?
.code
ENDIF
mov esp_reg, esp
print ustr$(esp_reg)," = ESP stack address",13,10
ENDM
numtostr PROTO LongVar:DWORD,answer:DWORD
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
LOCAL pnum[16]:DWORD
mov pnum[0], 10293847
mov pnum[4], -44444444
lea esi, pnum
ShowESP
mov eax, 87654321
print ntoa$(eax),13,10
ShowESP
print ntoa$([esi]),13,10
print ntoa$([esi+4]),13,10
print ntoa$(-12345678),13,10
print ntoa$(-1),13,10
print ntoa$(0),13,10
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
numtostr proc LongVar:DWORD,answer:DWORD
; -----------------------------------------
; This algorithm was designed by Paul Dixon
; -----------------------------------------
.data
align 4
chartab \
dd "00","10","20","30","40","50","60","70","80","90"
dd "01","11","21","31","41","51","61","71","81","91"
dd "02","12","22","32","42","52","62","72","82","92"
dd "03","13","23","33","43","53","63","73","83","93"
dd "04","14","24","34","44","54","64","74","84","94"
dd "05","15","25","35","45","55","65","75","85","95"
dd "06","16","26","36","46","56","66","76","86","96"
dd "07","17","27","37","47","57","67","77","87","97"
dd "08","18","28","38","48","58","68","78","88","98"
dd "09","19","29","39","49","59","69","79","89","99"
.code
push esi
push edi
mov eax, [esp+4][8] ; LongVar get number
mov ecx, [esp+8][8] ; answer get pointer to answer string
; --------------------------
; do a signed DWORD to ASCII
; --------------------------
or eax,eax ; test sign
jns udword ; if +ve, continue as for unsigned
neg eax ; else, make number positive
mov byte ptr [ecx],"-" ; include the - sign
inc ecx ; update the pointer
udword:
; -----------------------
; unsigned DWORD to ASCII
; -----------------------
mov esi,ecx ; get pointer to answer
mov edi,eax ; save a copy of the number
mov edx, 0D1B71759h ; =2^45\10000 13 bit extra shift
mul edx ; gives 6 high digits in edx
mov eax, 68DB9h ; =2^32\10000+1
shr edx,13 ; correct for multiplier offset used to give better accuracy
jz skiphighdigits ; if zero then don't need to process the top 6 digits
mov ecx,edx ; get a copy of high digits
imul ecx,10000 ; scale up high digits
sub edi,ecx ; subtract high digits from original. EDI now = lower 4 digits
mul edx ; get first 2 digits in edx
mov ecx,100 ; load ready for later
jnc next1 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZeroSupressed ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS1 ; continue with pairs of digits to the end
next1:
mul ecx ; get next 2 digits
jnc next2 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZS1a ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS2 ; continue with pairs of digits to the end
next2:
mul ecx ; get next 2 digits
jnc next3 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZS2a ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS3 ; continue with pairs of digits to the end
next3:
skiphighdigits:
mov eax,edi ; get lower 4 digits
mov ecx,100
mov edx, 28F5C29h ; 2^32\100 +1
mul edx
jnc next4 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZS3a ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS4 ; continue with pairs of digits to the end
next4:
mul ecx ; this is the last pair so don't supress a single zero
cmp edx,9 ; 1 digit or 2?
ja ZS4a ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
mov byte ptr [esi+1],0 ; zero terminate string
jmp xit ; all done
ZeroSupressed:
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dx
add esi,2 ; write them to answer
ZS1:
mul ecx ; get next 2 digits
ZS1a:
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dx ; write them to answer
add esi,2
ZS2:
mul ecx ; get next 2 digits
ZS2a:
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dx ; write them to answer
add esi,2
ZS3:
mov eax,edi ; get lower 4 digits
mov edx,28F5C29h ; 2^32\100 +1
mul edx ; edx= top pair
ZS3a:
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dx ; write to answer
add esi,2 ; update pointer
ZS4:
mul ecx ; get final 2 digits
ZS4a:
mov edx,chartab[edx*4] ; look them up
mov [esi],dx ; write to answer
mov byte ptr [esi+2],0 ; zero terminate string
xit:
sdwordend:
pop edi
pop esi
ret 8
numtostr endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
signed or unsigned ? :redface:
Hi Dave,
Quote from: hutch-- on March 15, 2015, 12:37:15 AMIt will handle both signed and unsigned 32 bit integers
lol
well, yah - unsigned if below 2147483648
that is what we call "signed integers"
Quote from: dedndave on March 15, 2015, 02:10:15 AM
signed or unsigned ? :redface:
Dave, do you see it as signed probably?
Erol, this code is not conditional, so, the algo is signed
; --------------------------
; do a signed DWORD to ASCII
; --------------------------
or eax,eax ; test sign
jns udword ; if +ve, continue as for unsigned
neg eax ; else, make number positive
mov byte ptr [ecx],"-" ; include the - sign
inc ecx ; update the pointer
It's probably better to add the third param to the algo: the isSigned boolean flag. And some code to check the flag and the signedness of the number at the same step.
numtostr proc LongVar:DWORD,answer:DWORD, isSigned:DWORD
push esi
push edi
mov eax, [esp+4][8] ; LongVar get number
mov ecx, [esp+8][8] ; answer get pointer to answer string
mov edx,[esp+4][8]
shl edx,1
mov edx,2
sbb edx,[esp+12][8] ; if signed and bool is 1 then edx is zero, no jump
; if not signed and bool is 1 then edx is not zero, jump over conversion to unsigned
; if bool is 0 then either of #31 bit set of the number - do not convert
jnz udword ; if +ve OR the unsigned mode continue as for unsigned
neg eax ; else, make number positive
mov byte ptr [ecx],"-" ; include the - sign
inc ecx ; update the pointer
udword:
the added/changed code is without indent.
Quote from: hutch-- on March 15, 2015, 12:37:15 AM
It will handle both signed and unsigned 32 bit integers...
i think it's a "signed routine"
Quote from: dedndave on March 15, 2015, 07:01:11 AM
Quote from: hutch-- on March 15, 2015, 12:37:15 AM
It will handle both signed and unsigned 32 bit integers...
i think it's a "signed routine"
My question was merely rhetorical, Dave :t
my point was this...
Hutch said it will handle both
it will handle signed values
there is no way to tell it you want anything else
Quote from: dedndave on March 15, 2015, 07:14:10 AM
my point was this...
Hutch said it will handle both
it will handle signed values
there is no way to tell it you want anything else
I did understand you, Dave :biggrin: And you may notice that am saying the same about signedness of algo and the need to add a flag to make algo (un)signed.
that's correct :t
range of signed dword integers: -2147483648 to +2147483647
range of unsigned dword integers: 0 to 4294967295
for my ling long kai fang routines, i provide 3 versions:
1) signed
2) unsigned
3) signed or unsigned
with the last one, there is an added argument to tell it whether you want signed or unsigned
Yes sad to say, I only did preliminary testing and did not modify the algo and the results are signed. I will have a play because I think there is a simple way to switch from signed to unsigned which can be tested cheaply.
If you block comment the following it produces unsigned. The other option which is what I originally preferred is to have one of each, signed and unsigned.
; ; --------------------------
; ; do a signed DWORD to ASCII
; ; --------------------------
; or eax,eax ; test sign
; jns udword ; if +ve, continue as for unsigned
; neg eax ; else, make number positive
; mov byte ptr [ecx],"-" ; include the - sign
; inc ecx ; update the pointer
Here is a quick play to do both algos separately. Results look like this.
1638212 = ESP stack address
87654321 +unsigned+
1638212 = ESP stack address
10293847 +unsigned+
-44444444 -signed-
-12345678 -signed-
-1 -signed-
4294967295 +unsigned+
0 +unsigned+
Press any key to continue ...
The test piece.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
comment * -----------------------------------------------------
Build this template with
"CONSOLE ASSEMBLE AND LINK"
----------------------------------------------------- *
utoa$ MACRO variable
LOCAL buffer
.data?
align 16
buffer db 32 dup (?)
.code
push OFFSET buffer
push variable
call unumtostr
mov eax, OFFSET buffer
EXITM <eax>
ENDM
stoa$ MACRO variable
LOCAL buffer
.data?
align 16
buffer db 32 dup (?)
.code
push OFFSET buffer
push variable
call snumtostr
mov eax, OFFSET buffer
EXITM <eax>
ENDM
ShowESP MACRO
IFNDEF esp_reg
.data?
esp_reg dd ?
.code
ENDIF
mov esp_reg, esp
print ustr$(esp_reg)," = ESP stack address",13,10
ENDM
unumtostr PROTO LongVar:DWORD,answer:DWORD
snumtostr PROTO LongVar:DWORD,answer:DWORD
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
LOCAL pnum[16]:DWORD
mov pnum[0], 10293847
mov pnum[4], -44444444
lea esi, pnum
ShowESP
mov eax, 87654321
print utoa$(eax)," +unsigned+",13,10
ShowESP
print utoa$([esi])," +unsigned+",13,10
print stoa$([esi+4])," -signed-",13,10
print stoa$(-12345678)," -signed-",13,10
print stoa$(-1)," -signed-",13,10
print utoa$(4294967295)," +unsigned+",13,10
print utoa$(0)," +unsigned+",13,10
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
unumtostr proc LongVar:DWORD,answer:DWORD
; -----------------------------------------
; This algorithm was designed by Paul Dixon
; -----------------------------------------
.data
align 4
chartab \
dd "00","10","20","30","40","50","60","70","80","90"
dd "01","11","21","31","41","51","61","71","81","91"
dd "02","12","22","32","42","52","62","72","82","92"
dd "03","13","23","33","43","53","63","73","83","93"
dd "04","14","24","34","44","54","64","74","84","94"
dd "05","15","25","35","45","55","65","75","85","95"
dd "06","16","26","36","46","56","66","76","86","96"
dd "07","17","27","37","47","57","67","77","87","97"
dd "08","18","28","38","48","58","68","78","88","98"
dd "09","19","29","39","49","59","69","79","89","99"
.code
push esi
push edi
mov eax, [esp+4][8] ; LongVar get number
mov ecx, [esp+8][8] ; answer get pointer to answer string
; ; --------------------------
; ; do a signed DWORD to ASCII
; ; --------------------------
; or eax,eax ; test sign
; jns udword ; if +ve, continue as for unsigned
; neg eax ; else, make number positive
; mov byte ptr [ecx],"-" ; include the - sign
; inc ecx ; update the pointer
udword:
; -----------------------
; unsigned DWORD to ASCII
; -----------------------
mov esi,ecx ; get pointer to answer
mov edi,eax ; save a copy of the number
mov edx, 0D1B71759h ; =2^45\10000 13 bit extra shift
mul edx ; gives 6 high digits in edx
mov eax, 68DB9h ; =2^32\10000+1
shr edx,13 ; correct for multiplier offset used to give better accuracy
jz skiphighdigits ; if zero then don't need to process the top 6 digits
mov ecx,edx ; get a copy of high digits
imul ecx,10000 ; scale up high digits
sub edi,ecx ; subtract high digits from original. EDI now = lower 4 digits
mul edx ; get first 2 digits in edx
mov ecx,100 ; load ready for later
jnc next1 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZeroSupressed ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS1 ; continue with pairs of digits to the end
next1:
mul ecx ; get next 2 digits
jnc next2 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZS1a ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS2 ; continue with pairs of digits to the end
next2:
mul ecx ; get next 2 digits
jnc next3 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZS2a ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS3 ; continue with pairs of digits to the end
next3:
skiphighdigits:
mov eax,edi ; get lower 4 digits
mov ecx,100
mov edx, 28F5C29h ; 2^32\100 +1
mul edx
jnc next4 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZS3a ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS4 ; continue with pairs of digits to the end
next4:
mul ecx ; this is the last pair so don't supress a single zero
cmp edx,9 ; 1 digit or 2?
ja ZS4a ; 2 digits, just continue with pairs of digits to the end
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
mov byte ptr [esi+1],0 ; zero terminate string
jmp xit ; all done
ZeroSupressed:
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dx
add esi,2 ; write them to answer
ZS1:
mul ecx ; get next 2 digits
ZS1a:
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dx ; write them to answer
add esi,2
ZS2:
mul ecx ; get next 2 digits
ZS2a:
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dx ; write them to answer
add esi,2
ZS3:
mov eax,edi ; get lower 4 digits
mov edx,28F5C29h ; 2^32\100 +1
mul edx ; edx= top pair
ZS3a:
mov edx,chartab[edx*4] ; look up 2 digits
mov [esi],dx ; write to answer
add esi,2 ; update pointer
ZS4:
mul ecx ; get final 2 digits
ZS4a:
mov edx,chartab[edx*4] ; look them up
mov [esi],dx ; write to answer
mov byte ptr [esi+2],0 ; zero terminate string
xit:
sdwordend:
pop edi
pop esi
ret 8
unumtostr endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
snumtostr proc LongVar:DWORD,answer:DWORD
; -----------------------------------------
; This algorithm was designed by Paul Dixon
; -----------------------------------------
.data
align 4
schartab \
dd "00","10","20","30","40","50","60","70","80","90"
dd "01","11","21","31","41","51","61","71","81","91"
dd "02","12","22","32","42","52","62","72","82","92"
dd "03","13","23","33","43","53","63","73","83","93"
dd "04","14","24","34","44","54","64","74","84","94"
dd "05","15","25","35","45","55","65","75","85","95"
dd "06","16","26","36","46","56","66","76","86","96"
dd "07","17","27","37","47","57","67","77","87","97"
dd "08","18","28","38","48","58","68","78","88","98"
dd "09","19","29","39","49","59","69","79","89","99"
.code
push esi
push edi
mov eax, [esp+4][8] ; LongVar get number
mov ecx, [esp+8][8] ; answer get pointer to answer string
; --------------------------
; do a signed DWORD to ASCII
; --------------------------
or eax,eax ; test sign
jns udword ; if +ve, continue as for unsigned
neg eax ; else, make number positive
mov byte ptr [ecx],"-" ; include the - sign
inc ecx ; update the pointer
udword:
; -----------------------
; unsigned DWORD to ASCII
; -----------------------
mov esi,ecx ; get pointer to answer
mov edi,eax ; save a copy of the number
mov edx, 0D1B71759h ; =2^45\10000 13 bit extra shift
mul edx ; gives 6 high digits in edx
mov eax, 68DB9h ; =2^32\10000+1
shr edx,13 ; correct for multiplier offset used to give better accuracy
jz skiphighdigits ; if zero then don't need to process the top 6 digits
mov ecx,edx ; get a copy of high digits
imul ecx,10000 ; scale up high digits
sub edi,ecx ; subtract high digits from original. EDI now = lower 4 digits
mul edx ; get first 2 digits in edx
mov ecx,100 ; load ready for later
jnc next1 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZeroSupressed ; 2 digits, just continue with pairs of digits to the end
mov edx,schartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS1 ; continue with pairs of digits to the end
next1:
mul ecx ; get next 2 digits
jnc next2 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZS1a ; 2 digits, just continue with pairs of digits to the end
mov edx,schartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS2 ; continue with pairs of digits to the end
next2:
mul ecx ; get next 2 digits
jnc next3 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZS2a ; 2 digits, just continue with pairs of digits to the end
mov edx,schartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS3 ; continue with pairs of digits to the end
next3:
skiphighdigits:
mov eax,edi ; get lower 4 digits
mov ecx,100
mov edx, 28F5C29h ; 2^32\100 +1
mul edx
jnc next4 ; if zero, supress them by ignoring
cmp edx,9 ; 1 digit or 2?
ja ZS3a ; 2 digits, just continue with pairs of digits to the end
mov edx,schartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
inc esi ; update pointer by 1
jmp ZS4 ; continue with pairs of digits to the end
next4:
mul ecx ; this is the last pair so don't supress a single zero
cmp edx,9 ; 1 digit or 2?
ja ZS4a ; 2 digits, just continue with pairs of digits to the end
mov edx,schartab[edx*4] ; look up 2 digits
mov [esi],dh ; but only write the 1 we need, supress the leading zero
mov byte ptr [esi+1],0 ; zero terminate string
jmp xit ; all done
ZeroSupressed:
mov edx,schartab[edx*4] ; look up 2 digits
mov [esi],dx
add esi,2 ; write them to answer
ZS1:
mul ecx ; get next 2 digits
ZS1a:
mov edx,schartab[edx*4] ; look up 2 digits
mov [esi],dx ; write them to answer
add esi,2
ZS2:
mul ecx ; get next 2 digits
ZS2a:
mov edx,schartab[edx*4] ; look up 2 digits
mov [esi],dx ; write them to answer
add esi,2
ZS3:
mov eax,edi ; get lower 4 digits
mov edx,28F5C29h ; 2^32\100 +1
mul edx ; edx= top pair
ZS3a:
mov edx,schartab[edx*4] ; look up 2 digits
mov [esi],dx ; write to answer
add esi,2 ; update pointer
ZS4:
mul ecx ; get final 2 digits
ZS4a:
mov edx,schartab[edx*4] ; look them up
mov [esi],dx ; write to answer
mov byte ptr [esi+2],0 ; zero terminate string
xit:
sdwordend:
pop edi
pop esi
ret 8
snumtostr endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
Quote from: hutch-- on March 15, 2015, 08:24:16 AM
The other option which is what I originally preferred is to have one of each, signed and unsigned.
if you're looking for speed, that's probably the best option
but - you could make the table global and put it in a module of its' own :t
deleted
The original signed algorithm was between 20 and 40 cycles for a 1-10 digit conversion including the routine overhead.
Just in case you are running a GUI app, the combination of SetDlgItemInt and WM_GETTEXT is an attractive original WinAPI option 8)
Convertion of 64 bit unsigned integer to decimal ASCIIZ string (http://www.madwizard.org/programming/snippets?id=25)
.586
.MMX
.model flat,stdcall
option casemap:none
.data
ALIGN 8
mmxb0F dq 0F0F0F0F0F0F0F0Fh
mmxb30 dq 3030303030303030h
num dq 12345678901234567890
.data?
buffer db 24 dup (?)
.code
mov edx,dword ptr num+4
mov eax,dword ptr num
mov edi, offset buffer
N19H EQU 00DE0B6B3H
N19L EQU 0A7640000H
N20H EQU 08AC72304H
N20L EQU 089E80000H
Q2Ammx proc uses edi lpBuffer, lpNumber
mov ecx,lpNumber
mov eax,[ecx]
mov edx,[ecx+4]
mov edi,lpBuffer
sub esp,12
xor ecx,ecx
cmp edx,N19H
jb @@nm18
jne @@cp20
cmp eax,N19L
jb @@nm18
@@cp20:
cmp edx,N20H
jb @@do19
jne @@do20
cmp eax,N20L
jb @@do19
@@do20:
mov cl,10h-1
sub eax,N20L
sbb edx,N20H
@@lp19:
inc ecx
@@do19:
sub eax,N19L
sbb edx,N19H
jae @@lp19
add eax,N19L
adc edx,N19H
@@nm18:
push edx
push eax
fild qword ptr [esp]
fbstp [esp]
mov [esp+9],ecx
mov edx,2
cmp dword ptr [esp+8],0
jne @@dg16
cmp dword ptr [esp+4],1
sbb edx,1
@@dg16:
bsr ecx,[esp+edx*4]
je @@zero
shr ecx,3
lea eax,[ecx+4*edx]
lea edx,[eax+eax]
cmp byte ptr [esp][eax],10h
sbb edx,-1
movq mm(7),mmxb0F
movq mm(6),mmxb30
movq mm(0),[esp]
movq mm(4),[esp+8]
movq mm(1),mm(0)
psrlq mm(1),4
pand mm(0),mm(7)
por mm(0),mm(6)
pand mm(1),mm(7)
por mm(1),mm(6)
movq mm(2),mm(0)
punpcklbw mm(0),mm(1)
movq [esp],mm(0)
punpckhbw mm(2),mm(1)
movq [esp+8],mm(2)
movq mm(5),mm(4)
psrlq mm(5),4
pand mm(4),mm(7)
por mm(4),mm(6)
pand mm(5),mm(7)
por mm(5),mm(6)
punpcklbw mm(4),mm(5)
movd [esp+16],mm(4)
emms
@@lpS:
mov eax,[esp+edx-3]
bswap eax
mov [edi],eax
add edi,4
sub edx,4
jns @@lpS
mov byte ptr [edi][edx][1],0
add esp,20
ret
@@zero:
mov dword ptr [edi],'0'
add esp,20
ret
Q2Ammx endp
end
64 bit to dec ASCIIZ - 2 with MMX (http://www.madwizard.org/programming/snippets?id=26)
.586
.MMX
.model flat,stdcall
option casemap:none
.data
ALIGN 8
mmxb0F dq 0F0F0F0F0F0F0F0Fh
mmxb30 dq 3030303030303030h
.code
Q2Ammxf proc uses edi lpBuffer,lpNumber
mov ecx,lpNumber
mov edi,lpBuffer
mov eax,[ecx]
mov edx,[ecx+4]
D05H equ 045639182h
D05L equ 044F40000h
D04H equ 03782DACEh
D04L equ 09D900000h
D01H equ 00DE0B6B3h
D01L equ 0A7640000h
QtoA:
sub esp,12
xor ecx,ecx
sub eax,D01L
sbb edx,D01H
jb @@a01f
sub eax,D04L
sbb edx,D04H
jb @@a05
mov cl,05h
sub eax,D05L
sbb edx,D05H
jb @@a05
mov cl,15h
sub eax,D05L
sbb edx,D05H
jae @@l01
mov cl,10h
@@a05:
add eax,D05L
adc edx,D05H
@@l01: inc ecx
sub eax,D01L
sbb edx,D01H
jae @@l01
dec ecx
@@a01f:
add eax,D01L
adc edx,D01H
push edx
push eax
fild qword ptr [esp]
fbstp [esp]
mov [esp+9],ecx
mov edx,2
cmp dword ptr [esp+8],0
jne @@dg16
cmp dword ptr [esp+4],1
sbb edx,1
@@dg16:
bsr ecx,[esp+edx*4]
je @@zero
shr ecx,3
lea eax,[ecx+4*edx]
lea edx,[eax+eax]
cmp byte ptr [esp][eax],10h
sbb edx,-1
movq mm(7),mmxb0F
movq mm(6),mmxb30
movq mm(0),[esp]
movq mm(4),[esp+8]
movq mm(1),mm(0)
psrlq mm(1),4
pand mm(0),mm(7)
por mm(0),mm(6)
pand mm(1),mm(7)
por mm(1),mm(6)
movq mm(2),mm(0)
punpcklbw mm(0),mm(1)
movq [esp],mm(0)
punpckhbw mm(2),mm(1)
movq [esp+8],mm(2)
movq mm(5),mm(4)
psrlq mm(5),4
pand mm(4),mm(7)
por mm(4),mm(6)
pand mm(5),mm(7)
por mm(5),mm(6)
punpcklbw mm(4),mm(5)
movd [esp+16],mm(4)
emms
@@lpS:
mov eax,[esp+edx-3]
bswap eax
mov [edi],eax
add edi,4
sub edx,4
jns @@lpS
mov byte ptr [edi][edx][1],0
add esp,20
ret
@@zero:
mov dword ptr [edi],'0'
add esp,20
ret
Q2Ammxf endp
end
Does anyone have a function similar to these that converts a qword 64bit value to ascii hex? ive searched the forums here and other places but cant seem to find anything, so just wondering if someone has one that they could share. Cheers.
Quote from: fearless on April 12, 2016, 08:29:49 AMDoes anyone have a function similar to these that converts a qword 64bit value to ascii hex?
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
SetGlobals MyQ:QWORD=1234567812345678h
Init
Inkey "MyQ=", Hex$(MyQ)
EndOfCode