Author Topic: How do you convert a binary number to ASCII decimal digits?  (Read 21296 times)

Offline JoeCoder

  • Jr. Member
  • *
  • Posts: 72
  • Country: by
Is there a standard way to do this or does everybody roll his own?
If you can't code it in assembly, it can't be coded!

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #1 on: June 15, 2011, 03:14:48 PM »
The x86 has minimal support for assisting this in the form of AAA and friends, but those are not available in long mode.

There are other ways to do this. One pure data way on the x86 would be to use a 256 byte lookup table and XLATB.

In general, it is a roll-your-own (or someone else's) situation... with emphasis on optimization (mostly eliminating inner loops) depending on how generic (e.g. printf) the conversion process needs to be.
« Last Edit: June 15, 2011, 03:16:50 PM by Keith Kanios »

Offline JoeCoder

  • Jr. Member
  • *
  • Posts: 72
  • Country: by
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #2 on: June 15, 2011, 05:43:45 PM »
Thanks Keith.
If you can't code it in assembly, it can't be coded!

Offline avcaballero

  • Full Member
  • **
  • Posts: 126
  • Country: es
    • Abre los Ojos al Ensamblador
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #3 on: June 27, 2011, 11:37:31 AM »
; avch
; A simple example. Surely it could be vastly enhanced
; FASM sintax
use16
org 100h
mov bx, 10
@MainLoop:
  mov si, CRLF
  mov ax, word [Number]
  @InnerLoop:
    dec si
    xor dx, dx
    div bx
    or dl, 30h
    mov byte [si], dl
    or ax, ax
  jnz @InnerLoop
  mov dx, si
  mov ah, 9
  int 21h
  dec word [Number]
jnz @MainLoop
ret
Number dw 0FFFFh
Text rb(7)
CRLF db 13, 10, "$"
; Execute with:
; w2ascii > Numbers.txt

Offline JoeCoder

  • Jr. Member
  • *
  • Posts: 72
  • Country: by
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #4 on: June 27, 2011, 06:08:30 PM »
thank you
If you can't code it in assembly, it can't be coded!

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2373
  • Country: us
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #5 on: June 28, 2011, 04:56:31 PM »
There are a lot of different ways to do this. This isn't particularly "good", but it's what I usually use.

Code: [Select]
;---------------------------------
; showeaxd - print a decimal representation of eax to stdout
; for "debug purposes only"... mostly
; expects: number in eax
; returns: nothing useful
;--------------------------------------
showeaxd:
    push eax
    push ebx
    push ecx
    push edx
    push esi
   
    sub esp, 10h ; an arbitrary "round number"
    lea ecx, [esp + 12]  ; another arbitrary number
    mov ebx, 10  ; we want to divide by 10
    xor esi, esi  ; counter
    mov byte [ecx], 0 ; why do I do this? I dunno.
.top:   
    dec ecx
    xor edx, edx
    div ebx
    add dl, '0'
    mov [ecx], dl
    inc esi
    or eax, eax
    jnz .top
   
    mov edx, esi
    mov ebx, 1
    mov eax, 4
    int 80h
   
    add esp, 10h

    pop esi
    pop edx
    pop ecx
    pop ebx
    pop eax

    ret
;---------------------------------

I'll be posting other methods, as the spirit moves me. I have on my drive a "fast" method written by Terje Mathison. Depends on multiplying by the reciprocal instead of the "div" (which is very slow). It is in the form of an "inline asm" C function. Needs a little "tweaking" before it's ready to post... and I really ought to figure out how it works! Not right now...

Best,
Frank


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2373
  • Country: us
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #6 on: June 28, 2011, 05:09:42 PM »
This is not strictly "on topic" for this thread, as it "goes the other way" - from ascii digits to a number. Happened to have it on hand...

Code: [Select]
;-------------------
; atoi - converts string to (unsigned!) integer
; expects: buffer in edx
; returns: number in eax - carry-flag set
; if a non-digit (except 0 and linefeed) was encountered
atoi:
    push ecx
    push edx
    xor eax, eax        ; clear "result"
.top:
    movzx ecx, byte [edx]
    inc edx

    cmp ecx, byte 0
    jz .done
    cmp ecx, byte 10
    jz .done
   
    cmp ecx, byte '0'
    jb .invalid
    cmp ecx, byte '9'
    ja .invalid
   
    ; we have a valid character - multiply
    ; result-so-far by 10, subtract '0'
    ; from the character to convert it to
    ; a number, and add it to result.
   
    lea eax, [eax + eax * 4]
    lea eax, [eax * 2 + ecx - '0']

    jmp short .top
.invalid:
    stc
.done:
    pop edx
    pop ecx
    ret
;--------------

This should be called "atou", not "atoi". Change it if you care.

Best,
Frank


Offline JoeCoder

  • Jr. Member
  • *
  • Posts: 72
  • Country: by
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #7 on: June 30, 2011, 08:52:44 AM »
Thanks Frank and everybody else. I'm in the middle of a bunch of stuff and haven't had time to get back to x86 for awhile. I hope I can soon. I was looking at AAA as I believe Keith suggested. I will look over your examples when I can. thanks to everybody for the help. Nice group of people!
If you can't code it in assembly, it can't be coded!

Offline ReturnInfinity

  • Jr. Member
  • *
  • Posts: 3
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #8 on: July 15, 2011, 04:58:43 PM »
I use the following in 64-bit mode:

; -----------------------------------------------------------------------------
; os_int_to_string -- Convert a binary interger into an string
;  IN:   RAX = binary integer
;   RDI = location to store string
; OUT:   RDI = points to end of string
;   All other registers preserved
; Min return value is 0 and max return value is 18446744073709551615 so your
; string needs to be able to store at least 21 characters (20 for the digits
; and 1 for the string terminator).
; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s
os_int_to_string:
   push rdx
   push rcx
   push rbx
   push rax

   mov rbx, 10               ; base of the decimal system
   xor ecx, ecx               ; number of digits generated
os_int_to_string_next_divide:
   xor edx, edx               ; RAX extended to (RDX,RAX)
   div rbx                  ; divide by the number-base
   push rdx               ; save remainder on the stack
   inc rcx                  ; and count this remainder
   cmp rax, 0               ; was the quotient zero?
   jne os_int_to_string_next_divide      ; no, do another division

os_int_to_string_next_digit:
   pop rax                  ; else pop recent remainder
   add al, '0'               ; and convert to a numeral
   stosb                  ; store to memory-buffer
   loop os_int_to_string_next_digit      ; again for other remainders
   xor al, al
   stosb                  ; Store the null terminator at the end of the string

   pop rax
   pop rbx
   pop rcx
   pop rdx
   ret
; -----------------------------------------------------------------------------


; -----------------------------------------------------------------------------
; os_string_to_int -- Convert a string into a binary interger
;  IN:   RSI = location of string
; OUT:   RAX = integer value
;   All other registers preserved
; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/uint2rax.s
os_string_to_int:
   push rsi
   push rdx
   push rcx
   push rbx

   xor eax, eax         ; initialize accumulator
   mov rbx, 10         ; decimal-system's radix
os_string_to_int_next_digit:
   mov cl, [rsi]         ; fetch next character
   cmp cl, '0'         ; char preceeds '0'?
   jb os_string_to_int_invalid   ; yes, not a numeral
   cmp cl, '9'         ; char follows '9'?
   ja os_string_to_int_invalid   ; yes, not a numeral
   mul rbx            ; ten times prior sum
   and rcx, 0x0F         ; convert char to int
   add rax, rcx         ; add to prior total
   inc rsi            ; advance source index
   jmp os_string_to_int_next_digit   ; and check another char
   
os_string_to_int_invalid:
   pop rbx
   pop rcx
   pop rdx
   pop rsi
   ret
; -----------------------------------------------------------------------------

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #9 on: July 15, 2011, 06:43:08 PM »
Yeesh... code blocks plz...

Offline brethren

  • Jr. Member
  • *
  • Posts: 28
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #10 on: July 16, 2011, 07:35:48 PM »
i posted a really fast signed dword to ascii routine
http://forum.nasm.us/index.php?topic=1042.0

challenge: just for kicks can anyone make a faster version ;)
« Last Edit: July 16, 2011, 07:40:15 PM by brethren »

Offline avcaballero

  • Full Member
  • **
  • Posts: 126
  • Country: es
    • Abre los Ojos al Ensamblador
Re: How do you convert a binary number to ASCII decimal digits?
« Reply #11 on: August 03, 2011, 06:39:04 AM »
A venerable mathematician said: "If I cannot draw it, it is that I do not understand it". Okay, life is too short to hook your routines in an example ;), although with no doubt that it is faster than mine. I let you an example in MS-DOS that prints 65535*2 signed numbers in 2.56 seconds inside DosBOX.

Greetings from Madrid