News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Dword to ascii (dw2a, dwtoa, dw2str, Str$, ...)

Started by jj2007, April 01, 2024, 03:42:50 AM

Previous topic - Next topic

NoCforMe

On each post, the text at top ("Today at xx:xx:xx AM/PM") is a link you can copy to link to that reply in the thread. Use the link button (3rd button in 5th group) to insert a link into the post.
Assembly language programming should be fun. That's why I do it.

jj2007


ahsat


jimg

Quote from: jj2007 on April 01, 2024, 10:24:11 AMThe div ebx is indeed the bottleneck in your algo. I've tried to replace it with a mul 0CCCCCCCDh but with little success, speedwise. It's a pity because your algo is really very elegant and short :thumbsup:


Using your version 3 and enabling test F I get

Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz (SSE4)

6026    cycles for 100 * dwtoa
6271    cycles for 100 * dw2str
22536  cycles for 100 * MasmBasic Str$()
15352  cycles for 100 * Ray's algo
5964    cycles for 100 * Ray+mul

6054    cycles for 100 * dwtoa
6152    cycles for 100 * dw2str
22515  cycles for 100 * MasmBasic Str$()
15347  cycles for 100 * Ray's algo
5983    cycles for 100 * Ray+mul

5941    cycles for 100 * dwtoa
6034    cycles for 100 * dw2str
22455  cycles for 100 * MasmBasic Str$()
15310  cycles for 100 * Ray's algo
5944    cycles for 100 * Ray+mul

6060    cycles for 100 * dwtoa
6359    cycles for 100 * dw2str
22421  cycles for 100 * MasmBasic Str$()
15315  cycles for 100 * Ray's algo
5984    cycles for 100 * Ray+mul

Averages:
6040    cycles for dwtoa
6212    cycles for dw2str
22485  cycles for MasmBasic Str$()
15331  cycles for Ray's algo
5974    cycles for Ray+mul

20      bytes for dwtoa
74      bytes for dw2str
16      bytes for MasmBasic Str$()
110    bytes for Ray's algo
74      bytes for Ray+mul

dwtoa                                  -123456789
dw2a                                    4171510507
dw2str                                  -123456789
MasmBasic Str$()                        -123456789
Ray's algo                              171510507
Ray+mul                                j

Seems faster with the multiply to me ?


ahsat

Quote from: jimg on April 02, 2024, 07:43:17 AMI've tried to replace it with a mul 0CCCCCCCDh but with little success, speedwise.
Quote from: jimg on April 02, 2024, 07:43:17 AMSeems faster with the multiply to me ?

If you made it faster, show me the code.

jj2007

Quote from: jimg on April 02, 2024, 07:43:17 AMUsing your version 3 and enabling test F I get

It's definitely faster, Jim, but look at the result: there was a reason why I disabled it :biggrin:

Some fine tuning needed; dwtoa and dw2str use the mul variant.

ahsat

Quote from: jj2007 on April 02, 2024, 09:40:50 AMIt's definitely faster, Jim, but look at the result:
Is there any chance I can see the code with the multiply?

jj2007

Quote from: ahsat on April 02, 2024, 09:46:58 AMIs there any chance I can see the code with the multiply?

It's in the archive posted in your thread as Test_F, but disabled. Here is the code:
_xmul    dd 0CCCCCCCDh
ctAnyToAnyMul:
  push edx        ; save edx, or a digit
  push ecx
  mov ecx, eax
;   int 3
  mul _xmul    ; something is wrong here
  shr edx, 3
  mov eax, edx
  add edx, edx
  lea edx, [edx*4+edx+"0"]
  sub edx, ecx
  neg edx
  pop ecx
  dec ecx        ; decrement digit count
  .if !Zero?        ; br if done
    call ctAnyToAnyMul    ; generate next digit
  .endif
  mov al, @digits[edx]    ; get the ascii value
  stosb            ; save it
  pop edx        ; restore edx, or get next digit
  ret

This is a multiply by 10, then add 30h:
  add edx, edx
  lea edx, [edx*4+edx+"0"]

Note it will probably work with minor changes, but I was too tired to fix it...

Instead of the decrement digit count, I would vote for a test eax, eax :cool:

jimg

it normally looks like this.  I added comments so it isn't so cryptic-

      mov ecx, 0CCCCCCCDh ; 8 * 1/10
      mov ebx,eax         ; save original
      mul ecx           ; num * 1/10 magic number
      shr edx, 3          ; magic number fixup
      lea edx,[edx*4+edx] ; *5
      add edx,edx         ; *10
      sub ebx,edx         ; remainder

jimg

