require_relative '../../spec_helper' require_relative 'fixtures/classes' require 'bigdecimal' describe "BigDecimal#add" do before :each do @one = BigDecimal("1") @zero = BigDecimal("0") @two = BigDecimal("2") @three = BigDecimal("3") @ten = BigDecimal("10") @eleven = BigDecimal("11") @nan = BigDecimal("NaN") @infinity = BigDecimal("Infinity") @infinity_minus = BigDecimal("-Infinity") @one_minus = BigDecimal("-1") @frac_1 = BigDecimal("1E-99999") @frac_2 = BigDecimal("0.9E-99999") @frac_3 = BigDecimal("12345E10") @frac_4 = BigDecimal("98765E10") @dot_ones = BigDecimal("0.1111111111") end it "returns a + b with given precision" do # documentation states, that precision ist optional, but it ain't, @two.add(@one, 1).should == @three @one .add(@two, 1).should == @three @one.add(@one_minus, 1).should == @zero @ten.add(@one, 2).should == @eleven @zero.add(@one, 1).should == @one @frac_2.add(@frac_1, 10000).should == BigDecimal("1.9E-99999") @frac_1.add(@frac_1, 10000).should == BigDecimal("2E-99999") @frac_3.add(@frac_4, 0).should == BigDecimal("0.11111E16") @frac_3.add(@frac_4, 1).should == BigDecimal("0.1E16") @frac_3.add(@frac_4, 2).should == BigDecimal("0.11E16") @frac_3.add(@frac_4, 3).should == BigDecimal("0.111E16") @frac_3.add(@frac_4, 4).should == BigDecimal("0.1111E16") @frac_3.add(@frac_4, 5).should == BigDecimal("0.11111E16") @frac_3.add(@frac_4, 6).should == BigDecimal("0.11111E16") end it "returns a + [Fixnum value] with given precision" do (1..10).each {|precision| @dot_ones.add(0, precision).should == BigDecimal("0." + "1" * precision) } BigDecimal("0.88").add(0, 1).should == BigDecimal("0.9") end it "returns a + [Bignum value] with given precision" do bignum = 10000000000000000000 (1..20).each {|precision| @dot_ones.add(bignum, precision).should == BigDecimal("0.1E20") } (21..30).each {|precision| @dot_ones.add(bignum, precision).should == BigDecimal( "0.10000000000000000000" + "1" * (precision - 20) + "E20") } end # TODO: # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17374 # # This doesn't work on MRI and looks like a bug to me: # one can use BigDecimal + Float, but not Bigdecimal.add(Float) # # it "returns a + [Float value] with given precision" do # (1..10).each {|precision| # @dot_ones.add(0.0, precision).should == BigDecimal("0." + "1" * precision) # } # # BigDecimal("0.88").add(0.0, 1).should == BigDecimal("0.9") # end describe "with Object" do it "tries to coerce the other operand to self" do object = mock("Object") object.should_receive(:coerce).with(@frac_3).and_return([@frac_3, @frac_4]) @frac_3.add(object, 1).should == BigDecimal("0.1E16") end end describe "with Rational" do it "produces a BigDecimal" do (@three + Rational(500, 2)).should == BigDecimal("0.253e3") end end it "favors the precision specified in the second argument over the global limit" do BigDecimalSpecs.with_limit(1) do BigDecimal('0.888').add(@zero, 3).should == BigDecimal('0.888') end BigDecimalSpecs.with_limit(2) do BigDecimal('0.888').add(@zero, 1).should == BigDecimal('0.9') end end it "uses the current rounding mode if rounding is needed" do BigDecimalSpecs.with_rounding(BigDecimal::ROUND_UP) do BigDecimal('0.111').add(@zero, 1).should == BigDecimal('0.2') BigDecimal('-0.111').add(@zero, 1).should == BigDecimal('-0.2') end BigDecimalSpecs.with_rounding(BigDecimal::ROUND_DOWN) do BigDecimal('0.999').add(@zero, 1).should == BigDecimal('0.9') BigDecimal('-0.999').add(@zero, 1).should == BigDecimal('-0.9') end BigDecimalSpecs.with_rounding(BigDecimal::ROUND_HALF_UP) do BigDecimal('0.85').add(@zero, 1).should == BigDecimal('0.9') BigDecimal('-0.85').add(@zero, 1).should == BigDecimal('-0.9') end BigDecimalSpecs.with_rounding(BigDecimal::ROUND_HALF_DOWN) do BigDecimal('0.85').add(@zero, 1).should == BigDecimal('0.8') BigDecimal('-0.85').add(@zero, 1).should == BigDecimal('-0.8') end BigDecimalSpecs.with_rounding(BigDecimal::ROUND_HALF_EVEN) do BigDecimal('0.75').add(@zero, 1).should == BigDecimal('0.8') BigDecimal('0.85').add(@zero, 1).should == BigDecimal('0.8') BigDecimal('-0.75').add(@zero, 1).should == BigDecimal('-0.8') BigDecimal('-0.85').add(@zero, 1).should == BigDecimal('-0.8') end BigDecimalSpecs.with_rounding(BigDecimal::ROUND_CEILING) do BigDecimal('0.85').add(@zero, 1).should == BigDecimal('0.9') BigDecimal('-0.85').add(@zero, 1).should == BigDecimal('-0.8') end BigDecimalSpecs.with_rounding(BigDecimal::ROUND_FLOOR) do BigDecimal('0.85').add(@zero, 1).should == BigDecimal('0.8') BigDecimal('-0.85').add(@zero, 1).should == BigDecimal('-0.9') end end it "uses the default ROUND_HALF_UP rounding if it wasn't explicitly changed" do BigDecimal('0.85').add(@zero, 1).should == BigDecimal('0.9') BigDecimal('-0.85').add(@zero, 1).should == BigDecimal('-0.9') end it "returns NaN if NaN is involved" do @one.add(@nan, 10000).should.nan? @nan.add(@one, 1).should.nan? end it "returns Infinity or -Infinity if these are involved" do @zero.add(@infinity, 1).should == @infinity @frac_2.add(@infinity, 1).should == @infinity @one_minus.add(@infinity, 1).should == @infinity @two.add(@infinity, 1).should == @infinity @zero.add(@infinity_minus, 1).should == @infinity_minus @frac_2.add(@infinity_minus, 1).should == @infinity_minus @one_minus.add(@infinity_minus, 1).should == @infinity_minus @two.add(@infinity_minus, 1).should == @infinity_minus @infinity.add(@zero, 1).should == @infinity @infinity.add(@frac_2, 1).should == @infinity @infinity.add(@one_minus, 1).should == @infinity @infinity.add(@two, 1).should == @infinity @infinity_minus.add(@zero, 1).should == @infinity_minus @infinity_minus.add(@frac_2, 1).should == @infinity_minus @infinity_minus.add(@one_minus, 1).should == @infinity_minus @infinity_minus.add(@two, 1).should == @infinity_minus @infinity.add(@infinity, 10000).should == @infinity @infinity_minus.add(@infinity_minus, 10000).should == @infinity_minus end it "returns NaN if Infinity + (- Infinity)" do @infinity.add(@infinity_minus, 10000).should.nan? @infinity_minus.add(@infinity, 10000).should.nan? end it "raises TypeError when adds nil" do -> { @one.add(nil, 10) }.should raise_error(TypeError) -> { @one.add(nil, 0) }.should raise_error(TypeError) end it "raises TypeError when precision parameter is nil" do -> { @one.add(@one, nil) }.should raise_error(TypeError) end it "raises ArgumentError when precision parameter is negative" do -> { @one.add(@one, -10) }.should raise_error(ArgumentError) end end