How do you deal with range overflow? The numbers beyond 32767 warp to -32766 in pico8's 16 bit signed system when calculating. This is sometimes enough, but not always. For example,
function distance(x1,y1,x2,y2) return sqrt((x2-x1)^2+(y2-y1)^2) end |
will sometimes (very often actually) return 0 as a result of taking sqrt of the negative wrapped number. This is occasionally crutial. Is there a workaround to compute this as if this was an unsigned system?
I'm not sure if this gives you the results you want, @collinthenewmaker.
You use ,2
in tonum()
and tostr()
to swap between a large integer saved as a string and back again to a real number that limits to -32768.9999 and 32767.9999.
function distance(x1,y1,x2,y2) return tostr(sqrt(tonum(x2,2)-tonum(x1,2))^2+(tonum(y2,2)-tonum(y1,2)^2),2) end x1="0" y1="0" x2="100000" y2="50000" cls() ?distance(x1,y1,x2,y2) |
I make use of this HERE:
You can use an approximation formula to avoid squaring and rooting the values.
Previous PICO-8 discussion: https://www.lexaloffle.com/bbs/?tid=36059
P.S. The 32-bit encoding suggestion does not work as written because the squaring operation will take the exponent into account, then round. E.g. tonum("500",2)^2 == 0
The 32-bit encoding trick does work with an approximation formula, which merely scales by a positive constant then adds:
function approx_dist(dx,dy) local maskx,masky=dx>>31,dy>>31 local a0,b0=(dx+maskx)^^maskx,(dy+masky)^^masky if a0>b0 then return a0*0.9609+b0*0.3984 end return b0*0.9609+a0*0.3984 end ?tostr(approx_dist(tonum("100000",2),tonum("50000",2)),2) |
prints 116008. In a higher precision floating point environment, I get approximately 111803.
My naive idea is this: Do numbers immediately wrap after performing math at them (32767+1=-32766) or do they wrap after you assign them to variables or return them (a= 32768, a=-32766)? If the latter, can the system compare the big numbers? If yes, i think you can do the sqrt(pythagorean stuff here) - 32766 to get a number in the 16bit range with it's 0 shifted to -32766, somehow emulating the unsigned system. you can then add 32766 back for comparing (if dist+32766<2 then ...).
Edit: You could actually not add 32766 and just use (if dist < 2-32766)
Here's something I came up with that combats the overflow issue while still using the original sqrt function
function distance(x1,y1,x2,y2) return sqrt(((x2-x1)/256)^2+((y2-y1)/256)^2)*256 end |
@colinthenewmaker.
I'm afraid that numbers wrap in memory as soon as the calculation occurs.
There was this post a few weeks ago which gives a distance formula without needing to square or sqrt the numbers: https://www.lexaloffle.com/bbs/?tid=49827
Overflow will still happen for large enough numbers but it'll take a lot longer. It quite happily calculates the distance between (0, 0) and (16384, 16384) as 23170.5, for instance.
[Please log in to post a comment]