summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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/>. */
#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"