From ad8fc7d9182c7374fffb62b696c30561b5e98968 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 23 Apr 2026 22:56:44 +0900 Subject: [PATCH] mruby-bigint: add multi-precision gcd tests Cover zero operands, power-of-2 fast path, negative operands, balanced multi-limb pairs with a shared Fibonacci factor, highly unbalanced pairs (to exercise the Euclidean fallback), and Fibonacci neighbors (always coprime). Declare a test dependency on mruby-numeric-ext since Integer#gcd is defined there. Co-authored-by: Claude --- mrbgems/mruby-bigint/mrbgem.rake | 2 ++ mrbgems/mruby-bigint/test/bigint.rb | 41 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/mrbgems/mruby-bigint/mrbgem.rake b/mrbgems/mruby-bigint/mrbgem.rake index a1039bf57..edd910b6e 100644 --- a/mrbgems/mruby-bigint/mrbgem.rake +++ b/mrbgems/mruby-bigint/mrbgem.rake @@ -4,6 +4,8 @@ MRuby::Gem::Specification.new('mruby-bigint') do |spec| spec.summary = 'Integer class extension to multiple-precision' spec.build.defines << "MRB_USE_BIGINT" + spec.add_test_dependency('mruby-numeric-ext', :core => 'mruby-numeric-ext') + spec.build.libmruby_core_objs << Dir.glob(File.join(__dir__, "core/**/*.c")).map { |fn| objfile(fn.relative_path_from(__dir__).pathmap("#{spec.build_dir}/%X")) } diff --git a/mrbgems/mruby-bigint/test/bigint.rb b/mrbgems/mruby-bigint/test/bigint.rb index 07f6c783e..289e93da8 100644 --- a/mrbgems/mruby-bigint/test/bigint.rb +++ b/mrbgems/mruby-bigint/test/bigint.rb @@ -155,3 +155,44 @@ assert 'Bigint abs' do assert_equal 36893488147419103232, n.abs assert_equal 36893488147419103232, (-n).abs end + +assert 'Bigint gcd' do + # zero cases + assert_equal 0, 0.gcd(0) + n = 1 << 200 + assert_equal n, n.gcd(0) + assert_equal n, 0.gcd(n) + + # power-of-2 fast path + assert_equal 1 << 100, (1 << 200).gcd(1 << 100) + assert_equal 1 << 100, (1 << 100).gcd(1 << 200) + assert_equal 1 << 40, (10 ** 50).gcd(1 << 40) + + # negative operands: result is the positive GCD + a = 1 << 200 + b = 3 << 200 + assert_equal a, a.gcd(b) + assert_equal a, (-a).gcd(b) + assert_equal a, a.gcd(-b) + assert_equal a, (-a).gcd(-b) + + # balanced multi-limb with known common factor + fib1000 = (1..1000).inject([0, 1]) { |(x, y), _| [y, x + y] }[0] + common = fib1000 + k, m = 1_000_003, 1_000_033 # small coprime primes + assert_equal common, (common * k).gcd(common * m) + assert_equal common, (common * m).gcd(common * k) + + # unbalanced: small coprime vs large + big = common * k + assert_equal 1, big.gcd(m) + assert_equal 1, m.gcd(big) + + # Fibonacci neighbors are always coprime + f100 = (1..100).inject([0, 1]) { |(x, y), _| [y, x + y] }[0] + f101 = (1..101).inject([0, 1]) { |(x, y), _| [y, x + y] }[0] + assert_equal 1, f100.gcd(f101) + + # Euclidean fallback path: operand sizes differ by several limbs + assert_equal 7, (7 * (1 << 4000)).gcd(7 * 13) +end