Hi everyone, I think this can't be a bug that only I just found out so I'm posting it here for some help instead of in the bugs forum.
I seem to be having the weirdest behaviour easing out a negative var towards 0: it never becomes zero again (either negative or positive), despite printing as such. Check the below reproducer code and gif, neither y==0 nor y==-0 conditions catch the zero, even though at first you can see true
.
Please help?
Thanks!

function _init() y=0 end function _update() y*=0.85 if btn(2) then y-=0.65 end end function _draw() cls() print("time: "..time()) print("y="..y) print("is y==0? "..(y==0 and 'true' or 'false')) print("is y==-0? "..(y==-0 and 'true' or 'false')) end |



Stuck in a line using tostr() to get the raw hexadecimal:
print("y="..tostr(y,1)) |
...and it looks like the way PICO-8's rounding works, 0.85 times 0xFFFF.FFFA (negative 0x0.0006) still equals 0xFFFF.FFFA, so it never gets any closer than that to 0.
I think it might be worth to stick in some close-enough check if you need the delta to reach zero.



Alternatively, if you want a very silly solution: it does converge from positive, so spending six tokens like:
y=0.85*abs(y)*sgn(y)--sgn(y) must be the last part! |
makes the math round towards 0 both ways and reach 0.



Weird rounding issues, got it - makes sense now. But that "silly" solution of yours is brilliant, I just can't wrap my head around how that works?! Shouldn't abs(y)*sgn(y)
be the same as y
? (more rounding voodoo happening I suppose?)



Also, after your kind explanation I went with the following close enough solution (I'm sure there's an obvious way to optimise what I have below, my pico-8 kung-fu is not good enough):
y*=0.85 if y>-0.1 and y<0.1 then y=0 end |



So, I think what happens is that PICO-8 rounds arithmetic down - i.e. towards negative infinity - which means for very small numbers, 0.85 times a positive y will round down and towards zero, but 0.85 times a negative y will round down and away from zero ... so by flipping the sign on negative numbers before doing arithmetic and again after, down will always be towards zero.
But I do think setting "this small number equals zero" is a better way to do it.



Ah got it, makes sense thanks!! Well I suppose your suggestion is the proper workaround when precision is required, whereas mine is just a shortcut for when rough is good enough. Thank you very much for everything!



Alternatively you could check against the hexidecimal value, rather than the decimal digit.
In your print statements, rather than check for y == -0
check instead for y == 0xffff.fffa
.
If you set a variable, say "z", to -0 then check its hex value, it will be 0x0000.0000 the same as setting to 0. Probably P8 is giving you a sane version of 0, even though you asked for otherwise.
But your countdown is dealing in the raw values, so you can check against the raw values via hexadecimal equivalence.



> Usually with decimal numbers like this, it can be difficult to determine the
> exact representation in binary, so what I usually do is implement a function
> to check if it is in a very small range:
Thanks @MrGoober, that's a slightly saner approach actually.
@ChristopherD in this case I really want the approximate check, i.e., catching a bunch of near enough values, not an exact one - and P8 was forcing me to deal with a precise value.



Hi @matamouros:
Don't forget that SGN(0)
= 1 in Pico-8 which is very non-standard with most BASIC programming languages as it is normally zero. That could also be giving you trouble.
You can fix it with a function:
function mysgn(a) if (a==0) return 0 return sgn(a) end |
[Please log in to post a comment]