FANDOM


Sometimes you want to encode a nonzero signed offset into an unsigned range, e.g. [-8..-1,+1..+8] into [0..7,8..15]. Normally this requires some conditional decoding to accommodate the gap in the middle where you didn't encode 0:

-- decode [0..7,8..15] -> -[8..-1,+1..+8]
if value>7 then
  offset = value-7   -- +1..+8
else
  offset = value-8   -- -8..-1
end

Or, more concisely:

-- decode [0..7,8..15] -> -[8..-1,+1..+8]
offset = value>7 and value-7 or value-8

The concise code above is 11 tokens in PICO-8. We can do better with some PICO-8 fixed-point math trickery:

-- decode [0..7,8..15] -> [-8..-1,+1..+8]
offset = flr(value*0x1.0001-0x7.0008)

What we're doing here is akin to walking down a sidewalk with a stride just a tiny bit longer than the distance between the lines on the sidewalk, and then adjusting our starting position so that when we get to the "middle" we step from just before one line to just after the next line, never actually touching the section between those lines, which is where our non-existent "0" value is.

This code is only 7 tokens. The only thing that needs to change for a different range is the constant that's subtracted. The integer bits should be the encoded value corresponding to -1 (7 in this case) and the fractional bits should be the encoded value corresponding to +1 (8 in this case).

Note that your range doesn't actually have to be balanced or a power-of-two in width. You could, for instance, encode [-20..-1,+1..+80] into [0..19,20..99] and then decode it like this:

-- decode [0..19,20..99] -> [-20..-1,+1..+80]
-- remember we're writing in hex here, 
-- so 19 becomes 0x13 and 20 becomes 0x14
offset = flr(value*0x1.0001-0x13.0014)


Bonus:

Just for fun, here's how you might do it in a C-style language:

// decode [0..19,20..99] -> [-20..-1,+1..+80]
offset = (value * 0x10001 - 0x130014) >> 16;

This is basically just doing inline fixed-point math, which is how PICO-8's numbers work under the hood.

Community content is available under CC-BY-SA unless otherwise noted.