flat assembler
Message board for the users of flat assembler.

Index > Main > IntToStrW (64-Bit)

Author
Thread Post new topic Reply to topic
nasm



Joined: 02 Nov 2021
Posts: 183
nasm 03 Feb 2024, 11:05
Hi

Do anyone have a procedure to convert a 64-bit signed integer to a unicode string.

I have one here but I noticed that it had a bug in it, it only converts to 32-bit, not 64-bit, even if the procedure states that it should do 64-bit.

I'm interested in both ways:
IntToStrW
StrToIntW

(Signed versions)


Last edited by nasm on 03 Feb 2024, 11:09; edited 1 time in total
Post 03 Feb 2024, 11:05
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20459
Location: In your JS exploiting you and your system
revolution 03 Feb 2024, 11:08
What do you mean by "unicode string"? Do you want a wide string (i.e. two bytes per character)?
Post 03 Feb 2024, 11:08
View user's profile Send private message Visit poster's website Reply with quote
nasm



Joined: 02 Nov 2021
Posts: 183
nasm 03 Feb 2024, 11:10
revolution wrote:
What do you mean by "unicode string"? Do you want a wide string (i.e. two bytes per character)?


Widestring is used in 90% of the cases so it would be wise to assume so. Which means you are not all that wise. Maybe you should let somebody else deal with this?

I guess you can call me "Being somewhat DIRECT" Very Happy

This is not the place for Very Happy Smile Sad Surprised Shocked Cool Laughing Mad Razz Embarassed Crying or Very sad Evil or Very Mad Twisted Evil Rolling Eyes Wink Exclamation Question Idea Arrow

we do coding here.

_________________
Do you think anyone will sell their soul over a 10 cent yoghurt with a bad after taste that lasts, a decade?
Post 03 Feb 2024, 11:10
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1043
Location: Russia
macomics 03 Feb 2024, 12:45
What is the problem with encoding ANSI string to WideString. It is enough to simply add zero characters after one.
fasm1 x86 INT64->ANSI
Code:
UintToStr: ; edx:eax = unsigned int64, ecx = char[24]
        push    edi
        push    esi
        push    ebp
        push    ebx
        push    ecx
        xor     esi, esi
        xor     ebp, ebp
        xor     ebx, ebx
        mov     edi, edx
        mov     ecx, 100
        test    edi, edi
        jnz     .dq
        cmp     eax, ecx
        mov     ecx, 0xA3D70A3E
        jae     .dd
        pop     edi
        mov     ch, 10
        push    edi
        cmp     al, ch
        jae     .last
        or      al, '0'
        stos    byte [edi]
        jmp     .quit

    @@:
        shrd    ebp, ebx, 8
        shrd    ebx, edx, 8
        inc     esi

   .dq:
        xor     edx, edx
        xchg    eax, edi
        div     ecx
        xchg    eax, edi
        div     ecx
        test    edi, edi
        jnz     @b
        mov     ecx, 0xA3D70A3E
        mov     edi, edx

    @@:
        shrd    ebp, ebx, 8
        shrd    ebx, edi, 8
        inc     esi

   .dd:
        mov     edi, eax
        mul     ecx
        mov     eax, edx
        shr     eax, 6
        imul    edx, eax, 100
        sub     edi, edx
        cmp     eax, 100
        jae     @b
        mov     edx, edi
        pop     edi
        mov     ecx, 2568
        push    edi
        div     ch
        or      eax, '00'
        cmp     al, '0'
        jz      @f
        stos    byte [edi]

    @@:
        mov     al, ah
        stos    byte [edi]
        mov     eax, edx
        test    esi, esi
        jz      .last

    @@:
        shld    edx, ebx, cl
        div     ch
        shld    ebx, ebp, cl
        or      ax, '00'
        shl     ebp, cl
        sub     dh, dh
        stos    word [edi]
        mov     eax, edx
        dec     esi
        jnz     @b

   .last:
        div     ch
        or      ax, '00'
        stos    word [edi]

   .quit:
        mov     eax, edi
        mov     [edi], dh
        pop     ecx
        sub     eax, ecx
        pop     ebx
        pop     ebp
        pop     esi
        pop     edi
        retn

