Skip to content

Commit d482eab

Browse files
committed
mruby-bigint/bigint.c: int.pow(n,m) to take bigint as exponential
1 parent 62c52d5 commit d482eab

File tree

3 files changed

+68
-29
lines changed

3 files changed

+68
-29
lines changed

include/mruby/internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ mrb_value mrb_bint_mul_ii(mrb_state *mrb, mrb_int x, mrb_int y);
199199
mrb_value mrb_bint_mod(mrb_state *mrb, mrb_value x, mrb_value y);
200200
mrb_value mrb_bint_rem(mrb_state *mrb, mrb_value x, mrb_value y);
201201
mrb_value mrb_bint_pow(mrb_state *mrb, mrb_value x, mrb_value y);
202-
mrb_value mrb_bint_powm(mrb_state *mrb, mrb_value x, mrb_int y, mrb_value z);
202+
mrb_value mrb_bint_powm(mrb_state *mrb, mrb_value x, mrb_value y, mrb_value z);
203203
mrb_value mrb_bint_and(mrb_state *mrb, mrb_value x, mrb_value y);
204204
mrb_value mrb_bint_or(mrb_state *mrb, mrb_value x, mrb_value y);
205205
mrb_value mrb_bint_xor(mrb_state *mrb, mrb_value x, mrb_value y);

mrbgems/mruby-bigint/core/bigint.c

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,41 @@ mpz_pow(mrb_state *mrb, mpz_t *zz, mpz_t *x, mrb_int e)
942942
}
943943

944944
static void
945-
mpz_powm(mrb_state *mrb, mpz_t *zz, mpz_t *x, mrb_int ex, mpz_t *n)
945+
mpz_powm(mrb_state *mrb, mpz_t *zz, mpz_t *x, mpz_t *ex, mpz_t *n)
946+
{
947+
mpz_t t, b;
948+
949+
if (uzero(ex)) {
950+
mpz_set_int(mrb, zz, 1);
951+
return;
952+
}
953+
954+
if (ex->sn < 0) {
955+
return;
956+
}
957+
958+
mpz_init_set_int(mrb, &t, 1);
959+
mpz_init_set(mrb, &b, x);
960+
961+
size_t len = digits(ex);
962+
for (size_t i=0; i<len; i++) {
963+
mp_limb e = ex->p[i];
964+
for (size_t j=0; j<sizeof(mp_limb)*8; j++) {
965+
if ((e & 1) == 1) {
966+
mpz_mul(mrb, &t, &t, &b);
967+
mpz_mod(mrb, &t, &t, n);
968+
}
969+
e >>= 1;
970+
mpz_mul(mrb, &b, &b, &b);
971+
mpz_mod(mrb, &b, &b, n);
972+
}
973+
}
974+
mpz_move(mrb, zz, &t);
975+
mpz_clear(mrb, &b);
976+
}
977+
978+
static void
979+
mpz_powm_i(mrb_state *mrb, mpz_t *zz, mpz_t *x, mrb_int ex, mpz_t *n)
946980
{
947981
mpz_t t, b;
948982

@@ -1429,31 +1463,36 @@ mrb_bint_pow(mrb_state *mrb, mrb_value x, mrb_value y)
14291463
}
14301464

