This quirk exists in Pico8 0.1.10C, and possibly other versions. Try this code out, and you'll see the results for i>=16 are the same:

for i=1,20 do print(i .. ' ' .. 1.11^i) end |

1.11 raised to the 20th power (equal to ~8.062) is still well within the overflow limits of pico8, but currently pico8 limits the possible exponent to 16 (resulting in ~5.309).

Here's a workaround for raising to higher power (if y is a positive power), that takes advantage of the property x^m * x^n = x^(m+n):

function pow(x,y) local r=1 while y>0 do r*=x^min(y,16) y-=16 end return r end |

Using this you can get the correct results. Just wondering, is this limitation intentional? It makes sense for integers, because 2^15-1 is the greatest positive integer you can express, and occasionally you might want to do 2^16 (if you're careful about the sign bit), but for fractions it seems a little strange. It's kind of uncommon to do this kind of math in pico8, so I could maybe live with it being a quirk of pico-8 though. If this behaviour isn't changed, could this limitation be documented in the manual?

Whoa, heh you're right, the right-hand side of the exponent gets truncated to an int and only works for non-negative values in the range 0..16. Must be using a repeated multiplication loop behind the scenes! You can still use sqrt(x) to do x^0.5 though, or do 1/x instead of x^-1, so not too bad.

It'd be to nice document though, saying it only handles ints between 0 and 16, and that you can use repeated multiplication, sqrt and 1/x to fill in some of the gaps.

In standard Lua 5.2, ^ is equivalent to math.pow and is defined in terms of C's pow function so any double value can be passed as an exponent.

You can do it a bit like multiplication, where you're keeping a running square you multiply through the result where the power value has 1 bits. You can do the same by sqrting and checking the fractional bits. The end result shouldn't really be more expensive than a naïve implementation using a multiply loop.

This is a lua implementation that handles all values, including fractional and negative numbers:

function pow(v,e) if(e<0) return 1/pow(v,-e) local ei=band(e,0xffff) local vi=v e-=ei local r=1 while ei!=0 do if(band(ei,1)!=0) r*=vi vi*=vi ei=band(ei/2,0xffff) end while e!=0 do v=sqrt(v) if(band(e,0x.8)!=0) r*=v e=band(e*2,0x.ffff) end return r end |

Not extensively tested, and not nearly as convenient as a caret operator, but it ought to work for anything that doesn't inherently overflow.

[Please log in to post a comment]