Log In  


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:

https://www.lexaloffle.com/bbs/?pid=101378


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)


1

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.


1

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]