From 8b5a9bfa3987390cf864f0923394e6031793c910 Mon Sep 17 00:00:00 2001 From: Jan Buiter Date: Thu, 1 Aug 2019 20:02:35 +0200 Subject: [PATCH] Implement pow operator for BigDecimal and BigRational (#7860) Co-Authored-By: Sijawusz Pur Rahnama Co-Authored-By: r00ster --- spec/std/big/big_decimal_spec.cr | 6 ++++++ spec/std/big/big_rational_spec.cr | 17 +++++++++++++++++ src/big/big_decimal.cr | 14 ++++++++++++++ src/big/big_rational.cr | 17 +++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/spec/std/big/big_decimal_spec.cr b/spec/std/big/big_decimal_spec.cr index 4f6e162963a4..8708d0f5f9c9 100644 --- a/spec/std/big/big_decimal_spec.cr +++ b/spec/std/big/big_decimal_spec.cr @@ -204,6 +204,12 @@ describe BigDecimal do (3 / 2.to_big_d).should eq(BigDecimal.new("1.5")) end + it "exponentiates" do + result = "12.34".to_big_d ** 5 + result.should be_a(BigDecimal) + result.to_s.should eq("286138.1721051424") + end + it "can be converted from other types" do 1.to_big_d.should eq (BigDecimal.new(1)) "1.5".to_big_d.should eq (BigDecimal.new(15, 1)) diff --git a/spec/std/big/big_rational_spec.cr b/spec/std/big/big_rational_spec.cr index 5f3edf0366e7..96969800fa98 100644 --- a/spec/std/big/big_rational_spec.cr +++ b/spec/std/big/big_rational_spec.cr @@ -185,6 +185,23 @@ describe BigRational do (br(10, 3) >> 2).should eq(br(5, 6)) end + describe "#**" do + it "exponentiates with positive powers" do + result = br(17, 11) ** 5 + result.should be_a(BigRational) + result.should eq(br(1419857, 161051)) + end + + it "exponentiates with negative powers" do + result = br(17, 11) ** -5 + result.should eq(br(161051, 1419857)) + end + + it "cannot raise 0 to a negative power" do + expect_raises(DivisionByZeroError) { br(0, 1) ** -1 } + end + end + it "#ceil" do br(2, 1).ceil.should eq(2) br(21, 10).ceil.should eq(3) diff --git a/src/big/big_decimal.cr b/src/big/big_decimal.cr index e18e8c7f0089..26a65e145e76 100644 --- a/src/big/big_decimal.cr +++ b/src/big/big_decimal.cr @@ -277,6 +277,20 @@ struct BigDecimal < Number end end + # Raises the decimal to the *other*th power + # + # ``` + # require "big" + # + # BigDecimal.new(1234, 2) ** 2 # => 152.2756 + # ``` + def **(other : Int) : BigDecimal + if other < 0 + raise ArgumentError.new("Negative exponent isn't supported") + end + BigDecimal.new(@value ** other, @scale * other) + end + def ceil : BigDecimal mask = power_ten_to(@scale) diff = (mask - @value % mask) % mask diff --git a/src/big/big_rational.cr b/src/big/big_rational.cr index 0357d03d4916..969eb5b23444 100644 --- a/src/big/big_rational.cr +++ b/src/big/big_rational.cr @@ -170,6 +170,23 @@ struct BigRational < Number BigRational.new { |mpq| LibGMP.mpq_neg(mpq, self) } end + # Raises the rational to the *other*th power + # + # This will raise `DivisionByZeroError` if rational is 0 and *other* is negative. + # + # ``` + # require "big" + # + # BigRational.new(2, 3) ** 2 # => 4/9 + # BigRational.new(2, 3) ** -1 # => 3/2 + # ``` + def **(other : Int) : BigRational + if other < 0 + return (self ** -other).inv + end + BigRational.new(numerator ** other, denominator ** other) + end + # Returns a new `BigRational` as 1/r. # # This will raise an exception if rational is 0.