14311465
mrb_value
1432-
mrb_bint_powm(mrb_state *mrb, mrb_value x, mrb_int exp, mrb_value mod)
1466+
mrb_bint_powm(mrb_state *mrb, mrb_value x, mrb_value exp, mrb_value mod)
14331467
{
14341468
struct RBigint *b = RBIGINT(x);
1435-
switch (mrb_type(mod)) {
1436-
case MRB_TT_INTEGER:
1437-
{
1438-
mrb_int m = mrb_integer(mod);
1439-
if (m == 0) mrb_int_zerodiv(mrb);
1440-
struct RBigint *b2 = bint_new_int(mrb, m);
1441-
struct RBigint *b3 = bint_new(mrb);
1442-
mpz_powm(mrb, &b3->mp, &b->mp, exp, &b2->mp);
1443-
return bint_norm(mrb, b3);
1469+
struct RBigint *b2, *b3;
1470+
1471+
if (mrb_bigint_p(mod)) {
1472+
b2 = RBIGINT(mod);
1473+
if (uzero(&b2->mp)) mrb_int_zerodiv(mrb);
1474+
}
1475+
else {
1476+
mrb_int m = mrb_integer(mod);
1477+
if (m == 0) mrb_int_zerodiv(mrb);
1478+
b2 = bint_new_int(mrb, m);
1479+
}
1480+
b3 = bint_new(mrb);
1481+
if (mrb_bigint_p(exp)) {
1482+
struct RBigint *be = RBIGINT(exp);
1483+
if (be->mp.sn < 0) {
1484+
mrb_raise(mrb, E_ARGUMENT_ERROR, "int.pow(n,m): n must be positive");
14441485
}
1445-
case MRB_TT_BIGINT:
1446-
{
1447-
struct RBigint *b2 = RBIGINT(mod);
1448-
struct RBigint *b3 = bint_new(mrb);
1449-
if (uzero(&b2->mp)) mrb_int_zerodiv(mrb);
1450-
mpz_powm(mrb, &b3->mp, &b->mp, exp, &b2->mp);
1451-
return bint_norm(mrb, b3);
1486+
mpz_powm(mrb, &b3->mp, &b->mp, &be->mp, &b2->mp);
1487+
}
1488+
else {
1489+
mrb_int e = mrb_integer(exp);
1490+
if (e < 0) {
1491+
mrb_raise(mrb, E_ARGUMENT_ERROR, "int.pow(n,m): n must be positive");
14521492
}
1453-
default:
1454-
mrb_raisef(mrb, E_TYPE_ERROR, "%v cannot be convert to integer", mod);
1493+
mpz_powm_i(mrb, &b3->mp, &b->mp, e, &b2->mp);
14551494
}
1456-
return mrb_nil_value();
1495+
return bint_norm(mrb, b3);
14571496
}
14581497

14591498
mrb_value

mrbgems/mruby-numeric-ext/src/numeric_ext.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,16 @@ int_powm(mrb_state *mrb, mrb_value x)
7373
) {
7474
mrb_raise(mrb, E_TYPE_ERROR, "int.pow(n,m): 2nd argument not allowed unless 1st argument is an integer");
7575
}
76-
exp = mrb_as_int(mrb, e);
77-
if (exp < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "int.pow(n,m): n must be positive");
7876
#ifdef MRB_USE_BIGINT
7977
if (mrb_bigint_p(x)) {
80-
return mrb_bint_powm(mrb, x, exp, m);
78+
return mrb_bint_powm(mrb, x, e, m);
8179
}
82-
if (mrb_bigint_p(m)) {
83-
return mrb_bint_powm(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), exp, m);
80+
if (mrb_bigint_p(e) || mrb_bigint_p(m)) {
81+
return mrb_bint_powm(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), e, m);
8482
}
8583
#endif
84+
exp = mrb_integer(e);
85+
if (exp < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "int.pow(n,m): n must be positive");
8686
if (!mrb_integer_p(m)) mrb_raise(mrb, E_TYPE_ERROR, "int.pow(n,m): m must be integer");
8787
mod = mrb_integer(m);
8888
if (mod < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "int.pow(n,m): m must be positive when 2nd argument specified");
@@ -96,7 +96,7 @@ int_powm(mrb_state *mrb, mrb_value x)
9696
result %= mod; base %= mod;
9797
if (mrb_int_mul_overflow(result, base, &tmp)) {
9898
#ifdef MRB_USE_BIGINT
99-
return mrb_bint_powm(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), mrb_integer(e), m);
99+
return mrb_bint_powm(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), e, m);
100100
#else
101101
mrb_int_overflow(mrb, "pow");
102102
#endif
@@ -110,7 +110,7 @@ int_powm(mrb_state *mrb, mrb_value x)
110110
base %= mod;
111111
if (mrb_int_mul_overflow(base, base, &tmp)) {
112112
#ifdef MRB_USE_BIGINT
113-
return mrb_bint_powm(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), mrb_integer(e), m);
113+
return mrb_bint_powm(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), e, m);
114114
#else
115115
mrb_int_overflow(mrb, "pow");
116116
#endif

0 commit comments

Comments
 (0)