ruby-decimal 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/helper.rb'
2
+
3
+ class TestCoercion < Test::Unit::TestCase
4
+
5
+
6
+ def setup
7
+ initialize_context
8
+ end
9
+
10
+ def test_coerce
11
+ assert_equal Decimal('7.1'), Decimal('0.1') + 7
12
+ assert_equal Decimal('7.1'), 7 + Decimal('0.1')
13
+ assert_equal Decimal('14'), Decimal(7) * 2
14
+ assert_equal Decimal('14'), 2 * Decimal(7)
15
+
16
+ assert_equal Decimal('7.1'), Decimal(7) + Rational(1,10)
17
+ assert_equal Decimal('7.1'), Rational(1,10) + Decimal(7)
18
+ assert_equal Decimal('1.4'), Decimal(7) * Rational(2,10)
19
+ assert_equal Decimal('1.4'), Rational(2,10) * Decimal(7)
20
+ end
21
+
22
+ end
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/helper.rb'
2
+
3
+ class TestComparisons < Test::Unit::TestCase
4
+
5
+
6
+ def setup
7
+ initialize_context
8
+ end
9
+
10
+ def test_hash
11
+ assert_equal Decimal('1.1').hash, Decimal('1.1').hash
12
+ assert_equal Decimal('1.1').hash, (Decimal('1.0')+Decimal('0.1')).hash
13
+ assert_equal Decimal('1.1',:precision=>10).hash, Decimal('1.1',:precision=>3).hash
14
+ assert_not_equal Decimal('1.0').hash, Decimal('1.1').hash
15
+ assert_not_equal Decimal('1.0').hash, 1.0.hash
16
+ assert_not_equal Decimal('1.0').hash, 1.hash
17
+
18
+ assert Decimal('1.1').eql?(Decimal('1.1'))
19
+ assert Decimal('1.1').eql?(Decimal('1.0')+Decimal('0.1'))
20
+ assert Decimal('1.1',:precision=>10).eql?(Decimal('1.1',:precision=>3))
21
+ assert !Decimal('1.1').eql?(Decimal('1.0'))
22
+ assert !Decimal('1.0').eql?(1.0)
23
+ assert !Decimal('1.0').eql?(1)
24
+ end
25
+
26
+ def test_equality
27
+ assert Decimal('1.1') == Decimal('1.1')
28
+ assert Decimal('1.1') == (Decimal('1.0')+Decimal('0.1'))
29
+ assert Decimal('1.1',:precision=>10) == Decimal('1.1',:precision=>3)
30
+ assert !(Decimal('1.1') == Decimal('1.0'))
31
+ #assert Decimal('1.1') == 1.1
32
+ #assert Decimal('1.0') == 1.0
33
+ #assert Decimal('1.0') == BigDecimal.new('1.000')
34
+ assert Decimal('1.0') == 1
35
+ assert Decimal('0.1') == Rational(1)/Rational(10)
36
+
37
+ assert !(Decimal.nan == Decimal.nan)
38
+ assert !(Decimal.nan == Decimal('1'))
39
+ assert !(Decimal.nan == Decimal('0'))
40
+ assert !(Decimal.nan == Decimal.infinity)
41
+ #assert !(Decimal.nan == (0.0/0.0))
42
+
43
+ assert !(Decimal.infinity(+1) == Decimal.infinity(-1))
44
+ assert !(Decimal.infinity(+1) == Decimal('0'))
45
+ assert Decimal.infinity(+1) == Decimal.infinity
46
+ assert Decimal.infinity(+1) == Decimal('1')/Decimal('0')
47
+ assert Decimal.infinity(-1) == Decimal('-1')/Decimal('0')
48
+
49
+ # TODO: test <=> <= etc.
50
+ end
51
+
52
+
53
+ end
@@ -0,0 +1,207 @@
1
+ require File.dirname(__FILE__) + '/helper.rb'
2
+
3
+ ROUNDINGS = {
4
+ 'ceiling' => :ceiling,
5
+ 'down' => :down,
6
+ 'floor' => :floor,
7
+ 'half_down' => :half_down,
8
+ 'half_even' => :half_even,
9
+ 'half_up' => :half_up,
10
+ 'up' => :up,
11
+ '05up' => :up05
12
+ }
13
+ FUNCTIONS = {
14
+ 'add'=>'add',
15
+ 'divide'=>'divide',
16
+ 'multiply'=>'multiply',
17
+ 'subtract'=>'subtract',
18
+ 'compare'=>'compare',
19
+ 'copyabs'=>'copy_abs',
20
+ 'copynegate'=>'copy_negate',
21
+ 'copysign'=>'copy_sign',
22
+ 'divideint'=>'divide_int',
23
+ 'logb'=>'logb',
24
+ 'minus'=>'minus',
25
+ 'plus'=>'plus',
26
+ 'reduce'=>'reduce',
27
+ 'remainder'=>'remainder',
28
+ 'remaindernear'=>'remainder_near',
29
+ 'scaleb'=>'scaleb',
30
+ 'rescale'=>'rescale',
31
+ 'quantize'=>'quantize',
32
+ 'samequantum'=>'same_quantum?',
33
+ 'tointegral'=>'to_integral_value',
34
+ 'tointegralx'=>'to_integral_exact',
35
+ 'fma'=>'fma',
36
+ 'squareroot'=>'sqrt',
37
+ 'abs'=>'abs',
38
+ 'nextminus'=>'next_minus',
39
+ 'nextplus'=>'next_plus',
40
+ 'nexttoward'=>'next_toward',
41
+ 'tosci'=>'to_sci_string',
42
+ 'toeng'=>'to_eng_string',
43
+ 'class'=>'number_class'
44
+ }
45
+ # Functions not yet implemented
46
+ PENDING = %w{
47
+ exp
48
+ power
49
+ ln
50
+ log10
51
+
52
+ rotate
53
+ shift
54
+ trim
55
+
56
+ and
57
+ or
58
+ xor
59
+ invert
60
+
61
+ max
62
+ min
63
+ maxmag
64
+ minmag
65
+ comparetotal
66
+ comparetotmag
67
+ }
68
+ IGNORED = PENDING + %w{
69
+ copy
70
+ apply
71
+ }
72
+
73
+ FLAG_NAMES = {
74
+ 'inexact'=>:Inexact,
75
+ 'rounded'=>:Rounded,
76
+ 'clamped'=>:Clamped,
77
+ 'subnormal'=>:Subnormal,
78
+ 'invalid_operation'=>:InvalidOperation,
79
+ 'underflow'=>:Underflow,
80
+ 'overflow'=>:Overflow,
81
+ 'division_by_zero'=>:DivisionByZero,
82
+ 'division_undefined'=>:InvalidOperation,
83
+ 'division_impossible'=>:DivisionImpossible,
84
+ 'conversion_syntax'=>:ConversionSyntax
85
+ }
86
+
87
+
88
+
89
+ def unquote(txt)
90
+ if txt[0,1]=="'" && txt[-1,1]=="'"
91
+ txt = txt[1...-1].gsub("''","'")
92
+ end
93
+ if txt[0,1]=='"' && txt[-1,1]=='"'
94
+ txt = txt[1...-1].gsub('""','"')
95
+ end
96
+ #txt = 'NaN' if txt=='#' || txt=='?'
97
+ txt = 'sNaN' if txt=='#'
98
+ txt = 'NaN' if txt=='?'
99
+ txt
100
+ end
101
+
102
+ class TestBasic < Test::Unit::TestCase
103
+
104
+ def test_dec
105
+ missing = []
106
+ dir = File.join(File.dirname(__FILE__), 'dectest')
107
+ dir = nil unless File.exists?(dir)
108
+ if dir
109
+ Dir[File.join(dir, '*.decTest')].each do |fn|
110
+
111
+ name = File.basename(fn,'.decTest').downcase
112
+ next if %w{ds dd dq}.include?(name[0,2]) ||
113
+ %w{decsingle decdouble decquad testall}.include?(name)
114
+
115
+ initialize_context
116
+
117
+
118
+ File.open(fn,'r') do |file|
119
+ file.each_line do |line|
120
+ next if line[0,2]=='--' || line.strip.empty?
121
+
122
+ if line.include?(' -> ')
123
+ # test
124
+ # to do :remove inline comments --... on the right of ->
125
+ sides = line.split('->')
126
+ # now split by whitespace but avoid breaking quoted strings (and take care or repeated quotes!)
127
+ lhs = sides.first.strip.scan(/"(?:[^"]|"")*"|'(?:[^']|'')*'|\S+/)
128
+ id = lhs.first
129
+ funct = lhs[1].downcase
130
+ valstemp = lhs[2..-1]
131
+ rhs = sides.last.strip.split
132
+ ans = rhs.first
133
+ flags = rhs[1..-1].map{|f| Decimal.class_eval(FLAG_NAMES[f.downcase].to_s)}.compact
134
+
135
+ next unless valstemp.grep(/#/).empty?
136
+
137
+ $test_id = id
138
+ funct = FUNCTIONS[original_funct=funct]
139
+ if funct
140
+ # do test
141
+ msg = "Test #{id}: #{funct}(#{valstemp.join(',')}) = #{ans}"
142
+ #File.open('dectests.txt','a'){|f| f.puts msg}
143
+ expected = result = result_flags = nil
144
+ Decimal.local_context do |context|
145
+ context.flags.clear!
146
+ exact_input = !['apply','to_sci_string', 'to_eng_string'].include?(funct)
147
+ if exact_input
148
+ p = context.precision
149
+ context.exact = true
150
+ end
151
+ valstemp.map!{|v| Decimal(unquote(v))}
152
+ context.precision = p if exact_input
153
+ result = context.send(funct, *valstemp)
154
+ result_flags = context.flags.dup
155
+ expected = unquote(ans)
156
+ context.exact = true
157
+ expected = Decimal(expected) unless result.is_a?(String)
158
+ end
159
+ result = 1 if result==true
160
+ result = 0 if result==false
161
+ expected_flags = Decimal::Flags(*flags)
162
+ if ans!='?'
163
+ assert_equal expected.to_s, result.to_s, msg
164
+ end
165
+ assert_equal expected_flags, result_flags, msg
166
+
167
+ else
168
+ missing << original_funct unless IGNORED.include?(original_funct) || missing.include?(original_funct)
169
+ end
170
+
171
+ elsif line.include?(':')
172
+ # directive
173
+ funct,value = line.split(':').map{|x| x.strip.downcase}
174
+ case funct
175
+ when 'rounding'
176
+ value = ROUNDINGS[value]
177
+ else
178
+ value = value.to_i
179
+ end
180
+ if value.nil?
181
+ #raise "error"
182
+ # to do: skip untill next valid value of same funct
183
+ else
184
+ case funct
185
+ when 'rounding','precision'
186
+ Decimal.context.send "#{funct}=", value
187
+ when 'maxexponent'
188
+ Decimal.context.emax = value
189
+ when 'minexponent'
190
+ Decimal.context.emin = value
191
+ when 'clamp'
192
+ Decimal.context.clamp = (value==0 ? false : true)
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ # assert_empty missing
202
+ # In Ruby 1.8 there's no assert_empty
203
+ assert missing.empty?, "#{missing.inspect} is not empty"
204
+
205
+ end
206
+
207
+ end
@@ -0,0 +1,100 @@
1
+ require File.dirname(__FILE__) + '/helper.rb'
2
+
3
+ class TestDefineConversions < Test::Unit::TestCase
4
+
5
+
6
+ def setup
7
+ initialize_context
8
+ end
9
+
10
+ def test_convert_to
11
+ d = Decimal('1.1')
12
+ x = d.convert_to(Rational)
13
+ assert x.is_a?(Rational)
14
+ assert_equal d.to_r, x
15
+
16
+ d = Decimal('11')
17
+ x = d.convert_to(Integer)
18
+ assert x.is_a?(Integer)
19
+ assert_equal d.to_i, x
20
+
21
+ d = Decimal('11')
22
+ x = d.convert_to(Float)
23
+ assert x.is_a?(Float)
24
+ assert_equal d.to_f, x
25
+ end
26
+
27
+
28
+ def test_big_decimal_conversions
29
+
30
+ Decimal.local_context do
31
+
32
+ Decimal.context.define_conversion_from(BigDecimal) do |x, context|
33
+ Decimal(x.to_s) # or use x.split etc.
34
+ end
35
+ assert Decimal('0') == BigDecimal.new('0')
36
+ assert_equal BigDecimal.new('0'), Decimal('0')
37
+ assert_equal BigDecimal.new('1.2345'), Decimal('1.2345')
38
+ assert_equal BigDecimal.new('-1.2345'), Decimal('-1.2345')
39
+ assert_equal BigDecimal.new('1.2345'), Decimal('0.0012345000E3')
40
+ assert_equal Decimal('7.1'), BigDecimal.new('7')+Decimal('0.1')
41
+ assert_equal Decimal('7.1'), Decimal('7')+BigDecimal.new('0.1')
42
+ assert_equal Decimal('1.1'), Decimal(BigDecimal.new('1.1'))
43
+ assert Decimal(BigDecimal.new('1.1')).is_a?(Decimal)
44
+
45
+ Decimal.context.define_conversion_to(BigDecimal) do |x|
46
+ BigDecimal.new(x.to_s) # TODO: use x.split and handle special values
47
+ end
48
+
49
+ ['0.1', '-0.1', '0.0', '1234567.1234567', '-1234567.1234567', '1.234E7', '1.234E-7'].each do |n|
50
+ f = BigDecimal.new(n)
51
+ d = Decimal(n)
52
+ c = d.convert_to(BigDecimal)
53
+ assert c.is_a?(BigDecimal)
54
+ assert_equal f, c
55
+ end
56
+ end
57
+
58
+ assert_raise(TypeError) { Decimal('0') == BigDecimal.new('0') }
59
+ assert_not_equal BigDecimal.new('0'), Decimal('0')
60
+ assert_not_equal BigDecimal.new('1.2345'), Decimal('1.2345')
61
+ assert_not_equal BigDecimal.new('-1.2345'), Decimal('-1.2345')
62
+ assert_not_equal BigDecimal.new('1.2345'), Decimal('0.0012345000E3')
63
+ assert_raise(TypeError) { BigDecimal.new('7')+Decimal('0.1') }
64
+ assert_raise(TypeError) { Decimal('7')+BigDecimal.new('0.1') }
65
+ assert_raise(TypeError) { Decimal(BigDecimal.new('1.1')) }
66
+
67
+ ['0.1', '-0.1', '0.0', '1234567.1234567', '-1234567.1234567', '1.234E7', '1.234E-7'].each do |n|
68
+ assert_raise(TypeError) { Decimal(n).convert_to(BigDecimal) }
69
+ end
70
+
71
+ end
72
+
73
+ def test_float_conversions
74
+
75
+ # Exact Float to Decimal conversion limited to context precision
76
+ # => Decimal('0.1') != Decimal(0.1) unless precision is low enough
77
+ Decimal.context.define_conversion_from(Float) do |x, context|
78
+ s,e = Math.frexp(x)
79
+ significand = Math.ldexp(s, Float::MANT_DIG).to_i
80
+ exponent = e - Float::MANT_DIG
81
+ # the number is (as a Rational) significand * exponent**Float::RADIX
82
+ Decimal(significand*(Float::RADIX**exponent ))
83
+ end
84
+
85
+ assert_equal 0.0, Decimal('0')
86
+ assert_equal Decimal('0'), 0.0
87
+ assert_equal 1234.5, Decimal('1234.5')
88
+ assert_equal Decimal('1234.5'), 1234.5
89
+ assert_equal(-1234.5, Decimal('-1234.5'))
90
+ assert_equal 1234.5, Decimal('0.0012345000E6')
91
+ assert_equal Decimal('7.1'), 7.0+Decimal('0.1')
92
+ Decimal.local_context(:precision=>12) do
93
+ assert_equal Decimal('7.1'), Decimal('7')+0.1
94
+ end
95
+ assert_equal Decimal('11'), Decimal(11.0)
96
+ assert Decimal(11.0).is_a?(Decimal)
97
+
98
+ end
99
+
100
+ end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/helper.rb'
2
+
3
+
4
+ class TestExact < Test::Unit::TestCase
5
+
6
+
7
+ def setup
8
+ initialize_context
9
+ end
10
+
11
+
12
+ def test_exact
13
+
14
+ Decimal.context.exact = true
15
+
16
+ assert_equal Decimal("9"*100+"E-50"), Decimal('1E50')-Decimal('1E-50')
17
+ assert_equal Decimal(2),Decimal(6)/Decimal(3)
18
+ assert_equal Decimal('1.5'),Decimal(6)/Decimal(4)
19
+ assert_equal Decimal('15241578780673678546105778281054720515622620750190521'), Decimal('123456789123456789123456789')*Decimal('123456789123456789123456789')
20
+ assert_nothing_raised(Decimal::Inexact){ Decimal(6)/Decimal(4) }
21
+ assert_raise(Decimal::Inexact){ Decimal(1)/Decimal(3) }
22
+ # assert_raise(Decimal::Inexact){ Decimal(2).sqrt }
23
+
24
+ assert_equal Decimal(2), Decimal('4').sqrt
25
+ assert_equal Decimal(4), Decimal('16').sqrt
26
+ assert_raise(Decimal::Inexact){ Decimal(2).sqrt }
27
+
28
+
29
+ end
30
+
31
+
32
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/helper.rb'
2
+
3
+
4
+ class TestFlags < Test::Unit::TestCase
5
+
6
+ def test_flags
7
+ f = DecimalSupport::Flags(:flag_one, :flag_three)
8
+ assert_equal "[:flag_one, :flag_three]", f.to_a.sort_by{|flg| flg.to_s}.inspect
9
+ f.values = DecimalSupport::FlagValues(:flag_one, :flag_two, :flag_three)
10
+ assert_equal "DecimalSupport::Flags[flag_one, flag_three] (0x5)", f.inspect
11
+ f[:flag_two] = true
12
+ assert_equal "DecimalSupport::Flags[flag_one, flag_two, flag_three] (0x7)", f.inspect
13
+ f[:flag_one] = false
14
+ assert_equal "DecimalSupport::Flags[flag_two, flag_three] (0x6)", f.inspect
15
+ f.clear!
16
+ assert_equal "DecimalSupport::Flags[] (0x0)", f.inspect
17
+ f << [:flag_one,:flag_two]
18
+ assert_equal "DecimalSupport::Flags[flag_one, flag_two] (0x3)", f.inspect
19
+ g = DecimalSupport::Flags(f.values)
20
+ g.bits = f.bits
21
+ assert_equal "DecimalSupport::Flags[flag_one, flag_two] (0x3)", g.inspect
22
+ assert g==f
23
+ g.set!
24
+ assert_equal "DecimalSupport::Flags[flag_one, flag_two, flag_three] (0x7)", g.inspect
25
+ assert g!=f
26
+
27
+ assert DecimalSupport::Flags(:flag_one, :flag_three)==DecimalSupport::Flags(:flag_three, :flag_one)
28
+ assert DecimalSupport::Flags(:flag_one, :flag_three)!=DecimalSupport::Flags(:flag_one)
29
+
30
+
31
+
32
+ end
33
+
34
+ end