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

P#77461 2020-05-31 19:30 ( Edited 2020-06-01 06:06)

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

P#77463 2020-05-31 21:36 ( Edited 2020-05-31 21:36)

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.

P#77474 2020-06-01 06:00

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.

P#77481 2020-06-01 09:59

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?

P#77482 2020-06-01 10:16 ( Edited 2020-06-01 10:16)
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.

P#77486 2020-06-01 14:03

> 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).

P#77487 2020-06-01 14:05

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.

P#77488 2020-06-01 15:28 ( Edited 2020-06-01 16:39)

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).

P#77492 2020-06-01 15:30

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-04-16 13:24:41 | 0.015s | Q:23