Log In  


Hi, I'm confused about the following. In my platformer game I apply a 0.85 factor to dx as friction. When I do this on a negative dx value (i.e. player moving to the left) dx never reaches zero and is represented as -0 (minus zero).

When I use that dx value by adding it to x, the x value keeps counting down a tiny fraction on every update.

I can work around it of course (e.g. setting it to 0 when abs(dx) is smaller than 0.0002), but I'd love to understand what's actually happening here. All pointers are appreciated :)

You can see it in action here:

Cart #yipobarode-0 | 2020-05-31 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA



I don’t have an answer, but start here: numbers are fixed-point values, not floating-point
https://pico-8.fandom.com/wiki/Lua#Values


Thanks, you’re right and that was a poorly chosen subject line. Fixed it now, although not 100% sure how to properly describe this behavior.


What may help you understand what is happening is looking at the hex value of your numbers, e.g. printing tostr(dx,true) instead of dx.


Thanks, didn't even know that tostr() accepts a second parameter!

So it gives me:

dx: 0xffff.fffa (non-zero).
x: 0x005b.7cde

I understand that Pico-8 rounds to 4 decimals, and that the smallest fraction below 0 is "-0".

However, why doesn't it then round to actual 0?


1

Your program is printing "-0" because Pico-8 only prints the first fractional digits, and doesn't print them at all if they are all zero. Your program is printing a negative number that is very close to zero: -0.00000000001 for example.

Eventually, after many iterations, dx will become zero because Pico-8 will run out of fractional binary digits and be unable to store such a tiny number.

In practice, programs do just clip velocity to zero when it falls below some threshold, to make game logic easier to write.


> Eventually, after many iterations, dx will become zero because Pico-8 will run out of fractional binary digits and be unable to store such a tiny number.

Got it, but why does this behave differently when dx is positive? If I apply the 0.85 factor multiple times to dx=1.5 I get to a zero value very quickly, yet when I do that on dx=-1.5 it shows this behavior.

I'm trying to understand what's the difference between the two cases (positive and negative).


Our expectation might be that numbers with (vanishingly) small absolute value are stored as 0x0000.0000, but actually that's only true for small positive numbers. Vanishingly small negative numbers are stored as 0xFFFF.FFFF. 0xFFFF.FFFF times a fraction equals 0xFFFF.FFFF, so taking fractions of tiny negative numbers leads towards 0xFFFF.FFFF (-0) and never 0x0000.0000 (0). And of course -0 != 0.

That's how I understand it, at least. Where we might expect one incorrect result (small non-zero number == 0), we instead find two distinct incorrect results (small non-zero negative number == -0) and (small non-zero positive number == 0). It's just a quirk of the way the fixed-precision arithmetic is implemented. dx==-0 isn't any more or less wrong than dx==0, just a bit more surprising.

As a practical solution, you could test abs(dx)<epsilon for some small epsilon.

Edit: Actually, I realised that abs(0xFFFF.FFFF)>0, so I suppose using 0xFFFF.FFFF (-0) to represent a vanishingly small negative number is actually a bit less correct/more incorrect than using 0x0000.0000 (0). -0 is weird.


Right, got it! Thanks for clarifying that for me, and indeed: I'm working around it be rounding down for a small enough value of abs(dx).



[Please log in to post a comment]