[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.
`