Revert to wraparound integer arithmetic, instead of going to float.

This commit is contained in:
Paul Eggert 2011-05-04 23:31:14 -07:00
parent 852a74a59b
commit c717b32678
9 changed files with 79 additions and 150 deletions

View file

@ -1,9 +1,6 @@
2011-05-03 Paul Eggert <eggert@cs.ucla.edu>
* numbers.texi (Integer Basics): Large integers are treated as floats.
(Arithmetic Operations, Math Functions): Large integers go to
floats instead of wrapping around.
* objects.texi (Integer Type): Likewise. (Bug#8611)
2011-04-30 Lars Magne Ingebrigtsen <larsi@gnus.org>

View file

@ -507,9 +507,9 @@ commonly used.
All of these functions except @code{%} return a floating point value
if any argument is floating.
If integer arithmetic overflows, the resulting value is converted
to floating point. Thus @code{(1+ 536870911)} may evaluate to
536870912.0, depending on your hardware.
It is important to note that in Emacs Lisp, arithmetic functions
do not check for overflow. Thus @code{(1+ 268435455)} may evaluate to
@minus{}268435456, depending on your hardware.
@defun 1+ number-or-marker
This function returns @var{number-or-marker} plus 1.
@ -826,7 +826,7 @@ On the other hand, shifting one place to the right looks like this:
As the example illustrates, shifting one place to the right divides the
value of a positive integer by two, rounding downward.
The function @code{lsh} does
The function @code{lsh}, like all Emacs Lisp arithmetic functions, does
not check for overflow, so shifting left can discard significant bits
and change the sign of the number. For example, left shifting
536,870,911 produces @minus{}2 on a 30-bit machine:
@ -1169,8 +1169,8 @@ approximately.
@defun expt x y
This function returns @var{x} raised to power @var{y}. If both
arguments are integers and @var{y} is nonnegative, the result is an
integer if it is in Emacs integer range.
arguments are integers and @var{y} is positive, the result is an
integer; in this case, overflow causes truncation, so watch out.
@end defun
@defun sqrt arg

View file

@ -179,10 +179,10 @@ to
@tex
@math{2^{29}-1})
@end tex
on most machines. (Some machines may provide a wider range.)
If integer arithmetic overflows, the resulting value is converted
+to floating point. Thus @code{(1+ 536870911)} may evaluate to
+536870912.0, depending on your hardware.
on most machines. (Some machines may provide a wider range.) It is
important to note that the Emacs Lisp arithmetic functions do not check
for overflow. Thus @code{(1+ 536870911)} is @minus{}536870912 on most
machines.
The read syntax for integers is a sequence of (base ten) digits with an
optional sign at the beginning and an optional period at the end. The
@ -195,8 +195,7 @@ leading @samp{+} or a final @samp{.}.
1 ; @r{The integer 1.}
1. ; @r{Also the integer 1.}
+1 ; @r{Also the integer 1.}
1073741825 ; @r{The floating point number 1073741825.0,}
; @r{on a 30-bit implementation.}
1073741825 ; @r{Also the integer 1 on a 30-bit implementation.}
@end group
@end example

View file

