summaryrefslogtreecommitdiff
path: root/bignum.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-07-17 13:53:24 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-07-17 13:53:24 +0000
commit15f7c7f9d4b28708216ca981312991a7850004eb (patch)
tree58d0b1efac4390491845fc49f93246e7565a83e1 /bignum.c
parent7c1a2f61921392a7f8df3e52ca7ae5b78252f522 (diff)
* bignum.c: An static assertion for relation of SIZEOF_LONG and
SIZEOF_BDIGITS is added. (bary_mul_precheck): Reduce comparisons. (bary_mul): Invoke bary_sq_fast or bary_mul1 if the bignum size is small. (bigfixize): Resize the argument bignum here. (bignorm): Don't call bigtrunc after bigfixize. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42028 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'bignum.c')
-rw-r--r--bignum.c121
1 files changed, 84 insertions, 37 deletions
diff --git a/bignum.c b/bignum.c
index 6e0e5e5647..3c4585f37e 100644
--- a/bignum.c
+++ b/bignum.c
@@ -47,6 +47,12 @@ STATIC_ASSERT(bdigit_dbl_signedness, 0 < (BDIGIT_DBL)-1);
STATIC_ASSERT(bdigit_dbl_signed_signedness, 0 > (BDIGIT_DBL_SIGNED)-1);
STATIC_ASSERT(rbignum_embed_len_max, RBIGNUM_EMBED_LEN_MAX <= (RBIGNUM_EMBED_LEN_MASK >> RBIGNUM_EMBED_LEN_SHIFT));
+#if SIZEOF_BDIGITS < SIZEOF_LONG
+STATIC_ASSERT(sizeof_long_and_sizeof_bdigit, SIZEOF_LONG % SIZEOF_BDIGITS == 0);
+#else
+STATIC_ASSERT(sizeof_long_and_sizeof_bdigit, SIZEOF_BDIGITS % SIZEOF_LONG == 0);
+#endif
+
#ifdef WORDS_BIGENDIAN
# define HOST_BIGENDIAN_P 1
#else
@@ -1911,22 +1917,40 @@ bary_mul_precheck(BDIGIT **zdsp, size_t *zlp, BDIGIT **xdsp, size_t *xlp, BDIGIT
assert(xl + yl <= zl);
- while (0 < xl && xds[xl-1] == 0)
- xl--;
- while (0 < yl && yds[yl-1] == 0)
- yl--;
-
nlsz = 0;
- while (0 < xl && xds[0] == 0) {
- xds++;
- xl--;
- nlsz++;
+
+ while (0 < xl) {
+ if (xds[xl-1] == 0) {
+ xl--;
+ }
+ else {
+ do {
+ if (xds[0] != 0)
+ break;
+ xds++;
+ xl--;
+ nlsz++;
+ } while (0 < xl);
+ break;
+ }
}
- while (0 < yl && yds[0] == 0) {
- yds++;
- yl--;
- nlsz++;
+
+ while (0 < yl) {
+ if (yds[yl-1] == 0) {
+ yl--;
+ }
+ else {
+ do {
+ if (xds[0] != 0)
+ break;
+ yds++;
+ yl--;
+ nlsz++;
+ } while (0 < yl);
+ break;
+ }
}
+
if (nlsz) {
MEMZERO(zds, BDIGIT, nlsz);
zds += nlsz;
@@ -1942,12 +1966,12 @@ bary_mul_precheck(BDIGIT **zdsp, size_t *zlp, BDIGIT **xdsp, size_t *xlp, BDIGIT
}
assert(xl <= yl);
- if (xl == 0) {
- MEMZERO(zds, BDIGIT, zl);
- return 1;
- }
+ if (xl <= 1) {
+ if (xl == 0) {
+ MEMZERO(zds, BDIGIT, zl);
+ return 1;
+ }
- if (xl == 1) {
if (xds[0] == 1) {
MEMCPY(zds, yds, BDIGIT, yl);
MEMZERO(zds+yl, BDIGIT, zl-yl);
@@ -2059,6 +2083,14 @@ bary_mul_toom3_start(BDIGIT *zds, size_t zl, BDIGIT *xds, size_t xl, BDIGIT *yds
static void
bary_mul(BDIGIT *zds, size_t zl, BDIGIT *xds, size_t xl, BDIGIT *yds, size_t yl)
{
+ if (xl < KARATSUBA_MUL_DIGITS) {
+ if (xds == yds && xl == yl)
+ bary_sq_fast(zds, zl, xds, xl);
+ else
+ bary_mul1(zds, zl, xds, xl, yds, yl);
+ return;
+ }
+
bary_mul_toom3_start(zds, zl, xds, xl, yds, yl, NULL, 0);
}
@@ -2275,28 +2307,45 @@ bigtrunc(VALUE x)
static inline VALUE
bigfixize(VALUE x)
{
- long len = RBIGNUM_LEN(x);
+ size_t len = RBIGNUM_LEN(x);
BDIGIT *ds = BDIGITS(x);
+#if SIZEOF_BDIGITS < SIZEOF_LONG
+ unsigned long u;
+#else
+ BDIGIT u;
+#endif
+
+ while (0 < len && ds[len-1] == 0)
+ len--;
if (len == 0) return INT2FIX(0);
- if (BIGSIZE(x) <= sizeof(long)) {
- long num = 0;
-#if SIZEOF_BDIGITS >= SIZEOF_LONG
- num = (long)ds[0];
-#else
- while (len--) {
- num = (long)(BIGUP(num) + ds[len]);
- }
+
+#if SIZEOF_BDIGITS < SIZEOF_LONG
+ if (sizeof(long)/SIZEOF_BDIGITS < len)
+ goto return_big;
+ else {
+ int i = (int)len;
+ u = 0;
+ while (i--) {
+ u = (long)(BIGUP(u) + ds[i]);
+ }
+ }
+#else /* SIZEOF_BDIGITS >= SIZEOF_LONG */
+ if (1 < len || LONG_MAX < ds[0])
+ goto return_big;
+ else
+ u = ds[0];
#endif
- if (num >= 0) {
- if (RBIGNUM_SIGN(x)) {
- if (POSFIXABLE(num)) return LONG2FIX(num);
- }
- else {
- if (NEGFIXABLE(-num)) return LONG2FIX(-num);
- }
- }
+
+ if (RBIGNUM_POSITIVE_P(x)) {
+ if (POSFIXABLE(u)) return LONG2FIX((long)u);
}
+ else {
+ if (u <= -FIXNUM_MIN) return LONG2FIX(-(long)u);
+ }
+
+ return_big:
+ rb_big_resize(x, len);
return x;
}
@@ -2305,8 +2354,6 @@ bignorm(VALUE x)
{
if (RB_TYPE_P(x, T_BIGNUM)) {
x = bigfixize(x);
- if (!FIXNUM_P(x))
- bigtrunc(x);
}
return x;
}