Page 1 of 1
How to output a Floating Point number ?
Posted: Tue Apr 08, 2008 10:51 am
by White-spirit
Hello ,
How to output a Floating Point number on the screen if the precision is unknown ?
I wrote a fasm code to do that but it displays for example 28.0710391998291015625 instead of 28.07104
Here's my code ( will be optimized after :
Code: Select all
format elf
public ftol
public print_float
extrn print
extrn putchar
extrn itoa
half dd 0.5
i dd ?
tmp dd ?
e dd ?
ftol:
fld [half]
fld dword [esp+4]
fsub st0, st1
fld dword [esp+4]
faddp st2, st0
fistp [i]
mov eax, [i]
fistp [i]
add eax, [i]
sar eax, 1
ret
print_float2:
push ebp
mov ebp, esp
mov ebx, dword [esp+8]
mov [tmp], ebx
push [tmp]
call ftol
add esp, 4
mov [e], eax
push 0
push 0
push 10
push [e]
call itoa
add esp, 16
push eax
call print
add esp, 4
push '.'
call putchar
add esp, 4
fld [tmp]
fisub [e]
fst [tmp]
.do:
push 10
fimul dword [esp]
fst [tmp]
push [tmp]
call ftol
add esp, 4
mov [e], eax
push 0
push 0
push 10
push [e]
call itoa
add esp, 16
push eax
call print
add esp, 4
fisub [e]
fst [tmp]
ftst
fstsw ax
fwait
sahf
jnz .do
leave
ret
Where's the problem please ?
PS : itoa, print, and putchar are my own written functions, so they aren't standard .
Thanks
Thanks .
Posted: Tue Apr 08, 2008 11:07 am
by JamesM
Hi,
Floating point errors are extremely common, you'll have to get used to them. Remember that in pure mathematical theory one cannot ever test for equality of two items of a continuous set. Some delta, or leeway value must be applied.
i.e. x == y iff x-delta < y < x+delta.
PS: Code comments are nice things.
Cheers,
James
Posted: Tue Apr 08, 2008 11:15 am
by White-spirit
Okay thanks, so there are no errors on the code instead of the floating point comparison ?
PS : it's hard for me to put comments on the code ( non-native English speaker ), but i'ill try
Posted: Tue Apr 08, 2008 2:13 pm
by arkady
JamesM is right about floating-point numbers. My tip for you, White-spirit is to change precision to 64 bits (long real?). "32-bits real numbers" (dd) have only 23 bits for mantissa so your 28.07104 is actually presented as:
(1+6328701/2^23)*2^4
which equals exactly 28,0710391998291015625. Precision.... And maybe try to avoid showing too many digits. 10 should be good for most purposes-with "long real FP numbers" it should be precise enough.
Posted: Tue Apr 08, 2008 4:28 pm
by Combuster
the amount of digits is limited to the actual precision - i.e. the maximum amount of digits you need to print to identify one specific float can be computed:
10log(2^(mantissa+1)) + 1
you can just count away the printed digits, and when you have enough digits, or you have a zero remainder, you can stop.
Posted: Tue Apr 08, 2008 5:45 pm
by bewing
Most hardware and software floating point methods only guarantee a specific number of digits of accuracy. Traditionally (since the '60s) a 4 byte floating point calculation is only guaranteed to be accurate to 7 digits -- that is, the sin() function's output will be wrong past the 7th digit, for example. An 8 byte float is guaranteed to 15 digits. You might want to consider these values to be your output maximums, on top of Combuster's method for stopping when the remainder goes to zero (or gets "close enough" to zero).
Posted: Wed Apr 09, 2008 5:20 am
by White-spirit
So it's not possible to print a floating point number without giving a specific precision ?
Posted: Wed Apr 09, 2008 8:04 am
by Solar
Remember (or check out) how floating points are actually represented by the CPU. Even something as simple as "0.1"
cannot be represented exactly. There is no way to get the "original" values back once they have been through a CPU's registers, except by rounding, and to round you have to state a precision...
Check out DBL_DIG and FLT_DIG in <float.h>.
Also remember that a float can be NaN (not a number), or Infinity, both of which are special bit patterns of a float your output code should be able to detect.
There is a reason why I haven't implemented floats in PDCLib yet.
Posted: Wed Apr 09, 2008 3:30 pm
by White-spirit
Okay thanks, actually I'ill print the floating point number in 10 digits ( it still doesn't look good because it can contain many digits :s ) , but I'ill not give up on searching a way to display a floating point number without specifying a precision
Posted: Fri Apr 11, 2008 2:29 am
by Solar
Still tackling the problem from the wrong end. The output of "28.0710391998291015625" is absolutely correct. Your initial value of "28.07104" was lost the moment you squeezed it into a FPU register.
If you want precise handling of such numbers, you have to implement a library that represents those numbers without using the FPU. More precision, less performance.
Posted: Fri Apr 11, 2008 6:00 am
by White-spirit
Okay thanks, I added a ".Xf" support to my printf function so I don't have to worry about that
.