Building chars from floats

Blitz3D Forums/Blitz3D Programming/Building chars from floats

_33(Posted 2007) [#1]
I'm trying to nail down this function properly, but it seems Floor is not giving me the answer that I expect.

For i# = -125.0 To 125.0 Step 15.75
ln = term_write_FLOAT(i) : Print "     length of string :"+ln
Next
WaitKey()


Function term_write_FLOAT%(num_in#)
   Local num_out%
   Local ln% = 0
   Local num_send_subsequent% = False
   If num_in < 0 Then num_in = Abs(num_in) : term_write(45) : ln = ln + 1
   num_out% = Floor (num_in * 0.000000001) Mod 10 : If num_out > 0 Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 1000000000
   num_out% = Floor (num_in * 0.00000001 ) Mod 10 : If num_out > 0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 100000000
   num_out% = Floor (num_in * 0.0000001  ) Mod 10 : If num_out > 0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 10000000
   num_out% = Floor (num_in * 0.000001   ) Mod 10 : If num_out > 0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 1000000
   num_out% = Floor (num_in * 0.00001    ) Mod 10 : If num_out > 0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 100000
   num_out% = Floor (num_in * 0.0001     ) Mod 10 : If num_out > 0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 10000
   num_out% = Floor (num_in * 0.001      ) Mod 10 : If num_out > 0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 1000
   num_out% = Floor (num_in * 0.01       ) Mod 10 : If num_out > 0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 100
   num_out% = Floor (num_in * 0.1        ) Mod 10 : If num_out > 0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 10
   num_out% = Floor (num_in              ) Mod 10 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out
   term_write(46) : ln = ln + 1 ; insert "."
   num_out% = Floor (num_in * 10.0) Mod 10 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.1 : If num_in = 0 Then Return ln
   num_out% = Floor (num_in * 100.0) Mod 10 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.01 : If num_in = 0 Then Return ln
   num_out% = Floor (num_in * 1000.0) Mod 10 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.001 : If num_in = 0 Then Return ln
   num_out% = Floor (num_in * 10000.0) Mod 10 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.0001 : If num_in = 0 Then Return ln
   num_out% = Floor (num_in * 100000.0) Mod 10 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.00001 : If num_in = 0 Then Return ln
   num_out% = Floor (num_in * 1000000.0) Mod 10 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.000001 : If num_in = 0 Then Return ln
   num_out% = Floor (num_in * 10000000.0) Mod 10 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.0000001 : If num_in = 0 Then Return ln
   num_out% = Floor (num_in * 100000000.0) Mod 10 : term_write(num_out + 48) : ln = ln + 1 : Return ln
End Function


Function term_write(char%)
   ; this is just a place holder function, not the actual
   Write Chr$(char)
End Function


BTW, the title might be misleading, because I specifically am not working with string content, so avoid the usual "why don't you use Mid$ and Str$" and so forth.


_33(Posted 2007) [#2]
Another test using floats only reveals the same results:
For i# = -125.0 To 125.0 Step 15.75
ln = term_write_FLOAT(i) : Print "     length of string :"+ln
Next
WaitKey()


Function term_write_FLOAT%(num_in#)
   Local num_out#
   Local ln% = 0
   Local num_send_subsequent% = False
   If num_in < 0.0 Then num_in = Abs(num_in) : term_write(45) : ln = ln + 1
   num_out = Floor (num_in * 0.000000001) Mod 10.0 : If num_out > 0.0 Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 1000000000.0
   num_out = Floor (num_in * 0.00000001 ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 100000000.0
   num_out = Floor (num_in * 0.0000001  ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 10000000.0
   num_out = Floor (num_in * 0.000001   ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 1000000.0
   num_out = Floor (num_in * 0.00001    ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 100000.0
   num_out = Floor (num_in * 0.0001     ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 10000.0
   num_out = Floor (num_in * 0.001      ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 1000.0
   num_out = Floor (num_in * 0.01       ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 100.0
   num_out = Floor (num_in * 0.1        ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_in = num_in - num_out * 10.0
   num_out = Floor (num_in              ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out
   term_write(46) : ln = ln + 1 ; insert "."
   num_out = Floor (num_in * 10.0       ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.1 : If num_in = 0.0 Then Return ln
   num_out = Floor (num_in * 100.0      ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.01 : If num_in = 0.0 Then Return ln
   num_out = Floor (num_in * 1000.0     ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.001 : If num_in = 0.0 Then Return ln
   num_out = Floor (num_in * 10000.0    ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.0001 : If num_in = 0.0 Then Return ln
   num_out = Floor (num_in * 100000.0   ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.00001 : If num_in = 0.0 Then Return ln
   num_out = Floor (num_in * 1000000.0  ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.000001 : If num_in = 0.0 Then Return ln
   num_out = Floor (num_in * 10000000.0 ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_in = num_in - num_out * 0.0000001 : If num_in = 0.0 Then Return ln
   num_out = Floor (num_in * 100000000.0) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : Return ln
End Function


Function term_write(char%)
   ; this is just a place holder function, not the actual
   Write Chr$(char)
End Function



b32(Posted 2007) [#3]
The Floor function rounds numbers, instead use Trunc(), it will cut off the fractional part.


_33(Posted 2007) [#4]
Trunc! I didn't even think of this, thanks.

Wait... Trunc??? That exists?


b32(Posted 2007) [#5]
Whoops .. ermm .. that's Delphi .. ahem .. After testing it, I see that Floor doesn't round numbers.. :/
Sorry .. my bad


_33(Posted 2007) [#6]
Rounding the number is not the issue for me, it's more that it doesn't return the proper value as it leaves something like 0.000001 somewhere along the line in this routine and I can't nail it down. I just want to fix that up.

Floor just doesn't seem to do a perfect job. It might be a bug in Blitz3D's math library. Or it might be me using this wrongly.

I've just edited my second example code. But the result is just the same.


b32(Posted 2007) [#7]
Hmm .. I see, I've heard about this floating point inaccuracy before. I believe it is quite common. Maybe you could avoid using floats ? If you multiply everything by a hundred, the numbers you are using could be integers.


TomToad(Posted 2007) [#8]
couldn't you just do something like:
FloatString$ = i#

Blitz Basic will convert numbers to strings automatically for you when you assign them to strings.
If you need to access each character of the string, you can do something like this
i# = 125.25
FloatString$ = i#
For t = 1 to Len(FloatString)
  Print Mid(FloatString,t,1)
Next



_33(Posted 2007) [#9]
Mid$ is about 8 times slower than Floor, Mod is about 4 times faster than Floor. I do not want to convert back and forth between floats and strings as it will eat up my cpu time in my terminal emulator just to print god forbid float numbers on the page with simple PokeByte's. Please make sense out of this.

Why do you think I gave myself all this trouble, when I could just use Mid$ and Len and whatnot?... Handling strings is EXTREMELY SLOW compared to sticking with Floats, or simply playing with numbers.


Floyd(Posted 2007) [#10]
I think you will find this "float to characters" project is just about impossible. It's possible, of course, but very complicated.

The best solution is most likely a DLL in some language that already has a solution built in. For example, in C/C++ you could use sprintf. Yeah, that's a string function so you may say it is slow. But your code will be slow too once you have beefed it up to the point where it actually works.

The problem is that you can't use simple floating point arithmetic to pick out the digits. Such arithmetic is approximate and you need exactness.


_33(Posted 2007) [#11]
I think you will find this "float to characters" project is just about impossible.

It's not a project really, just a simple function to convert a float back into char byte values to a bank. When I get the answer, I'll post it here.

If you consider using MID$ on a per digit basis, for yourself acceptable, then be my guest and use that.


_33(Posted 2007) [#12]
For i# = -125.0 To 125.0 Step 15.75
ln = term_write_FLOAT(i) : Print "     length of string :"+ln
Next
WaitKey()


Function term_write_FLOAT%(num_in#)
   Local num_out%
   Local num_comp# = 0
   Local ln% = 0
   Local num_send_subsequent% = False
   If num_in < 0.0 Then num_in = Abs(num_in) : term_write(45) : ln = ln + 1
   num_out = Floor (num_in * 0.000000001) Mod 10.0 : If num_out > 0.0 Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_comp = num_comp + num_out * 1000000000.0
   num_out = Floor (num_in * 0.00000001 ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_comp = num_comp + num_out * 100000000.0
   num_out = Floor (num_in * 0.0000001  ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_comp = num_comp + num_out * 10000000.0
   num_out = Floor (num_in * 0.000001   ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_comp = num_comp + num_out * 1000000.0
   num_out = Floor (num_in * 0.00001    ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_comp = num_comp + num_out * 100000.0
   num_out = Floor (num_in * 0.0001     ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_comp = num_comp + num_out * 10000.0
   num_out = Floor (num_in * 0.001      ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_comp = num_comp + num_out * 1000.0
   num_out = Floor (num_in * 0.01       ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_comp = num_comp + num_out * 100.0
   num_out = Floor (num_in * 0.1        ) Mod 10.0 : If num_out > 0.0 Or num_send_subsequent = True Then term_write(num_out + 48) : num_send_subsequent% = True : ln = ln + 1 : num_comp = num_comp + num_out * 10.0
   num_out = Floor (num_in              ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_comp = num_comp + num_out
   term_write(46) : ln = ln + 1 ; insert "."
   num_out = Floor (num_in * 10.0       ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_comp = num_comp + num_out * 0.1 : If num_comp >= num_in Then Return ln
   num_out = Floor (num_in * 100.0      ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_comp = num_comp + num_out * 0.01 : If num_comp >= num_in Then Return ln
   num_out = Floor (num_in * 1000.0     ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_comp = num_comp + num_out * 0.001 : If num_comp >= num_in Then Return ln
   num_out = Floor (num_in * 10000.0    ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_comp = num_comp + num_out * 0.0001 : If num_comp >= num_in Then Return ln
   num_out = Floor (num_in * 100000.0   ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_comp = num_comp + num_out * 0.00001 : If num_comp >= num_in Then Return ln
   num_out = Floor (num_in * 1000000.0  ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_comp = num_comp + num_out * 0.000001 : If num_comp >= num_in Then Return ln
   num_out = Floor (num_in * 10000000.0 ) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : num_comp = num_comp + num_out * 0.0000001 : If num_comp >= num_in Then Return ln
   num_out = Floor (num_in * 100000000.0) Mod 10.0 : term_write(num_out + 48) : ln = ln + 1 : Return ln
End Function


Function term_write(char%)
   ; this is just a place holder function, not the actual
   Write Chr$(char)
End Function


NOTE: Still not perfect, but better none the less.