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.
- data/History.txt +41 -0
- data/License.txt +20 -0
- data/Manifest.txt +42 -0
- data/README.txt +557 -0
- data/Rakefile +34 -0
- data/lib/flt.rb +9 -0
- data/lib/flt/b.rb +6 -0
- data/lib/flt/bigdecimal.rb +151 -0
- data/lib/flt/bin_num.rb +250 -0
- data/lib/flt/d.rb +6 -0
- data/lib/flt/dec_num.rb +1239 -0
- data/lib/flt/float.rb +458 -0
- data/lib/flt/math.rb +66 -0
- data/lib/flt/num.rb +4211 -0
- data/lib/flt/sugar.rb +102 -0
- data/lib/flt/support.rb +1335 -0
- data/lib/flt/tolerance.rb +561 -0
- data/lib/flt/tolerance/sugar.rb +77 -0
- data/lib/flt/version.rb +9 -0
- data/setup.rb +1585 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +192 -0
- data/tasks/git.rake +40 -0
- data/tasks/manifest.rake +48 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +39 -0
- data/tasks/rdoc.rake +50 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +279 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/test/all_tests.rb +23 -0
- data/test/helper.rb +101 -0
- data/test/reader.rb +68 -0
- data/test/test_basic.rb +396 -0
- data/test/test_bin.rb +245 -0
- data/test/test_bin_arithmetic.rb +94 -0
- data/test/test_binfloat_conversion.rb +24 -0
- data/test/test_coercion.rb +22 -0
- data/test/test_comparisons.rb +53 -0
- data/test/test_dectest.rb +216 -0
- data/test/test_define_conversions.rb +144 -0
- data/test/test_epsilon.rb +55 -0
- data/test/test_exact.rb +147 -0
- data/test/test_flags.rb +34 -0
- data/test/test_multithreading.rb +32 -0
- data/test/test_num_constructor.rb +133 -0
- data/test/test_odd_even.rb +78 -0
- data/test/test_round.rb +104 -0
- data/test/test_to_int.rb +104 -0
- data/test/test_to_rf.rb +36 -0
- data/test/test_tol.rb +102 -0
- data/test/test_ulp.rb +127 -0
- 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
|