mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
180 lines
5.2 KiB
Ruby
180 lines
5.2 KiB
Ruby
require_relative '../../spec_helper'
|
|
require_relative 'shared/modulo'
|
|
require 'bigdecimal'
|
|
|
|
module DivmodSpecs
|
|
def self.check_both_nan(array)
|
|
array.length.should == 2
|
|
array[0].should.nan?
|
|
array[1].should.nan?
|
|
end
|
|
def self.check_both_bigdecimal(array)
|
|
array.length.should == 2
|
|
array[0].kind_of?(BigDecimal).should == true
|
|
array[1].kind_of?(BigDecimal).should == true
|
|
end
|
|
end
|
|
|
|
# TODO: figure out a way to do the shared specs with helpers instead
|
|
# of spec'ing a method that does not really exist
|
|
describe "BigDecimal#mod_part_of_divmod" do
|
|
# BigDecimal#divmod[1] behaves exactly like #modulo
|
|
before :all do
|
|
class BigDecimal
|
|
def mod_part_of_divmod(arg)
|
|
divmod(arg)[1]
|
|
end
|
|
end
|
|
end
|
|
|
|
after :all do
|
|
class BigDecimal
|
|
undef mod_part_of_divmod
|
|
end
|
|
end
|
|
|
|
it_behaves_like :bigdecimal_modulo, :mod_part_of_divmod
|
|
|
|
it "raises ZeroDivisionError if other is zero" do
|
|
bd5667 = BigDecimal("5667.19")
|
|
|
|
-> { bd5667.mod_part_of_divmod(0) }.should raise_error(ZeroDivisionError)
|
|
-> { bd5667.mod_part_of_divmod(BigDecimal("0")) }.should raise_error(ZeroDivisionError)
|
|
-> { @zero.mod_part_of_divmod(@zero) }.should raise_error(ZeroDivisionError)
|
|
end
|
|
end
|
|
|
|
describe "BigDecimal#divmod" do
|
|
|
|
before :each do
|
|
@a = BigDecimal("42.00000000000000000001")
|
|
|
|
@zero = BigDecimal("0")
|
|
@zero_pos = BigDecimal("+0")
|
|
@zero_neg = BigDecimal("-0")
|
|
|
|
@one = BigDecimal("1")
|
|
@mixed = BigDecimal("1.23456789")
|
|
@pos_int = BigDecimal("2E5555")
|
|
@neg_int = BigDecimal("-2E5555")
|
|
@pos_frac = BigDecimal("2E-9999")
|
|
@neg_frac = BigDecimal("-2E-9999")
|
|
@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")
|
|
|
|
@special_vals = [@infinity, @infinity_minus, @nan]
|
|
@regular_vals = [
|
|
@one, @mixed, @pos_int, @neg_int, @pos_frac,
|
|
@neg_frac, @one_minus, @frac_1, @frac_2]
|
|
@zeroes = [@zero, @zero_pos, @zero_neg]
|
|
end
|
|
|
|
it "divides value, returns an array" do
|
|
res = @a.divmod(5)
|
|
res.kind_of?(Array).should == true
|
|
end
|
|
|
|
it "array contains quotient and modulus as BigDecimal" do
|
|
res = @a.divmod(5)
|
|
DivmodSpecs.check_both_bigdecimal(res)
|
|
res[0].should == BigDecimal('0.8E1')
|
|
res[1].should == BigDecimal('2.00000000000000000001')
|
|
|
|
BigDecimal('1').divmod(BigDecimal('2')).should == [0, 1]
|
|
BigDecimal('2').divmod(BigDecimal('1')).should == [2, 0]
|
|
|
|
BigDecimal('1').divmod(BigDecimal('-2')).should == [-1, -1]
|
|
BigDecimal('2').divmod(BigDecimal('-1')).should == [-2, 0]
|
|
|
|
BigDecimal('-1').divmod(BigDecimal('2')).should == [-1, 1]
|
|
BigDecimal('-2').divmod(BigDecimal('1')).should == [-2, 0]
|
|
end
|
|
|
|
it "can be reversed with * and +" do
|
|
# Example taken from BigDecimal documentation
|
|
a = BigDecimal("42")
|
|
b = BigDecimal("9")
|
|
q, m = a.divmod(b)
|
|
c = q * b + m
|
|
a.should == c
|
|
|
|
values = [@one, @one_minus, BigDecimal('2'), BigDecimal('-2'),
|
|
BigDecimal('5'), BigDecimal('-5'), BigDecimal('10'), BigDecimal('-10'),
|
|
BigDecimal('20'), BigDecimal('-20'), BigDecimal('100'), BigDecimal('-100'),
|
|
BigDecimal('1.23456789E10'), BigDecimal('-1.23456789E10')
|
|
]
|
|
|
|
# TODO: file MRI bug:
|
|
# BigDecimal('1').divmod(BigDecimal('3E-9'))[0] #=> 0.3E9,
|
|
# but really should be 0.333333333E9
|
|
values << BigDecimal('1E-10')
|
|
values << BigDecimal('-1E-10')
|
|
values << BigDecimal('2E55')
|
|
values << BigDecimal('-2E55')
|
|
values << BigDecimal('2E-5555')
|
|
values << BigDecimal('-2E-5555')
|
|
|
|
|
|
values_and_zeroes = values + @zeroes
|
|
values_and_zeroes.each do |val1|
|
|
values.each do |val2|
|
|
res = val1.divmod(val2)
|
|
DivmodSpecs.check_both_bigdecimal(res)
|
|
res[0].should == ((val1/val2).floor)
|
|
res[1].should == (val1 - res[0] * val2)
|
|
end
|
|
end
|
|
end
|
|
|
|
it "returns an array of two NaNs if NaN is involved" do
|
|
(@special_vals + @regular_vals + @zeroes).each do |val|
|
|
DivmodSpecs.check_both_nan(val.divmod(@nan))
|
|
DivmodSpecs.check_both_nan(@nan.divmod(val))
|
|
end
|
|
end
|
|
|
|
it "raises ZeroDivisionError if the divisor is zero" do
|
|
(@special_vals + @regular_vals + @zeroes - [@nan]).each do |val|
|
|
@zeroes.each do |zero|
|
|
-> { val.divmod(zero) }.should raise_error(ZeroDivisionError)
|
|
end
|
|
end
|
|
end
|
|
|
|
it "returns an array of Infinity and NaN if the dividend is Infinity" do
|
|
@regular_vals.each do |val|
|
|
array = @infinity.divmod(val)
|
|
array.length.should == 2
|
|
array[0].infinite?.should == (val > 0 ? 1 : -1)
|
|
array[1].should.nan?
|
|
end
|
|
end
|
|
|
|
it "returns an array of zero and the dividend if the divisor is Infinity" do
|
|
@regular_vals.each do |val|
|
|
array = val.divmod(@infinity)
|
|
array.length.should == 2
|
|
array[0].should == @zero
|
|
array[1].should == val
|
|
end
|
|
end
|
|
|
|
it "returns an array of two zero if the dividend is zero" do
|
|
@zeroes.each do |zero|
|
|
@regular_vals.each do |val|
|
|
zero.divmod(val).should == [@zero, @zero]
|
|
end
|
|
end
|
|
end
|
|
|
|
it "raises TypeError if the argument cannot be coerced to BigDecimal" do
|
|
-> {
|
|
@one.divmod('1')
|
|
}.should raise_error(TypeError)
|
|
end
|
|
|
|
end
|