flt 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 (56) hide show
  1. data/History.txt +41 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +42 -0
  4. data/README.txt +557 -0
  5. data/Rakefile +34 -0
  6. data/lib/flt.rb +9 -0
  7. data/lib/flt/b.rb +6 -0
  8. data/lib/flt/bigdecimal.rb +151 -0
  9. data/lib/flt/bin_num.rb +250 -0
  10. data/lib/flt/d.rb +6 -0
  11. data/lib/flt/dec_num.rb +1239 -0
  12. data/lib/flt/float.rb +458 -0
  13. data/lib/flt/math.rb +66 -0
  14. data/lib/flt/num.rb +4211 -0
  15. data/lib/flt/sugar.rb +102 -0
  16. data/lib/flt/support.rb +1335 -0
  17. data/lib/flt/tolerance.rb +561 -0
  18. data/lib/flt/tolerance/sugar.rb +77 -0
  19. data/lib/flt/version.rb +9 -0
  20. data/setup.rb +1585 -0
  21. data/tasks/ann.rake +80 -0
  22. data/tasks/bones.rake +20 -0
  23. data/tasks/gem.rake +192 -0
  24. data/tasks/git.rake +40 -0
  25. data/tasks/manifest.rake +48 -0
  26. data/tasks/notes.rake +27 -0
  27. data/tasks/post_load.rake +39 -0
  28. data/tasks/rdoc.rake +50 -0
  29. data/tasks/rubyforge.rake +55 -0
  30. data/tasks/setup.rb +279 -0
  31. data/tasks/spec.rake +54 -0
  32. data/tasks/svn.rake +47 -0
  33. data/tasks/test.rake +40 -0
  34. data/test/all_tests.rb +23 -0
  35. data/test/helper.rb +101 -0
  36. data/test/reader.rb +68 -0
  37. data/test/test_basic.rb +396 -0
  38. data/test/test_bin.rb +245 -0
  39. data/test/test_bin_arithmetic.rb +94 -0
  40. data/test/test_binfloat_conversion.rb +24 -0
  41. data/test/test_coercion.rb +22 -0
  42. data/test/test_comparisons.rb +53 -0
  43. data/test/test_dectest.rb +216 -0
  44. data/test/test_define_conversions.rb +144 -0
  45. data/test/test_epsilon.rb +55 -0
  46. data/test/test_exact.rb +147 -0
  47. data/test/test_flags.rb +34 -0
  48. data/test/test_multithreading.rb +32 -0
  49. data/test/test_num_constructor.rb +133 -0
  50. data/test/test_odd_even.rb +78 -0
  51. data/test/test_round.rb +104 -0
  52. data/test/test_to_int.rb +104 -0
  53. data/test/test_to_rf.rb +36 -0
  54. data/test/test_tol.rb +102 -0
  55. data/test/test_ulp.rb +127 -0
  56. metadata +147 -0
