[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: eq? or equal?: a curiosity in 5.1
- From: Rici Lake <lua@...>
- Date: Fri, 20 Jan 2006 09:40:40 -0500
Minus zero is one of those arcane things which one tends to just write
off as an arcane corner of IEEE-754 arithmetic, but it is actually
sometimes useful. For example, it avoids a discontinuity in the
definition of atan2 if one of the arguments underflows.
Lua 5.1 actually allows you to enter -0 as a constant, which is handy:
Lua 5.1 Copyright (C) 1994-2006 Lua.org, PUC-Rio
> = -0
-0
> = 0
0
So we can show the behaviour of atan2:
> for _, x in ipairs{minus0, zero} do for _, y in ipairs{minus0, zero}
do
>> print("atan2("..x..","..y..")="..math.atan2(x, y))
>> end end
atan2(-0,-0)=-3.1415926535898
atan2(-0,0)=-0
atan2(0,-0)=3.1415926535898
atan2(0,0)=0
Now, how to explain this?
> = math.atan2(-0, -0)
-3.1415926535898
> = math.atan2(-0, 0)
-3.1415926535898
> = math.atan2(0, -0)
0
> = math.atan2(0, 0)
0
The answer is that when lua is compiling a chunk, it keeps a table of
constants (strings and numbers) used in the chunk. The table's key is
the constant; this allows the compiler to avoid storing the "same"
constant twice.
However, Lua tables carefully respect numerical equality (as opposed to
identity) with the result that NaN is not a valid key, and that -0 and
0 are considered the same key. So whichever of -0 and 0 is the first
"zero" encountered in the chunk is the one which goes into the table.
Consequently:
> print(0, -0)
0 0
> print(-0, 0)
-0 -0
Furthermore, the Lua 5.1 compiler precomputes constant numeric
expressions. Hence:
> -- This compiles into LOADK / RETURN
> = -4e-324/2
-0
And consequently:
> = 0, -4e-324/2
0 0
> = -4e-324/2, 0
-0 -0
All of this is part of a question I encountered while trying to
implement IEEE 754r decimal floating point arithmetic. 754r decimal
floating point numbers are not normalized, unlike binary floating point
numbers. Consequently 80 and 80.00 have different representations,
although they are numerical equal. This makes sense because the main
use of decimal floating point would be financial calculations, where
the quantities tend to have the same number of fractional digits;
keeping the numbers unnormalized is much faster in common cases (as
well as generally providing a natural display representation.) More
rationale can be found here:
http://www2.hursley.ibm.com/decimal/decifaq4.html#unnari
However, it appears that the semantics of Lua tables with respect to
numbers is that numeric keys are hashed by equality, not identity. So a
decimal floating point number would need to be normalized to insert it
into a table. On the other hand, this would create possibly surprising
results, similar to the above but magnified. In a hypothetical
implementation, one might observe:
-- stand-alone interpreter, each line is a separate chunk
> quantity = 2
> price = 2.00
> = quantity * price
4.00
-- All in one chunk
> do
>> quantity = 2
>> price = 2.00
>> return quantity * price
> end
4
> do
>> price = 2.00
>> quantity = 2
>> return quantity * price
> end
4.0000
I would think that both the latter results would be surprising.
Of course, Lua does not implement decimal arithmetic "out of the box",
so the question is at least partially hypothetical. Still, I'm curious
what people think would be the correct implementation approach.