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 | |
parent | af612be8e0e54ffa602cede04d355a1399a02b81 (diff) | |
download | ruby-747894a32d6ea2b123b2abc292fd903c53a7aa36.tar.gz |
* 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
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | bignum.c | 46 | ||||
-rw-r--r-- | internal.h | 1 | ||||
-rw-r--r-- | time.c | 22 |
4 files changed, 58 insertions, 21 deletions
@@ -1,3 +1,13 @@ +Sat Jun 8 21:03:40 2013 Tanaka Akira <akr@fsij.org> + + * 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. + Sat Jun 8 20:24:23 2013 Tanaka Akira <akr@fsij.org> * time.c (rb_big_abs_find_maxbit): Use rb_absint_size. @@ -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) diff --git a/internal.h b/internal.h index 3b091e503e..05f4b537fc 100644 --- a/internal.h +++ b/internal.h @@ -121,6 +121,7 @@ VALUE rb_integer_float_cmp(VALUE x, VALUE y); VALUE rb_integer_float_eq(VALUE x, VALUE y); size_t rb_absint_size(VALUE val, int *number_of_leading_zero_bits); size_t rb_absint_size_in_word(VALUE val, size_t word_numbits, size_t *number_of_leading_zero_bits); +int rb_absint_singlebit_p(VALUE val); /* class.c */ VALUE rb_obj_methods(int argc, VALUE *argv, VALUE obj); @@ -313,25 +313,6 @@ rb_big_abs_find_maxbit(VALUE big) return res; } -static VALUE -rb_big_abs_find_minbit(VALUE big) -{ - BDIGIT *ds = RBIGNUM_DIGITS(big); - BDIGIT d; - long len = RBIGNUM_LEN(big); - long i; - VALUE res; - for (i = 0; i < len; i++) - if (ds[i]) - break; - if (i == len) - return Qnil; - res = mul(LONG2NUM(i), INT2FIX(SIZEOF_BDIGITS * CHAR_BIT)); - d = ds[i]; - res = add(res, LONG2FIX(ffs(d)-1)); - return res; -} - static wideval_t v2w_bignum(VALUE v) { @@ -346,8 +327,7 @@ v2w_bignum(VALUE v) return WINT2FIXWV(0); if (lt(maxbit, INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)) || (eq(maxbit, INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)) && - RBIGNUM_NEGATIVE_P(v) && - eq(rb_big_abs_find_minbit(v), INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)))) { + RBIGNUM_NEGATIVE_P(v) && rb_absint_singlebit_p(v))) { wideint_t i; i = 0; while (len) |