简体   繁体   中英

Assembly: convert number to 32-bit

I have a problem with one assembly task - I need to convert simple number (with comma- floating) input to 32-bit float representation and print it as the four-digit hex number.

Thanks.

Here's a quick example in NASM syntax.

  • It reads a number in from stdin
  • loops through the characters
  • builds the integer (characteristic) and fraction (mantissa) separately
    • Using the naive algorithm where you multiply by 10 or divide by the 10 power of the decimal place respectively
  • Then it converts the result to hex characters using a bit shift and a look up table

I used the SSE XMMx registers and functions because they are more clear and modern than the x87 FPU instructions. Also you mentioned the processor was 64bit so it should be compliant/compatible.

You can mess around with the program online at ideone.com

http://ideone.com/Q3naVN

Read the comments and try to learn something.

global _start

section .data
    ten     dq  10.0
    one     dq  1.0
    zero    dq  0.0
    negate  dq  8000000000000000h
    result  dd  0.0
    hex     db  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    length  dd  0
    buffer  db  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

section .text

_start:
    ;;
    ;; read the fp number from stdin
    ;;
    mov     ecx, buffer
    mov     edx, 32
    call    read
    mov     dword [length], eax
    movq    xmm0, qword [zero]
    movq    xmm1, qword [zero]
    movq    xmm2, qword [ten]
    movq    xmm4, qword [ten]
    ;;
    ;; loop through 1 character at a time
    ;;
    mov     ebx, dword [length]
    test    ebx, ebx
    jz      quit        ;; there's no input
    mov     ecx, 0      ;; offset counter
    mov     edx, 0      ;; 0 for before decimal, 1 for after decimal
    mov     edi, 0      ;; 0 for positive, 1 for negative
    mov     esi, buffer
    cmp     byte [esi], '-'
    jne     process
    mov     edi, 1      ;; the number is negative
    inc     ecx
process:
    movzx   eax, byte [esi + ecx]
    cmp     al, '.'     ;; does al contain a decimal point '.'
    jne     next_check
    test    edx, edx    ;; more than 1 decimal error
    jnz     quit
    mov     edx, 1
    jmp     continue_process
next_check:
    sub     eax, '0'    ;; ascii digit to binary
    js      end_process ;; not a digit since eax is negative
    cmp     eax, 10
    jge     end_process ;; not a digit since eax is >= 10
    test    edx, edx    ;; before or after decimal
    jnz     mantissa_process
    mulsd   xmm0, xmm2  ;; result characteristic * 10
   cvtsi2sd xmm3, eax
    addsd   xmm0, xmm3  ;; result characteristic + next digit
    jmp     continue_process
mantissa_process:
    cvtsi2sd    xmm3, eax
    divsd   xmm3, xmm2  ;; next digit / current mantissa power of 10
    addsd   xmm1, xmm3  ;; result mantissa + next fraction
    mulsd   xmm2, xmm4  ;; mantissa power * 10
continue_process:
    inc     ecx
    cmp     ecx, ebx
    jl      process
end_process:
    addsd   xmm0, xmm1  ;; characteristic + mantissa
    test    edi, edi    ;; is the number supposed to be negative ?
    jz      store_result
    movq    xmm3, qword [negate]
    por     xmm0, xmm3  ;; toggle the sign bit
 store_result:
   cvtsd2ss xmm0, xmm0  ;; double (64bit) to single (32) fp
    movd    eax, xmm0
    mov     dword[result], eax
    ;;
    ;; convert result to hex
    ;;
to_hex:
    mov edi, buffer
    mov esi, hex
    mov ebx, 0
    mov eax, dword [result]
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 7], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 6], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 5], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 4], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 3], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 2], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 1], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 0], bl
    ;;
    ;; print result
    ;;
print_dword:
    mov     ecx, buffer
    mov     edx, 8
    call    write
    ;;
    ;; quit
    ;;
quit:
    call    exit

exit:
    mov     eax, 01h    ; exit()
    xor     ebx, ebx    ; errno
    int     80h
read:
    mov     eax, 03h    ; read()
    mov     ebx, 00h    ; stdin
    int     80h
    ret
write:
    mov     eax, 04h    ; write()
    mov     ebx, 01h    ; stdout
    int     80h
    ret

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM