lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great Egor Skriptunoff once stated:
> On Thu, May 9, 2019 at 11:49 PM Sean Conner wrote:
> 
> > It was thus said that the Great Egor Skriptunoff once stated:
> > >
> > > BTW, math.abs(1<<63) in both Lua 5.3 and 5.4 returns negative value.
> > > That's a bug.
> >
> >   That's also a bug in most CPUs (those that are 2's complement), although
> > a
> > number will set the overflow flag [1] to signal the condision [2].
> >
> >
> CPUs are making all arithmetic modulo their word (2^32), this is how the
> CPU operations are declared in CPU architecture manual.
> So, it's not a bug in CPU.
> 
> Integer operators in Lua are explicitly declared modulo 2^64 (Lua manual
> section 3.4.1 - Arithmetic operators), so the following is OK:
> assert(-INT_MIN==INT_MIN)

  Actually, GCC disagrees:

	#include <limits.h>
	#include <assert.h>
	
	int main(void)
	{
	  assert(-INT_MIN == INT_MIN);
	  return 0;
	}

	[spc]lucy:/tmp>gcc x.c
	x.c: In function `Main':
	x.c:7: warning: integer overflow in expression
	[spc]lucy:/tmp>

  Which is fine, because that's undefined behavior in C.  From the C99
standard, 7.20.6.1.2:

	The abs, labs, and llabs functions compute the absolute value of an
	integer j.  If the result cannot be represented, the behavior is
	undefined.[265]

	[265] The absolute value of the most negative number cannot be
	represented in two's complement.

(Okay, so the code actually compiles, and the programs run without aborting,
but technically speaking, the program above is invoking undefined behavior.)

  Now, quoting section 3.4.1 of the Lua manual:

	With the exception of exponentiation and float division, the
	arithmetic operators work as follows: If both operands are integers,
	the operation is performed over integers and the result is an
	integer. ...

	In case of overflows in integer arithmetic, all operations wrap
	around, according to the usual rules of two-complement arithmetic.
	(In other words, they return the unique representable integer that
	is equal modulo 264 to the mathematical result.)

And indeed:

	Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio
	> assert(-math.mininteger == math.mininteger)
	true

> But Lua *math* library is supposed to give mathematically correct results.
> math.abs(INT_MIN) should return correct (float) value.
> The similar issue has already been successfully solved in Lua: function
> *tonumber* returns result having most suitable numeric subtype.

  Finally, quoting section 6.7 of the Lua manual:

	This library provides basic mathematical functions. It provides all
	its functions and constants inside the table math. Functions with
	the annotation "integer/float" give integer results for integer
	arguments and float results for float (or mixed) arguments. Rounding
	functions (math.ceil, math.floor, and math.modf) return an integer
	when the result fits in the range of an integer, or a float
	otherwise.

	math.abs(x)
		Returns the absolute valud of x. (integer/float)

  Nowhere does it state that the Lua *math* library is supposed to give
mathematically correct results, unless there's some part of the manual I'm
missing (the only type the term "correct" is applied to a function in the
math module is for math.atan()).

  So Lua (5.3) is basically handling things as C would, only it avoids the
whole "invoking undefined behavior" by calculating the absolute value of an
integer using unsigned arithmetic:

	static int math_abs (lua_State *L) {
	  if (lua_isinteger(L, 1)) {
	    lua_Integer n = lua_tointeger(L, 1);
	    if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n);
	    lua_pushinteger(L, n);
	  }
	  else
	    lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));
	  return 1;
	}

  So is the bug in the documentation, or the behavior?

  -spc