IntToStr: ; edx:eax = signed int64, ecx = char[24]
        cmp     edx, 0
        jge     UintToStr
        push    0
        push    0
        sub     [esp + 0], eax
        sbb     [esp + 4], edx
        pop     eax
        pop     edx
        inc     ecx
        call    UintToStr
        dec     ecx
        jc      @f
        inc     eax
        mov     byte [ecx], '-'

  @@:
        retn    
Unfortunately, the trick with registers will not work for 128-bit numbers. There will be more than 36 digits.

fasm1 x86 DigitalANSI->WIDE
Code:
DigitalANSI2WIDE: ; eax = characters, ecx = wchar_t[24]
        pushfd
        push    edi
        push    esi
        lea     esi, [ecx + eax - 1]
        lea     edi, [ecx + eax * 2 - 2]
        mov     ecx, eax
        mov     ah, 0
        std

  @@:
        lods    byte [esi]
        stos    word [edi]
        loop    @b
        pop     esi
        pop     edi
        popfd
        retn    
fasm1 x86 WIDE->INT64
Code:
WideStr2Int: ; eax = wchar_t[24], out edx:eax, ecx = break pointer
        pushfd
        push    esi
        push    ebp
        push    ebx
        push    0
        cld
        mov     ecx, 10
        mov     esi, eax
        xor     ebx, ebx
        xor     ebp, ebp
        cmp     word [esi], '-'
        jnz     .start
        lods    word [esi]
        inc     dword [esp]
        jmp     .start

  @@:
        xchg    eax, ebp
        mul     ecx
        test    edx, edx
        jnz     @f
        xchg    eax, ebx
        mul     ebx
        add     eax, ebp
        adc     edx, ebx
        jc      @f
        mov     ebx, eax
        mov     ebp, edx

  .start:
        lods    word [esi]
        sub     ax, '0'
        cmp     ax, 9
        jbe     @b

  @@:
        pop     ecx
        jecxz   @f
        xor     eax, ebx
        xor     edx, edx
        sub     eax, ebx
        sbb     edx, ebp
        jmp     .exit

  @@:
        mov     eax, ebx
        mov     edx, ebp

  .exit:
        lea     ecx, [esi - 2]
        pop     ebx
        pop     ebp
        pop     esi
        popfd
        retn    
I think you can rewrite for x86_64 yourself.
Post 03 Feb 2024, 12:45
View user's profile Send private message Reply with quote
nasm



Joined: 02 Nov 2021
Posts: 183
nasm 03 Feb 2024, 14:41
Anyone have 64-bit versions? Faster is better. You want to have this in good quality, it's a very important and frequently used routine. I'm not saying the one posted is bad, but I'm saying that if anyone have a better one, it is welcome.

_________________
Do you think anyone will sell their soul over a 10 cent yoghurt with a bad after taste that lasts, a decade?
Post 03 Feb 2024, 14:41
View user's profile Send private message Reply with quote
nasm



Joined: 02 Nov 2021
Posts: 183
nasm 03 Feb 2024, 15:47
Anyone who wants to share their proud work, don't be afraid to. Sharing is believing.

Your work will be handled professionally, and with care.
Post 03 Feb 2024, 15:47
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1043
Location: Russia
macomics 03 Feb 2024, 16:19
A lot of things have been optimized for proposed function:

  • The number of 64-bit divisions has been reduced from 19 to 5
  • Faster division through multiplication is used
  • Faster division of 8-bit numbers is used (Core i7 improve)
  • A register buffer is used instead of a buffer in memory

As a result:
Code:
Converting the number 999`999`999 to a string 100`000`000 times
 Performance test (NULL_FUNC) =        133 ms
                    wsprintfA =       8514 ms
                    wsprintfW =       8283 ms
 Performance test (NULL_FUNC) =        257 ms
                        Stack =       4610 ms
 Performance test (NULL_FUNC) =        241 ms
                        BCDv3 =       3202 ms  ; <<< Int2Str
 Performance test (NULL_FUNC) =        144 ms
              Delphi.internal =      23228 ms
                 Delphi.write =       5781 ms
 Performance test (NULL_FUNC) =        112 ms
                BCB6.internel =       7722 ms
                   BCB6.write =       6243 ms



