Floating point nuisance

Blitz3D Forums/Blitz3D Programming/Floating point nuisance

Neo Genesis10(Posted 2003) [#1]
Hiya guys. The feature editor I use saves information such as entity x, y and z etcetera. Recently though I found an anomaly while saving one of my objects. Using the debug information I recovered I found that an 'e' had crept into one of the floating point (namely the X coordinate of a door).

Here is the debug information as it was saved and also as it was loaded. Notice the Y and Z coordinates match perfectly (so it is unlikely to be a load error)...

---------------------------------
Saved Data
---------------------------------
X: 1.56462e-006
Y: -1.9
Z: 8.34981
Pitch: 0.0
Yaw: 0.0
Roll: 0.0
---------------------------------
Horizontal door:
Left open X value: -1.9
Right open X value: 1.9
---------------------------------
---------------------------------
Loaded Data
---------------------------------
X: 4.0
Y: -1.9
Z: 8.34981
Pitch: 0.0
Yaw: 0.0
Roll: 0.0
---------------------------------

How can I resolve this guys?


Difference(Posted 2003) [#2]
Good news: You probably don't need to resolve anything. It's all as it should be.
Very large and very small floating point values are written like that.

Your read function, needs to take that into account. Do you store the values as text?


DJWoodgate(Posted 2003) [#3]
Despite the fact that Y and Z are ok, you are doing something pretty convoluted to turn 1.56462e-006 into 4.0. I can't imagine what though!


Floyd(Posted 2003) [#4]
Blitz can read these strings and convert them to numbers.
The e format is not a problem.
Data  "X: 1.56462e-006" ,   "Y: -1.9" ,   "Z: 8.34981 "

For n = 1 To 3
	Read t$
	x# = Mid( t, Instr( t, ":" ) + 1 )
	Print 1000 * x
Next

WaitKey



Neo Genesis10(Posted 2003) [#5]
Good news: You probably don't need to resolve anything. It's all as it should be.
Okay, first of all it ISNT good news. I save the values using WriteFloat and load them using ReadFloat. I use the loaded value to position the object - this of course means that it shifts to the right by roughly 2.4 units.

Clearly this is going to be a problem though if more values like this appear. I dont want to save the data as a string since it takes up more space and I'd like to minimise the file size.

Floyd: I have tried this and it doesn't give the results I expect. This demo below gives a return value of 189.979996

Function LimitFloat#( value#, decimal_places=5)
	
	decimal_point = Instr( value, "." )
	
	tmp$ = Left$(value, decimal_point ) + Mid$(value, decimal_point+1, decimal_places) + "0"
	value# = tmp
	Return value#

End Function

Print LimitFloat#(189.987654321, 2)

Unusual yes. Also damned annoying.


Floyd(Posted 2003) [#6]
If you are using WriteFloat and ReadFloat then numbers read back exactly as written.

The displayed value 1.56462e-006 means 1.56462 with the decimal point moved six places to the left. So .00000156462 is the actual value. This is essentially zero.

I have no idea how any of this relates to the supposed value X = 4.0.

The LimitFloat# problem is another matter. Try this simple program.
x# = 189.98
Print x

This happens because older versions of Blitz try to display too many digits.
Newer versions will display 189.98, as expected.

But in fact there is no such number in floating point.
Decimal numbers are approximated in base two using an integer divided by some power of two.

189.98 is approximated by 12450529 / 65536, which is actually 189.9799957275...

When rounded to six digits this displays as 189.98.
Older versions show six digits after the decimal point, which gives 189.979996.
And neither is the exact value being used internally.

It's a fact of life. Floating point is approximate.


Difference(Posted 2003) [#7]
Try this:

Graphics 640,480,0,2

fname$="temp.tmp"

x#=1.0/10000000
y#=2.0/2487478
z#=4.0

f=WriteFile(fname$)
	WriteFloat f, x
	WriteFloat f, y
	WriteFloat f, z
CloseFile f

f=ReadFile(fname$)
	xi#=ReadFloat(f)
	yi#=ReadFloat(f)
	zi#=ReadFloat(f)
CloseFile f

DeleteFile  fname$

Print "Wrote: " + x# + " , " + y# + " , " + z#
Print "Read : " + xi# + " , " + yi# + " , " + zi#

WaitKey
End