aboutsummaryrefslogtreecommitdiffstats
path: root/src/floatfns.c
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/floatfns.c
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/floatfns.c')
-rw-r--r--src/floatfns.c42
1 files changed, 31 insertions, 11 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