News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Binary to Decimal using multiply

Started by FORTRANS, September 19, 2008, 04:40:14 PM

Previous topic - Next topic

drizz

The truth cannot be learned ... it can only be recognized.

drizz

like this
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

align 16
DwToStr5 proc dwValue,pBuffer
mov eax,[esp+1*4];val
mov edx,89705F41h; bits(4) == 3 == b, 2^(64-b)/1000000000
add eax,1
mov ecx,10
jz @F
mul edx
shrd eax,edx,(64-3) and 31
shr edx,(64-3) and 31
for mmx,<0,1,2,3,4,5,6>
%movd mm&mmx&,edx
mul ecx
endm
movd mm7,edx
punpcklbw mm0,mm1
punpcklbw mm2,mm3
punpcklbw mm4,mm5
punpcklbw mm6,mm7
punpcklwd mm0,mm2
punpcklwd mm4,mm6
punpckldq mm0,mm4
mul ecx
movd mm1,edx
mul ecx
movd mm2,edx
punpcklbw mm1,mm2
mov edx,'00'
mov eax,'0000'
mov ecx,[esp+2*4];buf
movd mm6,edx
movd mm7,eax
punpckldq mm7,mm7
paddb mm1,mm6
paddb mm0,mm7
movq [ecx+8],mm1
movq [ecx+0],mm0
ret 2*4
@@:
mov edx,[esp+2*4];buf
mov dword ptr [edx+0],'4924'
mov dword ptr [edx+4],'2769'
mov dword ptr [edx+8],'59'
ret 2*4

DwToStr5 endp

OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
The truth cannot be learned ... it can only be recognized.

NightWare

Quote from: drizz on September 24, 2008, 04:53:41 PM
it's fun reinventing the wheel  :bg
yep, especially this algo, it's a very interesting one, stable (only small difference between large and small values), very fast (it appear slower than LUT in speed test, but in real use it's another thing  :wink) and more important it's very adaptable to many case/digits...

qWord

#18
Quote from: FORTRANS on September 24, 2008, 04:33:46 PM
... I could post the binary if it interests you.
look intersting, pleas post - TIA

-----

Quote from: drizz on September 24, 2008, 08:20:54 PM
like this
on my core2duo and it takes ~39 clocks

I've also written an function using SSE2:

;RETURN: eax == pointer in buffer
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
align 16
d2a proc uDword:DWORD,lpBuffer:DWORD


    .data
        align 16
        fp_100k_div OWORD 0A7C5AC47h
        fp_100k_mul OWORD 100000
        fp_const    QWORD 068DB9h, 068DB9h
        fp_10       QWORD 10     , 10
        fp_asc      db 4 dup(030h)
                    db 030h,0,0,0
                    db 4 dup(030h)
                    db 030h,0,0,0
    ;   fp_cmp      db 10 dup (030h)
    ;               db 6 dup (0)
    .code

    mov eax,DWORD ptr [esp+4] ; uDword
    test eax,eax
    .if !ZERO?
        .if eax != -1

            lea eax,[eax+1]
            movd xmm0,eax
            pmuludq xmm0,fp_100k_div
            psrlq xmm0,16
            movdqa xmm1,xmm0
            pmuludq xmm1,fp_100k_mul

            psrlq xmm0,32
            psrlq xmm1,32

            punpcklqdq xmm0,xmm1

            pmuludq xmm0,OWORD ptr fp_const
            movdqa xmm1,xmm0

            pmuludq xmm1,OWORD ptr fp_10
            movdqa xmm2,xmm1
            pslld xmm1,8

            pmuludq xmm2,OWORD ptr fp_10
            movdqa xmm3,xmm2
            pslld xmm2,16

            pmuludq xmm3,OWORD ptr fp_10
            movdqa xmm4,xmm3
            pslld xmm3,24
            por xmm0,xmm1

            pmuludq xmm4,OWORD ptr fp_10
            por xmm2,xmm3
            psrlq xmm4,32
            psllq xmm4,32

            por xmm0,xmm2

            mov eax,DWORD ptr [esp+8] ; lpBuffer
            pxor xmm2,xmm2
            psrlq xmm0,32
            por xmm0,xmm4
            paddb xmm0,OWORD ptr fp_asc
            movdqa xmm1,xmm0
            punpcklqdq xmm1,xmm2
            punpckhqdq xmm2,xmm0
            psrldq xmm2,3
            por xmm1,xmm2

            ;movdqa xmm7,xmm1               ; suppress leading zeros
            ;pcmpeqb xmm7,OWORD ptr fp_cmp  ;
            ;pmovmskb edx,xmm7              ;
            ;not edx                        ;
            ;bsf edx,edx                    ;

            movdqa OWORD ptr [eax],xmm1
            lea eax,[eax+edx]
            ret 8
        .else
            mov eax,DWORD ptr [esp+8] ; lpBuffer
            mov DWORD ptr [eax],034393234h
            mov DWORD ptr [eax+4],032373639h
            mov DWORD ptr [eax+8],03539h
            ret 8
        .endif
    .else
        mov eax,DWORD ptr [esp+8] ;lpBuffer
        mov DWORD ptr [eax],030h
        ret 8
    .endif

