aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2017-03-03 09:17:51 -0800
committerPaul Eggert2017-03-03 09:19:08 -0800
commit74f87fd111904e5156727c72590d6fc4f67e8366 (patch)
treef6802878c5105def6d6889d5b8f71e4fe9285b79 /src
parentf1fe3fcfc568c1527714ff3a95e678816e2787d4 (diff)
downloademacs-74f87fd111904e5156727c72590d6fc4f67e8366.tar.gz
emacs-74f87fd111904e5156727c72590d6fc4f67e8366.zip
logb now works correctly on large integers
* admin/merge-gnulib (GNULIB_MODULES): Add count-leading-zeros. * etc/NEWS: Document the change. * lib/count-leading-zeros.c, lib/count-leading-zeros.h: * m4/count-leading-zeros.m4: New files, copied from Gnulib. * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. * src/floatfns.c: Include count-leading-zeros.h. (Flogb): Do not convert fixnum to float before taking the log, as the rounding error can cause the answer to be off by 1. * src/lisp.h (EMACS_UINT_WIDTH): New constant. * test/src/floatfns-tests.el (logb-extreme-fixnum): New test.
Diffstat (limited to 'src')
-rw-r--r--src/floatfns.c42
-rw-r--r--src/lisp.h6
2 files changed, 34 insertions, 14 deletions
diff --git a/src/floatfns.c b/src/floatfns.c
index dda03698093..94da22a3ba7 100644
--- a/src/floatfns.c
+++ b/src/floatfns.c
@@ -45,6 +45,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
45 45
46#include <math.h> 46#include <math.h>
47 47
48#include <count-leading-zeros.h>
49
48/* 'isfinite' and 'isnan' cause build failures on Solaris 10 with the 50/* 'isfinite' and 'isnan' cause build failures on Solaris 10 with the
49 bundled GCC in c99 mode. Work around the bugs with simple 51 bundled GCC in c99 mode. Work around the bugs with simple
50 implementations that are good enough. */ 52 implementations that are good enough. */
@@ -290,28 +292,46 @@ DEFUN ("float", Ffloat, Sfloat, 1, 1, 0,
290 return arg; 292 return arg;
291} 293}
292 294
295static int
296ecount_leading_zeros (EMACS_UINT x)
297{
298 return (EMACS_UINT_WIDTH == UINT_WIDTH ? count_leading_zeros (x)
299 : EMACS_UINT_WIDTH == ULONG_WIDTH ? count_leading_zeros_l (x)
300 : count_leading_zeros_ll (x));
301}
302
293DEFUN ("logb", Flogb, Slogb, 1, 1, 0, 303DEFUN ("logb", Flogb, Slogb, 1, 1, 0,
294 doc: /* Returns largest integer <= the base 2 log of the magnitude of ARG. 304 doc: /* Returns largest integer <= the base 2 log of the magnitude of ARG.
295This is the same as the exponent of a float. */) 305This is the same as the exponent of a float. */)
296 (Lisp_Object arg) 306 (Lisp_Object arg)
297{ 307{
298 Lisp_Object val;
299 EMACS_INT value; 308 EMACS_INT value;
300 double f = extract_float (arg); 309 CHECK_NUMBER_OR_FLOAT (arg);
301 310
302 if (f == 0.0) 311 if (FLOATP (arg))
303 value = MOST_NEGATIVE_FIXNUM;
304 else if (isfinite (f))
305 { 312 {
306 int ivalue; 313 double f = XFLOAT_DATA (arg);
307 frexp (f, &ivalue); 314
308 value = ivalue - 1; 315 if (f == 0)
316 value = MOST_NEGATIVE_FIXNUM;
317 else if (isfinite (f))
318 {
319 int ivalue;
320 frexp (f, &ivalue);
321 value = ivalue - 1;
322 }
323 else
324 value = MOST_POSITIVE_FIXNUM;
309 } 325 }
310 else 326 else
311 value = MOST_POSITIVE_FIXNUM; 327 {
328 EMACS_INT i = eabs (XINT (arg));
329 value = (i == 0
330 ? MOST_NEGATIVE_FIXNUM
331 : EMACS_UINT_WIDTH - 1 - ecount_leading_zeros (i));
332 }
312 333
313 XSETINT (val, value); 334 return make_number (value);
314 return val;
315} 335}
316 336
317 337
diff --git a/src/lisp.h b/src/lisp.h
index 220188cdb87..6d0b5283356 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -80,19 +80,19 @@ DEFINE_GDB_SYMBOL_END (GCTYPEBITS)
80# elif INTPTR_MAX <= INT_MAX && !defined WIDE_EMACS_INT 80# elif INTPTR_MAX <= INT_MAX && !defined WIDE_EMACS_INT
81typedef int EMACS_INT; 81typedef int EMACS_INT;
82typedef unsigned int EMACS_UINT; 82typedef unsigned int EMACS_UINT;
83enum { EMACS_INT_WIDTH = INT_WIDTH }; 83enum { EMACS_INT_WIDTH = INT_WIDTH, EMACS_UINT_WIDTH = UINT_WIDTH };
84# define EMACS_INT_MAX INT_MAX 84# define EMACS_INT_MAX INT_MAX
85# define pI "" 85# define pI ""
86# elif INTPTR_MAX <= LONG_MAX && !defined WIDE_EMACS_INT 86# elif INTPTR_MAX <= LONG_MAX && !defined WIDE_EMACS_INT
87typedef long int EMACS_INT; 87typedef long int EMACS_INT;
88typedef unsigned long EMACS_UINT; 88typedef unsigned long EMACS_UINT;
89enum { EMACS_INT_WIDTH = LONG_WIDTH }; 89enum { EMACS_INT_WIDTH = LONG_WIDTH, EMACS_UINT_WIDTH = ULONG_WIDTH };
90# define EMACS_INT_MAX LONG_MAX 90# define EMACS_INT_MAX LONG_MAX
91# define pI "l" 91# define pI "l"
92# elif INTPTR_MAX <= LLONG_MAX 92# elif INTPTR_MAX <= LLONG_MAX
93typedef long long int EMACS_INT; 93typedef long long int EMACS_INT;
94typedef unsigned long long int EMACS_UINT; 94typedef unsigned long long int EMACS_UINT;
95enum { EMACS_INT_WIDTH = LLONG_WIDTH }; 95enum { EMACS_INT_WIDTH = LLONG_WIDTH, EMACS_UINT_WIDTH = ULLONG_WIDTH };
96# define EMACS_INT_MAX LLONG_MAX 96# define EMACS_INT_MAX LLONG_MAX
97# ifdef __MINGW32__ 97# ifdef __MINGW32__
98# define pI "I64" 98# define pI "I64"