rubysl-bigdecimal 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/ext/rubysl/bigdecimal/bigdecimal.c +4760 -0
  9. data/ext/rubysl/bigdecimal/bigdecimal.h +220 -0
  10. data/ext/rubysl/bigdecimal/extconf.rb +6 -0
  11. data/lib/bigdecimal.rb +1 -0
  12. data/lib/bigdecimal/README +60 -0
  13. data/lib/bigdecimal/bigdecimal_en.html +796 -0
  14. data/lib/bigdecimal/bigdecimal_ja.html +799 -0
  15. data/lib/bigdecimal/jacobian.rb +85 -0
  16. data/lib/bigdecimal/ludcmp.rb +84 -0
  17. data/lib/bigdecimal/math.rb +235 -0
  18. data/lib/bigdecimal/newton.rb +77 -0
  19. data/lib/bigdecimal/sample/linear.rb +71 -0
  20. data/lib/bigdecimal/sample/nlsolve.rb +38 -0
  21. data/lib/bigdecimal/sample/pi.rb +20 -0
  22. data/lib/bigdecimal/util.rb +65 -0
  23. data/lib/rubysl/bigdecimal.rb +2 -0
  24. data/lib/rubysl/bigdecimal/version.rb +5 -0
  25. data/rubysl-bigdecimal.gemspec +24 -0
  26. data/spec/abs_spec.rb +49 -0
  27. data/spec/add_spec.rb +178 -0
  28. data/spec/case_compare_spec.rb +6 -0
  29. data/spec/ceil_spec.rb +122 -0
  30. data/spec/coerce_spec.rb +25 -0
  31. data/spec/comparison_spec.rb +80 -0
  32. data/spec/div_spec.rb +143 -0
  33. data/spec/divide_spec.rb +6 -0
  34. data/spec/divmod_spec.rb +233 -0
  35. data/spec/double_fig_spec.rb +8 -0
  36. data/spec/eql_spec.rb +5 -0
  37. data/spec/equal_value_spec.rb +6 -0
  38. data/spec/exponent_spec.rb +37 -0
  39. data/spec/finite_spec.rb +34 -0
  40. data/spec/fix_spec.rb +56 -0
  41. data/spec/fixtures/classes.rb +17 -0
  42. data/spec/floor_spec.rb +109 -0
  43. data/spec/frac_spec.rb +47 -0
  44. data/spec/gt_spec.rb +86 -0
  45. data/spec/gte_spec.rb +90 -0
  46. data/spec/induced_from_spec.rb +36 -0
  47. data/spec/infinite_spec.rb +31 -0
  48. data/spec/inspect_spec.rb +40 -0
  49. data/spec/limit_spec.rb +29 -0
  50. data/spec/lt_spec.rb +84 -0
  51. data/spec/lte_spec.rb +90 -0
  52. data/spec/minus_spec.rb +57 -0
  53. data/spec/mode_spec.rb +64 -0
  54. data/spec/modulo_spec.rb +11 -0
  55. data/spec/mult_spec.rb +23 -0
  56. data/spec/multiply_spec.rb +25 -0
  57. data/spec/nan_spec.rb +22 -0
  58. data/spec/new_spec.rb +120 -0
  59. data/spec/nonzero_spec.rb +28 -0
  60. data/spec/plus_spec.rb +49 -0
  61. data/spec/power_spec.rb +5 -0
  62. data/spec/precs_spec.rb +48 -0
  63. data/spec/quo_spec.rb +12 -0
  64. data/spec/remainder_spec.rb +83 -0
  65. data/spec/round_spec.rb +193 -0
  66. data/spec/shared/eql.rb +65 -0
  67. data/spec/shared/modulo.rb +146 -0
  68. data/spec/shared/mult.rb +97 -0
  69. data/spec/shared/power.rb +83 -0
  70. data/spec/shared/quo.rb +59 -0
  71. data/spec/shared/to_int.rb +27 -0
  72. data/spec/sign_spec.rb +46 -0
  73. data/spec/split_spec.rb +87 -0
  74. data/spec/sqrt_spec.rb +111 -0
  75. data/spec/sub_spec.rb +52 -0
  76. data/spec/to_f_spec.rb +54 -0
  77. data/spec/to_i_spec.rb +6 -0
  78. data/spec/to_int_spec.rb +7 -0
  79. data/spec/to_s_spec.rb +71 -0
  80. data/spec/truncate_spec.rb +100 -0
  81. data/spec/uminus_spec.rb +57 -0
  82. data/spec/uplus_spec.rb +19 -0
  83. data/spec/ver_spec.rb +10 -0
  84. data/spec/zero_spec.rb +27 -0
  85. metadata +243 -0
