0

How to print floating point number in assembly without library function i have try this but it it did not work for large numbers and i don't know this is correct way or not.

code:

    global print_float64
section .text
    print_float64:

        mov             r9              ,        0
        mov             r8              ,        0

        pxor            xmm1            ,        xmm1
        ucomisd         xmm0            ,        xmm1
        jnbe            .positive
        mov             r9              ,        1
        lea             rsi             ,        [rsp-8]
        mov        qword[rsi]           ,        -1
        cvtsi2sd        xmm1            ,        [rsi]
        mulsd           xmm0            ,        xmm1
    .positive:

        xor             rax             ,       rax
        cvttsd2si       eax             ,       xmm0
        mov             rdi             ,       10
        mov             rsi             ,       rsp
        dec             rsi             
        mov         byte[rsi]           ,       '.'
    .while1:
        xor             rdx             ,       rdx
        div             rdi
        add             rdx             ,       48
        dec             rsi 
        mov             [rsi]           ,       dl
        cmp             rax             ,       0
        jnbe            .while1

        cmp             r9              ,       1
        jne             .print
        dec             rsi
        mov         byte[rsi]           ,      '-'
    .print:
        mov             rax             ,       1
        mov             rdi             ,       1
        mov             rdx             ,       rsp
        sub             rdx             ,       rsi
        syscall

        mov             rax             ,       rsp
        sub             rax             ,       rsi
        add             r8              ,       rax

;------------------------------------------------------------------------------------------

        xor             rax             ,       rax
        cvttsd2si       eax             ,       xmm0
        cvtsi2sd        xmm1            ,       eax
        subsd           xmm0            ,       xmm1

        mov             rax             ,       100000
        cvtsi2sd        xmm1            ,       eax
        mulsd           xmm0            ,       xmm1
        xor             rax             ,       rax
        cvtsd2si        eax             ,       xmm0

        mov             rdi             ,       10
        mov             rsi             ,       rsp
    .while2:
        xor             rdx             ,       rdx
        div             rdi
        add             rdx             ,       48
        dec             rsi 
        mov             [rsi]           ,       dl
        cmp             rax             ,       0
        jnbe            .while2

        mov             rax             ,       1
        mov             rdi             ,       1
        mov             rdx             ,       rsp
        sub             rdx             ,       rsi
        syscall

        mov             rax             ,       rsp
        sub             rax             ,       rsi
        add             rax             ,       r8

        ret

logic for this code is it first prints number before the precision point by integer conversion and it will print 5 digits after precision point by multiplying by 100000 and again convert into integer and print. it the may be works for larger number if i convert 64 bit float to 64 bit int(rax) but i did not find the instruction to do this

1)What is the best way to print floating point number in assembly without library function.

I am using nasm with ubuntu 64

Thanks.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
srilakshmikanthanp
  • 2,231
  • 1
  • 8
  • 25
  • 1
    Printing floating point numbers correctly is surprising complicated; entire research papers have been written on this subject. Is an approximate approach that may fail to capture some significant digits acceptable? – fuz Apr 22 '20 at 14:23
  • I can not understand what did you mean ? can you explain clearly ? – srilakshmikanthanp Apr 22 '20 at 14:27
  • To convert a double to a 64 bit integer, use `cvtsd2si`. – fuz Apr 22 '20 at 14:27
  • It is very difficult to convert a floating point number to decimal without losing any precision. If you do it in any of the obvious ways (e.g. repeated division by 10), the last few digits are going to be incorrect due to rounding error. If the number is very large, or very small, almost all digits can be wrong. Correct conversion requires a lot of careful number manipulation to ensure that no digit is lost on the way. – fuz Apr 22 '20 at 14:29
  • cvtsd2si is for 32 bit integer or 64 bit integer i read in a book it converts into double word(32). it is correct in the book? – srilakshmikanthanp Apr 22 '20 at 14:39
  • `cvtsd2si` can convert both to 32 bit integers (e.g. in `cvtsd2si eax, xmm0`) or to 64 bit integers (e.g. in `cvtsd2si rax, xmm0)`. Refer to the Intel manuals for details. – fuz Apr 22 '20 at 14:44
  • can you tell what is the right way(other than repeated division by 10) to print or any reference( it is for my understanding only)? – srilakshmikanthanp Apr 22 '20 at 14:45
  • Repeatedly dividing by 10 certainly works, but may yield imprecise results. For a precise method see e.g. [this article](https://www.zverovich.net/2019/02/11/formatting-floating-point-numbers.html) and the papers it links for details. It is not an easy task to do. – fuz Apr 22 '20 at 14:47
  • does input floating point is also difficult (sorry for silly question i need a clarification) ? – srilakshmikanthanp Apr 22 '20 at 14:54
  • I think it's slightly easier to get right. Have never looked into how to do it. – fuz Apr 22 '20 at 15:25
  • *1)What is the best way to print floating point number in assembly without library function.* - How do you define best? Do you mean something simple that works for a toy program? Or do you want something as accurate and at least as efficient as the dtoa implementation in glibc? Normal people just copy the Netlib or glibc dtoa into their code because it's *hard*. [How does printf extract digits from a floating point number?](https://stackoverflow.com/q/51052417) or [How do you print the EXACT value of a floating point number?](https://stackoverflow.com/q/3215235). – Peter Cordes Apr 22 '20 at 20:13
  • @fuz: Yes, `strtod` is hard to implement, and also interesting: http://www.exploringbinary.com/how-glibc-strtod-works/ (glibc) vs. https://www.exploringbinary.com/how-strtod-works-and-sometimes-doesnt/ (the other widely used implementation, by David Gay) articles explain *how* the algorithms work, in a nice readable way. – Peter Cordes Apr 22 '20 at 20:15
  • @Sri: If you don't need full precision, [Convert float to string without sprintf()](https://stackoverflow.com/q/23191203) shows some C implementations. Or [Turn float into string](https://stackoverflow.com/q/17632150) talks about simple/naive algorithms. – Peter Cordes Apr 22 '20 at 20:34
  • @Peter Cordes simple code is ok. It is for understanding only. – srilakshmikanthanp Apr 23 '20 at 02:11
  • But *what* exactly do you want to understand? If you want to understand how real dtoa or `sprintf` works, to produce a string that will convert back into the same floating-point bit-pattern, then you need to look at how real implementations work, and *why* they have to be so complicated to avoid rounding error for a round trip from float to string and back. – Peter Cordes Apr 23 '20 at 02:20
  • @ Can you see my code i don't know this is correct way or not ? – srilakshmikanthanp Apr 23 '20 at 02:21
  • If want to get an idea how you could write a toy implementation that *isn't* always accurate, have a look at some of those links in my 2nd comment. It can be useful to understand why those won't work for all cases, e.g. when the integer part of a `double` is outside the range of `int64_t`. – Peter Cordes Apr 23 '20 at 02:21
  • 1
    The algorithm you describe sounds reasonable for double values between -2^63 and +2^63-1. Getting 5 digits at a time as integer sounds like a good choice to balance FP work vs. integer work. I didn't look at the implementation details to check if you were implementing your algorithm correctly. If you wanted to handle magnitudes outside that range, you could maybe branch on that and divide by a power of 10 first. (doubles with magnitude larger than 2^53 have no fractional part; the nearest values are +1.0 apart from each other, so that branch only needs to do whole numbers) – Peter Cordes Apr 23 '20 at 02:27

0 Answers0