Has anyone got recent code for dword to ascii, signed and unsigned ?

Started by hutch--, August 17, 2010, 04:40:43 PM

Previous topic - Next topic

hutch--

There are two old conversion routines in the masm32 library that I would like to modernise, the signed version "dwtoa" and an unsigned version done by Comrade that has a very similar looking conversion done in it.

They both perform the conversion then reverse the string to get it in the right order. I would be interested in seeing if anyone has a better or faster way to do either of these conversions.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Rockoon

Whats the actual specification?

So people dont have to go looking at the masm32 source, the current lib routines are


dwtoa proc dwValue:DWORD, lpBuffer:DWORD

    ; -------------------------------------------------------------
    ; convert DWORD to ascii string
    ; dwValue is value to be converted
    ; lpBuffer is the address of the receiving buffer
    ; EXAMPLE:
    ; invoke dwtoa,edx,ADDR buffer
    ;
    ; Uses: eax, ecx, edx.
    ; -------------------------------------------------------------

    push ebx
    push esi
    push edi

    mov eax, dwValue
    mov edi, [lpBuffer]

    test eax,eax
    jnz sign

  zero:
    mov word ptr [edi],30h
    jmp dtaexit

  sign:
    jns pos
    mov byte ptr [edi],'-'
    neg eax
    add edi, 1

  pos:
    mov ecx, 3435973837
    mov esi, edi

    .while (eax > 0)
      mov ebx,eax
      mul ecx
      shr edx, 3
      mov eax,edx
      lea edx,[edx*4+edx]
      add edx,edx
      sub ebx,edx
      add bl,'0'
      mov [edi],bl
      add edi, 1
    .endw

    mov byte ptr [edi], 0       ; terminate the string

    ; We now have all the digits, but in reverse order.

    .while (esi < edi)
      sub edi, 1
      mov al, [esi]
      mov ah, [edi]
      mov [edi], al
      mov [esi], ah
      add esi, 1
    .endw

  dtaexit:

    pop edi
    pop esi
    pop ebx

    ret

dwtoa endp


and


udw2str proc dwNumber:DWORD, pszString:DWORD

    push ebx
    push esi
    push edi

    mov     eax, [dwNumber]
    mov     esi, [pszString]
    mov     edi, [pszString]
    mov ecx,429496730

  @@redo:
    mov ebx,eax
    mul ecx
    mov eax,edx
    lea edx,[edx*4+edx]
    add edx,edx
    sub ebx,edx
    add bl,'0'
    mov [esi],bl
    inc esi
    test    eax, eax
    jnz     @@redo
    jmp     @@chks

  @@invs:
    dec     esi
    mov     al, [edi]
    xchg    [esi], al
    mov     [edi], al
    inc     edi
  @@chks:
    cmp     edi, esi
    jb      @@invs

    pop edi
    pop esi
    pop ebx


    ret

udw2str endp


The large magic numbers (3435973837 and 429496730) are 0.32 fixed point reciprocals (0.8 and 0.1, respectively) so that divisions dont have to be performed.

I'm not sure why 0.9 wasn't used in the first case.. maybe a precision issue. Later I will post a reliability study of these two fixed point reciprocals to prove that they work for all 32-bit input values.
When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

Rockoon

Testing the 0.1 reciprocal...


elapsed time = 10.4776606000014 seconds
errors = 644245094
first error = 1073741829

1073741829 / 10 = 107374182.9
(1073741829 * 429496730) >> 32 = 107374183
done


udw2str() is broken!!
When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

Rockoon

Testing the 0.8 reciprocal


elapsed time = 4.49280790000194 seconds
errors = 0
done


The 0.8 reciprocal is good for all unsigned 32-bit inputs (needs unsigned multiplication!)

The first routine works by multiplying by 0.8, and then dividing by 8 (via shift) to get the 0.1 reciprocal actually needed.

The reciprocals for 0.9, 0.4 and 0.2 also do not work, all erroring out below before hitting 2^31
When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

jj2007

Quote from: hutch-- on August 17, 2010, 04:40:43 PMThey both perform the conversion then reverse the string to get it in the right order. I would be interested in seeing if anyone has a better or faster way to do either of these conversions.

Sounds familiar... Str$() does the job, and is a bit faster than wsprintf but slower than dwtoa. It avoids the reversion by anticipating the overall length and working backwards. But I would not recommend that road for a general purpose dword-only routine. Reversing itself may cost around 16 cycles with Lingo's routine.