I couldn't resist.  This seems to produce the correct number.  Patched together from dwtoa and ctAnyToAnyMul.  Could use some refinement, I just wanted to see it work.

ctAnyToAnyMul:  ; setup
  test eax,eax
  jnz sign
  mov word ptr [edi],30h
  ret

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

ctanydoit:
  push edx ; save edx, or a digit
  xor edx,edx
  push ecx
      mov ecx,0CCCCCCCDh  ; 8 * 1/10
      mov ebx,eax         ; save original
      mul ecx             ; num * 1/10 magic number
      shr edx, 3          ; magic number fixup
      mov eax,edx
      lea edx,[edx*4+edx] ; *5
      add edx,edx         ; *10
      sub ebx,edx         ; remainder
      mov edx,ebx     
  pop ecx
  dec ecx ; decrement digit count
  .if !Zero? ; br if done
call ctanydoit ; generate next digit
  .endif
  mov al, @digits[edx] ; get the ascii value
  stosb ; save it
  pop edx ; restore edx, or get next digit
  ret

A little slower than dwtoa, but I didn't spend any time optimizing for speed.

ahsat

Quote from: jimg on April 02, 2024, 01:15:09 PMI couldn't resist.
That is really cool, if it works. But I would leave it up to the caller to handle the sigh, unless negative numbers break things.

ahsat

Quote from: jimg on April 02, 2024, 01:15:09 PMA little slower than dwtoa, but I didn't spend any time optimizing for speed.
It can be optimized a little, but I tested it and now see that it only works for base 10. I like my algorithm which will convert to any base.

jimg

Of course.  This was just for fun.  You'd need the magic number for each base you wanted to use.

jj2007

Quote from: jimg on April 02, 2024, 04:52:38 PMYou'd need the magic number for each base you wanted to use.

Which wouldn't be too difficult, actually.

.CODE
_xmul    dd 0CCCCCCCDh
ctAnyToAnyMul:
  push ecx        ; save edx, or a digit
  mov ecx, eax
  mul esi        ; e.g. 0CCCCCCCDh
  shr edx, 3
  mov eax, edx
  add edx, edx
  lea edx, [edx*4+edx-"0"+1]
  sub ecx, edx
  test eax, eax
  .if !Zero?        ; br if done
    call ctAnyToAnyMul    ; generate next digit
  .endif
  mov al, dl    ; @digits[edx]    ; get the ascii value
  stosb            ; save it
  pop ecx        ; restore edx, or get next digit
  ret
...
    mov eax, TheNumber
    mov edi, offset result2
    push esi
    mov esi, _xmul[0*4]    ; 0...2 index
    call ctAnyToAnyMul
    pop esi

And voilĂ , it beats good ol' dwtoa :biggrin:

AMD Athlon Gold 3150U with Radeon Graphics      (SSE4)
Averages:
3400    cycles for dwtoa
2180    cycles for dw2str
15316   cycles for MasmBasic Str$()
10984   cycles for Ray's algo I
3086    cycles for Ray+mul

20      bytes for dwtoa
82      bytes for dw2str
16      bytes for MasmBasic Str$()
110     bytes for Ray's algo I
64      bytes for Ray+mul

dwtoa                                   1234567
dw2a                                    1234567
dw2str                                  1234567
MasmBasic Str$()                        1234567
Ray's algo I                            001234567
Ray+mul

six_L

QuoteYou'd need the magic number for each base you wanted to use.
n/base = n*(1/base) ; Not all bases have magic numbers,so "div" can't change into "mul" sometimes.
Only 10,19,28,37,46,55 is a magic number in 2-60.

QuoteCheck if a number is magic (Recursive sum of digits is 1)
A number is said to be a magic number, if the sum of its digits are calculated till a single digit recursively by adding the sum of the digits after every addition. If the single digit comes out to be 1,then the number is a magic number.

For example-
Number= 50113
=> 5+0+1+1+3=10
=> 1+0=1
This is a Magic Number

For example-
Number= 1234
=> 1+2+3+4=10
=> 1+0=1
This is a Magic Number
ChkMagicNumber proc uses rbx n:QWORD
    Local sum:QWORD

    mov    rax,n
    mov    sum,0
    mov    rcx,10
    .while (rax > 0) || (sum > 9)
        .if    rax == 0
            mov    rax,sum
            mov    sum,0
        .endif
        xor    rdx,rdx
        div    rcx
        mov    rbx,sum
        add    rbx,rdx
        mov    sum,rbx
    .endw
    mov    rax,sum    ;rax = 1, n is a magic number.
    ret

ChkMagicNumber endp

Say you, Say me, Say the codes together for ever.