@ -1,8 +1,3 @@
2011-05-03 Paul Eggert <eggert@cs.ucla.edu>
* NEWS: Integer overflow now yields floating-point instead of
wrapping around. (Bug#8611)
2011-05-03 Leo Liu <sdl.web@gmail.com>
* NEWS: Mention the new command isearch-yank-pop.

View file

@ -728,12 +728,6 @@ soap-inspect.el is an interactive inspector for SOAP WSDL structures.
* Incompatible Lisp Changes in Emacs 24.1
+++
** Integer arithmetic overflow now yields the nearest floating-piont
value rather than wrapping around. For example, on a 32-bit machine,
(1+ 536870911) yields 536870912.0, instead of the -536870912 it
yielded in Emacs 23.3, or the 0 it yielded in Emacs 23.1.
---
** `char-direction-table' and the associated function `char-direction'
were deleted. They were buggy and inferior to the new support of

View file

@ -11,16 +11,6 @@
* term.c: Don't include <stdarg.h>, as <lisp.h> does that.
Arithmetic overflows now return float rather than wrapping around.
(Bug#8611).
* data.c: Include <intprops.h>.
(arith_driver): Use floating point if the accumulator would otherwise
go out of EMACS_INT range.
(arith_driver, Fadd1, Fsub1): Use floating point if the result is
out of Emacs fixnum range.
* bytecode.c (exec_byte_code): Likewise, for Bsub1, Badd1, Bnegate.
* floatfns.c (Fexpt): Likewise.
* callproc.c (Fcall_process): Use 'volatile' to avoid vfork clobbering.
* process.c (Fformat_network_address): Fix typo: args2 -> *args2.

View file

@ -1186,7 +1186,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
{
Lisp_Object v1;
v1 = TOP;
if (INTEGERP (v1) && MOST_NEGATIVE_FIXNUM < XINT (v1))
if (INTEGERP (v1))
{
XSETINT (v1, XINT (v1) - 1);
TOP = v1;
@ -1204,7 +1204,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
{
Lisp_Object v1;
v1 = TOP;
if (INTEGERP (v1) && XINT (v1) < MOST_POSITIVE_FIXNUM)
if (INTEGERP (v1))
{
XSETINT (v1, XINT (v1) + 1);
TOP = v1;
@ -1290,7 +1290,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
{
Lisp_Object v1;
v1 = TOP;
if (INTEGERP (v1) && - MOST_POSITIVE_FIXNUM <= XINT (v1))
if (INTEGERP (v1))
{
XSETINT (v1, - XINT (v1));
TOP = v1;

View file

@ -22,9 +22,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
#include <intprops.h>
#include "lisp.h"
#include "puresize.h"
#include "character.h"
@ -2429,8 +2426,10 @@ static Lisp_Object float_arith_driver (double, size_t, enum arithop,
static Lisp_Object
arith_driver (enum arithop code, size_t nargs, register Lisp_Object *args)
{
register Lisp_Object val;
register size_t argnum;
register EMACS_INT accum = 0;
register EMACS_INT next;
switch (SWITCH_ENUM_CAST (code))
{
@ -2452,89 +2451,58 @@ arith_driver (enum arithop code, size_t nargs, register Lisp_Object *args)
for (argnum = 0; argnum < nargs; argnum++)
{
EMACS_INT a = accum;
int use_float = 0;
/* Using args[argnum] as argument to CHECK_NUMBER_... */
Lisp_Object val = args[argnum];
val = args[argnum];
CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (val);
args[argnum] = val;
if (FLOATP (val))
use_float = 1;
else
return float_arith_driver ((double) accum, argnum, code,
nargs, args);
args[argnum] = val;
next = XINT (args[argnum]);
switch (SWITCH_ENUM_CAST (code))
{
EMACS_INT next = XINT (val);
switch (SWITCH_ENUM_CAST (code))
case Aadd:
accum += next;
break;
case Asub:
accum = argnum ? accum - next : nargs == 1 ? - next : next;
break;
case Amult:
accum *= next;
break;
case Adiv:
if (!argnum)
accum = next;
else
{
case Aadd:
if (next < 0
? a < TYPE_MINIMUM (EMACS_INT) - next
: TYPE_MAXIMUM (EMACS_INT) - next < a)
use_float = 1;
else
a += next;
break;
case Asub:
if (argnum == 0 && nargs != 1)
a = next;
else if (next < 0
? TYPE_MAXIMUM (EMACS_INT) + next < a
: a < TYPE_MINIMUM (EMACS_INT) + next)
use_float = 1;
else
a -= next;
break;
case Amult:
if (next < 0
? (a < 0
? a < TYPE_MAXIMUM (EMACS_INT) / next
: next != -1 && TYPE_MINIMUM (EMACS_INT) / next < a)
: (next != 0
&& (a < 0
? a < TYPE_MINIMUM (EMACS_INT) / next
: TYPE_MAXIMUM (EMACS_INT) / next < a)))
use_float = 1;
else
a *= next;
break;
case Adiv:
if (!argnum)
a = next;
else
{
if (next == 0)
xsignal0 (Qarith_error);
a /= next;
}
break;
case Alogand:
a &= next;
break;
case Alogior:
a |= next;
break;
case Alogxor:
a ^= next;
break;
case Amax:
if (!argnum || a < next)
a = next;
break;
case Amin:
if (!argnum || next < a)
a = next;
break;
if (next == 0)
xsignal0 (Qarith_error);
accum /= next;
}
break;
case Alogand:
accum &= next;
break;
case Alogior:
accum |= next;
break;
case Alogxor:
accum ^= next;
break;
case Amax:
if (!argnum || next > accum)
accum = next;
break;
case Amin:
if (!argnum || next < accum)
accum = next;
break;
}
if (use_float)
return float_arith_driver (accum, argnum, code, nargs, args);
accum = a;
}
return make_fixnum_or_float (accum);
XSETINT (val, accum);
return val;
}
#undef isnan
@ -2809,8 +2777,7 @@ Markers are converted to integers. */)
if (FLOATP (number))
return (make_float (1.0 + XFLOAT_DATA (number)));
if (XINT (number) + 1 == MOST_POSITIVE_FIXNUM + 1)
return make_float (XINT (number) + 1);
XSETINT (number, XINT (number) + 1);
return number;
}
@ -2824,8 +2791,7 @@ Markers are converted to integers. */)
if (FLOATP (number))
return (make_float (-1.0 + XFLOAT_DATA (number)));
if (XINT (number) - 1 == MOST_NEGATIVE_FIXNUM - 1)
return make_float (XINT (number) - 1);
XSETINT (number, XINT (number) - 1);
return number;
}

View file

@ -491,39 +491,27 @@ DEFUN ("expt", Fexpt, Sexpt, 2, 2, 0,
y = XINT (arg2);
acc = 1;
if ((x == 0 && y != 0) || x == 1 || (x == -1 && (y & 1)))
return arg1;
if (x == -1)
y = 0;
while (1)
if (y < 0)
{
if (y & 1)
{
if (x < 0
? (acc < 0
? acc < MOST_POSITIVE_FIXNUM / x
: MOST_NEGATIVE_FIXNUM / x < acc)
: (acc < 0
? acc < MOST_NEGATIVE_FIXNUM / x
: MOST_POSITIVE_FIXNUM / x < acc))
break;
acc *= x;
}
y >>= 1;
if (y == 0)
{
XSETINT (val, acc);
return val;
}
if (x < 0
? x < MOST_POSITIVE_FIXNUM / x
: MOST_POSITIVE_FIXNUM / x < x)
break;
x *= x;
if (x == 1)
acc = 1;
else if (x == -1)
acc = (y & 1) ? -1 : 1;
else
acc = 0;
}
else
{
while (y > 0)
{
if (y & 1)
acc *= x;
x *= x;
y = (unsigned)y >> 1;
}
}
XSETINT (val, acc);
return val;
}
f1 = FLOATP (arg1) ? XFLOAT_DATA (arg1) : XINT (arg1);
f2 = FLOATP (arg2) ? XFLOAT_DATA (arg2) : XINT (arg2);