]> git.eshelyaron.com Git - emacs.git/commitdiff
Revert to wraparound integer arithmetic, instead of going to float.
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 5 May 2011 06:31:14 +0000 (23:31 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 5 May 2011 06:31:14 +0000 (23:31 -0700)
doc/lispref/ChangeLog
doc/lispref/numbers.texi
doc/lispref/objects.texi
etc/ChangeLog
etc/NEWS
src/ChangeLog
src/bytecode.c
src/data.c
src/floatfns.c

index bca76b8a23cb5347c7e568de0b6bb0af4f033135..163de31f22098945759b3b15d8283b1919f37716 100644 (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>
 
index ebf5660febe25edf7993bdcb40db7ba61506ae0e..2c73a03a26c5f90c6d201ef88762bf369900fb0a 100644 (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
index 6dd7878e53ba7ba1d1a055e4ab75d24641a62683..c58d54f13fc8f74839dce7e4874de118a6bf9a37 100644 (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
 
index bba73855d6e1910ef3ff4c50f74629c111372669..0eb21406105ce099cb4355f269a90cfd8075f4d3 100644 (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.
index 669c143ba7f05114e44f44c475cd94d7b3892010..5094ecfc4fc365fce61510e50d92eb42f2e78919 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -728,12 +728,6 @@ soap-inspect.el is an interactive inspector for SOAP WSDL structures.
 \f
 * 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
index ee2db31056207a54bda53e05487292d16e17ba2b..2b4f498a0b943c2418802eb9fd3596b12557b3db 100644 (file)
 
        * 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.
index ce79b011bbbdd9b2566f469afa235198d9d4a16e..c3cd3d430720ead25156ada46795922ae1605b3d 100644 (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;
index beff570d5526dee913dcac4ef10083deca6908a2..577ae777d893f2c4ecd741b6b670f2cd58d5944d 100644 (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;
 }
index 5c28677286415dbab5f74d15d5ca704db8994b57..1232fc0afa1df4be7bb1e2efb294ee8b75bba492 100644 (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)
+         if (x == 1)
+           acc = 1;
+         else if (x == -1)
+           acc = (y & 1) ? -1 : 1;
+         else
+           acc = 0;
+       }
+      else
+       {
+         while (y > 0)
            {
-             XSETINT (val, acc);
-             return val;
+             if (y & 1)
+               acc *= x;
+             x *= x;
+             y = (unsigned)y >> 1;
            }
-
-         if (x < 0
-             ? x < MOST_POSITIVE_FIXNUM / x
-             : MOST_POSITIVE_FIXNUM / x < x)
-           break;
-         x *= x;
        }
+      XSETINT (val, acc);
+      return val;
     }
   f1 = FLOATP (arg1) ? XFLOAT_DATA (arg1) : XINT (arg1);
   f2 = FLOATP (arg2) ? XFLOAT_DATA (arg2) : XINT (arg2);