Converting the number 123 to a string 1`000`000`000 times
 Performance test (NULL_FUNC) =       1505 ms
                    wsprintfA =      40110 ms
                    wsprintfW =      35956 ms
 Performance test (NULL_FUNC) =       2263 ms
                        Stack =      12650 ms
 Performance test (NULL_FUNC) =       2878 ms
                        BCDv3 =       7336 ms  ; <<< Int2Str
 Performance test (NULL_FUNC) =       1461 ms
              Delphi.internal =     193737 ms
                 Delphi.write =      13918 ms
 Performance test (NULL_FUNC) =       1220 ms
                BCB6.internel =      24880 ms
                   BCB6.write =      15985 ms


Converting numbers [0 .. 4`294`967`295] to a string
 Performance test (NULL_FUNC) =       6313 ms
                    wsprintfA =     386826 ms
                    wsprintfW =     373225 ms
 Performance test (NULL_FUNC) =      10083 ms
                        Stack =     220307 ms
 Performance test (NULL_FUNC) =      12421 ms
                        BCDv3 =     145853 ms  ; <<< Int2Str
 Performance test (NULL_FUNC) =       6531 ms
              Delphi.internal =    1017640 ms
                 Delphi.write =     137686 ms
 Performance test (NULL_FUNC) =       6321 ms
                BCB6.internel =     352538 ms
                   BCB6.write =     293513 ms    

Performance test (NULL_FUNC) - This is a test loop call with an empty function of the corresponding prototype to find out the execution delays created by the loop and the framing of the function (prologue and epilogue)
wsprintfX - Windows
Stack - A function that uses a shortened division cycle, but stores data on the stack
BCDv3 - Current Int2Str
Delphi.internal - IntToStr from Delphi 7 (in the DLL library)
Delphi.write - A function written manually in Delphi 7 (in the DLL library)
BCB6.internel - IntToStr from Borland C Builder v6.0 (in the DLL library)
BCB6.write - A function written manually in Borland C Builder v6.0 (in the DLL library)

The number from the line 'Performance test (NULL_FUNC)' above lines with test must be subtracted in order to compare results. But even without this, you can see which function works better.
Post 03 Feb 2024, 16:19
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1043
Location: Russia
macomics 03 Feb 2024, 17:34
In general, if you just correct e to r for all registers, then everything will work for 128-bit numbers.
I will test the speed of work later

Code:
Uint2Str: ; rdx:rax = unsigned int128, rcx = char[40]
  .magic                = 0xA3D70A3D70A3D70A ; = 64 * 10000000000000000h / 100

        push    rdi
        push    rsi
        push    rbp
        push    rbx
        push    rcx
        mov     rbx, rdx
        or      rbp, -1
        xor     rsi, rsi
        xor     rdi, rdi
        mov     ecx, 100
        test    rbx, rbx
        jnz     .qd
        cmp     rax, rcx
        mov     rcx, .magic
        jae     .dq
        mov     ch, 10
        mov     rbx, [rsp]
        cmp     al, ch
        jae     .last
        or      al, '0'
        mov     byte [rbx], al
        inc     rbx
        jmp     .quit

  @@:
        shrd    rdi, rsi, 8
        shrd    rsi, rbp, 8
        shrd    rbp, rdx, 8

  .qd:
        xor     rdx, rdx
        xchg    rax, rbx
        div     rcx
        xchg    rax, rbx
        div     rcx
        test    rbx, rbx
        jnz     @b
        mov     rbx, rdx
        mov     rcx, .magic

  @@:
        shrd    rdi, rsi, 8
        shrd    rsi, rbp, 8
        shrd    rbp, rbx, 8

  .dq:
        mov     rbx, rax
        mul     rcx
        mov     rax, rdx
        shr     rax, 6
        imul    rdx, rax, 100
        sub     rbx, rdx
        cmp     rax, 100
        jae     @b
        mov     ecx, 2568
        mov     edx, ebx
        div     ch
        mov     rbx, [rsp]
        or      eax, '00'
        cmp     al, '0'
        jz      @f
        mov     [rbx], al
        inc     rbx

    @@:
        mov     al, ah
        mov     [rbx], al
        inc     rbx
        mov     eax, edx
        test    rbp, rbp
        js      .last

    @@:
        shld    rdx, rbp, cl
        div     ch
        shld    rbp, rsi, cl
        or      ax, '00'
        shld    rsi, rdi, cl
        sub     dh, dh
        mov     [rbx], ax
        shl     rdi, cl
        mov     eax, edx
        add     rbx, 2
        test    rbp, rbp
        jns     @b

   .last:
        div     ch
        or      ax, '00'
        mov     [rbx], ax
        add     rbx, 2

   .quit:
        pop     rcx
        mov     rax, rbx
        mov     [rbx], dil
        sub     rax, rcx
        pop     rbx
        pop     rbp
        pop     rsi
        pop     rdi
        clc
        retn