d2a endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF


its a bit faster than drizz's one: 
(test-value = 1234567890)
without suppressing leading zeros: ~ 29 clocks  :green
with suppressing: ~ 37 clocks

regards qWord

EDIT: there was some sensless instructions (movdqa xmm3,xmm0 and psubd xmm3,xmm1 ) in code. I've delete them out

FPU in a trice: SmplMath
It's that simple!

FORTRANS

Quote from: qWord on September 24, 2008, 11:59:40 PM
Quote from: FORTRANS on September 24, 2008, 04:33:46 PM
... I could post the binary if it interests you.
look intersting, pleas post - TIA


   Here it is.

   I should note that the thread that NightWare pointed out also shows that
leading zero suppression is easily done using the fact that a MULtiply sets the
carry and overflow flags if the high byte, word, or double word is nonzero.  I
stated earlier that that looked messy.  Oops.  And using a constant in memory,
rather than loading it in a register, would save an instruction.

Regards,

Steve N.

[attachment deleted by admin]

jj2007

Quote from: qWord on September 24, 2008, 11:59:40 PM
I've also written an function using SSE2:

Looks interesting, especially since it does not use the FPU registers. Can you extend it to qwords?

258 cycles for float$ REAL8     1.234568

drizz

and what do you guys think of this one :)

; no frame
align 16
DwToStr7 proc dwValue,pBuffer
mov edx,089705F41H
mov eax,[esp+1*4];val
mul edx
mov [esp+1*4],ebx
add eax,070000000H
adc edx,0
movd mm0,edx
psrld mm0,1
and edx,01FFFFFFFH
mov ecx,eax
mov ebx,edx
shld edx,eax,2;mul by 5
shl eax,2
add eax,ecx
adc edx,ebx
mov ecx,00FFFFFFFH
movd mm1,edx
and edx,ecx
add edx,edx
lea edx,[edx*4+edx]
movd mm2,edx
and edx,ecx
add edx,edx
lea edx,[edx*4+edx]
movd mm3,edx
and edx,ecx
add edx,edx
lea edx,[edx*4+edx]
movd mm4,edx
and edx,ecx
add edx,edx
lea edx,[edx*4+edx]
movd mm5,edx
and edx,ecx
add edx,edx
lea edx,[edx*4+edx]
movd mm6,edx
and edx,ecx
add edx,edx
lea edx,[edx*4+edx]
movd mm7,edx
punpckldq mm0,mm1
punpckldq mm2,mm3
punpckldq mm4,mm5
punpckldq mm6,mm7
psrld mm0,32-4
psrld mm2,32-4
psrld mm4,32-4
psrld mm6,32-4
mov eax,'0000'
movd mm7,eax
packssdw mm0,mm2
packssdw mm4,mm6
punpckldq mm7,mm7
packsswb mm0,mm4
paddb mm0,mm7
and edx,ecx
add edx,edx
lea edx,[edx*4+edx]
and ecx,edx
shr edx,28
add ecx,ecx
lea ecx,[ecx*4+ecx]
shr ecx,28-8
mov ebx,[esp+1*4]
mov eax,[esp+2*4];buf
and ecx,0FF00h
lea edx,[edx+ecx+'00']
movq [eax+0],mm0
mov [eax+8],edx
ret 2*4
DwToStr7 endp
The truth cannot be learned ... it can only be recognized.

NightWare

Quote from: jj2007 on September 25, 2008, 09:52:54 PMLooks interesting, especially since it does not use the FPU registers. Can you extend it to qwords?
jj, i've no time for a real8 version, but this real4 version may help you :
.DATA
ALIGN 16
_TCA_Simd_Multiplicateur_Decimales_ REAL4 100000000.0f

.CODE
ALIGN 16
;
; convertir une valeur IEEE en texte au format décimale signé  (format : -x xxx xxx xxx . xxx xxx xx, soit 20 caractères
; en comptant le signe...).
; note : XMM0 et XMM1 sont modifiés
;
; syntaxe :
; mov eax,{the real4 value}
; mov esi,{OFFSET of the string to create}
; call Real4ToString
;
; Return :
; eax = length of the string
;
;
Real4ToString PROC
push ebx ;; empiler ebx
push ecx ;; empiler ecx
push edx ;; empiler edx
push esi ;; empiler esi
push edi ;; empiler edi

