summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2026-01-12 17:05:12 -0800
committerTakashi Kokubun <takashikkbn@gmail.com>2026-01-12 17:05:12 -0800
commit893dcb5f25cbb0574ae73aa8fc926fd26750a27f (patch)
tree58f9a612805834d78586693aa297fbe16a818014
parentb170f02e0f2a7831b51a9279ee2d35a5e4ecace9 (diff)
merge revision(s) 19e539c9ee1701b34189fa0c1feb942adeb0e326: [Backport #21814]
[PATCH] [Bug #21814] Fix negative bignum modulo If modulo is zero, do not apply bias even if the divisor is zero. `BIGNUM_POSITIVE_P` is true even on bignum zero.
-rw-r--r--bignum.c9
-rw-r--r--test/ruby/test_numeric.rb4
2 files changed, 11 insertions, 2 deletions
diff --git a/bignum.c b/bignum.c
index ed53d75149..ee2fa1ed30 100644
--- a/bignum.c
+++ b/bignum.c
@@ -7070,7 +7070,7 @@ int_pow_tmp3(VALUE x, VALUE y, VALUE m, int nega_flg)
zn = mn;
z = bignew(zn, 1);
bary_powm_gmp(BDIGITS(z), zn, BDIGITS(x), xn, BDIGITS(y), yn, BDIGITS(m), mn);
- if (nega_flg & BIGNUM_POSITIVE_P(z)) {
+ if (nega_flg && BIGNUM_POSITIVE_P(z) && !BIGZEROP(z)) {
z = rb_big_minus(z, m);
}
RB_GC_GUARD(x);
@@ -7098,7 +7098,7 @@ int_pow_tmp3(VALUE x, VALUE y, VALUE m, int nega_flg)
x = rb_int_modulo(x, m);
}
- if (nega_flg && rb_int_positive_p(tmp)) {
+ if (nega_flg && rb_int_positive_p(tmp) && !rb_int_zero_p(tmp)) {
tmp = rb_int_minus(tmp, m);
}
return tmp;
@@ -7210,6 +7210,11 @@ rb_int_powm(int const argc, VALUE * const argv, VALUE const num)
rb_raise(rb_eTypeError, "Integer#pow() 2nd argument not allowed unless all arguments are integers");
}
+ if (rb_int_zero_p(a) && !rb_int_zero_p(b)) {
+ /* shortcut; 0**x => 0 except for x == 0 */
+ return INT2FIX(0);
+ }
+
if (rb_int_negative_p(m)) {
m = rb_int_uminus(m);
nega_flg = 1;
diff --git a/test/ruby/test_numeric.rb b/test/ruby/test_numeric.rb
index 3bf93ef20d..35496ac875 100644
--- a/test/ruby/test_numeric.rb
+++ b/test/ruby/test_numeric.rb
@@ -489,6 +489,10 @@ class TestNumeric < Test::Unit::TestCase
assert_equal(0, 0.pow(3, 1))
assert_equal(0, 2.pow(3, 1))
assert_equal(0, -2.pow(3, 1))
+
+ min, max = RbConfig::LIMITS.values_at("FIXNUM_MIN", "FIXNUM_MAX")
+ assert_equal(0, 0.pow(2, min))
+ assert_equal(0, Integer.sqrt(max+1).pow(2, min))
end
end