IntToStr: ; rdx:rax = signed int128, rcx = char[48]
        cmp     rdx, 0
        jge     UintToStr
        push    0
        push    0
        sub     [rsp + 0], rax
        sbb     [rsp + 4], rdx
        pop     rax
        pop     rdx
        inc     rcx
        call    UintToStr
        dec     rcx
        jc      @f
        inc     rax
        mov     byte [rcx], '-'

  @@:
        retn    
Post 03 Feb 2024, 17:34
View user's profile Send private message Reply with quote
nasm



Joined: 02 Nov 2021
Posts: 183
nasm 03 Feb 2024, 20:53
I haven't tested it yet, I will look at it soon. Great work, looks complicated.
Post 03 Feb 2024, 20:53
View user's profile Send private message Reply with quote
SeproMan



Joined: 11 Oct 2009
Posts: 70
Location: Belgium
SeproMan 04 Feb 2024, 19:47
Quote:
Do anyone have a procedure to convert a 64-bit signed integer to a unicode string.


A solution for Linux:

Code:
; IN (rdi,rsi) OUT (rax) MOD (rcx,rdx,rdi)
IntToStrW:
  push  rsi              ; (1)
  sub   rsp, 24          ; At most 19 digits
  mov   rax, rsp
  xchg  rax, rdi         ; -> RAX is 64-bit integer, RDI is temp buffer (stack)
  mov   ecx, 10          ; CONST RCX = 10
  test  rax, rax
  jns   .more
  mov   word [rsi], '-'
  add   rsi, 2
  neg   rax

.more:
  xor   edx, edx
  div   rcx              ; RDX:RAX / RCX
  add   edx, '0'
  mov   [rdi], dl
  inc   rdi
  test  rax, rax
  jnz   .more

.copy:
  dec   rdi
  movzx eax, byte [rdi]
  mov   [rsi], ax
  add   rsi, 2
  cmp   rdi, rsp
  ja    .copy
  add   rsp, 24

  mov   rax, rsi
  pop   rsi              ; (1)
  sub   rax, rsi
  shr   eax, 1           ; -> RAX is number of unicode characters
  ret
    


A solution for Windows:

Code:
; IN (rcx,rdx) OUT (rax) MOD (rcx,r8,r9)
IntToStrW:
  push  rdx              ; (1)
  mov   r9, rdx
  sub   rsp, 24          ; At most 19 digits
  mov   rax, rsp
  xchg  rax, rcx         ; -> RAX is 64-bit integer, RCX is temp buffer (stack)
  mov   r8d, 10          ; CONST R8 = 10
  test  rax, rax
  jns   .more
  mov   word [rdx], '-'
  add   r9, 2
  neg   rax

.more:
  xor   edx, edx
  div   r8               ; RDX:RAX / R8
  add   edx, '0'
  mov   [rcx], dl
  inc   rcx
  test  rax, rax
  jnz   .more

