floats misbehaving?

Blitz3D Forums/Blitz3D Beginners Area/floats misbehaving?

Adam_128(Posted 2003) [#1]
hi, I am using some floating point variables in my game, but it seem that after a while, some very irregular (and crazy) numbers can come out of just simple float math. I created a small program to show off my problem. You can use the up/down arrow key's to increase/decrease the value.. if you hit up and down a few times, you will notice that instead of

27.05

you will get

27.8999 <-???

or

-40.04 <-???

why is this? The program is only adding .05, but somehow I get weird numbers. Its very frustrating


here's the code:



x#=1.05
SetBuffer(BackBuffer())
Graphics 640,480
Color 255,255,255

While Not KeyDown(1)
Cls

If KeyDown(200) Then x#=x#-.05
If KeyDown(208) Then x#=x#-.05

Text 150,150,Str$(x#)
Flip()

Wend

End


Ross C(Posted 2003) [#2]
I've alos noticed this. I did code once that was subtracting and adding 0.1 to a number, and it would sometimes give weird numbers like 0.29999999. And when the number was supposed to be 0, it was 4.97263e-07 or something.


jfk EO-11110(Posted 2003) [#3]
This is a rounding error due to the limited range of 32 Bit Floating Point. But you were wrong when you said 27.05 will be 27.8999. The rounding error is only 0.0001, so 27.05 might be 27.0499.

You can fix this using INT - which will round the number, so you would have to
x=int(x*1000)/1000

I agree, 32 Bit floating Point Numners are not the perfect choice for mathematically advanced stuff, but in the games and Multimedia Design it's ok.


Ice9(Posted 2003) [#4]
Never trust a floating point math for accuracy.
I think AMD processors are less accurate for floating point math than Intel but AMD is a little faster doing it.


x#=105.0
SetBuffer(BackBuffer())
Graphics 640,480
Color 255,255,255

While Not KeyDown(1)
Cls

If KeyDown(200) Then x#=x#-5.0
If KeyDown(208) Then x#=x#-5.0

Text 150,150,Str$(x#*0.01)
Flip()

Wend

End


_PJ_(Posted 2003) [#5]
so....

how would one perform mathematical operations reliably with fractions?


soja(Posted 2003) [#6]
Usually the difference is so insignificant, it doesn't matter. If you really wanted precision, you would have to use doubles (which aren't supported natively by Blitz, as I understand it).

When it does (generally) matter, it's because you want to compare a float to another number. If that were the case, you could convert it to an Int like jfk suggests above. You could also subtract the two numbers and verify that the difference is less than .0001 or something.


PowerPC603(Posted 2003) [#7]
You could try this instead:

If KeyHit(200) Then x#=x#+.05
If KeyHit(208) Then x#=x#-.05

If you used KeyDown, then every time the main loop executes,
0.05 if added or substracted from x#.
As long as you're holding the keys, the numbers will change.

Using KeyHit, it will only happen once for each keypress.


AbbaRue(Posted 2003) [#8]
I think the "Then x#=x#-5.0" being used in both lines was just a typo error.


Adam_128(Posted 2003) [#9]
yea sorry, I meant x#=x#-.05

The big issue here is that my number seem to be off for some darn reason..

In order to create a wrapping map, I use a grid of 4x4 320x200 tiles.. the tiles swap position based on where you are scrolling, so at anyone time, you are either on or between tiles 1-4.

each tile gets its on var (til1x#,til2x# etc..) and each one is incremented/decremented with the same value, however they seem to not want to move together properly.. when scrolling around the tiles will be out of sync with one another, and you can see gaps in between the four tiles. if you stop scrolling at the right place, the gaps dissapear. Also the objects on the screen do not move at the same rate it seems, and everything just jumps around... any ideas?? I can email code if anyone is intersted in looking :)


jfk EO-11110(Posted 2003) [#10]
You could increment only one tiles position and move the other tiles relative to that one tile. Something like:

t1#=t1#+.1

for i=0 to 20
drawblock tile(i),t1#+(tilewidth#*i),whatever#
next


soja(Posted 2003) [#11]
Could this be as simple as a rounding problem (since pixels are indexed by integers)?? i.e. are you sure you have Ints and Floats and % and # all in the right spot?


MadMax(Posted 2003) [#12]
It's a problem with Floats. If you use floats, you'll have to accept it. The 3d part of Blitz seems designed to use floats, and they usualy work very well.

There are ways to avoid using floats, but one has to be aware of certain rules.

The way I go about it is, use floats only if necessary. But then, this actitude for some strange reason that escapes me completely is not welcome. So if you want to avoid useless arguments stick with floats.


Adam_128(Posted 2003) [#13]
hmm, Wish I could use integers, but I am using floats for physics.. like speed up, slow down, and various speeds. I think that all the float manipulation is what is putting the sprites/ 4tiles in different locations.


Adam_128(Posted 2003) [#14]
I just thought of something...


int (3.9) = 4
int (3.4) = 3

Perhaps since the int function is rounding, a couple of the tiles get offset by an extra pixel..

Would using an int function that does not round work? also is there such a thing?


Floyd(Posted 2003) [#15]
A different Int function would not help. The 'off by one' problem would crop up somewhere else.

The real solution was suggested earlier.

Use your current system to find the location of *one* tile. Then draw the others based on that.

If this one tile is at location i,j and a tile has width 50 then
the tile immediately to the right would be at i+50,j.


Oldefoxx(Posted 2003) [#16]
A regular fraction is actually one integer divided by another. An irregular fraction cannot be reduced to this
form.

Thne answer in most cases is simple. If you had a grid of say 200x200 elements, than any X or Y position would be considered to be a fraction where 200 is the divisior. But if you do not divide by 200 until you need the fractional value, you can treat the value representing the X or Y as being an integer, and use INT() to get the nearest integer value. IN the final step of determining precisely where you are on the grid, you would divide both X and Y by 200 to get the proportional results.

The only problem could be in the manner in which the FPU resolves fractional values into integers. It does not exactly follow the rule that anything from .0 up to but less than .5 is equal to .0, and that anything from .5 up to but less than the next integer value is equal to the next integer value. Rather, it holds that any value that is .5x, is either truncated to the integer value our rounded up by 1 to the next integer value based on whether the x value is found to be either even or odd. It is a strange fule, apparently pressed by the financial community that wanted to ensure no one got cheated by financial transactions that involved fractional values, but it can play havoc with some mathematical computations.