Lua bug with −0

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

< Using the GnomeDateEdit widget

Miniblog

(nuggets of inanity)

Tuesday Apr 24th 2007, 16:54 »
Just took the annual web design survey that AListApart do. I don't realy consider myself to be a web designer, but I have been doing a lot of HTML and CSS lately.
Monday Apr 23rd 2007, 18:23 »
Strange, there appears to be a bare-knuckle boxing match going on in the field outside my flat. Wish they wouldn't make so much noise about it.
Thursday Mar 1st 2007, 18:47 »
“In its written form, Hebrew has no vowels, making it the ideal language for texting.”
—Said in jest on some Radio 4 programme just now.

Archive: 2007 · 2006 · 2005 · 2004
Feed