; on commence par obtenir la valeur absolue, on teste si la valeur est signée
btr eax,31 ;; tester le signe, et conserver la valeur absolue de eax
jnc Label00 ;; si le bit n'est pas positionné, aller Label00
mov BYTE PTR [esi],"-" ;; sinon, on place le signe - dans le premier octet de la chaine
inc esi ;; et on incrémente l'adresse en esi
; ensuite on va séparer la partie entière et la partie décimales
Label00: movd XMM1,eax ;; placer la variable das XMM1
cvttss2si eax,XMM1 ;; placer l'entier (sans arrondi) de XMM1 dans eax
cvtsi2ss XMM0,eax ;; placer l'entier en eax dans XMM0 au format réel4
subss XMM1,XMM0 ;; soustraire XMM0 à XMM1
mulss XMM1,_TCA_Simd_Multiplicateur_Decimales_ ;; multiplier les décimales restantes par le multiplicateur (maintenant XMM0 posséde les décimales dans la partie entière)
; là on teste s'il y a un arrondi à l'entier supérieur
cvtss2si edi,XMM1 ;; placer l'entier (les décimales multipliées par notre multiplicateur) de XMM1 dans edi
cmp edi,99999999 ;; on teste si il reste quelquechose dans edi (après un traitement décimale virtuel)
jnae Label01 ;; si ce n'est pas supérieur ou égal, il n'y a pas d'arrondi, alors aller Label01
inc eax ;; sinon, c'est qu'il faut arrondir à la valeur supérieure, donc on augmente eax d'1
Label01: mov ecx,eax ;; copier eax dans ecx
; inc eax ;; pour que la division qui suit donne le résultat exact (inutile puisque valeurs signées)
; jnz Label02 ;; si FFFFFFFFh+1 <>0, aller Label02
;; CasSpecial :
; mov DWORD PTR [esi],"4924" ;; ) placer directement la valeur correspondante
; mov DWORD PTR [esi+4],"2769" ;; )
; mov WORD PTR [esi+8],"59" ;; )
; jmp Label14 ;; aller Label14
;ALIGN 4
; on va diviser eax par 100000 de manière optimisée
Label02: mov edx,2814749768 ;; placer 2814749768 (remplacement de 2814749767 et eax+1) dans edx
; mov edx,2814749767 ;; placer 2814749767 dans edx
mul edx ;; multiplier eax par 2814749768
shr edx,16 ;; décaler edx de 16 bits à droite
mov eax,100000 ;; placer 100000 dans eax
mov ebx,edx ;; copier edx dans ebx
mul edx ;; multiplier edx par 100000
sub ecx,eax ;; soustraire le résultat en eax à ecx
test ebx,ebx ;; fixer les flags de ebx
mov edx,ebx ;; replacer ebx dans edx
mov ebx,10 ;; placer 10 (notre multiplicateur décimale) dans ebx
jz Label03 ;; si c'est égal à 0, aller Label03
; sinon, on traite la partie supérieure du nombre
mov eax,429497 ;; on remplace eax par 429497
mul edx ;; multiplier edx par 429497 (pour pouvoir extraire correctement les 5 décimales supérieures)
jc Label04 ;; s'il existe un dépassement, aller Label04
dec esi ;; décrémenter l'adresse
mul ebx ;; multiplier eax par 10
jc Label05 ;; s'il existe un dépassement, aller Label05
dec esi ;; décrémenter l'adresse
mul ebx ;; multiplier eax par 10
jc Label06 ;; s'il existe un dépassement, aller Label06
dec esi ;; décrémenter l'adresse
mul ebx ;; multiplier eax par 10
jc Label07 ;; s'il existe un dépassement, aller Label07
dec esi ;; décrémenter l'adresse
jmp Label08 ;; Label08
;ALIGN 4
; ici, on traite la partie inférieure du nombre
Label03: mov eax,429497 ;; on remplace eax par 429497
sub esi,5 ;; enlever 5 caractères à esi
mul ecx ;; multiplier ecx par 429497 (pour pouvoir extraire correctement les 5 décimales supérieures)
jc Label09 ;; s'il existe un dépassement, aller Label09
dec esi ;; décrémenter l'adresse
mul ebx ;; multiplier eax par 10
jc Label10 ;; s'il existe un dépassement, aller Label10
dec esi ;; décrémenter l'adresse
mul ebx ;; multiplier eax par 10
jc Label11 ;; s'il existe un dépassement, aller Label11
dec esi ;; décrémenter l'adresse
mul ebx ;; multiplier eax par 10
jc Label12 ;; s'il existe un dépassement, aller Label12
dec esi ;; décrémenter l'adresse
jmp Label13 ;; aller Label13
;ALIGN 4
; ici, on va placer XXXXXXXXXX et le zéro final
Label04: add dl,"0" ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi],dl ;; placer l'octet en dl à l'adresse en esi
mul ebx ;; multiplier eax par 10
Label05: add dl,"0" ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+1],dl ;; placer l'octet en dl à l'adresse en esi
mul ebx ;; multiplier eax par 10
Label06: add dl,"0" ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+2],dl ;; placer l'octet en dl à l'adresse en esi
mul ebx ;; multiplier eax par 10
Label07: add dl,"0" ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+3],dl ;; placer l'octet en dl à l'adresse en esi
Label08: mul ebx ;; multiplier eax par 10
add dl,"0" ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+4],dl ;; placer l'octet en dl à l'adresse en esi
mov eax,429497 ;; on remplace eax par 429497
mul ecx ;; multiplier ecx par 429497 (pour pouvoir extraire correctement les 5 décimales supérieures)
Label09: add dl,"0" ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+5],dl ;; placer l'octet en dl à l'adresse en esi
mul ebx ;; multiplier eax par 10
Label10: add dl,"0" ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+6],dl ;; placer l'octet en dl à l'adresse en esi
mul ebx ;; multiplier eax par 10
Label11: add dl,"0" ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+7],dl ;; placer l'octet en dl à l'adresse en esi
mul ebx ;; multiplier eax par 10
Label12: add dl,"0" ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+8],dl ;; placer l'octet en dl à l'adresse en esi
Label13: mul ebx ;; multiplier eax par 10
add dl,"0" ;; ajouter le caractère de base "0" à la valeur en dx
mov BYTE PTR [esi+9],dl ;; placer l'octet en dl et le 0 final en dh à l'adresse en esi
; ensuite on teste si il y a une partie décimale
Label14: add esi,10 ;; (peut pas regrouper cette addition avec celle qui suit, a cause du cas spécial...)
test edi,edi ;; ) pas de décimales ?, alors aller Label18
jz Label18 ;; )
cmp edi,99999999 ;; ) on a déjà arrondi le nombre ?, alors aller Label18
ja Label18 ;; )
; on poursuis en placant le point de séparation et les décimales
mov eax,edi ;; placer les décimales dans eax
lea edi,[esi+1] ;; sauvegarder l'adresse (du début des décimales) dans edi
mov BYTE PTR [esi],"." ;; sinon, écrire le point de séparation
add esi,9 ;; placer la limite de la chaîne (adresse de début des décimales + le nombre de décimales maxi) dans esi
mov ecx,3435973837 ;; placer notre multiplicateur magique dans ecx
Label15: dec esi ;; décrémenter l'adresse à écrire
mov ebx,eax ;; sauvegarder eax dans ebx
mul ecx ;; ) diviser eax par 10
shr edx,3 ;; )
mov eax,edx ;; copier le dépassement obtenu en edx dans eax
lea edx,[edx*4+eax] ;; ) multiplier eax par 10, et placer le résultat dans edx
add edx,edx ;; )
sub ebx,edx ;; soustraire edx à ebx
jz Label15 ;; si ebx est égal à 0 (rien n'a à être inscript), aller Label15
add bl,"0" ;; sinon, ajouter le caractère de base (et passer à la boucle suivante...)
mov BYTE PTR [esi],bl ;; sauvegarde du caractére
cmp esi,edi ;; ) test à effectuer, s'il n'y a qu'un seul caractère
jbe Label17 ;; )
push esi ;; sauvegarder l'adresse du dernier caractère
; ici, on n'a plus a se soucier des zéros de fin
Label16: dec esi ;; décrémenter l'adresse à écrire
mov ebx,eax ;; sauvegarder eax dans ebx
mul ecx ;; ) diviser eax par 10
shr edx,3 ;; )
mov eax,edx ;; copier le dépassement obtenu en edx dans eax
lea edx,[edx*4+edx] ;; ) multiplier edx par 10
add edx,edx ;; )
sub ebx,edx ;; soustraire edx à ebx
add bl,"0" ;; ajouter le caractère de base
mov BYTE PTR [esi],bl ;; sauvegarde du caractére
cmp esi,edi ;; comparer l'adresse à celle de début de la partie décimale
ja Label16 ;; tant que c'est supérieur, aller Label16
; enfin, on sort
pop esi ;; restaurer l'adresse du dernier caractère
Label17: inc esi ;; incrémenter l'adresse pour placer le zéro final
; sortie alternative... (quand pas de partie décimale)
Label18: mov BYTE PTR [esi],0 ;; placer le 0 final
mov eax,esi ;; copier esi (l'adresse en cours) dans eax

pop edi ;; désempiler edi
pop esi ;; désempiler esi
pop edx ;; désempiler edx
pop ecx ;; désempiler ecx
pop ebx ;; désempiler ebx
sub eax,esi ;; pour obtenir la taille de la chaîne créée dans eax
ret ;; retourner (sortir de la procédure)
Real4ToString ENDP

jj2007

Quote from: NightWare on September 26, 2008, 02:13:07 AM
jj, i've no time for a real8 version, but this real4 version may help you :
Merci beaucoup, je vais voir si ça accelère les r4.

NightWare

here 2 uDw2A algos, except instead of 5+5 digits it's 2+4+4 and 4+4+2 (easier to convert to mmx/sse2), both algos are a bit slower for large values, but a bit faster for small (most used) values. beside, here (due to the used "divisions") no need to take care of FFFFFFFFh.

ALIGN 16
;
; convert a dword to ascii string (2+4+4 digits)
;
; syntax :
; mov eax,{the value}
; mov esi,{OFFSET of the string to create}
; call uDw2A
;
; Return :
; eax = length of the string
;
uDw2A PROC
push ebx ;; empiler ebx
push ecx ;; empiler ecx
push edx ;; empiler edx
push esi ;; empiler esi
push edi ;; empiler edi

; on va diviser eax par 10000 de manière optimisée
mov edx,3518437209 ;; placer 3518437209 dans edx
mov ecx,eax ;; copier eax dans ecx
mul edx ;; multiplier eax par 3518437209
shr edx,13 ;; décaler edx de 13 bits à droite
mov eax,10000 ;; placer 10000 dans eax
mov edi,edx ;; copier edx dans edi
mul edx ;; multiplier edx par 10000
sub ecx,eax ;; soustraire le résultat en eax à ecx
test edi,edi ;; fixer les flags de edi
mov edx,edi ;; replacer edi dans edx
mov edi,10 ;; placer 10 (notre multiplicateur décimale) dans edi
jz Label01 ;; si c'est égal à 0, aller Label01
; on va diviser eax par 10000 de manière optimisée
mov eax,3518437209 ;; placer 3518437209 dans eax
mov ebx,edx ;; copier edx dans ebx
mul edx ;; multiplier eax par 3518437209
shr edx,13 ;; décaler edx de 13 bits à droite
mov eax,10000 ;; placer 10000 dans eax
mov edi,edx ;; copier edx dans edi
mul edx ;; multiplier edx par 10000
sub ebx,eax ;; soustraire le résultat en eax à ecx
test edi,edi ;; fixer les flags de edi
mov edx,edi ;; replacer edi dans edx
mov edi,10 ;; placer 10 (notre multiplicateur décimale) dans edi
jz Label00 ;; si c'est égal à 0, aller Label00
;ALIGN 4
; sinon, on traite la partie XX-------- du nombre
mov eax,429496730 ;; on remplace eax par 429496730
mul edx ;; multiplier eax par 10
jc Label02 ;; s'il existe un dépassement, aller Label02
dec esi ;; décrémenter l'adresse
jmp Label03 ;; aller Label03
;ALIGN 4
; sinon, on traite la partie --XXXX---- du nombre
Label00: sub esi,2 ;; enlever 2 caractères à esi (XX--------)
mov eax,4294968 ;; on remplace eax par 4294968
mul ebx ;; multiplier ecx par 4294968 (pour pouvoir extraire correctement les 4 décimales supérieures)
jc Label04 ;; s'il existe un dépassement, aller Label04
dec esi ;; décrémenter l'adresse
mul edi ;; multiplier eax par 10
jc Label05 ;; s'il existe un dépassement, aller Label05
dec esi ;; décrémenter l'adresse
mul edi ;; multiplier eax par 10
jc Label06 ;; s'il existe un dépassement, aller Label06
dec esi ;; décrémenter l'adresse
jmp Label07 ;; aller Label07
;ALIGN 4
; ici, on traite la partie ------XXXX du nombre
Label01: sub esi,6 ;; enlever 6 caractères à esi (XXXXXX----)
mov eax,4294968 ;; on remplace eax par 4294968
mul ecx ;; multiplier ecx par 4294968 (pour pouvoir extraire correctement les 4 décimales supérieures)
jc Label08 ;; s'il existe un dépassement, aller Label08
dec esi ;; décrémenter l'adresse
mul edi ;; multiplier eax par 10
jc Label09 ;; s'il existe un dépassement, aller Label09
dec esi ;; décrémenter l'adresse
mul edi ;; multiplier eax par 10
jc Label10 ;; s'il existe un dépassement, aller Label10
dec esi ;; décrémenter l'adresse
jmp Label11 ;; aller Label11
;ALIGN 4
; ici, on va placer XXXXXXXXXX et le zéro final
Label02: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi],dl ;; placer l'octet en dl à l'adresse en esi
Label03: mul edi ;; multiplier eax par 10
add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+1],dl ;; placer l'octet en dl à l'adresse en esi
mov eax,4294968 ;; on remplace eax par 4294968
mul ebx ;; multiplier ebx par 4294968 (pour pouvoir extraire correctement les 4 décimales supérieures)
Label04: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+2],dl ;; placer l'octet en dl à l'adresse en esi
mul edi ;; multiplier eax par 10
Label05: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+3],dl ;; placer l'octet en dl à l'adresse en esi
mul edi ;; multiplier eax par 10
Label06: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+4],dl ;; placer l'octet en dl à l'adresse en esi
Label07: mul edi ;; multiplier eax par 10
add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+5],dl ;; placer l'octet en dl à l'adresse en esi
mov eax,4294968 ;; on remplace eax par 4294968
mul ecx ;; multiplier ecx par 4294968 (pour pouvoir extraire correctement les 4 décimales supérieures)
Label08: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+6],dl ;; placer l'octet en dl à l'adresse en esi
mul edi ;; multiplier eax par 10
Label09: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+7],dl ;; placer l'octet en dl à l'adresse en esi
mul edi ;; multiplier eax par 10
Label10: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+8],dl ;; placer l'octet en dl à l'adresse en esi
Label11: mul edi ;; multiplier eax par 10
add dx,30h ;; ajouter le caractère de base "0" à la valeur en dx
mov WORD PTR [esi+9],dx ;; placer l'octet en dl et le 0 final en dh à l'adresse en esi
lea eax,[esi+10] ;; copier esi (l'adresse en cours+10) dans eax

pop edi ;; désempiler edi
pop esi ;; désempiler esi
pop edx ;; désempiler edx
pop ecx ;; désempiler ecx
pop ebx ;; désempiler ebx
sub eax,esi ;; pour obtenir la taille de la chaîne créée dans eax
ret ;; retourner (sortir de la procédure)
uDw2A ENDP


ALIGN 16
;
; convert a dword to ascii string (4+4+2 digits)
;
; syntax :
; mov eax,{the value}
; mov esi,{OFFSET of the string to create}
; call uDw2A
;
; Return :
; eax = length of the string
;
uDw2A PROC
push ebx ;; empiler ebx
push ecx ;; empiler ecx
push edx ;; empiler edx
push esi ;; empiler esi
push edi ;; empiler edi

; on va diviser eax par 100 de manière optimisée
mov edx,2748779070 ;; placer 2748779069+1 dans edx
mov ecx,eax ;; copier eax dans ecx
mul edx ;; multiplier eax par 3518437209
shr edx,6 ;; décaler edx de 6 bits à droite
mov eax,100 ;; placer 100 dans eax
mov edi,edx ;; copier edx dans edi
mul edx ;; multiplier edx par 10000
sub ecx,eax ;; soustraire le résultat en eax à ecx
test edi,edi ;; fixer les flags de edi
mov edx,edi ;; replacer edi dans edx
mov edi,10 ;; placer 10 (notre multiplicateur décimale) dans edi
jz Label01 ;; si c'est égal à 0, aller Label01
; on va diviser eax par 10000 de manière optimisée
mov eax,3518437209 ;; placer 3518437209 dans eax
mov ebx,edx ;; copier edx dans ebx
mul edx ;; multiplier eax par 3518437209
shr edx,13 ;; décaler edx de 19 bits à droite
mov eax,10000 ;; placer 10000 dans eax
mov edi,edx ;; copier edx dans edi
mul edx ;; multiplier edx par 10000
sub ebx,eax ;; soustraire le résultat en eax à ecx
test edi,edi ;; fixer les flags de edi
mov edx,edi ;; replacer edi dans edx
mov edi,10 ;; placer 10 (notre multiplicateur décimale) dans edi
jz Label00 ;; si c'est égal à 0, aller Label00
;ALIGN 4
; sinon, on traite la partie XXXX------ du nombre
mov eax,4294968 ;; on remplace eax par 4294968 (pour pouvoir extraire correctement les 4 décimales supérieures)
mul edx ;; multiplier eax par 10
jc Label02 ;; s'il existe un dépassement, aller Label02
dec esi ;; décrémenter l'adresse
mul edi ;; multiplier eax par 10
jc Label03 ;; s'il existe un dépassement, aller Label03
dec esi ;; décrémenter l'adresse
mul edi ;; multiplier eax par 10
jc Label04 ;; s'il existe un dépassement, aller Label04
dec esi ;; décrémenter l'adresse
jmp Label05 ;; s'il existe un dépassement, aller Label05
;ALIGN 4
; sinon, on traite la partie ----XXXX-- du nombre
Label00: mov eax,4294968 ;; on remplace eax par 4294968 (pour pouvoir extraire correctement les 4 décimales supérieures)
sub esi,4 ;; enlever 4 caractères à esi (XXXX------)
mul ebx ;; multiplier ebx par 4294968
jc Label06 ;; s'il existe un dépassement, aller Label06
dec esi ;; décrémenter l'adresse
mul edi ;; multiplier eax par 10
jc Label07 ;; s'il existe un dépassement, aller Label07
dec esi ;; décrémenter l'adresse
mul edi ;; multiplier eax par 10
jc Label08 ;; s'il existe un dépassement, aller Label08
dec esi ;; décrémenter l'adresse
jmp Label09 ;; s'il existe un dépassement, aller Label09
;ALIGN 4
; ici, on traite la partie --------XX du nombre
Label01: mov eax,429496730 ;; on remplace eax par 429496730
sub esi,8 ;; enlever 8 caractères à esi (XXXXXXXX--)
mul ecx ;; multiplier ecx par 429496730 (pour pouvoir extraire correctement les 2 décimales supérieures)
jc Label10 ;; s'il existe un dépassement, aller Label10
dec esi ;; décrémenter l'adresse
jmp Label11 ;; aller Label11
;ALIGN 4
; ici, on va placer XXXXXXXXXX et le zéro final
Label02: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi],dl ;; placer l'octet en dl à l'adresse en esi
mul edi ;; multiplier eax par 10
Label03: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+1],dl ;; placer l'octet en dl à l'adresse en esi
mul edi ;; multiplier eax par 10
Label04: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+2],dl ;; placer l'octet en dl à l'adresse en esi
Label05: mul edi ;; multiplier eax par 10
add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+3],dl ;; placer l'octet en dl à l'adresse en esi
mov eax,4294968 ;; on remplace eax par 4294968
mul ebx ;; multiplier ebx par 4294968 (pour pouvoir extraire correctement les 4 décimales supérieures)
Label06: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+4],dl ;; placer l'octet en dl à l'adresse en esi
mul edi ;; multiplier eax par 10
Label07: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+5],dl ;; placer l'octet en dl à l'adresse en esi
mul edi ;; multiplier eax par 10
Label08: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+6],dl ;; placer l'octet en dl à l'adresse en esi
Label09: mul edi ;; multiplier eax par 10
add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+7],dl ;; placer l'octet en dl à l'adresse en esi
mov eax,429496730 ;; on remplace eax par 429496730
mul ecx ;; multiplier ecx par 4294968 (pour pouvoir extraire correctement les 4 décimales supérieures)
Label10: add dl,30h ;; ajouter le caractère de base "0" à la valeur en edx
mov BYTE PTR [esi+8],dl ;; placer l'octet en dl à l'adresse en esi
Label11: mul edi ;; multiplier eax par 10
add dx,30h ;; ajouter le caractère de base "0" à la valeur en dx
mov WORD PTR [esi+9],dx ;; placer l'octet en dl et le 0 final en dh à l'adresse en esi
lea eax,[esi+10] ;; copier esi (l'adresse en cours+10) dans eax

pop edi ;; désempiler edi
pop esi ;; désempiler esi
pop edx ;; désempiler edx
pop ecx ;; désempiler ecx
pop ebx ;; désempiler ebx
sub eax,esi ;; pour obtenir la taille de la chaîne créée dans eax
ret ;; retourner (sortir de la procédure)
uDw2A ENDP


and here a sse2 test, 21 cycles on my computer :
.DATA
ALIGN 16
Div100 DWORD 0A3D70A3Eh,000000000h,000000000h,000000000h ;; 0,0,0,2748779070 (pratiquer un shr ,6 ensuite)
Div10000 DWORD 0D1B71759h,000000000h,000000000h,000000000h ;; 0,0,0,3518437209 (pratiquer un shr ,13 ensuite)
Mul10x2 DWORD 00000000Ah,000000000h,00000000Ah,000000000h ;; 0,10,0,10
Mul100 DWORD 000000064h,000000000h,000000000h,000000000h ;; 0,0,0,100
Mul10000 DWORD 000002710h,000000000h,000000000h,000000000h ;; 0,0,0,10000
PushBits100 DWORD 01999999Ah,000000000h,000000000h,000000000h ;; 0,0,0,429496730
PushBits10000x2 DWORD 000418938h,000000000h,000418938h,000000000h ;; 0,4294968,0,4294968
BaseDecValues DWORD 030303030h,030303030h,000003030h,000000000h ;; "0000000000"


.CODE
ALIGN 16
;
; convert a dword to ascii string, sse2 version but leading zeros
;
; syntax :
; mov eax,{the value}
; mov esi,{OFFSET of the string to create}
; call uDw2A_Sse2
;
; Return :
; nothing
;
uDw2A_Sse2 PROC

movd XMM3,eax ;; XMM3 = 0,0,0,Val
; on sépare les parties XXXX,XXXX et XX
movss XMM6,DWORD PTR Div100 ;; XMM6 = 0,0,0,2748779070
movss XMM7,DWORD PTR Mul100 ;; XMM7 = 0,0,0,100
movdqa XMM4,XMM3 ;; XMM4 = _,_,_,Val
pmuludq XMM6,XMM3 ;; XMM6 = _,_,Hi+Mi,_
psrlq XMM6,32+6 ;; XMM6 = 0,0,0,Hi+Mi/100
movss XMM3,XMM6 ;; XMM3 = 0,0,0,Hi+Mi/100
pmuludq XMM7,XMM6 ;; XMM7 = 0,0,0,Hi+Mi
psubd XMM4,XMM7 ;; XMM4 = 0,0,0,Lo
; on sépare les parties XXXX et XXXX
movss XMM6,DWORD PTR Div10000 ;; XMM6 = 0,0,0,3518437209
movss XMM7,DWORD PTR Mul10000 ;; XMM7 = 0,0,0,10000
movdqa XMM1,XMM3 ;; XMM1 = _,_,_,Hi+Mi
pmuludq XMM6,XMM3 ;; XMM6 = _,_,Hi,_
psrlq XMM6,32+13 ;; XMM6 = 0,0,0,Hi/10000
movss XMM0,XMM6 ;; XMM0 = 0,0,0,Hi/10000
pmuludq XMM7,XMM6 ;; XMM7 = 0,0,0,Hi
psubd XMM1,XMM7 ;; XMM4 = 0,0,0,Mi
; ici, on calcul et sépare les valeurs des caractères
movdqa XMM6,OWORD PTR Mul10x2 ;; XMM6 = 0,10,0,10
movlhps XMM0,XMM1 ;; XMM0 = 0,Mi,0,Hi
pmuludq XMM0,OWORD PTR PushBits10000x2 ;; XMM0 = _,Mi*4294968 (D4),_,Hi*4294968 (D0)
pmuludq XMM4,OWORD PTR PushBits100 ;; XMM0 = _,_,_,Lo*429496730 (D8)
movdqa XMM1,XMM0 ;; XMM1 = _Mi,_,Hi
pmuludq XMM1,XMM6 ;; XMM1 = _,Mi*10 (D5),_,Hi*10 (D1)
movdqa XMM5,XMM4 ;; XMM5 = _,_,_,Lo
movdqa XMM2,XMM1 ;; XMM2 = _Mi,_,Hi
pmuludq XMM2,XMM6 ;; XMM2 = _,Mi*10 (D6),_,Hi*10 (D2)
pmuludq XMM5,XMM6 ;; XMM1 = _,_,_,Lo*10 (D9)
movdqa XMM3,XMM2 ;; XMM3 = _Mi,_,Hi
pmuludq XMM3,XMM6 ;; XMM3 = _,Mi*10 (D7),_,Hi*10 (D3)
; ici, on fusionne les caractères
punpcklbw XMM4,XMM5 ;; XMM4 = _,D9+D8,_,_
pslld XMM1,8 ;; XMM1 = D5,_,D1,_
pslld XMM2,16 ;; XMM2 = D6,_,D2,_
pslld XMM3,24 ;; XMM3 = D7,_,D3,_
por XMM0,XMM1 ;; ) XMM0 = Mi,_,Hi,_
por XMM0,XMM2 ;; )
por XMM0,XMM3 ;; )
shufps XMM0,XMM4,0EDh ;; XMM0 = _,Lo,Mi,Hi
; ici, on ajoute le caractère de base aux caractères obtenus, et on sauvegarde
paddb XMM0,OWORD PTR BaseDecValues ;; XMM0 = _,Lo,Mi,Hi + "0000000000"
movdqa OWORD PTR [esi],XMM0 ;; placer la valeur

; movdqa XMM1,XMM0 ;; ) suppress leading zeros
; pcmpeqb XMM1,OWORD PTR BaseDecValues ;; )
; pmovmskb edx,XMM1 ;; )
; not edx ;; )
; bsf edx,edx ;; )
; add esi,edx ;; )

ret ;; retourner (sortir de la procédure)
uDw2A_Sse2 ENDP


eaOn

Quote from: qWord on September 24, 2008, 02:24:43 AM
thx drizz,

I've just got the idea that it could be possible to obtain the quotient and reminder of and division by 100000 with only two multiplications (particularly with regard to SIMD-instructions), but afaics the precession is the problem.

regards qWord


.
Actually, there is a slight significance from what your saying.
Look here. http://www.masm32.com/board/index.php?topic=10039.0
Check the lastDigit,thirdDigit.... section below.
The only difference is that its hex to decimal conversion and it is build on 16-bit DOS asm.

As matter of fact it is possible. From my experience in 16-bit programming, the quotient will be stored in ax while the remainder is stored in dx if you divide ax with dx.