@@ -0,0 +1,6 @@
1
+ require File.expand_path('../shared/eql.rb', __FILE__)
2
+
3
+
4
+ describe "BigDecimal#===" do
5
+ it_behaves_like(:bigdecimal_eql, :===)
6
+ end
data/spec/ceil_spec.rb ADDED
@@ -0,0 +1,122 @@
1
+ require 'bigdecimal'
2
+
3
+ describe "BigDecimal#ceil" do
4
+ before(:each) do
5
+ @zero = BigDecimal("0")
6
+ @one = BigDecimal("1")
7
+ @three = BigDecimal("3")
8
+ @four = BigDecimal("4")
9
+ @mixed = BigDecimal("1.23456789")
10
+ @mixed_big = BigDecimal("1.23456789E100")
11
+ @pos_int = BigDecimal("2E5555")
12
+ @neg_int = BigDecimal("-2E5555")
13
+ @pos_frac = BigDecimal("2E-9999")
14
+ @neg_frac = BigDecimal("-2E-9999")
15
+
16
+ @infinity = BigDecimal("Infinity")
17
+ @infinity_neg = BigDecimal("-Infinity")
18
+ @nan = BigDecimal("NaN")
19
+ @zero_pos = BigDecimal("+0")
20
+ @zero_neg = BigDecimal("-0")
21
+ end
22
+
23
+ ruby_version_is "" ... "1.9" do
24
+ it "returns a BigDecimal" do
25
+ @mixed.ceil.kind_of?(BigDecimal).should == true
26
+ @pos_int.ceil(2).kind_of?(BigDecimal).should == true
27
+ end
28
+ end
29
+
30
+ ruby_version_is "1.9" do
31
+ it "returns an Integer, if n is unspecified" do
32
+ @mixed.ceil.kind_of?(Integer).should == true
33
+ end
34
+
35
+ it "returns a BigDecimal, if n is specified" do
36
+ @pos_int.ceil(2).kind_of?(BigDecimal).should == true
37
+ end
38
+ end
39
+
40
+ it "returns the smallest integer greater or equal to self, if n is unspecified" do
41
+ @pos_int.ceil.should == @pos_int
42
+ @neg_int.ceil.should == @neg_int
43
+ @pos_frac.ceil.should == BigDecimal("1")
44
+ @neg_frac.ceil.should == @zero
45
+ @zero.ceil.should == 0
46
+ @zero_pos.ceil.should == @zero_pos
47
+ @zero_neg.ceil.should == @zero_neg
48
+
49
+
50
+ BigDecimal('2.3').ceil.should == 3
51
+ BigDecimal('2.5').ceil.should == 3
52
+ BigDecimal('2.9999').ceil.should == 3
53
+ BigDecimal('-2.3').ceil.should == -2
54
+ BigDecimal('-2.5').ceil.should == -2
55
+ BigDecimal('-2.9999').ceil.should == -2
56
+ end
57
+
58
+ ruby_version_is "" ... "1.9" do
59
+ it "returns the same value, if self is special value" do
60
+ @infinity.ceil.should == @infinity
61
+ @infinity_neg.ceil.should == @infinity_neg
62
+ @nan.ceil.nan?.should == true
63
+ end
64
+ end
65
+
66
+ ruby_version_is "1.9" do
67
+ it "raise exception, if self is special value" do
68
+ lambda { @infinity.ceil }.should raise_error(FloatDomainError)
69
+ lambda { @infinity_neg.ceil }.should raise_error(FloatDomainError)
70
+ lambda { @nan.ceil }.should raise_error(FloatDomainError)
71
+ end
72
+ end
73
+
74
+ it "returns n digits right of the decimal point if given n > 0" do
75
+ @mixed.ceil(1).should == BigDecimal("1.3")
76
+ @mixed.ceil(5).should == BigDecimal("1.23457")
77
+
78
+ BigDecimal("-0.03").ceil(1).should == BigDecimal("0")
79
+ BigDecimal("0.03").ceil(1).should == BigDecimal("0.1")
80
+
81
+ BigDecimal("23.45").ceil(0).should == BigDecimal('24')
82
+ BigDecimal("23.45").ceil(1).should == BigDecimal('23.5')
83
+ BigDecimal("23.45").ceil(2).should == BigDecimal('23.45')
84
+
85
+ BigDecimal("-23.45").ceil(0).should == BigDecimal('-23')
86
+ BigDecimal("-23.45").ceil(1).should == BigDecimal('-23.4')
87
+ BigDecimal("-23.45").ceil(2).should == BigDecimal('-23.45')
88
+
89
+ BigDecimal("2E-10").ceil(0).should == @one
90
+ BigDecimal("2E-10").ceil(9).should == BigDecimal('1E-9')
91
+ BigDecimal("2E-10").ceil(10).should == BigDecimal('2E-10')
92
+ BigDecimal("2E-10").ceil(11).should == BigDecimal('2E-10')
93
+
94
+ (1..10).each do |n|
95
+ # 0.4, 0.34, 0.334, etc.
96
+ (@one.div(@three,20)).ceil(n).should == BigDecimal("0.#{'3'*(n-1)}4")
97
+ # 1.4, 1.34, 1.334, etc.
98
+ (@four.div(@three,20)).ceil(n).should == BigDecimal("1.#{'3'*(n-1)}4")
99
+ (BigDecimal('31').div(@three,20)).ceil(n).should == BigDecimal("10.#{'3'*(n-1)}4")
100
+ end
101
+ (1..10).each do |n|
102
+ # -0.4, -0.34, -0.334, etc.
103
+ (-@one.div(@three,20)).ceil(n).should == BigDecimal("-0.#{'3'* n}")
104
+ end
105
+ (1..10).each do |n|
106
+ (@three.div(@one,20)).ceil(n).should == @three
107
+ end
108
+ (1..10).each do |n|
109
+ (-@three.div(@one,20)).ceil(n).should == -@three
110
+ end
111
+ end
112
+
113
+ it "sets n digits left of the decimal point to 0, if given n < 0" do
114
+ BigDecimal("13345.234").ceil(-2).should == BigDecimal("13400.0")
115
+ @mixed_big.ceil(-99).should == BigDecimal("0.13E101")
116
+ @mixed_big.ceil(-100).should == BigDecimal("0.2E101")
117
+ @mixed_big.ceil(-95).should == BigDecimal("0.123457E101")
118
+ BigDecimal("1E10").ceil(-30).should == BigDecimal('1E30')
119
+ BigDecimal("-1E10").ceil(-30).should == @zero
120
+ end
121
+
122
+ end
@@ -0,0 +1,25 @@
1
+ require 'bigdecimal'
2
+
3
+ describe "BigDecimal#coerce" do
4
+
5
+ it "returns [other, self] both as BigDecimal" do
6
+ one = BigDecimal("1.0")
7
+ five_point_28 = BigDecimal("5.28")
8
+ zero_minus = BigDecimal("-0.0")
9
+ some_value = 32434234234234234234
10
+
11
+ BigDecimal("1.2").coerce(1).should == [one, BigDecimal("1.2")]
12
+ five_point_28.coerce(1.0).should == [one, BigDecimal("5.28")]
13
+ one.coerce(one).should == [one, one]
14
+ one.coerce(2.5).should == [2.5, one]
15
+ BigDecimal("1").coerce(3.14).should == [3.14, one]
16
+ a, b = zero_minus.coerce(some_value)
17
+ a.should == BigDecimal(some_value.to_s)
18
+ b.should == zero_minus
19
+ a, b = one.coerce(some_value)
20
+ a.should == BigDecimal(some_value.to_s)
21
+ b.to_f.should be_close(1.0, TOLERANCE) # can we take out the to_f once BigDecimal#- is implemented?
22
+ b.should == one
23
+ end
24
+
25
+ end
@@ -0,0 +1,80 @@
1
+ require 'bigdecimal'
2
+
3
+ describe "BigDecimal#<=>" do
4
+ before(:each) do
5
+ @zero = BigDecimal("0")
6
+ @zero_pos = BigDecimal("+0")
7
+ @zero_neg = BigDecimal("-0")
8
+ @mixed = BigDecimal("1.23456789")
9
+ @mixed_big = BigDecimal("1.23456789E100")
10
+ @pos_int = BigDecimal("2E5555")
11
+ @neg_int = BigDecimal("-2E5555")
12
+ @pos_frac = BigDecimal("2E-9999")
13
+ @neg_frac = BigDecimal("-2E-9999")
14
+
15
+ @int_mock = mock('123')
16
+ class << @int_mock
17
+ def coerce(other)
18
+ return [other, BigDecimal('123')]
19
+ end
20
+ def >= (other)
21
+ BigDecimal('123') >= other
22
+ end
23
+ end
24
+
25
+ @values = [@mixed, @pos_int, @neg_int, @pos_frac, @neg_frac,
26
+ -2**32, -2**31, -2**30, -2**16, -2**8, -100, -10, -1,
27
+ @zero , 1, 2, 10, 2**8, 2**16, 2**32, @int_mock, @zero_pos, @zero_neg]
28
+
29
+ @infinity = BigDecimal("Infinity")
30
+ @infinity_neg = BigDecimal("-Infinity")
31
+ @nan = BigDecimal("NaN")
32
+ end
33
+
34
+
35
+ it "returns 0 if a == b" do
36
+ (@pos_int <=> @pos_int).should == 0
37
+ (@neg_int <=> @neg_int).should == 0
38
+ (@pos_frac <=> @pos_frac).should == 0
39
+ (@neg_frac <=> @neg_frac).should == 0
40
+ (@zero <=> @zero).should == 0
41
+ (@infinity <=> @infinity).should == 0
42
+ (@infinity_neg <=> @infinity_neg).should == 0
43
+ end
44
+
45
+ it "returns 1 if a > b" do
46
+ (@pos_int <=> @neg_int).should == 1
47
+ (@pos_frac <=> @neg_frac).should == 1
48
+ (@pos_frac <=> @zero).should == 1
49
+ @values.each { |val|
50
+ (@infinity <=> val).should == 1
51
+ }
52
+ end
53
+
54
+ it "returns -1 if a < b" do
55
+ (@zero <=> @pos_frac).should == -1
56
+ (@neg_int <=> @pos_frac).should == -1
57
+ (@pos_frac <=> @pos_int).should == -1
58
+ @values.each { |val|
59
+ (@infinity_neg <=> val).should == -1
60
+ }
61
+ end
62
+
63
+ it "returns nil if NaN is involved" do
64
+ @values += [@infinity, @infinity_neg, @nan]
65
+ @values << nil
66
+ @values << Object.new
67
+ @values.each { |val|
68
+ (@nan <=> val).should == nil
69
+ }
70
+ end
71
+
72
+ it "returns nil if the argument is nil" do
73
+ (@zero <=> nil).should == nil
74
+ (@infinity <=> nil).should == nil
75
+ (@infinity_neg <=> nil).should == nil
76
+ (@mixed <=> nil).should == nil
77
+ (@pos_int <=> nil).should == nil
78
+ (@neg_frac <=> nil).should == nil
79
+ end
80
+ end
data/spec/div_spec.rb ADDED
@@ -0,0 +1,143 @@
1
+ require File.expand_path('../shared/quo', __FILE__)
2
+ require 'bigdecimal'
3
+
4
+ describe "BigDecimal#div with precision set to 0" do
5
+ # TODO: figure out if there is a better way to do these
6
+ # shared specs rather than sending [0]. See other specs
7
+ # that share :bigdecimal_quo.
8
+ it_behaves_like :bigdecimal_quo, :div, [0]
9
+ end
10
+
11
+ describe "BigDecimal#div" do
12
+
13
+ before(:each) do
14
+ @one = BigDecimal("1")
15
+ @zero = BigDecimal("0")
16
+ @zero_plus = BigDecimal("+0")
17
+ @zero_minus = BigDecimal("-0")
18
+ @two = BigDecimal("2")
19
+ @three = BigDecimal("3")
20
+ @nan = BigDecimal("NaN")
21
+ @infinity = BigDecimal("Infinity")
22
+ @infinity_minus = BigDecimal("-Infinity")
23
+ @one_minus = BigDecimal("-1")
24
+ @frac_1 = BigDecimal("1E-99999")
25
+ @frac_2 = BigDecimal("0.9E-99999")
26
+ end
27
+
28
+ it "returns a / b with optional precision" do
29
+ @two.div(@one).should == @two
30
+ @one.div(@two).should == @zero
31
+ # ^^ is this really intended for a class with arbitrary precision?
32
+ @one.div(@two, 1).should == BigDecimal("0.5")
33
+ @one.div(@one_minus).should == @one_minus
34
+ @one_minus.div(@one_minus).should == @one
35
+ @frac_2.div(@frac_1, 1).should == BigDecimal("0.9")
36
+ @frac_1.div(@frac_1).should == @one
37
+
38
+ res = "0." + "3" * 1000
39
+ (1..100).each { |idx|
40
+ @one.div(@three, idx).to_s("F").should == "0." + res[2, idx]
41
+ }
42
+ end
43
+
44
+ ruby_version_is "" ... "1.9" do
45
+ it "returns NaN if NaN is involved" do
46
+ @one.div(@nan).nan?.should == true
47
+ @nan.div(@one).nan?.should == true
48
+ end
49
+
50
+ it "returns NaN if divided by Infinity and no precision given" do
51
+ @zero.div(@infinity).nan?.should == true
52
+ @frac_2.div(@infinity).nan?.should == true
53
+ end
54
+ end
55
+
56
+ ruby_version_is "1.9" do
57
+ it "raises FloatDomainError if NaN is involved" do
58
+ lambda { @one.div(@nan) }.should raise_error(FloatDomainError)
59
+ lambda { @nan.div(@one) }.should raise_error(FloatDomainError)
60
+ end
61
+
62
+ it "returns 0 if divided by Infinity and no precision given" do
63
+ @zero.div(@infinity).should == 0
64
+ @frac_2.div(@infinity).should == 0
65
+ end
66
+ end
67
+
68
+ it "returns 0 if divided by Infinity with given precision" do
69
+ @zero.div(@infinity, 0).should == 0
70
+ @frac_2.div(@infinity, 1).should == 0
71
+ @zero.div(@infinity, 100000).should == 0
72
+ @frac_2.div(@infinity, 100000).should == 0
73
+ end
74
+
75
+ ruby_version_is "" ... "1.9" do
76
+ it "returns NaN if divided by zero and no precision given" do
77
+ @one.div(@zero).nan?.should == true
78
+ @one.div(@zero_plus).nan?.should == true
79
+ @one.div(@zero_minus).nan?.should == true
80
+ end
81
+
82
+ it "returns NaN if zero is divided by zero" do
83
+ @zero.div(@zero).nan?.should == true
84
+ @zero_minus.div(@zero_plus).nan?.should == true
85
+ @zero_plus.div(@zero_minus).nan?.should == true
86
+
87
+ @zero.div(@zero, 0).nan?.should == true
88
+ @zero_minus.div(@zero_plus, 0).nan?.should == true
89
+ @zero_plus.div(@zero_minus, 0).nan?.should == true
90
+
91
+ @zero.div(@zero, 10).nan?.should == true
92
+ @zero_minus.div(@zero_plus, 10).nan?.should == true
93
+ @zero_plus.div(@zero_minus, 10).nan?.should == true
94
+ end
95
+
96
+ it "returns NaN if (+|-) Infinity divided by 1 and no precision given" do
97
+ @infinity_minus.div(@one).nan?.should == true
98
+ @infinity.div(@one).nan?.should == true
99
+ @infinity_minus.div(@one_minus).nan?.should == true
100
+ end
101
+ end
102
+
103
+ ruby_version_is "1.9" do
104
+ it "raises ZeroDivisionError if divided by zero and no precision given" do
105
+ lambda { @one.div(@zero) }.should raise_error(ZeroDivisionError)
106
+ lambda { @one.div(@zero_plus) }.should raise_error(ZeroDivisionError)
107
+ lambda { @one.div(@zero_minus) }.should raise_error(ZeroDivisionError)
108
+
109
+ lambda { @zero.div(@zero) }.should raise_error(ZeroDivisionError)
110
+ lambda { @zero_minus.div(@zero_plus) }.should raise_error(ZeroDivisionError)
111
+ lambda { @zero_plus.div(@zero_minus) }.should raise_error(ZeroDivisionError)
112
+ end
113
+
114
+ it "returns NaN if zero is divided by zero" do
115
+ @zero.div(@zero, 0).nan?.should == true
116
+ @zero_minus.div(@zero_plus, 0).nan?.should == true
117
+ @zero_plus.div(@zero_minus, 0).nan?.should == true
118
+
119
+ @zero.div(@zero, 10).nan?.should == true
120
+ @zero_minus.div(@zero_plus, 10).nan?.should == true
121
+ @zero_plus.div(@zero_minus, 10).nan?.should == true
122
+ end
123
+
124
+ it "raises FloatDomainError if (+|-) Infinity divided by 1 and no precision given" do
125
+ lambda { @infinity_minus.div(@one) }.should raise_error(FloatDomainError)
126
+ lambda { @infinity.div(@one) }.should raise_error(FloatDomainError)
127
+ lambda { @infinity_minus.div(@one_minus) }.should raise_error(FloatDomainError)
128
+ end
129
+ end
130
+
131
+ it "returns (+|-)Infinity if (+|-)Infinity by 1 and precision given" do
132
+ @infinity_minus.div(@one, 0).should == @infinity_minus
133
+ @infinity.div(@one, 0).should == @infinity
134
+ @infinity_minus.div(@one_minus, 0).should == @infinity
135
+ end
136
+
137
+ it "returns NaN if Infinity / ((+|-) Infinity)" do
138
+ @infinity.div(@infinity_minus, 100000).nan?.should == true
139
+ @infinity_minus.div(@infinity, 1).nan?.should == true
140
+ end
141
+
142
+
143
+ end
@@ -0,0 +1,6 @@
1
+ require File.expand_path('../shared/quo', __FILE__)
2
+ require 'bigdecimal'
3
+
4
+ describe "BigDecimal#/" do
5
+ it_behaves_like :bigdecimal_quo, :/, []
6
+ end
@@ -0,0 +1,233 @@
1
+ require File.expand_path('../shared/modulo', __FILE__)
2
+ require 'bigdecimal'
3
+
4
+ module DivmodSpecs
5
+ def self.check_both_nan(array)
6
+ array.length.should == 2
7
+ array[0].nan?.should == true
8
+ array[1].nan?.should == true
9
+ end
10
+ def self.check_both_bigdecimal(array)
11
+ array.length.should == 2
12
+ array[0].kind_of?(BigDecimal).should == true
13
+ array[1].kind_of?(BigDecimal).should == true
14
+ end
15
+ end
16
+
17
+ # TODO: figure out a way to do the shared specs with helpers instead
18
+ # of spec'ing a method that does not really exist
19
+ describe "BigDecimal#mod_part_of_divmod" do
20
+ # BigDecimal#divmod[1] behaves exactly like #modulo
21
+ before :all do
22
+ class BigDecimal
23
+ def mod_part_of_divmod(arg)
24
+ divmod(arg)[1]
25
+ end
26
+ end
27
+ end
28
+
29
+ after :all do
30
+ class BigDecimal
31
+ undef mod_part_of_divmod
32
+ end
33
+ end
34
+
35
+ it_behaves_like :bigdecimal_modulo, :mod_part_of_divmod
36
+
37
+ ruby_version_is "" ... "1.9" do
38
+ it "does NOT raise ZeroDivisionError if other is zero" do
39
+ bd6543 = BigDecimal.new("6543.21")
40
+ bd5667 = BigDecimal.new("5667.19")
41
+ a = BigDecimal("1.0000000000000000000000000000000000000000005")
42
+ b = BigDecimal("1.00000000000000000000000000000000000000000005")
43
+
44
+ bd5667.send(@method, 0).nan?.should == true
45
+ bd5667.send(@method, BigDecimal("0")).nan?.should == true
46
+ @zero.send(@method, @zero).nan?.should == true
47
+ end
48
+ end
49
+
50
+ ruby_version_is "1.9" do
51
+ it "raises ZeroDivisionError if other is zero" do
52
+ bd6543 = BigDecimal.new("6543.21")
53
+ bd5667 = BigDecimal.new("5667.19")
54
+ a = BigDecimal("1.0000000000000000000000000000000000000000005")
55
+ b = BigDecimal("1.00000000000000000000000000000000000000000005")
56
+
57
+ lambda { bd5667.send(@method, 0) }.should raise_error(ZeroDivisionError)
58
+ lambda { bd5667.send(@method, BigDecimal("0")) }.should raise_error(ZeroDivisionError)
59
+ lambda { @zero.send(@method, @zero) }.should raise_error(ZeroDivisionError)
60
+ end
61
+ end
62
+ end
63
+
64
+ describe "BigDecimal#divmod" do
65
+
66
+ before(:each) do
67
+ @a = BigDecimal("42.00000000000000000001")
68
+
69
+ @zero = BigDecimal("0")
70
+ @zero_pos = BigDecimal("+0")
71
+ @zero_neg = BigDecimal("-0")
72
+
73
+ @one = BigDecimal("1")
74
+ @mixed = BigDecimal("1.23456789")
75
+ @pos_int = BigDecimal("2E5555")
76
+ @neg_int = BigDecimal("-2E5555")
77
+ @pos_frac = BigDecimal("2E-9999")
78
+ @neg_frac = BigDecimal("-2E-9999")
79
+ @nan = BigDecimal("NaN")
80
+ @infinity = BigDecimal("Infinity")
81
+ @infinity_minus = BigDecimal("-Infinity")
82
+ @one_minus = BigDecimal("-1")
83
+ @frac_1 = BigDecimal("1E-99999")
84
+ @frac_2 = BigDecimal("0.9E-99999")
85
+
86
+ @special_vals = [@infinity, @infinity_minus, @nan]
87
+ @regular_vals = [
88
+ @one, @mixed, @pos_int, @neg_int, @pos_frac,
89
+ @neg_frac, @one_minus, @frac_1, @frac_2]
90
+ @zeroes = [@zero, @zero_pos, @zero_neg]
91
+ end
92
+
93
+ it "divides value, returns an array" do
94
+ res = @a.divmod(5)
95
+ res.kind_of?(Array).should == true
96
+ end
97
+
98
+ it "array contains quotient and modulus as BigDecimal" do
99
+ res = @a.divmod(5)
100
+ DivmodSpecs::check_both_bigdecimal(res)
101
+ res[0].should == BigDecimal('0.8E1')
102
+ res[1].should == BigDecimal('2.00000000000000000001')
103
+
104
+ BigDecimal('1').divmod(BigDecimal('2')).should == [0, 1]
105
+ BigDecimal('2').divmod(BigDecimal('1')).should == [2, 0]
106
+
107
+ BigDecimal('1').divmod(BigDecimal('-2')).should == [-1, -1]
108
+ BigDecimal('2').divmod(BigDecimal('-1')).should == [-2, 0]
109
+
110
+ BigDecimal('-1').divmod(BigDecimal('2')).should == [-1, 1]
111
+ BigDecimal('-2').divmod(BigDecimal('1')).should == [-2, 0]
112
+ end
113
+
114
+ it "Can be reversed with * and +" do
115
+ # Example taken from BigDecimal documentation
116
+ a = BigDecimal.new("42")
117
+ b = BigDecimal.new("9")
118
+ q, m = a.divmod(b)
119
+ c = q * b + m
120
+ a.should == c
121
+
122
+ values = [@one, @one_minus, BigDecimal('2'), BigDecimal('-2'),
123
+ BigDecimal('5'), BigDecimal('-5'), BigDecimal('10'), BigDecimal('-10'),
124
+ BigDecimal('20'), BigDecimal('-20'), BigDecimal('100'), BigDecimal('-100'),
125
+ BigDecimal('1.23456789E10'), BigDecimal('-1.23456789E10')
126
+ ]
127
+
128
+ # TODO: file MRI bug:
129
+ # BigDecimal('1').divmod(BigDecimal('3E-9'))[0] #=> 0.3E9,
130
+ # but really should be 0.333333333E9
131
+ ruby_bug "#206", "1.8" do #MRI's precision is very low in some cases
132
+ values << BigDecimal('1E-10')
133
+ values << BigDecimal('-1E-10')
134
+ values << BigDecimal('2E55')
135
+ values << BigDecimal('-2E55')
136
+ values << BigDecimal('2E-5555')
137
+ values << BigDecimal('-2E-5555')
138
+
139
+
140
+ values_and_zeroes = values + @zeroes
141
+ values_and_zeroes.each do |val1|
142
+ values.each do |val2|
143
+ res = val1.divmod(val2)
144
+ DivmodSpecs::check_both_bigdecimal(res)
145
+ res[0].should == ((val1/val2).floor)
146
+ res[1].should == (val1 - res[0] * val2)
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ ruby_version_is "" ... "1.9" do
153
+ it "properly handles special values" do
154
+ values = @special_vals + @zeroes
155
+ values.each do |val1|
156
+ values.each do |val2|
157
+ DivmodSpecs::check_both_nan(val1.divmod(val2))
158
+ end
159
+ end
160
+
161
+ @special_vals.each do |val1|
162
+ @regular_vals.each do |val2|
163
+ DivmodSpecs::check_both_nan(val1.divmod(val2))
164
+ end
165
+ end
166
+
167
+ @regular_vals.each do |val1|
168
+ @special_vals.each do |val2|
169
+ DivmodSpecs::check_both_nan(val1.divmod(val2))
170
+ end
171
+ end
172
+ end
173
+
174
+ it "returns an array of two NaNs if the argument is zero" do
175
+ values = @regular_vals + @special_vals
176
+ values.each do |val1|
177
+ @zeroes.each do |val2|
178
+ DivmodSpecs::check_both_nan(val1.divmod(val2))
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ ruby_version_is "1.9" do
185
+ it "returns an array of two NaNs if NaN is involved" do
186
+ (@special_vals + @regular_vals + @zeroes).each do |val|
187
+ DivmodSpecs::check_both_nan(val.divmod(@nan))
188
+ DivmodSpecs::check_both_nan(@nan.divmod(val))
189
+ end
190
+ end
191
+
192
+ it "raises ZeroDivisionError if the divisor is zero" do
193
+ (@special_vals + @regular_vals + @zeroes - [@nan]).each do |val|
194
+ @zeroes.each do |zero|
195
+ lambda { val.divmod(zero) }.should raise_error(ZeroDivisionError)
196
+ end
197
+ end
198
+ end
199
+
200
+ it "returns an array of Infinity and NaN if the dividend is Infinity" do
201
+ @regular_vals.each do |val|
202
+ array = @infinity.divmod(val)
203
+ array.length.should == 2
204
+ array[0].infinite?.should == (val > 0 ? 1 : -1)
205
+ array[1].nan?.should == true
206
+ end
207
+ end
208
+
209
+ it "returns an array of zero and the dividend if the divisor is Infinity" do
210
+ @regular_vals.each do |val|
211
+ array = val.divmod(@infinity)
212
+ array.length.should == 2
213
+ array[0].should == @zero
214
+ array[1].should == val
215
+ end
216
+ end
217
+
218
+ it "returns an array of two zero if the diviend is zero" do
219
+ @zeroes.each do |zero|
220
+ @regular_vals.each do |val|
221
+ zero.divmod(val).should == [@zero, @zero]
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+ it "raises TypeError if the argument cannot be coerced to BigDecimal" do
228
+ lambda {
229
+ @one.divmod('1')
230
+ }.should raise_error(TypeError)
231
+ end
232
+
233
+ end