.copy:
  dec   rcx
  movzx eax, byte [rcx]
  mov   [r9], ax
  add   r9, 2
  cmp   rcx, rsp
  ja    .copy
  add   rsp, 24

  mov   rax, r9
  pop   rdx              ; (1)
  sub   rax, rdx
  shr   eax, 1           ; -> RAX is number of unicode characters
  ret
    

_________________
Real Address Mode.
Post 04 Feb 2024, 19:47
View user's profile Send private message Reply with quote
nasm



Joined: 02 Nov 2021
Posts: 183
nasm 05 Feb 2024, 09:39
Keep in mind folks that StrToInt is also a welcome solution. It goes in any direction. Your work is appreciated. Will test it later. Thanks guys and ladies and buddies.
Post 05 Feb 2024, 09:39
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1043
Location: Russia
macomics 08 Feb 2024, 21:56
I found some free time and tested version of 64-bit function, which I wrote in browser using a calculator here

The constant that I calculated on the calculator can't be used to replace div by mul for 64-bit numbers. It gives errors from the very beginning of the range of natural numbers. I have not yet been able to find a constant to replace 64-bit division with multiplication. But I can suggest the following function, which has been checked for correctness. By sunday, I will test several variants of the functions for performance and post the results.

Code:
;       WIDE                    ; ANSI
IntToStr: ; rdx:rax = signed int128, rcx = char[48]; mod: r8, r9
        cmp     rdx, 0
        jge     UintToStr
        mov     r8, rax
        mov     r9, rdx
        xor     rax, rax
        cqo
        add     rcx, 2          ; inc   rcx
        sub     rax, r8
        sbb     rdx, r9
        call    UintToStr
        lea     rcx, [rcx - 2]  ; dec   rcx
        jc      @f
        inc     rax
        mov     word [rcx], '-' ; mov   byte [rcx], '-'

  @@:
        retn



UintToStr: ; rdx:rax = signed int128, rcx = char[48]; mod: r8, r9
  .magic                = 0xA3D70A3E ; 1 + 64 * 0x10000000000000000 div 100

        push    rdi
        push    rsi
        push    rbp
        push    rbx
        push    rcx
        mov     rbx, rdx
        or      rbp, -1
        xor     rsi, rsi
        xor     rdi, rdi
        mov     ecx, 2568
        mov     r9, 0xFFFFFFFF00000000
        mov     r8, 100
        test    rbx, rbx
        jnz     .qd
        test    rax, r9
        jnz     .dq
        cmp     rax, r8
        mov     r8d, .magic
        jae     .dd
        mov     rbx, [rsp]
        cmp     al, ch
        jae     .last
        or      eax, '0'
        mov     [rbx], ax       ; mov   [rbx], al
        add     rbx, 2          ; inc   rbx
        jmp     .quit

  @@:
        shrd    rdi, rsi, cl
        shrd    rsi, rbp, cl
        shrd    rbp, rdx, cl

  .qd:
        xor     rdx, rdx
        xchg    rax, rbx
        div     r8
        xchg    rax, rbx
        div     r8
        test    rbx, rbx
        jnz     @b

  @@:
        shrd    rdi, rsi, cl
        shrd    rsi, rbp, cl
        shrd    rbp, rdx, cl

  .dq:
        xor     rdx, rdx
        div     r8
        test    rax, r9
        jnz     @b
        mov     ebx, edx
        mov     r8d, .magic

  @@:
        shrd    rdi, rsi, cl
        shrd    rsi, rbp, cl
        shrd    rbp, rbx, cl

  .dd:
        mov     ebx, eax
        mul     r8d
        mov     eax, edx
        shr     eax, 6
        imul    edx, eax, 100
        sub     ebx, edx
        cmp     eax, 100
        jae     @b
        mov     ecx, 2568
        mov     edx, ebx
        div     ch
        mov     rbx, [rsp]
        or      eax, '00'
        cmp     al, '0'
        jz      @f
        shl     eax, cl         ; <remove>
        xchg    al, ah          ; <remove>
        mov     [rbx], ax       ; mov   [rbx], al
        add     rbx, 2          ; inc   rbx
        shr     eax, cl         ; <remove>

    @@:
        shr     eax, cl
        mov     [rbx], ax       ; mov   [rbx], al
        add     rbx, 2          ; inc   rbx
        mov     eax, edx
        test    rbp, rbp
        js      .last

    @@:
        div     ch
        shld    rdx, rbp, cl
        or      ax, '00'
        shld    rbp, rsi, cl
        shl     eax, cl         ; <remove>
        shld    rsi, rdi, cl
        xchg    al, ah          ; <remove>
        mov     [rbx], eax      ; mov   [rbx], ax
        shl     rdi, cl
        movzx   eax, dl
        add     rbx, 4          ; add   rbx, 2
        test    rbp, rbp
        jns     @b

   .last:
        div     ch
        or      ax, '00'
        shl     eax, cl         ; <remove>
        xchg    al, ah          ; <remove>
        mov     [rbx], eax      ; mov   [rbx], ax
        add     rbx, 4          ; add   rbx, 2

   .quit:
        pop     rcx
        mov     rax, rbx
        mov     [rbx], r9w      ; mov   [rbx], r9b
        sub     rax, rcx
        shr     al, 1           ; <remove>
        pop     rbx
        pop     rbp
        pop     rsi
        pop     rdi
        retn    

