News:

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

ULONG to ASCII

Started by baltoro, April 27, 2011, 09:31:07 PM

Previous topic - Next topic

baltoro

I was exploring the Internet, and I found this site: The Assembly Gems Page. It's an old Swedish site (last update is 1998),...and, the code is presented in Turbo Assembler (TASM) IDEAL mode style. I am not familiar with TASM, but, it looks an awful lot like MASM to me. Anyway, I was reading through the examples, and, some of the techniques were a mystery to me. The webpage is here: ulong2ascii. Here's a brief description: ulong2ascii converts a 32-bit unsigned integer into a decimal ASCIIZ string (a null terminated string as used by the C language). I've read through a similar routine from the MASM library that does the same thing, so I thought I would understand it.

Note: Define a symbol FASTMUL if the target CPU has a fast integer multiply (5 cycles or less), e.g. K6 and PentiumII. For CPUs with slow integer multiply such as PentiumMMX, undefine FASTMUL to replace one of the multiplies with a table look up. Note that the table lookup might cause cache misses.

Here is the code:

;
; ulong2ascii
;
; input:
;   eax = unsigned long to be converted to ASCIIZ string
;   edi = pointer to character buffer which receives result (at least 11 chars)
;
; output:
;   none (buffer filled with numbers)
;
; destroys:
;   eax, ebx, ecx, edx, esi, edi
;   eflags
;

MACRO   ulong2ascii
        DATASEG

IFNDEF FASTMUL
cvttab  DD      0000000000      ; 0 * 1e9
        DD      1000000000      ; 1 * 1e9
        DD      2000000000      ; 2 * 1e9
        DD      3000000000      ; 3 * 1e9
        DD      4000000000      ; 4 * 1e9
ENDIF
          CODESEG

        mov     ecx,eax         ; save original argument
        mov     esi,89705f41h   ; 1e-9*2^61 rounded
        mul     esi             ; divide by 1e9 by mult. with recip.
        add     eax,80000000h   ; round division result
        mov     esi,0abcc7712h  ; 2^28/1e8 * 2^30 rounded up
        adc     edx,0           ; EDX<31:29> = argument / 1e9
        mov     eax,ecx         ; restore original argument
        shr     edx,29          ; leading decimal digit, 0...4
        mov     ecx,8           ; produce eight more digits
        mov     ebx,edx         ; flags whether non-zero digit seen yet
        or      edx,'0'         ; convert digit to ASCII
        mov     [edi],dl        ; store out to memory
        cmp     ebx,1           ; first digit nonzero ? CY=0 : CY=1
        sbb     edi,-1          ; incr. pointer if first digit non-zero
IFDEF FASTMUL
        imul    ebx,1000000000  ; multiply quotient digit by divisor
        sub     eax,ebx         ; remainder after first digit
ELSE
        sub     eax,[cvttab+ebx*4]      ; subtract quotient digit * divisor
ENDIF
        mul     esi             ;  convert number < 1e9
        shld    edx,eax, 2      ;   into fraction such
        inc     edx             ;    that 1.0 = 2^28
        mov     eax,edx         ; save result
        shr     eax,28          ; next digit
        and     edx,0fffffffh   ; fraction part
        or      ebx,eax         ; any non-zero yet ?
        or      eax,'0'         ; convert digit to ASCII
$cvt_loop:
        mov     [edi],al        ; store digit out to memory
        add     edx,edx         ; 2*fraction
        cmp     ebx,1           ; any non-zero digit seen ? CY=0 : CY=1
        lea     edx,[edx*4+edx] ; 10*fraction, new digit EAX<31:28>,
                                ; new fraction EAX<27:0>
        sbb     edi,-1          ; incr. ptr if any non-zero digit seen
        mov     eax,edx         ; save result
        shr     eax,28          ; next digit = integer part
        and     edx,0fffffffh   ; fraction part
        or      ebx,eax         ; any non-zero digit yet ?
        or      eax,'0'         ; convert digit to ASCII
        dec     ecx             ; one more digit
        jnz     $cvt_loop       ; until all nine digits done
        mov     [edi],al        ; store last digit out to memory
        mov     [byte ptr edi+1],ah     ; place string end marker
