Hi list,
a few hours ago I noticed for the first time that print(0*-2) prints
"-0" instead of "0" - because Lua supports
<https://en.wikipedia.org/wiki/Signed_zero> - and I tried to write a
function that would "fix" the "-0"s in the cases that I don't want
them... and well, it turns out that this doesn't work on Lua 5.1.5:
fix0 = function (x) if (x == -0) then return 0 else return x end end
Here's a test:
--snip--snip--
cd
cat > /tmp/testminus0.lua <<'%%%'
f = function (x) if (x == 0) then return 0 else return x end end
g = function (x) if (x == -0) then return 0 else return x end end --
buggy on Lua5.1
h = function (x) if (x == -0) then return 42 else return x end end
print(f(0), f(-0), f(99))
print(g(0), g(-0), g(99))
print(h(0), h(-0), h(99))
%%%
Here's a couple of disassemblies (main chunk removed to focus on the function):
$ luac5.1 -l -l -
function fix0(x) if (x == -0) then return 0 else return x end end
function <stdin:1,1> (7 instructions, 28 bytes at 0x55c0112fbba0)
1 param, 2 slots, 0 upvalues, 1 local, 1 constant, 0 functions
1 [1] EQ 0 0 -1 ; - -0
2 [1] JMP 3 ; to 6
3 [1] LOADK 1 -1 ; -0
4 [1] RETURN 1 2
5 [1] JMP 1 ; to 7
6 [1] RETURN 0 2
7 [1] RETURN 0 1
constants (1) for 0x55c0112fbba0:
1 -0
locals (1) for 0x55c0112fbba0:
0 x 1 7
upvalues (0) for 0x55c0112fbba0:
$ luac5.1 -l -l -
function fix42(x) if (x == -0) then return 42 else return x end end
function <stdin:1,1> (7 instructions, 28 bytes at 0x5584b577aba0)
1 param, 2 slots, 0 upvalues, 1 local, 2 constants, 0 functions
1 [1] EQ 0 0 -1 ; - -0
2 [1] JMP 3 ; to 6
3 [1] LOADK 1 -2 ; 42
4 [1] RETURN 1 2
5 [1] JMP 1 ; to 7
6 [1] RETURN 0 2
7 [1] RETURN 0 1
constants (2) for 0x5584b577aba0:
1 -0
2 42
locals (1) for 0x5584b577aba0:
0 x 1 7
upvalues (0) for 0x5584b577aba0:
This gives us a clue: there is no 0 (positive zero) constant compiled into the chunk at all. A bit of poking at the 5.1 source code reveals the addk() function [1], which is responsible for adding a constant. It ultimately performs the test for whether the constant already exists a few levels down using the luai_numeq() macro [2], which simply uses == to compare them... but 0 and -0 are defined by the IEEE standard to be equal, so whichever one (positive or negative zero) is compiled first in a chunk or function will be used for both throughout that chunk or function.