Now the following modifications are present in this function:

  • Accounting for the length of the bit sequence of the input number;
  • Reducing the length of number splitting cycles by dividing by 100 (N^2);
  • Reducing buffer accesses due to the condition (n > 100) and writing to the buffer at the beginning of the iteration;
  • Processor registers are used for buffering, not a buffer in the stack or memory.
Post 08 Feb 2024, 21:56
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1043
Location: Russia
macomics 11 Feb 2024, 16:22
As promised, I tested various options for the functions. You will find their implementations in the attached archive. All functions have been checked for the correctness of converting numbers into strings (numbers do not have leading zeros and end with a character with the code 0, and even more so they coincide with the original number after the reverse conversion).

Function 1 - uses a non-shortened translation cycle (two divisions per digit) and a non-shortened conversion cycle (one char at a time).

Function 2 - does not use a shortened translation cycle (two divisions per digit), but reduces the conversion cycle (by dividing by the square of the base = 100).

Function 3 - uses a shortened translation cycle (two divisions per digit until the highest part of the 128-bit number is zeroed, then one at a time), and a non-shortened conversion cycle (one char at a time).

Function 4 - uses a shortened translation cycle (two divisions per digit until the highest part of the 128-bit number is zeroed, then one at a time), and reduces the conversion cycle (by dividing by the square of the base = 100).

Function 5 - uses a twice-shortened translation cycle (two divisions per digit before zeroing the highest part of a 128-bit number, then one division before zeroing the highest part of a 64-bit number and a cycle of divisions expressed through multiplications for 32-bit numbers), and a non-shortened conversion cycle (one character at a time).

Function 6 - uses a twice-shortened translation cycle (two divisions per digit before zeroing the highest part of a 128-bit number, then one division before zeroing the highest part of a 64-bit number and a cycle of divisions expressed through multiplications for 32-bit numbers), and reduces the conversion cycle (by dividing by the square of the base = 100).

