diff options
| author | Paul Eggert | 2017-09-30 15:36:52 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-09-30 15:38:14 -0700 |
| commit | 8136df6a8cbf071266eb38f5baef005f4e9241a3 (patch) | |
| tree | 4ade7520c5be858be40b7939a0338e4a48288c85 | |
| parent | d247e1d30abcb77665f829ca98a5bdef69ff4bc3 (diff) | |
| download | emacs-8136df6a8cbf071266eb38f5baef005f4e9241a3.tar.gz emacs-8136df6a8cbf071266eb38f5baef005f4e9241a3.zip | |
Make logcount act like CL on negative arg
Behaving like Common Lisp is less likely to lead to surprises,
as it yields the same answers on 32- vs 64-bit machines.
* doc/lispref/numbers.texi (Bitwise Operations):
Document behavior on negative integers.
* src/data.c (Flogcount):
Behave like Common Lisp for negative arguments.
* test/src/data-tests.el (data-tests-popcnt)
(data-tests-logcount): Test negative args too.
| -rw-r--r-- | doc/lispref/numbers.texi | 7 | ||||
| -rw-r--r-- | src/data.c | 6 | ||||
| -rw-r--r-- | test/src/data-tests.el | 4 |
3 files changed, 13 insertions, 4 deletions
diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi index 5058063af4d..be74b0c6111 100644 --- a/doc/lispref/numbers.texi +++ b/doc/lispref/numbers.texi | |||
| @@ -1113,9 +1113,14 @@ bit is one in the result if, and only if, the @var{n}th bit is zero in | |||
| 1113 | @defun logcount integer | 1113 | @defun logcount integer |
| 1114 | This function returns the @dfn{Hamming weight} of @var{integer}: the | 1114 | This function returns the @dfn{Hamming weight} of @var{integer}: the |
| 1115 | number of ones in the binary representation of @var{integer}. | 1115 | number of ones in the binary representation of @var{integer}. |
| 1116 | If @var{integer} is negative, it returns the number of zero bits in | ||
| 1117 | its two's complement binary representation. The result is always | ||
| 1118 | nonnegative. | ||
| 1116 | 1119 | ||
| 1117 | @example | 1120 | @example |
| 1118 | (logcount 42) ; 42 = #b101010 | 1121 | (logcount 43) ; 43 = #b101011 |
| 1122 | @result{} 4 | ||
| 1123 | (logcount -43) ; -43 = #b111...1010101 | ||
| 1119 | @result{} 3 | 1124 | @result{} 3 |
| 1120 | @end example | 1125 | @end example |
| 1121 | @end defun | 1126 | @end defun |
diff --git a/src/data.c b/src/data.c index fd8cdd19aa2..2e7f3e017be 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -3071,11 +3071,13 @@ usage: (logxor &rest INTS-OR-MARKERS) */) | |||
| 3071 | 3071 | ||
| 3072 | DEFUN ("logcount", Flogcount, Slogcount, 1, 1, 0, | 3072 | DEFUN ("logcount", Flogcount, Slogcount, 1, 1, 0, |
| 3073 | doc: /* Return population count of VALUE. | 3073 | doc: /* Return population count of VALUE. |
| 3074 | If VALUE is negative, the count is of its two's complement representation. */) | 3074 | This is the number of one bits in the two's complement representation |
| 3075 | of VALUE. If VALUE is negative, return the number of zero bits in the | ||
| 3076 | representation. */) | ||
| 3075 | (Lisp_Object value) | 3077 | (Lisp_Object value) |
| 3076 | { | 3078 | { |
| 3077 | CHECK_NUMBER (value); | 3079 | CHECK_NUMBER (value); |
| 3078 | EMACS_UINT v = XUINT (value); | 3080 | EMACS_INT v = XINT (value) < 0 ? -1 - XINT (value) : XINT (value); |
| 3079 | return make_number (EMACS_UINT_WIDTH <= UINT_WIDTH | 3081 | return make_number (EMACS_UINT_WIDTH <= UINT_WIDTH |
| 3080 | ? count_one_bits (v) | 3082 | ? count_one_bits (v) |
| 3081 | : EMACS_UINT_WIDTH <= ULONG_WIDTH | 3083 | : EMACS_UINT_WIDTH <= ULONG_WIDTH |
diff --git a/test/src/data-tests.el b/test/src/data-tests.el index d1154cc5c44..374d1689b9e 100644 --- a/test/src/data-tests.el +++ b/test/src/data-tests.el | |||
| @@ -109,12 +109,14 @@ | |||
| 109 | 109 | ||
| 110 | (defun data-tests-popcnt (byte) | 110 | (defun data-tests-popcnt (byte) |
| 111 | "Calculate the Hamming weight of BYTE." | 111 | "Calculate the Hamming weight of BYTE." |
| 112 | (if (< byte 0) | ||
| 113 | (setq byte (lognot byte))) | ||
| 112 | (setq byte (- byte (logand (lsh byte -1) #x55555555))) | 114 | (setq byte (- byte (logand (lsh byte -1) #x55555555))) |
| 113 | (setq byte (+ (logand byte #x33333333) (logand (lsh byte -2) #x33333333))) | 115 | (setq byte (+ (logand byte #x33333333) (logand (lsh byte -2) #x33333333))) |
| 114 | (lsh (* (logand (+ byte (lsh byte -4)) #x0f0f0f0f) #x01010101) -24)) | 116 | (lsh (* (logand (+ byte (lsh byte -4)) #x0f0f0f0f) #x01010101) -24)) |
| 115 | 117 | ||
| 116 | (ert-deftest data-tests-logcount () | 118 | (ert-deftest data-tests-logcount () |
| 117 | (should (cl-loop for n in (number-sequence 0 255) | 119 | (should (cl-loop for n in (number-sequence -255 255) |
| 118 | always (= (logcount n) (data-tests-popcnt n)))) | 120 | always (= (logcount n) (data-tests-popcnt n)))) |
| 119 | ;; https://oeis.org/A000120 | 121 | ;; https://oeis.org/A000120 |
| 120 | (should (= 11 (logcount 9727))) | 122 | (should (= 11 (logcount 9727))) |