floats misbehaving?
Blitz3D Forums/Blitz3D Beginners Area/floats misbehaving?
| ||
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 |
| ||
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. |
| ||
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. |
| ||
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 |
| ||
so.... how would one perform mathematical operations reliably with fractions? |
| ||
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. |
| ||
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. |
| ||
I think the "Then x#=x#-5.0" being used in both lines was just a typo error. |
| ||
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 :) |
| ||
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 |
| ||
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? |
| ||
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. |
| ||
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. |
| ||
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? |
| ||
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. |
| ||
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. |