diff options
| author | Paul Eggert | 2017-03-03 09:17:51 -0800 |
|---|---|---|
| committer | Paul Eggert | 2017-03-03 09:19:08 -0800 |
| commit | 74f87fd111904e5156727c72590d6fc4f67e8366 (patch) | |
| tree | f6802878c5105def6d6889d5b8f71e4fe9285b79 /lib | |
| parent | f1fe3fcfc568c1527714ff3a95e678816e2787d4 (diff) | |
| download | emacs-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 'lib')
| -rw-r--r-- | lib/count-leading-zeros.c | 3 | ||||
| -rw-r--r-- | lib/count-leading-zeros.h | 114 | ||||
| -rw-r--r-- | lib/gnulib.mk | 10 |
3 files changed, 126 insertions, 1 deletions
diff --git a/lib/count-leading-zeros.c b/lib/count-leading-zeros.c new file mode 100644 index 00000000000..d0c0704f582 --- /dev/null +++ b/lib/count-leading-zeros.c | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | #include <config.h> | ||
| 2 | #define COUNT_LEADING_ZEROS_INLINE _GL_EXTERN_INLINE | ||
| 3 | #include "count-leading-zeros.h" | ||
diff --git a/lib/count-leading-zeros.h b/lib/count-leading-zeros.h new file mode 100644 index 00000000000..e197137e66e --- /dev/null +++ b/lib/count-leading-zeros.h | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | /* count-leading-zeros.h -- counts the number of leading 0 bits in a word. | ||
| 2 | Copyright (C) 2012-2017 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 3 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 16 | |||
| 17 | /* Written by Eric Blake. */ | ||
| 18 | |||
| 19 | #ifndef COUNT_LEADING_ZEROS_H | ||
| 20 | #define COUNT_LEADING_ZEROS_H 1 | ||
| 21 | |||
| 22 | #include <limits.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | |||
| 25 | #ifndef _GL_INLINE_HEADER_BEGIN | ||
| 26 | #error "Please include config.h first." | ||
| 27 | #endif | ||
| 28 | _GL_INLINE_HEADER_BEGIN | ||
| 29 | #ifndef COUNT_LEADING_ZEROS_INLINE | ||
| 30 | # define COUNT_LEADING_ZEROS_INLINE _GL_INLINE | ||
| 31 | #endif | ||
| 32 | |||
| 33 | /* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN, | ||
| 34 | expand to code that computes the number of leading zeros of the local | ||
| 35 | variable 'x' of type TYPE (an unsigned integer type) and return it | ||
| 36 | from the current function. */ | ||
| 37 | #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) | ||
| 38 | # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ | ||
| 39 | return x ? BUILTIN (x) : CHAR_BIT * sizeof x; | ||
| 40 | #elif _MSC_VER | ||
| 41 | # pragma intrinsic _BitScanReverse | ||
| 42 | # pragma intrinsic _BitScanReverse64 | ||
| 43 | # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ | ||
| 44 | do \ | ||
| 45 | { \ | ||
| 46 | unsigned long result; \ | ||
| 47 | return MSC_BUILTIN (&result, x) ? result : CHAR_BIT * sizeof x; \ | ||
| 48 | } \ | ||
| 49 | while (0) | ||
| 50 | #else | ||
| 51 | # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ | ||
| 52 | do \ | ||
| 53 | { \ | ||
| 54 | int count; \ | ||
| 55 | unsigned int leading_32; \ | ||
| 56 | if (! x) \ | ||
| 57 | return CHAR_BIT * sizeof x; \ | ||
| 58 | for (count = 0; \ | ||
| 59 | (leading_32 = ((x >> (sizeof (TYPE) * CHAR_BIT - 32)) \ | ||
| 60 | & 0xffffffffU), \ | ||
| 61 | count < CHAR_BIT * sizeof x - 32 && !leading_32); \ | ||
| 62 | count += 32) \ | ||
| 63 | x = x << 31 << 1; \ | ||
| 64 | return count + count_leading_zeros_32 (leading_32); \ | ||
| 65 | } \ | ||
| 66 | while (0) | ||
| 67 | |||
| 68 | /* Compute and return the number of leading zeros in X, | ||
| 69 | where 0 < X < 2**32. */ | ||
| 70 | COUNT_LEADING_ZEROS_INLINE int | ||
| 71 | count_leading_zeros_32 (unsigned int x) | ||
| 72 | { | ||
| 73 | /* http://graphics.stanford.edu/~seander/bithacks.html */ | ||
| 74 | static const char de_Bruijn_lookup[32] = { | ||
| 75 | 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1, | ||
| 76 | 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0 | ||
| 77 | }; | ||
| 78 | |||
| 79 | x |= x >> 1; | ||
| 80 | x |= x >> 2; | ||
| 81 | x |= x >> 4; | ||
| 82 | x |= x >> 8; | ||
| 83 | x |= x >> 16; | ||
| 84 | return de_Bruijn_lookup[((x * 0x07c4acddU) & 0xffffffffU) >> 27]; | ||
| 85 | } | ||
| 86 | #endif | ||
| 87 | |||
| 88 | /* Compute and return the number of leading zeros in X. */ | ||
| 89 | COUNT_LEADING_ZEROS_INLINE int | ||
| 90 | count_leading_zeros (unsigned int x) | ||
| 91 | { | ||
| 92 | COUNT_LEADING_ZEROS (__builtin_clz, _BitScanReverse, unsigned int); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* Compute and return the number of leading zeros in X. */ | ||
| 96 | COUNT_LEADING_ZEROS_INLINE int | ||
| 97 | count_leading_zeros_l (unsigned long int x) | ||
| 98 | { | ||
| 99 | COUNT_LEADING_ZEROS (__builtin_clzl, _BitScanReverse, unsigned long int); | ||
| 100 | } | ||
| 101 | |||
| 102 | #if HAVE_UNSIGNED_LONG_LONG_INT | ||
| 103 | /* Compute and return the number of leading zeros in X. */ | ||
| 104 | COUNT_LEADING_ZEROS_INLINE int | ||
| 105 | count_leading_zeros_ll (unsigned long long int x) | ||
| 106 | { | ||
| 107 | COUNT_LEADING_ZEROS (__builtin_clzll, _BitScanReverse64, | ||
| 108 | unsigned long long int); | ||
| 109 | } | ||
| 110 | #endif | ||
| 111 | |||
| 112 | _GL_INLINE_HEADER_END | ||
| 113 | |||
| 114 | #endif /* COUNT_LEADING_ZEROS_H */ | ||
diff --git a/lib/gnulib.mk b/lib/gnulib.mk index 4398fe37173..e4aa90ecac9 100644 --- a/lib/gnulib.mk +++ b/lib/gnulib.mk | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | # the same distribution terms as the rest of that program. | 21 | # the same distribution terms as the rest of that program. |
| 22 | # | 22 | # |
| 23 | # Generated by gnulib-tool. | 23 | # Generated by gnulib-tool. |
| 24 | # Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=unsetenv --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings | 24 | # Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=unsetenv --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | MOSTLYCLEANFILES += core *.stackdump | 27 | MOSTLYCLEANFILES += core *.stackdump |
| @@ -151,6 +151,14 @@ EXTRA_DIST += close-stream.h | |||
| 151 | 151 | ||
| 152 | ## end gnulib module close-stream | 152 | ## end gnulib module close-stream |
| 153 | 153 | ||
| 154 | ## begin gnulib module count-leading-zeros | ||
| 155 | |||
| 156 | libgnu_a_SOURCES += count-leading-zeros.c | ||
| 157 | |||
| 158 | EXTRA_DIST += count-leading-zeros.h | ||
| 159 | |||
| 160 | ## end gnulib module count-leading-zeros | ||
| 161 | |||
| 154 | ## begin gnulib module count-one-bits | 162 | ## begin gnulib module count-one-bits |
| 155 | 163 | ||
| 156 | libgnu_a_SOURCES += count-one-bits.c | 164 | libgnu_a_SOURCES += count-one-bits.c |