data/test/test_bin.rb ADDED
@@ -0,0 +1,245 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
+
3
+ class TestBin < Test::Unit::TestCase
4
+
5
+
6
+ def setup
7
+ initialize_context
8
+ end
9
+
10
+ def test_binfloat
11
+ assert_equal 2, Float::RADIX
12
+
13
+ BinNum.context = BinNum::FloatContext
14
+ assert_equal 23.0, (BinNum(20) + BinNum(3)).to_f
15
+ assert_equal 1.0/3, (BinNum(1) / BinNum(3)).to_f
16
+ assert_equal Math.sqrt(2), BinNum(2).sqrt.to_f
17
+ assert_equal 9, BinNum(345).number_of_digits
18
+ assert_equal 0.1, BinNum('0.1', :fixed).to_f
19
+
20
+ assert_equal 23.0, (BinNum(20) + BinNum(3))
21
+ assert_equal 1.0/3, (BinNum(1) / BinNum(3))
22
+ assert_equal Math.sqrt(2), BinNum(2).sqrt
23
+ assert_equal 0.1, BinNum('0.1', :fixed)
24
+
25
+ assert_equal Float::MAX, BinNum.context.maximum_finite
26
+ assert_equal Float::MIN, BinNum.context.minimum_normal
27
+
28
+ numbers = %w{
29
+ 0.123437
30
+ 0.123437E57
31
+ 0.1
32
+ 0.1111111111111111111111111
33
+ 0.1E56
34
+ 0.5 0.125 7333 0.126
35
+ 1069756.78125
36
+ 106975678125E-5
37
+ 2.1E6
38
+ 3E20
39
+ }
40
+ numbers += %w{0.12343749827397239423432 3423322.345} if Flt.float_correctly_rounded?
41
+
42
+ numbers.each do |n|
43
+ assert_equal Float(n), BinNum(n, :fixed).to_f
44
+ end
45
+
46
+ end
47
+
48
+ def test_text_to_float_rounding
49
+
50
+ BinNum.context.precision = 8
51
+ BinNum.context.rounding = :down
52
+ assert_equal "11001100", BinNum('0.1', :fixed).split[1].to_s(2)
53
+ BinNum.context.rounding = :floor
54
+ assert_equal "11001100", BinNum('0.1', :fixed).split[1].to_s(2)
55
+ BinNum.context.rounding = :ceiling
56
+ assert_equal "11001100", BinNum('-0.1', :fixed).split[1].to_s(2)
57
+ BinNum.context.rounding = :down
58
+ assert_equal "11001100", BinNum('-0.1', :fixed).split[1].to_s(2)
59
+
60
+ BinNum.context.rounding = :up
61
+ assert_equal "11001101", BinNum('0.1', :fixed).split[1].to_s(2)
62
+ BinNum.context.rounding = :ceiling
63
+ assert_equal "11001101", BinNum('0.1', :fixed).split[1].to_s(2)
64
+ BinNum.context.rounding = :floor
65
+ assert_equal "11001101", BinNum('-0.1', :fixed).split[1].to_s(2)
66
+ BinNum.context.rounding = :up
67
+ assert_equal "11001101", BinNum('-0.1', :fixed).split[1].to_s(2)
68
+
69
+ BinNum.context.rounding = :half_up
70
+ assert_equal "11001101", BinNum('0.1', :fixed).split[1].to_s(2)
71
+ BinNum.context.rounding = :half_down
72
+ assert_equal "11001101", BinNum('0.1', :fixed).split[1].to_s(2)
73
+ BinNum.context.rounding = :half_even
74
+ assert_equal "11001101", BinNum('0.1', :fixed).split[1].to_s(2)
75
+ BinNum.context.rounding = :half_up
76
+ assert_equal "11001101", BinNum('-0.1', :fixed).split[1].to_s(2)
77
+ BinNum.context.rounding = :half_down
78
+ assert_equal "11001101", BinNum('-0.1', :fixed).split[1].to_s(2)
79
+ BinNum.context.rounding = :half_even
80
+ assert_equal "11001101", BinNum('-0.1', :fixed).split[1].to_s(2)
81
+
82
+ BinNum.context.rounding = :half_up
83
+ assert_equal "10000001", BinNum('128.5', :fixed).split[1].to_s(2)
84
+ BinNum.context.rounding = :half_down
85
+ assert_equal "10000000", BinNum('128.5', :fixed).split[1].to_s(2)
86
+ BinNum.context.rounding = :half_even
87
+ assert_equal "10000000", BinNum('128.5', :fixed).split[1].to_s(2)
88
+ BinNum.context.rounding = :half_up
89
+ assert_equal "10000010", BinNum('129.5', :fixed).split[1].to_s(2)
90
+ BinNum.context.rounding = :half_down
91
+ assert_equal "10000001", BinNum('129.5', :fixed).split[1].to_s(2)
92
+ BinNum.context.rounding = :half_even
93
+ assert_equal "10000010", BinNum('129.5', :fixed).split[1].to_s(2)
94
+
95
+ BinNum.context.rounding = :half_up
96
+ assert_equal "10000001", BinNum('-128.5', :fixed).split[1].to_s(2)
97
+ BinNum.context.rounding = :half_down
98
+ assert_equal "10000000", BinNum('-128.5', :fixed).split[1].to_s(2)
99
+ BinNum.context.rounding = :half_even
100
+ assert_equal "10000000", BinNum('-128.5', :fixed).split[1].to_s(2)
101
+ BinNum.context.rounding = :half_up
102
+ assert_equal "10000010", BinNum('-129.5', :fixed).split[1].to_s(2)
103
+ BinNum.context.rounding = :half_down
104
+ assert_equal "10000001", BinNum('-129.5', :fixed).split[1].to_s(2)
105
+ BinNum.context.rounding = :half_even
106
+ assert_equal "10000010", BinNum('-129.5', :fixed).split[1].to_s(2)
107
+
108
+ BinNum.context.rounding = :up
109
+ assert_equal "10000001", BinNum('128.5', :fixed).split[1].to_s(2)
110
+ BinNum.context.rounding = :down
111
+ assert_equal "10000000", BinNum('128.5', :fixed).split[1].to_s(2)
112
+ BinNum.context.rounding = :ceiling
113
+ assert_equal "10000001", BinNum('128.5', :fixed).split[1].to_s(2)
114
+ BinNum.context.rounding = :floor
115
+ assert_equal "10000000", BinNum('128.5', :fixed).split[1].to_s(2)
116
+
117
+ BinNum.context.rounding = :up
118
+ assert_equal "10000001", BinNum('-128.5', :fixed).split[1].to_s(2)
119
+ BinNum.context.rounding = :down
120
+ assert_equal "10000000", BinNum('-128.5', :fixed).split[1].to_s(2)
121
+ BinNum.context.rounding = :ceiling
122
+ assert_equal "10000000", BinNum('-128.5', :fixed).split[1].to_s(2)
123
+ BinNum.context.rounding = :floor
124
+ assert_equal "10000001", BinNum('-128.5', :fixed).split[1].to_s(2)
125
+
126
+ BinNum.context.rounding = :up
127
+ assert_equal "10000010", BinNum('129.5', :fixed).split[1].to_s(2)
128
+ BinNum.context.rounding = :down
129
+ assert_equal "10000001", BinNum('129.5', :fixed).split[1].to_s(2)
130
+ BinNum.context.rounding = :ceiling
131
+ assert_equal "10000010", BinNum('129.5', :fixed).split[1].to_s(2)
132
+ BinNum.context.rounding = :floor
133
+ assert_equal "10000001", BinNum('129.5', :fixed).split[1].to_s(2)
134
+
135
+ BinNum.context.rounding = :up
136
+ assert_equal "10000010", BinNum('-129.5', :fixed).split[1].to_s(2)
137
+ BinNum.context.rounding = :down
138
+ assert_equal "10000001", BinNum('-129.5', :fixed).split[1].to_s(2)
139
+ BinNum.context.rounding = :ceiling
140
+ assert_equal "10000001", BinNum('-129.5', :fixed).split[1].to_s(2)
141
+ BinNum.context.rounding = :floor
142
+ assert_equal "10000010", BinNum('-129.5', :fixed).split[1].to_s(2)
143
+
144
+ BinNum.context.precision = 9
145
+ BinNum.context.rounding = :down
146
+ assert_equal "110011001", BinNum('0.1', :fixed).split[1].to_s(2)
147
+ BinNum.context.rounding = :floor
148
+ assert_equal "110011001", BinNum('0.1', :fixed).split[1].to_s(2)
149
+ BinNum.context.rounding = :ceiling
150
+ assert_equal "110011001", BinNum('-0.1', :fixed).split[1].to_s(2)
151
+ BinNum.context.rounding = :down
152
+ assert_equal "110011001", BinNum('-0.1', :fixed).split[1].to_s(2)
153
+
154
+ BinNum.context.rounding = :up
155
+ assert_equal "110011010", BinNum('0.1', :fixed).split[1].to_s(2)
156
+ BinNum.context.rounding = :ceiling
157
+ assert_equal "110011010", BinNum('0.1', :fixed).split[1].to_s(2)
158
+ BinNum.context.rounding = :floor
159
+ assert_equal "110011010", BinNum('-0.1', :fixed).split[1].to_s(2)
160
+ BinNum.context.rounding = :up
161
+ assert_equal "110011010", BinNum('-0.1', :fixed).split[1].to_s(2)
162
+
163
+ BinNum.context.rounding = :half_up
164
+ assert_equal "110011010", BinNum('0.1', :fixed).split[1].to_s(2)
165
+ BinNum.context.rounding = :half_down
166
+ assert_equal "110011010", BinNum('0.1', :fixed).split[1].to_s(2)
167
+ BinNum.context.rounding = :half_even
168
+ assert_equal "110011010", BinNum('0.1', :fixed).split[1].to_s(2)
169
+ BinNum.context.rounding = :half_up
170
+ assert_equal "110011010", BinNum('-0.1', :fixed).split[1].to_s(2)
171
+ BinNum.context.rounding = :half_down
172
+ assert_equal "110011010", BinNum('-0.1', :fixed).split[1].to_s(2)
173
+ BinNum.context.rounding = :half_even
174
+ assert_equal "110011010", BinNum('-0.1', :fixed).split[1].to_s(2)
175
+
176
+ end
177
+
178
+ def test_text_to_float_exact
179
+ BinNum.context.exact = :quiet
180
+ %w{
181
+ 0.1
182
+ 0.12343749827397239423432
183
+ 0.123437
184
+ 0.1111111111111111111111111
185
+ 0.126
186
+ 3423322.345
187
+ }.each do |n|
188
+ BinNum.context.flags[Num::Inexact] = false
189
+ b = BinNum(n, :fixed)
190
+ assert b.nan?, "BinNum('#{n}') is NaN in exact precision mode"
191
+ assert BinNum.context.flags[Num::Inexact], "BinNum('#{n}') sets Inexact flag"
192
+ end
193
+ %w{
194
+ 0.123437E57
195
+ 0.1E56
196
+ 0.5 0.125 7333
197
+ 1069756.78125
198
+ 106975678125E-5
199
+ 2.1E6
200
+ 3E20
201
+ }.each do |n|
202
+ BinNum.context.flags[Num::Inexact] = false
203
+ b = BinNum(n, :fixed)
204
+ assert_equal Float(n), BinNum(n, :fixed).to_f
205
+ assert !b.nan?, "BinNum('#{n}') is not NaN in exact precision mode"
206
+ assert !BinNum.context.flags[Num::Inexact], "BinNum('#{n}') does not set Inexact flag"
207
+ end
208
+ end
209
+
210
+ def test_float_to_bin_float
211
+ %w{
212
+ 0.12343749827397239423432
213
+ 0.123437
214
+ 0.123437E57
215
+ 0.1
216
+ 0.1111111111111111111111111
217
+ 0.1E56
218
+ 0.5 0.125 7333 0.126
219
+ 3423322.345
220
+ 1069756.78125
221
+ 106975678125E-5
222
+ 2.1E6
223
+ 3E20
224
+ 1.1
225
+ 1.1E31
226
+ -1.1E31
227
+ 0.0
228
+ -0.0
229
+ }.each do |n|
230
+ f = Float(n)
231
+ assert_equal f, BinNum(f).to_f
232
+ end
233
+ nan = 0.0/0.0
234
+ inf = 1.0/0.0
235
+ minf = -1.0/0.0
236
+ assert_equal(-1, BinNum(-0.0).sign)
237
+ assert_equal(-1, BinNum(minf).sign)
238
+ assert_equal(+1, BinNum(0.0).sign)
239
+ assert_equal(+1, BinNum(inf).sign)
240
+ assert BinNum(nan).nan?, "Float NaN to BinNum produces NaN"
241
+ assert BinNum(inf).infinite?, "Float +Infinity to BinNum produces Infinite"
242
+ assert BinNum(minf).infinite?, "Float -Infinity to BinNum produces Infinite"
243
+ end
244
+
245
+ end
@@ -0,0 +1,94 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
+
3
+ # These tests assume that Float arithmetic is correctly rounded
4
+ # Random tests using Float as a reference
5
+ class TestBinArithmetic < Test::Unit::TestCase
6
+
7
+ def setup
8
+ initialize_context
9
+ srand 93831
10
+ @test_float_data ||= Array.new(1000){random_num(Float)} + singular_nums(Float) # + special_nums(Float)
11
+ end
12
+
13
+ def test_addition
14
+ float_emulation_context
15
+ each_pair(@test_float_data) do |x, y|
16
+ z = x + y
17
+ assert_equal z, (BinNum(x)+BinNum(y)).to_f
18
+ end
19
+ end
20
+
21
+ def test_subtraction
22
+ float_emulation_context
23
+ each_pair(@test_float_data) do |x, y|
24
+ z = x - y
25
+ assert_equal z, (BinNum(x)-BinNum(y)).to_f
26
+ end
27
+ end
28
+
29
+ def test_multiplication
30
+ float_emulation_context
31
+ each_pair(@test_float_data) do |x, y|
32
+ z = x * y
33
+ assert_equal z, (BinNum(x)*BinNum(y)).to_f
34
+ end
35
+ end
36
+
37
+ def test_division
38
+ float_emulation_context
39
+ each_pair(@test_float_data) do |x, y|
40
+ # next if y.abs < Float::EPSILON*x.abs
41
+ next if y.zero?
42
+ z = x / y
43
+ # if z != (BinNum(x)/BinNum(y)).to_f
44
+ # puts "x=#{float_split(x).inspect}"
45
+ # puts "y=#{float_split(y).inspect}"
46
+ # puts "z=#{float_split(z).inspect}"
47
+ # puts "->#{(BinNum(x)/BinNum(y)).split.inspect}"
48
+ # end
49
+ assert_equal z, (BinNum(x)/BinNum(y)).to_f
50
+ end
51
+ end
52
+
53
+ def test_power
54
+ float_emulation_context
55
+ each_pair(@test_float_data) do |x, y|
56
+ next if x.zero? && y.zero?
57
+ x = x.abs
58
+ xx = BinNum(x)
59
+ yy = BinNum(y)
60
+ z = x**y
61
+ zz = nil
62
+ begin
63
+ zz = xx**yy
64
+ rescue=>err
65
+ if err.is_a?(Num::Overflow)
66
+ zz = BinNum.infinity
67
+ else
68
+ zz = err.to_s
69
+ end
70
+ end
71
+ ok = true
72
+ zzz = nil
73
+ if zz != z
74
+ # Math.power may not be accurate enough
75
+ zzz = +BinNum.context(:precision=>512) { xx**yy }
76
+ if zzz != zz
77
+ ok = false
78
+ end
79
+ end
80
+ assert ok, "#{x}**#{y} (#{Float.context.split(x).inspect}**#{Float.context.split(y).inspect}) Incorrect: #{zz.split.inspect} instead of #{zzz && zzz.split.inspect}"
81
+ end
82
+ end
83
+
84
+ def test_sqrt
85
+ float_emulation_context
86
+ @test_float_data.each do |x|
87
+ context = x.class.context
88
+ x = context.abs(x)
89
+ z = context.sqrt(x)
90
+ assert_equal z, BinNum(x).sqrt.to_f
91
+ end
92
+ end
93
+
94
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
+
3
+
4
+ class TestBinfloatConversion < Test::Unit::TestCase
5
+
6
+ def setup
7
+ initialize_context
8
+ end
9
+
10
+ def test_conversions
11
+ float_emulation_context
12
+ srand 12322
13
+ [:half_even, :half_up, :half_down, :down, :up, :floor, :ceiling].each do |rounding|
14
+ BinNum.context.rounding = rounding
15
+ 1000.times do
16
+ x = random_float
17
+ txt = BinNum(x).to_s
18
+ y = BinNum(txt, :fixed).to_f
19
+ assert_equal x, y, "FAIL #{Float.context.split(x).inspect} #{rounding} #{Float.context.split(y).inspect} #{x.class}"
20
+ end
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.join(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 DecNum('7.1'), DecNum('0.1') + 7
12
+ assert_equal DecNum('7.1'), 7 + DecNum('0.1')
13
+ assert_equal DecNum('14'), DecNum(7) * 2
14
+ assert_equal DecNum('14'), 2 * DecNum(7)
15
+
16
+ assert_equal DecNum('7.1'), DecNum(7) + Rational(1,10)
17
+ assert_equal DecNum('7.1'), Rational(1,10) + DecNum(7)
18
+ assert_equal DecNum('1.4'), DecNum(7) * Rational(2,10)
19
+ assert_equal DecNum('1.4'), Rational(2,10) * DecNum(7)
20
+ end
21
+
22
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.join(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 DecNum('1.1').hash, DecNum('1.1').hash
12
+ assert_equal DecNum('1.1').hash, (DecNum('1.0')+DecNum('0.1')).hash
13
+ assert_equal DecNum('1.1',:precision=>10).hash, DecNum('1.1',:precision=>3).hash
14
+ assert_not_equal DecNum('1.0').hash, DecNum('1.1').hash
15
+ assert_not_equal DecNum('1.0').hash, 1.0.hash
16
+ assert_not_equal DecNum('1.0').hash, 1.hash
17
+
18
+ assert DecNum('1.1').eql?(DecNum('1.1'))
19
+ assert DecNum('1.1').eql?(DecNum('1.0')+DecNum('0.1'))
20
+ assert DecNum('1.1',:precision=>10).eql?(DecNum('1.1',:precision=>3))
21
+ assert !DecNum('1.1').eql?(DecNum('1.0'))
22
+ assert !DecNum('1.0').eql?(1.0)
23
+ assert !DecNum('1.0').eql?(1)
24
+ end
25
+
26
+ def test_equality
27
+ assert DecNum('1.1') == DecNum('1.1')
28
+ assert DecNum('1.1') == (DecNum('1.0')+DecNum('0.1'))
29
+ assert DecNum('1.1',:precision=>10) == DecNum('1.1',:precision=>3)
30
+ assert !(DecNum('1.1') == DecNum('1.0'))
31
+ #assert DecNum('1.1') == 1.1
32
+ #assert DecNum('1.0') == 1.0
33
+ #assert DecNum('1.0') == BigDecimal.new('1.000')
34
+ assert DecNum('1.0') == 1
35
+ assert DecNum('0.1') == Rational(1)/Rational(10)
36
+
37
+ assert !(DecNum.nan == DecNum.nan)
38
+ assert !(DecNum.nan == DecNum('1'))
39
+ assert !(DecNum.nan == DecNum('0'))
40
+ assert !(DecNum.nan == DecNum.infinity)
41
+ #assert !(DecNum.nan == (0.0/0.0))
42
+
43
+ assert !(DecNum.infinity(+1) == DecNum.infinity(-1))
44
+ assert !(DecNum.infinity(+1) == DecNum('0'))
45
+ assert DecNum.infinity(+1) == DecNum.infinity
46
+ assert DecNum.infinity(+1) == DecNum('1')/DecNum('0')
47
+ assert DecNum.infinity(-1) == DecNum('-1')/DecNum('0')
48
+
49
+ # TODO: test <=> <= etc.
50
+ end
51
+
52
+
53
+ end
@@ -0,0 +1,216 @@
1
+ require File.expand_path(File.join(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
+ 'power'=>'power',
45
+ 'log10'=>'log10',
46
+ 'exp'=>'exp',
47
+ 'ln'=>'ln'
48
+ }
49
+ # Functions not yet implemented
50
+ PENDING = %w{
51
+ rotate
52
+ shift
53
+ trim
54
+
55
+ and
56
+ or
57
+ xor
58
+ invert
59
+
60
+ max
61
+ min
62
+ maxmag
63
+ minmag
64
+ comparetotal
65
+ comparetotmag
66
+ }
67
+ IGNORED = PENDING + %w{
68
+ copy
69
+ apply
70
+ }
71
+
72
+ FLAG_NAMES = {
73
+ 'inexact'=>:Inexact,
74
+ 'rounded'=>:Rounded,
75
+ 'clamped'=>:Clamped,
76
+ 'subnormal'=>:Subnormal,
77
+ 'invalid_operation'=>:InvalidOperation,
78
+ 'underflow'=>:Underflow,
79
+ 'overflow'=>:Overflow,
80
+ 'division_by_zero'=>:DivisionByZero,
81
+ 'division_undefined'=>:InvalidOperation,
82
+ 'division_impossible'=>:DivisionImpossible,
83
+ 'conversion_syntax'=>:ConversionSyntax
84
+ }
85
+
86
+ # Excluded tests that we don't currently pass
87
+ EXCEPTIONS = %w{
88
+ powx1183 powx1184
89
+ powx4001 powx4002 powx4003 powx4005
90
+ powx4008 powx4010 powx4012 powx4014
91
+ logx901 logx902 logx903 logx903 logx905
92
+ expx901 expx902 expx903 expx905
93
+ lnx901 lnx902 lnx903 lnx905
94
+ }
95
+
96
+
97
+ def unquote(txt)
98
+ if txt[0,1]=="'" && txt[-1,1]=="'"
99
+ txt = txt[1...-1].gsub("''","'")
100
+ end
101
+ if txt[0,1]=='"' && txt[-1,1]=='"'
102
+ txt = txt[1...-1].gsub('""','"')
103
+ end
104
+ #txt = 'NaN' if txt=='#' || txt=='?'
105
+ txt = 'sNaN' if txt=='#'
106
+ txt = 'NaN' if txt=='?'
107
+ txt
108
+ end
109
+
110
+ class TestBasic < Test::Unit::TestCase
111
+
112
+ def test_dec
113
+ missing = []
114
+ dir = File.join(File.dirname(__FILE__), 'dectest')
115
+ dir = nil unless File.exists?(dir)
116
+ if dir
117
+ Dir[File.join(dir, '*.decTest')].each do |fn|
118
+
119
+ name = File.basename(fn,'.decTest').downcase
120
+ next if %w{ds dd dq}.include?(name[0,2]) ||
121
+ %w{decsingle decdouble decquad testall}.include?(name)
122
+
123
+ initialize_context
124
+
125
+
126
+ File.open(fn,'r') do |file|
127
+ file.each_line do |line|
128
+ next if line[0,2]=='--' || line.strip.empty?
129
+
130
+ if line.include?(' -> ')
131
+ # test
132
+ # to do :remove inline comments --... on the right of ->
133
+ sides = line.split('->')
134
+ # now split by whitespace but avoid breaking quoted strings (and take care or repeated quotes!)
135
+ lhs = sides.first.strip.scan(/"(?:[^"]|"")*"|'(?:[^']|'')*'|\S+/)
136
+ id = lhs.first
137
+ funct = lhs[1].downcase
138
+ valstemp = lhs[2..-1]
139
+ rhs = sides.last.strip.split
140
+ ans = rhs.first
141
+ flags = rhs[1..-1].map{|f| DecNum.class_eval(FLAG_NAMES[f.downcase].to_s)}.compact
142
+
143
+ next unless valstemp.grep(/#/).empty?
144
+
145
+ $test_id = id
146
+ funct = FUNCTIONS[original_funct=funct]
147
+ next if EXCEPTIONS.include?(id)
148
+ if funct
149
+ # do test
150
+ msg = " Test #{id}: #{funct}(#{valstemp.join(',')}) = #{ans}"
151
+ #File.open('dectests.txt','a'){|f| f.puts msg}
152
+ expected = result = result_flags = nil
153
+ DecNum.local_context do |context|
154
+ context.flags.clear!
155
+ exact_input = !['apply','to_sci_string', 'to_eng_string'].include?(funct)
156
+ if exact_input
157
+ p = context.precision
158
+ context.exact = true
159
+ end
160
+ valstemp.map!{|v| DecNum(unquote(v))}
161
+ context.precision = p if exact_input
162
+ result = context.send(funct, *valstemp)
163
+ result_flags = context.flags.dup
164
+ expected = unquote(ans)
165
+ context.exact = true
166
+ expected = DecNum(expected) unless result.is_a?(String)
167
+ end
168
+ result = 1 if result==true
169
+ result = 0 if result==false
170
+ expected_flags = DecNum::Flags(*flags)
171
+ if ans!='?'
172
+ assert_equal expected.to_s, result.to_s, msg
173
+ end
174
+ assert_equal expected_flags, result_flags, msg
175
+
176
+ else
177
+ missing << original_funct unless IGNORED.include?(original_funct) || missing.include?(original_funct)
178
+ end
179
+
180
+ elsif line.include?(':')
181
+ # directive
182
+ funct,value = line.split(':').map{|x| x.strip.downcase}
183
+ case funct
184
+ when 'rounding'
185
+ value = ROUNDINGS[value]
186
+ else
187
+ value = value.to_i
188
+ end
189
+ if value.nil?
190
+ #raise "error"
191
+ # to do: skip untill next valid value of same funct
192
+ else
193
+ case funct
194
+ when 'rounding','precision'
195
+ DecNum.context.send "#{funct}=", value
196
+ when 'maxexponent'
197
+ DecNum.context.emax = value
198
+ when 'minexponent'
199
+ DecNum.context.emin = value
200
+ when 'clamp'
201
+ DecNum.context.clamp = (value==0 ? false : true)
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ # assert_empty missing
211
+ # In Ruby 1.8 there's no assert_empty
212
+ assert missing.empty?, "#{missing.inspect} is not empty"
213
+
214
+ end
215
+
216
+ end