emacs-devel
[Top][All Lists]
Advanced

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

Re: Merging bignum to master


From: Andy Moreton
Subject: Re: Merging bignum to master
Date: Thu, 16 Aug 2018 00:41:32 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1.50 (windows-nt)

On Tue 14 Aug 2018, Andy Moreton wrote:

> On Sun 12 Aug 2018, Tom Tromey wrote:
>
>>>>>>> "Basil" == Basil L Contovounesios <address@hidden> writes:
>>
>> Basil> It'd be nice if expt could be updated to handle bignums:
>>
>> What do you think of this?

Tom and Basil, please try the following patch for expt.
I have given it some light sanity testing on Windows 64bit.

    AndyM


diff --git a/src/floatfns.c b/src/floatfns.c
index bbf7df4db3..0e7e3090e8 100644
--- a/src/floatfns.c
+++ b/src/floatfns.c
@@ -204,29 +204,38 @@ DEFUN ("expt", Fexpt, Sexpt, 2, 2, 0,
        doc: /* Return the exponential ARG1 ** ARG2.  */)
   (Lisp_Object arg1, Lisp_Object arg2)
 {
-  CHECK_FIXNUM_OR_FLOAT (arg1);
+  CHECK_NUMBER (arg1);
   CHECK_FIXNUM_OR_FLOAT (arg2);
-  if (FIXNUMP (arg1)     /* common lisp spec */
-      && FIXNUMP (arg2)   /* don't promote, if both are ints, and */
-      && XFIXNUM (arg2) >= 0) /* we are sure the result is not fractional */
-    {                          /* this can be improved by pre-calculating */
-      EMACS_INT y;             /* some binary powers of x then accumulating */
-      EMACS_UINT acc, x;  /* Unsigned so that overflow is well defined.  */
-      Lisp_Object val;
-
-      x = XFIXNUM (arg1);
-      y = XFIXNUM (arg2);
-      acc = (y & 1 ? x : 1);
-
-      while ((y >>= 1) != 0)
-       {
-         x *= x;
-         if (y & 1)
-           acc *= x;
-       }
-      XSETINT (val, acc);
-      return val;
+
+  if (INTEGERP (arg1)           /* common lisp spec */
+      && FIXNUMP (arg2)         /* don't promote, if both are ints, and */
+      && XFIXNUM (arg2) >= 0    /* we are sure the result is not fractional */
+      && (sizeof (EMACS_INT) <= sizeof (long)
+          || (long) XFIXNUM (arg2) == XFIXNUM (arg2)))
+    {
+      Lisp_Object res;
+      mpz_t val;
+
+      mpz_init (val);
+      if (BIGNUMP (arg1))
+        {
+          mpz_pow_ui (val, XBIGNUM (arg1)->value, XFIXNUM (arg2));
+        }
+      else if (XFIXNUM (arg1) >= 0)
+        {
+          mpz_ui_pow_ui (val, XFIXNUM (arg1), XFIXNUM (arg2));
+        }
+      else
+        {
+          mpz_ui_pow_ui (val, -XFIXNUM (arg1), XFIXNUM (arg2));
+          if (XFIXNUM (arg2) & 1)
+            mpz_neg (val, val);
+        }
+      res = make_number (val);
+      mpz_clear (val);
+      return res;
     }
+
   return make_float (pow (XFLOATINT (arg1), XFLOATINT (arg2)));
 }
 







reply via email to

[Prev in Thread] Current Thread [Next in Thread]