ENDM

                                                                Author: Norbert Juffa                               


Most of it seems pretty straightforward, except for the lines (near the beginning): 

        mov     esi,89705f41h   ; 1e-9*2^61 rounded
        mul     esi             ; divide by 1e9 by mult. with recip.
        add     eax,80000000h   ; round division result
        mov     esi,0abcc7712h  ; 2^28/1e8 * 2^30 rounded up
        adc     edx,0           ; EDX<31:29> = argument / 1e9


I have no clue what he is trying to accomplish here. I understand the instructuions, but, not why he chose these particular values to operate on the original ulong input.   
Any advice would be appreciated. Thanks.

:eek P.S. I found this when doing a Forum search for TASM: "Bogdan Ontanu is an expert on TASM." :eek
Baltoro

drizz

max unsigned dword is 4294967295, that's 10 digits.
"mul" gives 64bit result of two 32bit values.
topmost digit is 4 max(can also be 3 2 1 0; 4294967295) Trunc(4294967295 * 1e-9) = 4.
410 = 1002 hence you only need 3 bits to represent topmost digit.
64 - 3 = 61 ==> 2^61
with fixed point arithmetic, we take the point to be :
111.1111111111111111111111111111111111111111111111111111111111111 == EDX::EAX
so to get topmost digit in those 3 bits we multiply the value by 1e-9*2^61 =  2305843009.213693952 = 230584300910 = 89705F4116
then author takes different multiplier for the rest 9 digits (0abcc7712h)

.... more procs here and info:
http://www.masm32.com/board/index.php?topic=11741.0
The truth cannot be learned ... it can only be recognized.

baltoro

DRIZZ,...THANKS !!! That's just the information I was looking for,...
I had just found this message of yours: in Binary to Decimal using multiply, where you do something similiar. Thanks for explaining it. I had just a vague concept of what was going on, but, didn't know what the 89705f41h value was. THANKS !!!
So, just to be clear,...the EDX register is ALWAYS altered by the MUL instruction if the destination operand is 32-bit ???
Baltoro

jj2007

Quote from: baltoro on April 27, 2011, 11:00:24 PMthe EDX register is ALWAYS altered by the MUL instruction if the destination operand is 32-bit ???

Yes. If you want to avoid that, use e.g. imul eax, eax, 123

baltoro

Drizz,
Thanks, again,...I appreciate the information. You are a goldmine of optimal assembly language routines,...
:eek There is an awful lot about assembly programming that I am completely oblivious to,... :eek

...And, this is a CLASSIC:
Quote from:  DAVE:eek ...i would be interested to see how fast my current virgin is,... :eek
Baltoro

dedndave

 :bg

baltoro,
if you search the laboratory sub-forum, you will find that the guys have had hours of fun writing and comparing dword to ascii routines
it is one of the most fun things to write
i couldn't compete with them, so i wrote a set of routines for dealing with large integers   :P
for that, search for Ling Long Kai Fang

we need to delete all the old threads, so we can do it all again - lol

baltoro

:eek Yeah, I've read a number of them in monthes past,...I could never understand the thrill of competitive routine emitting,...(probably because it's beyond my capabilities) :eek
But, definitely, a great source of programming ideas. The one thing that I thought you guys did extremely well was the long, protracted discussions of computing (especially, floating-point) precision,...something, that as a novice you know intuitively is critically important,...but, is almost impossible to visualize or implement accurately.
In fact, if you could compile all the thinking that those posts represent into one huge text,...say, a BIBLE of assembly priogramming, everyone could retire and move to Fiji. Unfortunately, there's only a few people on the planet that are really fanatical about MASM enough to actually read it,... :eek
For most people (and, this includes me), critical thinking is actually painful, and, induces all kinds of bizarre psychological abnormalities,... :eek
Baltoro