Skip to content

Commit

Permalink
Support BigDecimal comparison with and initialization from BigRational
Browse files Browse the repository at this point in the history
  • Loading branch information
Sija committed Feb 2, 2018
1 parent 995d3f9 commit ac84c3b
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 4 deletions.
10 changes: 10 additions & 0 deletions spec/std/big/big_decimal_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ describe BigDecimal do

BigDecimal.new(BigDecimal.new(2))
.should eq(BigDecimal.new(2.to_big_i))

BigDecimal.new(BigRational.new(1, 2))
.should eq(BigDecimal.new(BigInt.new(5), 1))
end

it "raises InvalidBigDecimalException when initializing from invalid input" do
Expand Down Expand Up @@ -181,6 +184,7 @@ describe BigDecimal do
BigInt.new(15).to_big_d.should eq (BigDecimal.new(15, 0))
1.5.to_big_d.should eq (BigDecimal.new(15, 1))
1.5.to_big_f.to_big_d.should eq (BigDecimal.new(15, 1))
1.5.to_big_r.to_big_d.should eq(BigDecimal.new(15, 1))
end

it "can be converted from scientific notation" do
Expand Down Expand Up @@ -243,6 +247,12 @@ describe BigDecimal do

(BigDecimal.new("6.5") > 7).should be_false
(BigDecimal.new("7.5") > 6).should be_true

BigDecimal.new("0.5").should eq(BigRational.new(1, 2))
BigDecimal.new("0.25").should eq(BigDecimal.new("0.25"))

BigRational.new(1, 2).should eq(BigDecimal.new("0.5"))
BigRational.new(1, 4).should eq(BigDecimal.new("0.25"))
end

it "keeps precision" do
Expand Down
30 changes: 26 additions & 4 deletions src/big/big_decimal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ struct BigDecimal < Number
DEFAULT_MAX_DIV_ITERATIONS = 100_u64

include Comparable(Int)
include Comparable(BigDecimal)
include Comparable(Float)
include Comparable(BigRational)
include Comparable(BigDecimal)

getter value : BigInt
getter scale : UInt64
Expand Down Expand Up @@ -133,6 +134,13 @@ struct BigDecimal < Number
initialize(num.to_s)
end

# Creates a new `BigDecimal` from `BigRational`.
def initialize(num : BigRational)
num_as_big_d = num.numerator.to_big_d / num.denominator.to_big_d
@value = num_as_big_d.value
@scale = num_as_big_d.scale
end

def - : BigDecimal
BigDecimal.new(-@value, @scale)
end
Expand Down Expand Up @@ -225,15 +233,16 @@ struct BigDecimal < Number
end
end

def <=>(other : Int | Float)
def <=>(other : Int | Float | BigRational)
self <=> BigDecimal.new(other)
end

def ==(other : BigDecimal) : Bool
if @scale > other.scale
case @scale
when .>(other.scale)
scaled = other.value * power_ten_to(@scale - other.scale)
@value == scaled
elsif @scale < other.scale
when .<(other.scale)
scaled = @value * power_ten_to(other.scale - @scale)
scaled == other.value
else
Expand Down Expand Up @@ -458,6 +467,19 @@ struct Float
end
end

struct BigRational
include Comparable(BigDecimal)

def <=>(other : BigDecimal)
to_big_d <=> other
end

# Converts `self` to `BigDecimal`.
def to_big_d
BigDecimal.new(self)
end
end

class String
# Converts `self` to `BigDecimal`.
def to_big_d
Expand Down

0 comments on commit ac84c3b

Please sign in to comment.