diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2018-05-18 20:17:33 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2018-05-18 20:17:33 -0700 |
commit | a580c45de5a825165f46d95206d9ac3c2c52fcd6 (patch) | |
tree | 849e617a4ee8730435782c3ecc8a14f1fb2594a2 | |
parent | aaac04d9e0cdcdd974c065bbff3d212a5eb5cd3a (diff) | |
download | txr-a580c45de5a825165f46d95206d9ac3c2c52fcd6.tar.gz txr-a580c45de5a825165f46d95206d9ac3c2c52fcd6.tar.bz2 txr-a580c45de5a825165f46d95206d9ac3c2c52fcd6.zip |
logcount: new function.
This is in ANSI CL; potentially useful and hard to
implement efficiently in user code.
* arith.c (logcount): New function.
* eval.c (eval_init): Register logcount intrinsic.
* lib.h (logcount): Declared.
* mpi/mi.c (s_mp_count_ones): New static function.
(mp_count_ones): New function.
* mpi/mpi.h (mp_count_ones): Declared.
* txr.1: Documented.
-rw-r--r-- | arith.c | 40 | ||||
-rw-r--r-- | eval.c | 1 | ||||
-rw-r--r-- | lib.h | 1 | ||||
-rw-r--r-- | mpi/mpi.c | 59 | ||||
-rw-r--r-- | mpi/mpi.h | 1 | ||||
-rw-r--r-- | txr.1 | 19 |
6 files changed, 121 insertions, 0 deletions
@@ -2697,6 +2697,46 @@ val maskv(struct args *bits) return accum; } +val logcount(val n) +{ + val self = lit("logcount"); + + switch (type(n)) { + case NUM: + case CHR: + { + int_ptr_t c = c_num(n); + uint_ptr_t d = c; + if (c < 0) + d = ~d; +#if SIZEOF_PTR == 8 + d = ((d & 0xAAAAAAAAAAAAAAAA) >> 1) + (d & 0x5555555555555555); + d = ((d & 0xCCCCCCCCCCCCCCCC) >> 2) + (d & 0x3333333333333333); + d = ((d & 0xF0F0F0F0F0F0F0F0) >> 4) + (d & 0x0F0F0F0F0F0F0F0F); + d = ((d & 0xFF00FF00FF00FF00) >> 8) + (d & 0x00FF00FF00FF00FF); + d = ((d & 0xFFFF0000FFFF0000) >> 16) + (d & 0x0000FFFF0000FFFF); + d = ((d & 0xFFFFFFFF00000000) >> 32) + (d & 0x00000000FFFFFFFF); +#elif SIZEOF_PTR == 4 + d = ((d & 0xAAAAAAAA) >> 1) + (d & 0x55555555); + d = ((d & 0xCCCCCCCC) >> 2) + (d & 0x33333333); + d = ((d & 0xF0F0F0F0) >> 4) + (d & 0x0F0F0F0F); + d = ((d & 0xFF00FF00) >> 8) + (d & 0x00FF00FF); + d = ((d & 0xFFFF0000) >> 16) + (d & 0x0000FFFF); + return unum(d); +#else +#error fixme: only 4 or 8 byte pointers supported +#endif + } + case BGNUM: + { + mp_size co = mp_count_ones(mp(n)); + return unum(co); + } + default: + uw_throwf(error_s, lit("~a: non-integral operand ~s"), self, n, nao); + } +} + /* * Source: * Better Approximations to Cumulative Normal Functions @@ -6481,6 +6481,7 @@ void eval_init(void) reg_fun(intern(lit("bit"), user_package), func_n2(bit)); reg_fun(intern(lit("mask"), user_package), func_n0v(maskv)); reg_fun(intern(lit("width"), user_package), func_n1(width)); + reg_fun(intern(lit("logcount"), user_package), func_n1(logcount)); reg_fun(intern(lit("sort-group"), user_package), func_n3o(sort_group, 1)); reg_fun(intern(lit("unique"), user_package), func_n2ov(unique, 1)); @@ -752,6 +752,7 @@ val sign_extend(val num, val nbits); val ash(val a, val bits); val bit(val a, val bit); val maskv(struct args *bits); +val logcount(val n); val string_own(wchar_t *str); val string(const wchar_t *str); val string_utf8(const char *str); @@ -2499,6 +2499,65 @@ mp_size mp_count_bits(mp_int *mp) return s_highest_bit_mp(mp); } +static mp_size s_mp_count_ones(mp_int *mp) +{ + mp_size ix; + mp_size c; + mp_digit *dp = DIGITS(mp); + + for (c = 0, ix = USED(mp) - 1; ix < MP_SIZE_MAX; ix--) { + mp_digit d = dp[ix]; +#if MP_DIGIT_SIZE == 8 + d = ((d & 0xAAAAAAAAAAAAAAAA) >> 1) + (d & 0x5555555555555555); + d = ((d & 0xCCCCCCCCCCCCCCCC) >> 2) + (d & 0x3333333333333333); + d = ((d & 0xF0F0F0F0F0F0F0F0) >> 4) + (d & 0x0F0F0F0F0F0F0F0F); + d = ((d & 0xFF00FF00FF00FF00) >> 8) + (d & 0x00FF00FF00FF00FF); + d = ((d & 0xFFFF0000FFFF0000) >> 16) + (d & 0x0000FFFF0000FFFF); + d = ((d & 0xFFFFFFFF00000000) >> 32) + (d & 0x00000000FFFFFFFF); + c += d; +#elif MP_DIGIT_SIZE == 4 + d = ((d & 0xAAAAAAAA) >> 1) + (d & 0x55555555); + d = ((d & 0xCCCCCCCC) >> 2) + (d & 0x33333333); + d = ((d & 0xF0F0F0F0) >> 4) + (d & 0x0F0F0F0F); + d = ((d & 0xFF00FF00) >> 8) + (d & 0x00FF00FF); + d = ((d & 0xFFFF0000) >> 16) + (d & 0x0000FFFF); + c += d; +#elif MP_DIGIT_SIZE == 2 + d = ((d & 0xAAAA) >> 1) + (d & 0x5555); + d = ((d & 0xCCCC) >> 2) + (d & 0x3333); + d = ((d & 0xF0F0) >> 4) + (d & 0x0F0F); + d = ((d & 0xFF00) >> 8) + (d & 0x00FF); + c += d; +#elif MP_DIGIT_SIZE == 1 + d = ((d & 0xAA) >> 1) + (d & 0x55); + d = ((d & 0xCC) >> 2) + (d & 0x33); + d = ((d & 0xF0) >> 4) + (d & 0x0F); + c += d; +#else +#error fixme: unsupported MP_DIGIT_SIZE +#endif + } + + return c; +} + +mp_size mp_count_ones(mp_int *mp) +{ + if (SIGN(mp) == MP_NEG) { + mp_int tmp; + mp_size res; + if ((res = mp_init_copy(&tmp, mp)) != MP_OKAY) + return res; + if ((res = s_mp_sub_d(&tmp, 1) != MP_OKAY)) + return res; + res = s_mp_count_ones(&tmp); + mp_clear(&tmp); + return res; + } + + return s_mp_count_ones(mp); +} + mp_size mp_is_pow_two(mp_int *mp) { return s_mp_ispow2(mp) >= 0; @@ -177,6 +177,7 @@ mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str); mp_err mp_to_unsigned_buf(mp_int *mp, unsigned char *str, size_t size); mp_size mp_count_bits(mp_int *mp); +mp_size mp_count_ones(mp_int *mp); mp_size mp_is_pow_two(mp_int *mp); #if MP_COMPAT_MACROS @@ -36263,6 +36263,25 @@ two's complement bitfield 01 denotes 1, and 10 denotes -2. The argument may be a character. +.coNP Function @ logcount +.synb +.mets (logcount << integer ) +.syne +.desc +The +.code logcount +function considers +.meta integer +to have a two's complement representation. If the integer is positive, +it returns the count of bits in that representation whose value is 1. +If +.meta integer +is negative, it returns the count of zero bits instead. If +.meta integer +is zero, the value returned is zero. + +The argument may be a character. + .SS* Exception Handling An |