From 9866e500142f4974f2c21b2b29c8a89dcabe41f2 Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Wed, 21 Feb 2024 18:25:38 +0800 Subject: [PATCH] Add `BigRational#%`, `#tdiv`, `#remainder` (#14306) --- spec/std/big/big_rational_spec.cr | 72 +++++++++++++++++++++++++++++-- src/big/big_rational.cr | 46 ++++++++++++++++++++ 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/spec/std/big/big_rational_spec.cr b/spec/std/big/big_rational_spec.cr index 7b28a4938966..0dcc75c10b87 100644 --- a/spec/std/big/big_rational_spec.cr +++ b/spec/std/big/big_rational_spec.cr @@ -218,10 +218,74 @@ describe BigRational do end it "#//" do - (br(10, 7) // br(3, 7)).should eq(br(9, 3)) - expect_raises(DivisionByZeroError) { br(10, 7) / br(0, 10) } - (br(10, 7) // 3).should eq(0) - (1 // br(10, 7)).should eq(0) + (br(18, 7) // br(4, 5)).should eq(br(3, 1)) + (br(-18, 7) // br(4, 5)).should eq(br(-4, 1)) + (br(18, 7) // br(-4, 5)).should eq(br(-4, 1)) + (br(-18, 7) // br(-4, 5)).should eq(br(3, 1)) + + (br(18, 5) // 2).should eq(br(1, 1)) + (br(-18, 5) // 2).should eq(br(-2, 1)) + (br(18, 5) // -2).should eq(br(-2, 1)) + (br(-18, 5) // -2).should eq(br(1, 1)) + (br(18, 5) // 2.to_big_i).should eq(br(1, 1)) + + expect_raises(DivisionByZeroError) { br(18, 7) // br(0, 1) } + expect_raises(DivisionByZeroError) { br(18, 7) // 0 } + + (8 // br(10, 7)).should eq(5) + (-8 // br(10, 7)).should eq(-6) + (8 // br(-10, 7)).should eq(-6) + (-8 // br(-10, 7)).should eq(5) + + expect_raises(DivisionByZeroError) { 8 // br(0, 7) } + end + + it "#%" do + (br(18, 7) % br(4, 5)).should eq(br(6, 35)) + (br(-18, 7) % br(4, 5)).should eq(br(22, 35)) + (br(18, 7) % br(-4, 5)).should eq(br(-22, 35)) + (br(-18, 7) % br(-4, 5)).should eq(br(-6, 35)) + + (br(18, 5) % 2).should eq(br(8, 5)) + (br(-18, 5) % 2).should eq(br(2, 5)) + (br(18, 5) % -2).should eq(br(-2, 5)) + (br(-18, 5) % -2).should eq(br(-8, 5)) + (br(18, 5) % 2.to_big_i).should eq(br(8, 5)) + + expect_raises(DivisionByZeroError) { br(18, 7) % br(0, 1) } + expect_raises(DivisionByZeroError) { br(18, 7) % 0 } + end + + it "#tdiv" do + br(18, 7).tdiv(br(4, 5)).should eq(br(3, 1)) + br(-18, 7).tdiv(br(4, 5)).should eq(br(-3, 1)) + br(18, 7).tdiv(br(-4, 5)).should eq(br(-3, 1)) + br(-18, 7).tdiv(br(-4, 5)).should eq(br(3, 1)) + + br(18, 5).tdiv(2).should eq(br(1, 1)) + br(-18, 5).tdiv(2).should eq(br(-1, 1)) + br(18, 5).tdiv(-2).should eq(br(-1, 1)) + br(-18, 5).tdiv(-2).should eq(br(1, 1)) + br(18, 5).tdiv(2.to_big_i).should eq(br(1, 1)) + + expect_raises(DivisionByZeroError) { br(18, 7).tdiv(br(0, 1)) } + expect_raises(DivisionByZeroError) { br(18, 7).tdiv(0) } + end + + it "#remainder" do + br(18, 7).remainder(br(4, 5)).should eq(br(6, 35)) + br(-18, 7).remainder(br(4, 5)).should eq(br(-6, 35)) + br(18, 7).remainder(br(-4, 5)).should eq(br(6, 35)) + br(-18, 7).remainder(br(-4, 5)).should eq(br(-6, 35)) + + br(18, 5).remainder(2).should eq(br(8, 5)) + br(-18, 5).remainder(2).should eq(br(-8, 5)) + br(18, 5).remainder(-2).should eq(br(8, 5)) + br(-18, 5).remainder(-2).should eq(br(-8, 5)) + br(18, 5).remainder(2.to_big_i).should eq(br(8, 5)) + + expect_raises(DivisionByZeroError) { br(18, 7).remainder(br(0, 1)) } + expect_raises(DivisionByZeroError) { br(18, 7).remainder(0) } end it "#- (negation)" do diff --git a/src/big/big_rational.cr b/src/big/big_rational.cr index a9466a5466a0..b14c8f4b2d4a 100644 --- a/src/big/big_rational.cr +++ b/src/big/big_rational.cr @@ -151,6 +151,52 @@ struct BigRational < Number Number.expand_div [BigInt, BigFloat, BigDecimal], BigRational + def //(other : BigRational) : BigRational + check_division_by_zero other + BigRational.new((numerator * other.denominator) // (denominator * other.numerator)) + end + + def //(other : Int) : BigRational + check_division_by_zero other + BigRational.new(numerator // (denominator * other)) + end + + def %(other : BigRational) : BigRational + check_division_by_zero other + BigRational.new( + (numerator * other.denominator) % (denominator * other.numerator), + denominator * other.denominator, + ) + end + + def %(other : Int) : BigRational + check_division_by_zero other + BigRational.new(numerator % (denominator * other), denominator) + end + + def tdiv(other : BigRational) : BigRational + check_division_by_zero other + BigRational.new((numerator * other.denominator).tdiv(denominator * other.numerator)) + end + + def tdiv(other : Int) : BigRational + check_division_by_zero other + BigRational.new(numerator.tdiv(denominator * other)) + end + + def remainder(other : BigRational) : BigRational + check_division_by_zero other + BigRational.new( + (numerator * other.denominator).remainder(denominator * other.numerator), + denominator * other.denominator, + ) + end + + def remainder(other : Int) : BigRational + check_division_by_zero other + BigRational.new(numerator.remainder(denominator * other), denominator) + end + def ceil : BigRational BigRational.new(-(-numerator // denominator)) end