11
\$\begingroup\$

I have implemented an algorithm which converts a signed integer to its ASCII equivalent string with the corresponding sign as a first byte. I have tested it on several numbers and it worked correctly. But as a newbie I might have not noticed some logic mistakes or flaws.

I am asking for any ideas how to make this more efficient and elegant.

;;;;MACRO SECTION//////////////////////////////////////////////////////////////

%macro Int2ascii 2                  ;1 - number, 2 - string

    mov     r12, %2                 ;move ADDRESS of string

    mov     eax, dword[%1]
    cmp     eax, 0
    jge     %%placePlus             ;check either number is negative or positive

    %%placeMinus:
        mov     byte [r12], "-"     ;fill the first (0th) byte with the sign
        mov     rdi, -1             ;remember the sign
        ;neg     eax                ;negate number and forgot the sign (deprecated: see EDIT 1)
        jmp     %%skipPlacePlus 

    %%placePlus:
        mov     byte [r12], "+"
        mov     rdi, 1               ;remember the sign

    %%skipPlacePlus:

    xor     rcx, rcx                ;digit counter here (used implicitely in %%fillLoop)
    mov     ebx, 10 

    %%divideLoop:
        cdq                         ;eax -> edx:eax
        idiv    ebx                 ;signed division, reminder is also signed
        imul    rdx, rdi            ;"unsign" the current reminder
        ;div     ebx                ;(deprecated: see EDIT 1)
        push    rdx                 ;push the reminder to stack

        inc     rcx                 ;increment digit counter

        cmp     eax, 0
        jne     %%divideLoop

    mov     rdi, 1                  ;note that the first (0th) byte was number sign (+/-) 

    %%fillLoop:
        pop     rax                     ;pop back reminders

        add     al, "0"                 ;ascii code for digit
        mov     byte [r12 + rdi], al    ;fill string 
        inc     rdi 
        loop    %%fillLoop 

    mov     byte [r12 + rdi], 0x00      ;terminate string

%endmacro

Example of output

As @TobySpeight suggested I have tested the above algorithm on numbers: -1, 0, 1, 9, 10, 0x7fffffff, 0x80000000. Output is (gdb session):

(gdb) x/s &sNegOne
0x600377:   "-1"
(gdb) x/s &sZero
0x600368:   "+0"
(gdb) x/s &sPosOne
0x600386:   "+1"
(gdb) x/s &sNine
0x600395:   "+9"
(gdb) x/s &sTen
0x6003a4:   "+10"
(gdb) x/s &sNumber1
0x6003b3:   "+2147483647"
(gdb) x/s &sNumber2
0x6003c2:   "-2147483648"

I have realized that trying to consider only unsigned positive numbers leads to double-word overflow for initially valid double-word number 0x80000000 but invalid after taking absolute value 0x7fffffff + 1 which is no longer signed double-word number. I have overcome it by signed division. The problem here is for signed division reminders are also signed and no more applicable for storing as digits without additional processing which is just multiplying by -1 or 1 depending on sign.

\$\endgroup\$
  • \$\begingroup\$ Most newbies write less-readable assembly than you did. Nice job so far. \$\endgroup\$ – Mast Mar 15 '18 at 16:51
  • 2
    \$\begingroup\$ "I have tested it on several numbers" is a good start. Better would be "Here is a test suite that exercises all the boundary cases" - I recommend you demonstrate at least -1, 0, +1, 9, 10, 0x7fffffff, 0x80000000. \$\endgroup\$ – Toby Speight Mar 15 '18 at 17:32
  • \$\begingroup\$ @TobySpeight, on all suggested numbers it works fine except, of course, ... the last one: 0x80000000. This is because my negation line (when I'm "forgotting" the sign). Double-word overflows there. I will be thinking how to overcome this problem. Thank you. \$\endgroup\$ – LRDPRDX Mar 15 '18 at 18:36
  • \$\begingroup\$ You don't want to use cdq. That sign extends EAX into EDX, but since you're treating EAX as unsigned at that point you just want to zero out EDX. \$\endgroup\$ – 1201ProgramAlarm Mar 15 '18 at 19:05
  • \$\begingroup\$ @1201ProgramAlarm, you are absolutely right, thank you. But see the EDIT1 section (coming soon). \$\endgroup\$ – LRDPRDX Mar 15 '18 at 19:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.