diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-06-08 12:05:57 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-06-08 12:05:57 +0000 |
commit | 747894a32d6ea2b123b2abc292fd903c53a7aa36 (patch) | |
tree | c6a59d1b30a97c752b4367aa6ffb9050a609f74f /bignum.c | |
parent | af612be8e0e54ffa602cede04d355a1399a02b81 (diff) |
* bignum.c (rb_absint_singlebit_p): New function.
* internal.h (rb_absint_singlebit_p): Declared.
* time.c (v2w_bignum): Use rb_absint_singlebit_p instead of
rb_big_abs_find_minbit.
(rb_big_abs_find_minbit): Removed.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41177 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'bignum.c')
-rw-r--r-- | bignum.c | 46 |
1 files changed, 46 insertions, 0 deletions
@@ -537,6 +537,52 @@ rb_absint_size_in_word(VALUE val, size_t word_numbits_arg, size_t *number_of_lea return numwords; } +int +rb_absint_singlebit_p(VALUE val) +{ + BDIGIT *dp; + BDIGIT *de; + BDIGIT fixbuf[(sizeof(long) + SIZEOF_BDIGITS - 1) / SIZEOF_BDIGITS]; + BDIGIT d; + + val = rb_to_int(val); + + if (FIXNUM_P(val)) { + long v = FIX2LONG(val); + if (v < 0) { + v = -v; + } +#if SIZEOF_BDIGITS == SIZEOF_LONG + fixbuf[0] = v; +#else + { + int i; + for (i = 0; i < numberof(fixbuf); i++) { + fixbuf[i] = (BDIGIT)(v & ((1L << (SIZEOF_BDIGITS * CHAR_BIT)) - 1)); + v >>= SIZEOF_BDIGITS * CHAR_BIT; + } + } +#endif + dp = fixbuf; + de = fixbuf + numberof(fixbuf); + } + else { + dp = BDIGITS(val); + de = dp + RBIGNUM_LEN(val); + } + while (dp < de && de[-1] == 0) + de--; + while (dp < de && dp[0] == 0) + dp++; + if (dp == de) /* no bit set. */ + return 0; + if (dp != de-1) /* two non-zero words. two bits set, at least. */ + return 0; + d = *dp; + d = d & (d - 1); /* Clear the least significant bit set */ + return d == 0; +} + #define INTEGER_PACK_WORDORDER_MASK \ (INTEGER_PACK_MSWORD_FIRST | \ INTEGER_PACK_LSWORD_FIRST) |