diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/floatfns.c | 42 | ||||
-rw-r--r-- | src/lisp.h | 6 |
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/>. */ #include <math.h> +#include <count-leading-zeros.h> + /* 'isfinite' and 'isnan' cause build failures on Solaris 10 with the bundled GCC in c99 mode. Work around the bugs with simple implementations that are good enough. */ @@ -290,28 +292,46 @@ DEFUN ("float", Ffloat, Sfloat, 1, 1, 0, return arg; } +static int +ecount_leading_zeros (EMACS_UINT x) +{ + return (EMACS_UINT_WIDTH == UINT_WIDTH ? count_leading_zeros (x) + : EMACS_UINT_WIDTH == ULONG_WIDTH ? count_leading_zeros_l (x) + : count_leading_zeros_ll (x)); +} + DEFUN ("logb", Flogb, Slogb, 1, 1, 0, doc: /* Returns largest integer <= the base 2 log of the magnitude of ARG. This is the same as the exponent of a float. */) (Lisp_Object arg) { - Lisp_Object val; EMACS_INT value; - double f = extract_float (arg); + CHECK_NUMBER_OR_FLOAT (arg); - if (f == 0.0) - value = MOST_NEGATIVE_FIXNUM; - else if (isfinite (f)) + if (FLOATP (arg)) { - int ivalue; - frexp (f, &ivalue); - value = ivalue - 1; + double f = XFLOAT_DATA (arg); + + if (f == 0) + value = MOST_NEGATIVE_FIXNUM; + else if (isfinite (f)) + { + int ivalue; + frexp (f, &ivalue); + value = ivalue - 1; + } + else + value = MOST_POSITIVE_FIXNUM; } else - value = MOST_POSITIVE_FIXNUM; + { + EMACS_INT i = eabs (XINT (arg)); + value = (i == 0 + ? MOST_NEGATIVE_FIXNUM + : EMACS_UINT_WIDTH - 1 - ecount_leading_zeros (i)); + } - XSETINT (val, value); - return val; + return make_number (value); } 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) # elif INTPTR_MAX <= INT_MAX && !defined WIDE_EMACS_INT typedef int EMACS_INT; typedef unsigned int EMACS_UINT; -enum { EMACS_INT_WIDTH = INT_WIDTH }; +enum { EMACS_INT_WIDTH = INT_WIDTH, EMACS_UINT_WIDTH = UINT_WIDTH }; # define EMACS_INT_MAX INT_MAX # define pI "" # elif INTPTR_MAX <= LONG_MAX && !defined WIDE_EMACS_INT typedef long int EMACS_INT; typedef unsigned long EMACS_UINT; -enum { EMACS_INT_WIDTH = LONG_WIDTH }; +enum { EMACS_INT_WIDTH = LONG_WIDTH, EMACS_UINT_WIDTH = ULONG_WIDTH }; # define EMACS_INT_MAX LONG_MAX # define pI "l" # elif INTPTR_MAX <= LLONG_MAX typedef long long int EMACS_INT; typedef unsigned long long int EMACS_UINT; -enum { EMACS_INT_WIDTH = LLONG_WIDTH }; +enum { EMACS_INT_WIDTH = LLONG_WIDTH, EMACS_UINT_WIDTH = ULLONG_WIDTH }; # define EMACS_INT_MAX LLONG_MAX # ifdef __MINGW32__ # define pI "I64" |