Version 'S' - uses a stack to buffer digits. The 'R' version uses registers.
Version 'A' - generates ASCII characters. The 'W' version is WideChar.
The 'Cur' version is used by me (although I will probably return the previous one now). The 'Old' version is the previous version of the function I am using.
Code:
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
 Test name    |  IntToStr_v1SA |  IntToStr_v2SA |  IntToStr_v3SA |  IntToStr_v4SA |  IntToStr_v5SA |  IntToStr_v6SA |    IntToStrCur |    IntToStrOld |      wsprintfA |      wsprintfW 
              |  IntToStr_v1RA |  IntToStr_v2RA |  IntToStr_v3RA |  IntToStr_v4RA |  IntToStr_v5RA |  IntToStr_v6RA |                |                |                |
              |  IntToStr_v1SW |  IntToStr_v2SW |  IntToStr_v3SW |  IntToStr_v4SW |  IntToStr_v5SW |  IntToStr_v6SW |                |                |                |
              |  IntToStr_v1RW |  IntToStr_v2RW |  IntToStr_v3RW |  IntToStr_v4RW |  IntToStr_v5RW |  IntToStr_v6RW |                |                |                |
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
     Test32 0 |      40,465102 |      27,062468 |      19,584408 |      14,722758 |       3,890590 |       3,698597 |       5,935235 |       5,177087 |      34,669194 |      31,648878 
              |      45,971380 |      29,127479 |      20,691218 |      15,837081 |       5,683810 |       5,156656 |                |                |                |
              |      40,950618 |      27,188282 |      19,629393 |      16,243488 |       3,707793 |       4,257237 |                |                |                |
              |      46,047060 |      30,062751 |      21,234906 |      16,594077 |       5,726811 |       6,072606 |                |                |                |
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
     Test32 1 |      92,051504 |      44,609781 |      41,478786 |      24,117753 |       7,781698 |       7,756330 |      11,571971 |       8,643268 |      57,881268 |      57,037049 
              |     101,176805 |      53,171002 |      51,132716 |      27,984795 |      13,913113 |      12,108637 |                |                |                |
              |      92,168039 |      51,071010 |      42,046187 |      26,680333 |       7,750881 |       9,380711 |                |                |                |
              |     101,250950 |      57,820211 |      51,499064 |      32,794736 |      13,923139 |      16,091782 |                |                |                |
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
     Test32 2 |       1,141072 |       0,650029 |       0,496988 |       0,308176 |       0,100212 |       0,090782 |       0,156103 |       0,120643 |       0,673903 |       0,664181 
              |       1,184458 |       0,699826 |       0,608439 |       0,376070 |       0,166694 |       0,146282 |                |                |                |
              |       1,142848 |       0,661379 |       0,499384 |       0,347342 |       0,101524 |       0,112249 |                |                |                |
              |       1,187946 |       0,762256 |       0,615211 |       0,433289 |       0,167109 |       0,184783 |                |                |                |
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
     Test64 3 |       3,314981 |       1,725764 |       1,633232 |       0,894895 |       1,018157 |       0,597882 |       0,805450 |       0,689710 |              - |              - 
              |       3,522207 |       2,106134 |       1,856625 |       1,273519 |       1,200720 |       0,951388 |                |                |                |
              |       3,314903 |       1,811896 |       1,633203 |       0,978236 |       1,020433 |       0,680179 |                |                |                |
              |       3,526217 |       2,300655 |       1,865511 |       1,466905 |       1,222308 |       1,146217 |                |                |                |
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
     Test64 4 |     108,754703 |      60,924724 |      49,042170 |      29,860293 |       8,897663 |       8,670448 |      15,334207 |      11,838544 |              - |              - 
              |     119,697428 |      71,046716 |      61,107990 |      37,709629 |      16,616310 |      14,541726 |                |                |                |
              |     108,909579 |      64,384195 |      49,388848 |      34,461131 |       8,863242 |      10,400419 |                |                |                |
              |     119,876236 |      76,741607 |      61,486518 |      43,373020 |      17,035374 |      18,260533 |                |                |                |
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
     Test64 5 |      15,898995 |       8,268931 |       7,518533 |       4,201759 |       2,156827 |       1,800477 |       2,772112 |       2,207858 |              - |              - 
              |      17,360790 |       9,476832 |       8,992276 |       5,362431 |       3,227618 |       2,991756 |                |                |                |
              |      15,893796 |       8,706692 |       7,525887 |       4,539428 |       2,153175 |       2,336504 |                |                |                |
              |      17,370066 |      10,622754 |       9,030594 |       6,481560 |       3,314039 |       3,949815 |                |                |                |
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
    Test128 6 |       8,862853 |       4,953373 |       7,221445 |       4,063538 |       6,588030 |       3,822474 |       4,181027 |       3,985687 |              - |              - 
              |       9,371115 |       5,913213 |       7,648396 |       5,055771 |       6,977727 |       4,727004 |                |                |                |
              |       8,925735 |       5,122470 |       7,315418 |       4,234970 |       6,612387 |       3,922024 |                |                |                |
              |       9,345278 |       6,154636 |       7,580831 |       5,312088 |       6,929218 |       4,950434 |                |                |                |
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
    Test128 7 |       3,886227 |       2,071753 |       2,276122 |       1,286343 |       1,671305 |       0,983787 |       1,214280 |       1,093103 |              - |              - 
              |       4,308330 |       2,640669 |       2,504311 |       1,818897 |       1,861156 |       1,487809 |                |                |                |
              |       3,897550 |       2,167384 |       2,285433 |       1,396126 |       1,678297 |       1,073904 |                |                |                |
              |       4,113681 |       2,768264 |       2,492403 |       1,970451 |       1,841311 |       1,647236 |                |                |                |
