I found a bug in Lua recently, involving the strange value −0. Floating point numbers can have this value, which is distinct from a positive 0. The two compare as equal, but are different when converted to strings.
The Lua compiler collects constant values for each function into a table, so that it doesn't have to store multiple identical constants more then once in the bytecode. Unfortunately, Lua tables can't have both 0 and −0 as keys in the same table, so if you have both constants in the same function you end up with both having the same value in the compiled code. It seems that the first one seen takes precedence:
lua -e 'print(0, -0)' # -> 0 0 lua -e 'print(-0, 0)' # -> -0 -0
This happens in at least Lua version 5.1.2 and 5.1.3.
You can work around this problem by forcing the negative 0 to be calculated at run time, like this:
local POS0 = 0 local NEG0 = -POS0 print(POS0, NEG0)
Or by putting the constants in separate functions, where they each have a constant table to themselves:
function pos0 () return 0 end function neg0 () return -0 end print(pos0(), neg0())
I think if I ever have to use this kind of thing, I'll use this trick to get the value:
local NEG0 = (function () return -0 end)()
While I'm talking about this, here's how you can distinguish the values in those rare situations when you need to:
-- 0 and -0 are the same compared numerically, but -- different when compared as strings. assert(0 == NEG0) assert(0 <= NEG0) assert(tostring(0) ~= tostring(NEG0)) -- Stringification can also be used to detect negative -- numbers of any value. The ‘not not’ is just to -- convert the return value to a true boolean. function is_negative (n) return not not tostring(n):find("^-") end assert(is_negative(0) == false) assert(is_negative(NEG0) == true) -- This even works for other weird values like -- negative infinity. assert(is_negative(tonumber("inf")) == false) assert(is_negative(tonumber("-inf")) == true)
There are a couple of ways to fix the bug, although I don't know the Lua source code well enough to do it myself. For one thing the constant table could store a special place-holder key instead of −0, and then just replace it when the bytecode is produced. Or, since negative numbers are parsed as an application of the unary minus operator on a positive number, the constant folding could be inhibited in this one case, so the negative 0 wouldn't exist until run time.
In one way Lua handles −0 better than other programming languages. Because it only uses floating point numbers, the negative 0 value is always available. Most languages have a separate integer type, which doesn't distinguish between 0 and −0. For example in Perl you get different results for integer and floating point values:
perl -le 'print 0, " ", -0' # -> 0 0 perl -le 'print 0.0, " ", -0.0' # -> 0 -0