Intel(R) Celeron(R) M CPU        420  @ 1.60GHz (SSE3)
xmm0=12345.68
237     cycles for unsigned Str$(xmm0)
231     cycles for unsigned Str$(12345)
460     cycles for wsprintf 12345
65      cycles for dwtoa

raymond

If anyone is interested in comparisons, the umdtoa (and smdtoa for signed dwords) in the latest version of the fpulib is quite similar to the dwtoa routine. The minor differences are:
- no string reversal, but the address of the first character of the null-terminated string is returned in EAX
- the number of characters of the string (excluding the terminating 0) is returned in ECX

Similar procedures for qwords (umqtoa and smqtoa) are also included in the same fpulib.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

hutch--

Thanks Ray,

Its good to get someone whose maths is better developed than mine.  :U  (eenie meanie minie moe technology)  :bg
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

hutch--

Ray,

I am getting a 404 page not found error on the link on your page.

No matter, I cheated and FTP downloaded them.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

jj2007

Quote from: raymond on August 18, 2010, 02:19:38 AM
If anyone is interested in comparisons, the umdtoa (and smdtoa for signed dwords) in the latest version of the fpulib is quite similar to the dwtoa routine. The minor differences are:
- no string reversal, but the address of the first character of the null-terminated string is returned in EAX
- the number of characters of the string (excluding the terminating 0) is returned in ECX

Same speed as dwtoa, at least on my P4.
MasmBasic Str$() returns a zero-delimited string in eax and the number of used chars in edx - useful for parsing & replacing. It converts also qwords and similar stuff.

Intel(R) Pentium(R) 4 CPU 3.40GHz (SSE3)
xmm0=12345.68
12345
12345

568     cycles for unsigned Str$(xmm0)
587     cycles for signed Str$(xmm0)
529     cycles for unsigned Str$(12345)
1106    cycles for wsprintf 12345
104     cycles for umdtoa 12345
105     cycles for dwtoa 12345

547     cycles for unsigned Str$(xmm0)
592     cycles for signed Str$(xmm0)
532     cycles for unsigned Str$(12345)
1105    cycles for wsprintf 12345
106     cycles for umdtoa 12345
106     cycles for dwtoa 12345

Rockoon

When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

jj2007

Quote from: Rockoon on August 18, 2010, 05:34:19 PM
JJ, did you upload the right file? Doesnt look like it.

It will assemble fine if you either set useMB = 0 or install MasmBasic (the version of today ::) - I hesitate to advertise it because it's not thoroughly tested*), and install Ray's lib posted by Hutch above.


* Test if Str$() returns correct results:
include \masm32\MasmBasic\MasmBasic.inc
Init
xor ebx, ebx
xor edi, edi ; error count
.Repeat
.if !bx
Print Str$("ebx=%i\n", ebx) ; do some animation, the whole proggie takes ages...
.endif
.if ebx!=Val(Str$(ebx))
deb 2, "We got a problem", eax, ebx ; didn't see this one, though ;-)
inc edi
.endif
dec ebx
.Until Zero?
deb 2, "All done, thanks", ebx, edi
Exit
end start

raymond

QuoteI am getting a 404 page not found error on the link on your page.

Fixed it. The source code had the file name in uppercase letters while the zip file had its name mostly in lower case letters. :red

Seems to work OK now. Thanks for reporting it. I'll try to be a bit more careful in the future.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

dedndave

if that's the worst thing you do this week, Raymond, your ok in my book   :U

prescott w/htt
Intel(R) Pentium(R) 4 CPU 3.00GHz (SSE3)

1119    cycles for wsprintf 12345
115     cycles for umdtoa 12345
107     cycles for dwtoa 12345

1148    cycles for wsprintf 12345
106     cycles for umdtoa 12345
105     cycles for dwtoa 12345

1133    cycles for wsprintf 12345
108     cycles for umdtoa 12345
104     cycles for dwtoa 12345

1174    cycles for wsprintf 12345
105     cycles for umdtoa 12345
104     cycles for dwtoa 12345

FORTRANS

Hi,

PIII, dwtoa_vs_Str$ results.

Regards,

Steve N.


pre-P4 (SSE1)
12345
12345

579     cycles for wsprintf 12345
82      cycles for umdtoa 12345
96      cycles for dwtoa 12345

579     cycles for wsprintf 12345
82      cycles for umdtoa 12345
96      cycles for dwtoa 12345


--- ok ---