--------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------
Test32 0     > 123 @ 1`000`000`000
Test32 1     > 123456 @ 1`000`000`000
Test32 2     > [0xFFFF`FFFF`FFFF`FFFF`FFFF`FFFF`FA0A`1F00 .. 0xFFFF`FFFF`FFFF`FFFF`FFFF`FFFF`FFFF`FFFF]
Test64 3     > [0xFFFF`FFFF`FA0A`1F00 .. 0xFFFF`FFFF`FFFF`FFFF]
Test64 4     > [0 .. 999`999`999]
Test64 5     > 9`876`543`210 @ 100`000`000
Test128 6    > 0x7FFF`FFFF`FFFF`FFFF`FFFF`FFFF`FFFF`FFFF @ 10`000`000
Test128 7    > 0x05F5`E100`0000`0000`0000 .. 0x0000`0001`0000`0000`0000 / 0x0001`0000`0000`0000    


By the way, I didn't expect my old version of the working function to be better than the current one.


Description:
Download
Filename: IntToStr_code.zip
Filesize: 13.78 KB
Downloaded: 139 Time(s)

Post 11 Feb 2024, 16:22
View user's profile Send private message Reply with quote
SeproMan



Joined: 11 Oct 2009
Posts: 70
Location: Belgium
SeproMan 16 Feb 2024, 19:19
Quote:
Keep in mind folks that StrToInt is also a welcome solution.


Next codes assume that the unicode text is a valid representation of a signed 64-bit number. So there is at least one decimal digit, optionally prepended with a minus and always followed by a terminating zero.

A solution for Linux:

Code:
; IN (rdi) OUT (rax) MOD (rdx)
StrToIntW:
  push  rdi                       ; (1) String address
  xor   rax, rax
  cmp   word [rdi], '-'
  jne   .more
  add   rdi, 2                    ; Skip minus

.more:
  movzx edx, word [rdi]           ; RDX now holds a digit
  add   rdi, 2
  lea   rax, [rax + rax * 4]      ; RAX = RAX * 10 + NewDigit
  lea   rax, [rdx + rax * 2 - 48]
  cmp   word [rdi], 0
  jne   .more

  pop   rdi                       ; (1) Restore string address
  cmp   word [rdi], '-'
  jne   .done
  neg   rax
.done:
  ret
    


A solution for Windows:

Code:
; IN (rcx) OUT (rax) MOD (rdx)
StrToIntW:
  push  rcx                       ; (1) String address
  xor   rax, rax
  cmp   word [rcx], '-'
  jne   .more
  add   rcx, 2                    ; Skip minus

.more:
  movzx edx, word [rcx]           ; RDX now holds a digit
  add   rcx, 2
  lea   rax, [rax + rax * 4]      ; RAX = RAX * 10 + NewDigit
  lea   rax, [rdx + rax * 2 - 48]
  cmp   word [rcx], 0
  jne   .more

  pop   rcx                       ; (1) Restore string address
  cmp   word [rcx], '-'
  jne   .done
  neg   rax
.done:
  ret
    

_________________
Real Address Mode.
Post 16 Feb 2024, 19:19
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.