diff options
| author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2026-03-24 14:26:54 +0900 |
|---|---|---|
| committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2026-03-24 14:49:12 +0900 |
| commit | 930edc12d75ff8f496751e2e33416b259d1deafc (patch) | |
| tree | f0b570c951cfb44b9c97f17680fdf9239f32e8a7 | |
| parent | 3b32c93e570903336a59509f2d6c5686da8d1e3c (diff) | |
merge revision(s) 19e539c9ee1701b34189fa0c1feb942adeb0e326: [Backport #21814]
[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.c | 9 | ||||
| -rw-r--r-- | test/ruby/test_numeric.rb | 4 | ||||
| -rw-r--r-- | version.h | 2 |
3 files changed, 12 insertions, 3 deletions
@@ -7008,7 +7008,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); @@ -7036,7 +7036,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; @@ -7148,6 +7148,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 ab492743f6..133d3202e2 100644 --- a/test/ruby/test_numeric.rb +++ b/test/ruby/test_numeric.rb @@ -483,6 +483,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 @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 10 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 201 +#define RUBY_PATCHLEVEL 202 #include "ruby/version.h" #include "ruby/internal/abi.h" |
