Handmade Hero»Forums»Code
Christian
10 posts
Floating point rounding error
So I am making a 2d platformer, heavily influenced by HH. I use more or less the same collision detection and simulation system as HH (I'm on episode 130). It works fine except that the character gets stuck on the geometry sometimes because of rounding errors.

[attachment=54]float-error.png[/attachment]

The green man should move smoothly up the ramp and onto the platform. It works most of the time, but sometimes the square's corner (in the red circle) gets a rounding error moving it up (as shown on drawing 2). This makes the man hit the corner and stop. He is the center of the sim region, so the next frame when the sim region has moved, there is no rounding error and he can move again. But by this time he has lost his velocity. Hope this makes sense.

How do I avoid this problem? The corner's coordinate are something like (10.8217773, 10.8217926). It is the 0.0000153 difference that gives the problem.

Thanks
3 posts
Floating point rounding error
I'm still real new to this, but couldn't you use an epsilon to account for floating-point errors?
Christian
10 posts
Floating point rounding error
Yeah maybe. If the guy jumps and lands on the ramp the epsilon would keep him high enough for it to work, but if he hits the ramp from different angle (almost parallel with the ramp) I am afraid the epsilon would not move him far enough away.

Is it the only option?
Bryan Taylor
55 posts
Floating point rounding error
Use fixed point to store positions. This gives you an even amount of precision over your entire world. Only use floats for *deltas* between positions. Then, if needed, you can tune a single epsilon value for your calculation that works everywhere (rather than special-casing "am I far from the origin.")

All you ever really do with positions is subtraction (to find delta vectors), so it doesn't incur too much extra code. (Fixed point mul/div is a pain in the ass, avoid it if you can.)
Christian
10 posts
Floating point rounding error
I have never used fixed point position before. I guess that would fix some of the rounding errors.

I could also multiply every position with 10000 or something and just use plain ints or is that a bad idea?
Bryan Taylor
55 posts
Floating point rounding error
Edited by Jeroen van Rijn on Reason: quoted member's account renamed
chr_stoev
I have never used fixed point position before. I guess that would fix some of the rounding errors.

I could also multiply every position with 10000 or something and just use plain ints or is that a bad idea?

That is, more or less, what fixed point is.

Decide on a level of precision you want. For example, a common format is 24.8 -- a 32 bit integer where we treat the lowest 8 bits as a fractional part. (You can choose whatever arbitrary split you want.) You multiply a float by 256 and then round to produce the correct fixed point value. Going the other way around, you can subtract two fixed point values, cast the result to float, and then divide by 256 to get your delta as a float value. (Make sure you cast *after* the subtraction, when you have a smaller number that can actually fit in a float's precision range.)

Conceptually, you can think of fixed point as being the top of a fraction, with the bottom being whatever your implied fractional size is. So, for 24.8:

fixed(n) = (n * 256) / 256

Now, this doesn't necessarily *fix* your issue. If your physics are getting hung up on tiny inconsistencies you probably need some kind of epsilon in there to smooth things over. (Assuming your math is correct otherwise.) But trying to find said epsilon without consistent precision is going to be incredibly frustrating.
Aidan
12 posts
Floating point rounding error
By adding epsilons, you're inherently adding some inaccuracy to your simulation. You really want to make sure it won't cause more problems then it solves, and that there aren't any simpler solutions. Switching to fixed point seems like a large and bulky change that would make it an eternal headache to interact with the collision system from places that don't also use fixed point. Also, fixed point is slower than just using floats.

I'd suggest looking into implementing rounded rectangles as a collision primitive you support. having them means you could set up you collision areas to look more like this

[attachment=55]roundedrectangle.png[/attachment]

Not having a hard corner on the collider means you don't get the stopping problem.