flt 1.1.2 → 1.2.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 +5 -0
- data/README.txt +3 -2
- data/lib/flt/float.rb +8 -4
- data/lib/flt/math.rb +140 -59
- data/lib/flt/num.rb +7 -3
- data/lib/flt/version.rb +2 -2
- data/test/test_basic.rb +52 -46
- data/test/test_bin.rb +1 -1
- data/test/test_dectest.rb +3 -2
- data/test/test_trig.rb +67 -36
- metadata +3 -7
data/History.txt
CHANGED
data/README.txt
CHANGED
@@ -567,7 +567,8 @@ EXPAND+
|
|
567
567
|
|
568
568
|
= Roadmap
|
569
569
|
|
570
|
-
*
|
571
|
-
*
|
570
|
+
* Math (trigonometry) functions for DecNum & BinNum (reorganization of DecNum::Math)
|
571
|
+
* Complex support.
|
572
|
+
* Implement the missing GDA functions:
|
572
573
|
rotate, shift, trim, and, or, xor, invert,
|
573
574
|
max, min, maxmag, minmag, comparetotal, comparetotmag
|
data/lib/flt/float.rb
CHANGED
@@ -44,9 +44,13 @@ require 'singleton'
|
|
44
44
|
#
|
45
45
|
# Float::MIN : Minimum normalized positive floating-point number
|
46
46
|
# b**(emin - 1).
|
47
|
+
# In JRuby this is the mininimum denormal number!
|
47
48
|
#
|
48
49
|
# Float::ROUNDS : Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown.
|
49
50
|
#
|
51
|
+
# Note: Ruby 1.9.2 Adds Float::INFINITY and Float::NAN
|
52
|
+
#
|
53
|
+
#
|
50
54
|
# Additional contants defined here:
|
51
55
|
#
|
52
56
|
# Float::DECIMAL_DIG : Number of decimal digits, n, such that any floating-point number can be rounded
|
@@ -56,11 +60,11 @@ require 'singleton'
|
|
56
60
|
# ceil(1 + pmax * log10(b)) otherwise
|
57
61
|
# DECIMAL_DIG = (MANT_DIG*Math.log(RADIX)/Math.log(10)).ceil+1
|
58
62
|
#
|
59
|
-
# Float::MIN_N : Minimum normalized number == MAX_D.next == MIN
|
63
|
+
# Float::MIN_N : Minimum normalized number == MAX_D.next == MIN (not in JRuby)
|
60
64
|
#
|
61
65
|
# Float::MAX_D : Maximum denormal number == MIN_N.prev
|
62
66
|
#
|
63
|
-
# Float::MIN_D : Minimum non zero positive denormal number == 0.0.next
|
67
|
+
# Float::MIN_D : Minimum non zero positive denormal number == 0.0.next (== MIN in JRuby)
|
64
68
|
#
|
65
69
|
# Float::MAX_F : Maximum significand
|
66
70
|
class Float
|
@@ -110,7 +114,7 @@ class Flt::FloatContext
|
|
110
114
|
|
111
115
|
# NaN (not a number value)
|
112
116
|
def nan
|
113
|
-
0.0/0.0
|
117
|
+
0.0/0.0 # Ruby 1.9.2: Float::NAN
|
114
118
|
end
|
115
119
|
|
116
120
|
# zero value with specified sign
|
@@ -120,7 +124,7 @@ class Flt::FloatContext
|
|
120
124
|
|
121
125
|
# infinity value with specified sign
|
122
126
|
def infinity(sign=+1)
|
123
|
-
(sign < 0) ? -1.0/0.0 : 1.0/0.0
|
127
|
+
(sign < 0) ? -1.0/0.0 : 1.0/0.0 # Ruby 1.9.2: (sing < 0) ? -Float::INFINITY : Float::INFINITY
|
124
128
|
end
|
125
129
|
|
126
130
|
def int_radix_power(n)
|
data/lib/flt/math.rb
CHANGED
@@ -1,10 +1,5 @@
|
|
1
1
|
require 'flt/dec_num'
|
2
2
|
|
3
|
-
# TODO:
|
4
|
-
# * convert arguments as Context#_convert does, to accept non DecNum arguments
|
5
|
-
# * Better precision (currently is within about 2 ulps of the correct result)
|
6
|
-
# * Speed optimization
|
7
|
-
|
8
3
|
module Flt
|
9
4
|
class DecNum
|
10
5
|
module Math
|
@@ -18,7 +13,6 @@ module Flt
|
|
18
13
|
HALF = DecNum('0.5')
|
19
14
|
|
20
15
|
# Pi
|
21
|
-
$no_cache = false
|
22
16
|
@@pi_cache = nil # truncated pi digits as a string
|
23
17
|
@@pi_cache_digits = 0
|
24
18
|
PI_MARGIN = 10
|
@@ -68,7 +62,10 @@ module Flt
|
|
68
62
|
end
|
69
63
|
end
|
70
64
|
|
71
|
-
# Cosine of angle in
|
65
|
+
# Cosine of an angle given in the units specified by DecNum.context.angle:
|
66
|
+
# * :rad for radians
|
67
|
+
# * :deg for degrees
|
68
|
+
# * :grad for gradians
|
72
69
|
def cos(x)
|
73
70
|
x = x.abs
|
74
71
|
rev_sign = false
|
@@ -82,6 +79,7 @@ module Flt
|
|
82
79
|
else
|
83
80
|
rev_sign = !rev_sign
|
84
81
|
end
|
82
|
+
x = to_rad(x)
|
85
83
|
i, lasts, fact, num = 1, 0, 1, DecNum(x)
|
86
84
|
s = num
|
87
85
|
x2 = -x*x
|
@@ -96,7 +94,10 @@ module Flt
|
|
96
94
|
return rev_sign ? (-s) : (+s)
|
97
95
|
end
|
98
96
|
|
99
|
-
# Sine of angle in
|
97
|
+
# Sine of an angle given in the units specified by DecNum.context.angle:
|
98
|
+
# * :rad for radians
|
99
|
+
# * :deg for degrees
|
100
|
+
# * :grad for gradians
|
100
101
|
def sin(x)
|
101
102
|
sign = x.sign
|
102
103
|
s = nil
|
@@ -106,7 +107,7 @@ module Flt
|
|
106
107
|
x,k,pi_2 = reduce_angle2(x,2)
|
107
108
|
sign = -sign if k>1
|
108
109
|
x = pi_2 - x if k % 2 == 1
|
109
|
-
x =
|
110
|
+
x = to_rad(x)
|
110
111
|
i, lasts, fact, num = 1, 0, 1, DecNum(x)
|
111
112
|
s = num
|
112
113
|
x2 = -x*x
|
@@ -121,6 +122,7 @@ module Flt
|
|
121
122
|
return (+s).copy_sign(sign)
|
122
123
|
end
|
123
124
|
|
125
|
+
# Tangent of an angle
|
124
126
|
def tan(x)
|
125
127
|
+DecNum.context do |local_context|
|
126
128
|
local_context.precision += 2 # extra digits for intermediate steps
|
@@ -129,19 +131,22 @@ module Flt
|
|
129
131
|
end
|
130
132
|
end
|
131
133
|
|
132
|
-
# Arc-tangent.
|
134
|
+
# Arc-tangent in units specified by DecNum.context.angle
|
133
135
|
def atan(x)
|
134
136
|
s = nil
|
137
|
+
conversion = true
|
135
138
|
DecNum.context do |local_context|
|
136
139
|
local_context.precision += 2
|
137
140
|
if x == 0
|
138
141
|
return DecNum.zero
|
139
142
|
elsif x.abs > 1
|
140
143
|
if x.infinite?
|
141
|
-
s = (
|
144
|
+
s = (quarter_cycle).copy_sign(x)
|
145
|
+
conversion = false
|
142
146
|
break
|
143
147
|
else
|
144
|
-
c = (
|
148
|
+
# c = (quarter_cycle).copy_sign(x)
|
149
|
+
c = (HALF*pi).copy_sign(x)
|
145
150
|
x = 1 / x
|
146
151
|
end
|
147
152
|
end
|
@@ -161,7 +166,7 @@ module Flt
|
|
161
166
|
s = c - s
|
162
167
|
end
|
163
168
|
end
|
164
|
-
return +s
|
169
|
+
return conversion ? rad_to(s) : +s
|
165
170
|
end
|
166
171
|
|
167
172
|
def atan2(y, x)
|
@@ -172,19 +177,19 @@ module Flt
|
|
172
177
|
if x != 0
|
173
178
|
if y_is_real
|
174
179
|
a = y!=0 ? atan(y / x) : DecNum.zero
|
175
|
-
a +=
|
180
|
+
a += half_cycle.copy_sign(y) if x < 0
|
176
181
|
return a
|
177
182
|
elsif abs_y == abs_x
|
178
183
|
x = DecNum(1).copy_sign(x)
|
179
184
|
y = DecNum(1).copy_sign(y)
|
180
|
-
return
|
185
|
+
return half_cycle * (2 - x) / (4 * y)
|
181
186
|
end
|
182
187
|
end
|
183
188
|
|
184
189
|
if y != 0
|
185
190
|
return atan(DecNum.infinity(y.sign))
|
186
191
|
elsif x < 0
|
187
|
-
return
|
192
|
+
return half_cycle.copy_sign(x)
|
188
193
|
else
|
189
194
|
return DecNum.zero
|
190
195
|
end
|
@@ -195,11 +200,11 @@ module Flt
|
|
195
200
|
return DecNum.context.exception(Num::InvalidOperation, 'asin needs -1 <= x <= 1') if x.abs > 1
|
196
201
|
|
197
202
|
if x == -1
|
198
|
-
return -
|
203
|
+
return -quarter_cycle
|
199
204
|
elsif x == 0
|
200
205
|
return DecNum.zero
|
201
206
|
elsif x == 1
|
202
|
-
return
|
207
|
+
return quarter_cycle
|
203
208
|
end
|
204
209
|
|
205
210
|
DecNum.context do |local_context|
|
@@ -212,29 +217,21 @@ module Flt
|
|
212
217
|
|
213
218
|
def acos(x)
|
214
219
|
|
215
|
-
# We can compute acos(x) = pi/2 - asin(x)
|
216
|
-
# but we must take care with x near 1, where that formula would cause loss of precision
|
217
|
-
|
218
220
|
return DecNum.context.exception(Num::InvalidOperation, 'acos needs -1 <= x <= 2') if x.abs > 1
|
219
221
|
|
220
222
|
if x == -1
|
221
|
-
return
|
223
|
+
return half_cycle
|
222
224
|
elsif x == 0
|
223
|
-
return
|
225
|
+
return quarter_cycle
|
224
226
|
elsif x == 1
|
225
227
|
return DecNum.zero
|
226
228
|
end
|
227
229
|
|
228
|
-
# some identities:
|
229
|
-
# acos(x) = pi/2 - asin(x) # (but this losses accuracy near x=+1)
|
230
|
-
# acos(x) = pi/2 - atan(x/(1-x*x).sqrt) # this too
|
231
|
-
# acos(x) = asin((1-x*x).sqrt) for x>=0; for x<=0 acos(x) = pi/2 - asin((1-x*x).sqrt)
|
232
|
-
|
233
230
|
if x < HALF
|
234
231
|
DecNum.context do |local_context|
|
235
232
|
local_context.precision += 3
|
236
233
|
x = x/(1-x*x).sqrt
|
237
|
-
x =
|
234
|
+
x = quarter_cycle - atan(x)
|
238
235
|
end
|
239
236
|
else
|
240
237
|
# valid for x>=0
|
@@ -255,7 +252,7 @@ module Flt
|
|
255
252
|
end
|
256
253
|
end
|
257
254
|
|
258
|
-
# TODO:
|
255
|
+
# TODO: add angular units to context; add support for degrees
|
259
256
|
|
260
257
|
def pi2(decimals=nil)
|
261
258
|
decimals ||= DecNum.context.precision
|
@@ -298,34 +295,7 @@ module Flt
|
|
298
295
|
end
|
299
296
|
|
300
297
|
def modtwopi(x)
|
301
|
-
return +DecNum.context(:precision=>DecNum.context.precision*3){x.modulo(
|
302
|
-
# This seems to be slower and less accurate:
|
303
|
-
# prec = DecNum.context.precision
|
304
|
-
# pi_2 = pi2(prec*2)
|
305
|
-
# return x if x < pi_2
|
306
|
-
# ex = x.fractional_exponent
|
307
|
-
# DecNum.context do |local_context|
|
308
|
-
# # x.modulo(pi_2)
|
309
|
-
# local_context.precision *= 2
|
310
|
-
# if ex > prec
|
311
|
-
# # consider exponent separately
|
312
|
-
# fd = nil
|
313
|
-
# excess = ex - prec
|
314
|
-
# x = x.scaleb(prec-ex)
|
315
|
-
# # now obtain 2*prec digits from inv2pi after the initial excess digits
|
316
|
-
# digits = nil
|
317
|
-
# inv_2pi = inv2pi(local_context.precision+excess)
|
318
|
-
# DecNum.context do |extended_context|
|
319
|
-
# extended_context.precision += excess
|
320
|
-
# digits = (inv2pi.scaleb(excess)).fraction_part
|
321
|
-
# end
|
322
|
-
# x *= digits*pi_2
|
323
|
-
# end
|
324
|
-
# # compute the fractional part of the division by 2pi
|
325
|
-
# inv_2pi ||= inv2pi
|
326
|
-
# x = pi_2*((x*inv2pi).fraction_part)
|
327
|
-
# end
|
328
|
-
# +x
|
298
|
+
return +DecNum.context(:precision=>DecNum.context.precision*3){x.modulo(one_cycle)}
|
329
299
|
end
|
330
300
|
|
331
301
|
# Reduce angle to [0,2Pi)
|
@@ -338,12 +308,123 @@ module Flt
|
|
338
308
|
# we could reduce first to pi*2 to avoid the mod k0 operation
|
339
309
|
k,r,divisor = DecNum.context do
|
340
310
|
DecNum.context.precision *= 3
|
341
|
-
m = k0.nil? ?
|
311
|
+
m = k0.nil? ? one_cycle : half_cycle/k0
|
342
312
|
a.divmod(m)+[m]
|
343
313
|
end
|
344
314
|
[r, k.modulo(k0*2).to_i, divisor]
|
345
315
|
end
|
346
316
|
|
317
|
+
def one_cycle
|
318
|
+
case DecNum.context.angle
|
319
|
+
when :rad
|
320
|
+
pi2
|
321
|
+
when :deg
|
322
|
+
DecNum(360)
|
323
|
+
when :grad
|
324
|
+
DecNum(400)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def half_cycle
|
329
|
+
case DecNum.context.angle
|
330
|
+
when :rad
|
331
|
+
pi
|
332
|
+
when :deg
|
333
|
+
DecNum(180)
|
334
|
+
when :grad
|
335
|
+
DecNum(200)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
def quarter_cycle
|
340
|
+
case DecNum.context.angle
|
341
|
+
when :rad
|
342
|
+
HALF*pi
|
343
|
+
when :deg
|
344
|
+
DecNum(90)
|
345
|
+
when :grad
|
346
|
+
DecNum(100)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def to_rad(x)
|
351
|
+
case DecNum.context.angle
|
352
|
+
when :rad
|
353
|
+
+x
|
354
|
+
else
|
355
|
+
+DecNum.context(:precision=>DecNum.context.precision+3){x*pi/half_cycle}
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
def to_deg(x)
|
360
|
+
case DecNum.context.angle
|
361
|
+
when :deg
|
362
|
+
+x
|
363
|
+
else
|
364
|
+
+DecNum.context(:precision=>DecNum.context.precision+3){x*DecNum(180)/half_cycle}
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
def to_grad(x)
|
369
|
+
case DecNum.context.angle
|
370
|
+
when :deg
|
371
|
+
+x
|
372
|
+
else
|
373
|
+
+DecNum.context(:precision=>DecNum.context.precision+3){x*DecNum(200)/half_cycle}
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def to_angle(angular_units, x)
|
378
|
+
return +x if angular_units == DecNum.context.angle
|
379
|
+
case angular_units
|
380
|
+
when :rad
|
381
|
+
to_rad(x)
|
382
|
+
when :deg
|
383
|
+
to_deg(x)
|
384
|
+
when :grad
|
385
|
+
to_grad(x)
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def rad_to(x)
|
390
|
+
case DecNum.context.angle
|
391
|
+
when :rad
|
392
|
+
+x
|
393
|
+
else
|
394
|
+
+DecNum.context(:precision=>DecNum.context.precision+3){x*half_cycle/pi}
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
def deg_to(x)
|
399
|
+
case DecNum.context.angle
|
400
|
+
when :deg
|
401
|
+
+x
|
402
|
+
else
|
403
|
+
+DecNum.context(:precision=>DecNum.context.precision+3){x*half_cycle/DecNum(180)}
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def grad_to(x)
|
408
|
+
case DecNum.context.angle
|
409
|
+
when :grad
|
410
|
+
+x
|
411
|
+
else
|
412
|
+
+DecNum.context(:precision=>DecNum.context.precision+3){x*half_cycle/DecNum(200)}
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
def angle_to(x, angular_units)
|
417
|
+
return +x if angular_units == DecNum.context.angle
|
418
|
+
case angular_units
|
419
|
+
when :rad
|
420
|
+
rad_to(x)
|
421
|
+
when :deg
|
422
|
+
deg_to(x)
|
423
|
+
when :grad
|
424
|
+
grad_to(x)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
347
428
|
#end
|
348
429
|
|
349
430
|
end # Math
|
data/lib/flt/num.rb
CHANGED
@@ -408,6 +408,7 @@ class Num < Numeric
|
|
408
408
|
@flags = Num::Flags()
|
409
409
|
@coercible_type_handlers = num_class.base_coercible_types.dup
|
410
410
|
@conversions = num_class.base_conversions.dup
|
411
|
+
@angle = :rad # angular units: :rad (radians) / :deg (degrees) / :grad (gradians)
|
411
412
|
end
|
412
413
|
assign options.first
|
413
414
|
|
@@ -476,7 +477,7 @@ class Num < Numeric
|
|
476
477
|
@num_class.int_div_radix_power(x,n)
|
477
478
|
end
|
478
479
|
|
479
|
-
attr_accessor :rounding, :emin, :emax, :flags, :traps, :ignored_flags, :capitals, :clamp
|
480
|
+
attr_accessor :rounding, :emin, :emax, :flags, :traps, :ignored_flags, :capitals, :clamp, :angle
|
480
481
|
|
481
482
|
# TODO: consider the convenience of adding accessors of this kind:
|
482
483
|
# def rounding(new_rounding=nil)
|
@@ -593,6 +594,7 @@ class Num < Numeric
|
|
593
594
|
@capitals = options[:capitals ] unless options[:capitals ].nil?
|
594
595
|
@clamp = options[:clamp ] unless options[:clamp ].nil?
|
595
596
|
@exact = options[:exact ] unless options[:exact ].nil?
|
597
|
+
@angle = options[:angle ] unless options[:angle ].nil?
|
596
598
|
update_precision
|
597
599
|
end
|
598
600
|
end
|
@@ -615,6 +617,7 @@ class Num < Numeric
|
|
615
617
|
@exact = other.exact
|
616
618
|
@coercible_type_handlers = other.coercible_type_handlers.dup
|
617
619
|
@conversions = other.conversions.dup
|
620
|
+
@angle = other.angle
|
618
621
|
end
|
619
622
|
|
620
623
|
def dup
|
@@ -971,7 +974,7 @@ class Num < Numeric
|
|
971
974
|
def inspect
|
972
975
|
class_name = self.class.to_s.split('::').last
|
973
976
|
"<#{class_name}:\n" +
|
974
|
-
instance_variables.map { |v| " #{v}: #{
|
977
|
+
instance_variables.map { |v| " #{v}: #{instance_variable_get(v).inspect}"}.join("\n") +
|
975
978
|
">\n"
|
976
979
|
end
|
977
980
|
|
@@ -4151,7 +4154,8 @@ class Num < Numeric
|
|
4151
4154
|
:traps=>[DivisionByZero, Overflow, InvalidOperation],
|
4152
4155
|
:ignored_flags=>[],
|
4153
4156
|
:capitals=>true,
|
4154
|
-
:clamp=>true
|
4157
|
+
:clamp=>true,
|
4158
|
+
:angle=>:rad
|
4155
4159
|
)
|
4156
4160
|
|
4157
4161
|
end
|
data/lib/flt/version.rb
CHANGED
data/test/test_basic.rb
CHANGED
@@ -1,53 +1,59 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
s
|
3
|
+
module TestFunctions
|
4
|
+
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def exp(x,c=nil)
|
8
|
+
|
9
|
+
i, lasts, s, fact, num = 0, 0, 1, 1, 1
|
10
|
+
DecNum.local_context(c) do
|
11
|
+
# result context
|
12
|
+
DecNum.local_context do |context|
|
13
|
+
# working context
|
14
|
+
context.precision += 2
|
15
|
+
context.rounding = DecNum::ROUND_HALF_EVEN
|
16
|
+
while s != lasts
|
17
|
+
lasts = s
|
18
|
+
i += 1
|
19
|
+
fact *= i
|
20
|
+
num *= x
|
21
|
+
s += num / fact
|
22
|
+
end
|
17
23
|
end
|
24
|
+
+s
|
18
25
|
end
|
19
|
-
+s
|
20
26
|
end
|
21
|
-
end
|
22
27
|
|
23
|
-
def exp1(x, c=nil)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
28
|
+
def exp1(x, c=nil)
|
29
|
+
return DecNum(BigDecimal("NaN")) if x.infinite? || x.nan?
|
30
|
+
y = nil
|
31
|
+
ext = 2
|
32
|
+
DecNum.local_context(c) do |context|
|
33
|
+
n = (context.precision += ext)
|
34
|
+
|
35
|
+
one = DecNum("1")
|
36
|
+
x1 = one
|
37
|
+
y = one
|
38
|
+
d = y
|
39
|
+
z = one
|
40
|
+
i = 0
|
41
|
+
while d.nonzero? && ((m = n - (y.fractional_exponent - d.fractional_exponent).abs) > 0)
|
42
|
+
m = ext if m < ext
|
43
|
+
x1 *= x
|
44
|
+
i += 1
|
45
|
+
z *= i
|
46
|
+
|
47
|
+
#d = x1.divide(z,:precision=>m)
|
48
|
+
context.precision = m
|
49
|
+
d = x1/z
|
50
|
+
context.precision = n
|
51
|
+
|
52
|
+
y += d
|
53
|
+
end
|
48
54
|
end
|
55
|
+
return +y
|
49
56
|
end
|
50
|
-
return +y
|
51
57
|
end
|
52
58
|
|
53
59
|
def return_from_local_context
|
@@ -324,10 +330,10 @@ class TestBasic < Test::Unit::TestCase
|
|
324
330
|
DecNum.context.precision = 100
|
325
331
|
DecNum.context.rounding = :half_even
|
326
332
|
e_100 = "2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427"
|
327
|
-
assert_equal e_100, exp(DecNum(1)).to_s
|
328
|
-
assert_equal DecNum(e_100), exp(DecNum(1))
|
329
|
-
assert_equal e_100, exp1(DecNum(1)).to_s
|
330
|
-
assert_equal DecNum(e_100), exp1(DecNum(1))
|
333
|
+
assert_equal e_100, TestFunctions.exp(DecNum(1)).to_s
|
334
|
+
assert_equal DecNum(e_100), TestFunctions.exp(DecNum(1))
|
335
|
+
assert_equal e_100, TestFunctions.exp1(DecNum(1)).to_s
|
336
|
+
assert_equal DecNum(e_100), TestFunctions.exp1(DecNum(1))
|
331
337
|
end
|
332
338
|
|
333
339
|
def test_special
|
data/test/test_bin.rb
CHANGED
@@ -23,7 +23,7 @@ class TestBin < Test::Unit::TestCase
|
|
23
23
|
assert_equal 0.1, BinNum('0.1', :fixed)
|
24
24
|
|
25
25
|
assert_equal Float::MAX, BinNum.context.maximum_finite
|
26
|
-
assert_equal Float::
|
26
|
+
assert_equal Float::MIN_N, BinNum.context.minimum_normal
|
27
27
|
|
28
28
|
numbers = %w{
|
29
29
|
0.123437
|
data/test/test_dectest.rb
CHANGED
@@ -125,7 +125,8 @@ class TestBasic < Test::Unit::TestCase
|
|
125
125
|
|
126
126
|
File.open(fn,'r') do |file|
|
127
127
|
file.each_line do |line|
|
128
|
-
|
128
|
+
line = line.split('--').first.strip if line.include?('--')
|
129
|
+
next if line.strip.empty?
|
129
130
|
|
130
131
|
if line.include?(' -> ')
|
131
132
|
# test
|
@@ -148,7 +149,7 @@ class TestBasic < Test::Unit::TestCase
|
|
148
149
|
if funct
|
149
150
|
# do test
|
150
151
|
msg = " Test #{id}: #{funct}(#{valstemp.join(',')}) = #{ans}"
|
151
|
-
File.open('dectests.txt','a'){|f| f.puts msg}
|
152
|
+
#File.open('dectests.txt','a'){|f| f.puts msg}
|
152
153
|
expected = result = result_flags = nil
|
153
154
|
DecNum.local_context do |context|
|
154
155
|
context.flags.clear!
|
data/test/test_trig.rb
CHANGED
@@ -7,70 +7,101 @@ class TestTrig < Test::Unit::TestCase
|
|
7
7
|
|
8
8
|
|
9
9
|
def setup
|
10
|
-
@
|
11
|
-
[
|
12
|
-
|
13
|
-
|
10
|
+
@data = {}
|
11
|
+
Dir[File.join(File.dirname(__FILE__), "trigtest/*.txt")].each do |fn|
|
12
|
+
if File.basename(fn) =~ /\A([a-z]+)(\d+)_(\d+)_([a-z]+)\.txt\Z/
|
13
|
+
method = $1.to_sym
|
14
|
+
radix = $2.to_i
|
15
|
+
prec = $3.to_i
|
16
|
+
angle = $4.to_sym
|
17
|
+
@data[radix] ||= {}
|
18
|
+
@data[radix][angle] ||= {}
|
19
|
+
@data[radix][angle][prec] ||= {}
|
20
|
+
@data[radix][angle][prec][method] = File.read(fn).split("\n").map do |line|
|
21
|
+
line.split.map{|x| Flt::DecNum(x)}
|
22
|
+
end
|
14
23
|
end
|
15
24
|
end
|
16
25
|
end
|
17
26
|
|
18
|
-
def check(f)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
27
|
+
def check(f, radix=10, angle=:rad)
|
28
|
+
class_num = Num[radix]
|
29
|
+
@data[radix][angle].keys.each do |prec|
|
30
|
+
class_num.context(:precision=>prec, :angle=>angle) do
|
31
|
+
class_num.context.traps[DecNum::DivisionByZero] = false
|
32
|
+
data = @data[radix][angle][prec][f]
|
33
|
+
data.each do |x, result|
|
34
|
+
assert_equal result, class_num::Math.send(f, x), "#{f}(#{x})==#{result} [#{radix} #{angle} #{prec}]"
|
35
|
+
end
|
23
36
|
end
|
24
37
|
end
|
25
38
|
end
|
26
39
|
|
27
|
-
def check_relaxed(f, ulps=
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
40
|
+
def check_relaxed(f, radix=10, angle=:rad, ulps=1)
|
41
|
+
class_num = Num[radix]
|
42
|
+
@data[radix][angle].keys.each do |prec|
|
43
|
+
class_num.context(:precision=>prec, :angle=>angle) do
|
44
|
+
class_num.context.traps[DecNum::DivisionByZero] = false
|
45
|
+
data = @data[radix][angle][prec][f]
|
46
|
+
data.each do |x, result|
|
47
|
+
y = class_num::Math.send(f, x)
|
48
|
+
if result.special?
|
49
|
+
assert_equal result, y, "#{f}(#{x})==#{result} [#{radix} #{angle} #{prec}]"
|
50
|
+
else
|
51
|
+
err_ulps = (y-result).abs/result.ulp
|
52
|
+
assert err_ulps<=ulps, "#{f}(#{x})==#{result} to within #{ulps} ulps; error: #{err_ulps} ulps (#{y}) [#{radix} #{angle} #{prec}]"
|
53
|
+
end
|
54
|
+
end
|
34
55
|
end
|
35
56
|
end
|
36
57
|
end
|
37
58
|
|
38
|
-
|
39
|
-
# def test_trig
|
40
|
-
# DecNum.context(:precision=>12) do
|
41
|
-
# @data12.keys.each do |f|
|
42
|
-
# data = @data12[f]
|
43
|
-
# data.each do |x, result|
|
44
|
-
# assert_equal result, DecNum::Math.send(f, x), "#{f}(#{x})==#{result}"
|
45
|
-
# end
|
46
|
-
# end
|
47
|
-
# end
|
48
|
-
# end
|
49
|
-
|
50
|
-
# separate tests per function
|
51
|
-
|
52
59
|
def test_sin
|
53
|
-
|
60
|
+
check :sin, 10, :rad
|
54
61
|
end
|
55
62
|
|
56
63
|
def test_cos
|
57
|
-
|
64
|
+
check :cos, 10, :rad
|
58
65
|
end
|
59
66
|
|
60
67
|
def test_tan
|
61
|
-
check_relaxed :tan
|
68
|
+
check_relaxed :tan, 10, :rad
|
62
69
|
end
|
63
70
|
|
64
71
|
def test_asin
|
65
|
-
check_relaxed :asin
|
72
|
+
check_relaxed :asin, 10, :rad
|
66
73
|
end
|
67
74
|
|
68
75
|
def test_acos
|
69
|
-
check_relaxed :acos
|
76
|
+
check_relaxed :acos, 10, :rad
|
70
77
|
end
|
71
78
|
|
72
79
|
def test_atan
|
73
|
-
check_relaxed :atan
|
80
|
+
check_relaxed :atan, 10, :rad
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_sin_deg
|
84
|
+
check_relaxed :sin, 10, :deg
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_cos_deg
|
88
|
+
check_relaxed :cos, 10, :deg
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_tan_deg
|
92
|
+
check_relaxed :tan, 10, :deg
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_asin_deg
|
96
|
+
check_relaxed :asin, 10, :deg
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_acos_deg
|
100
|
+
check_relaxed :acos, 10, :deg
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_atan_deg
|
104
|
+
check_relaxed :atan, 10, :deg
|
74
105
|
end
|
75
106
|
|
76
107
|
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 23
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 1
|
8
|
-
- 1
|
9
7
|
- 2
|
10
|
-
|
8
|
+
- 0
|
9
|
+
version: 1.2.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Javier Goizueta
|
@@ -15,7 +14,7 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-15 00:00:00 +02:00
|
19
18
|
default_executable:
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
@@ -26,7 +25,6 @@ dependencies:
|
|
26
25
|
requirements:
|
27
26
|
- - ">="
|
28
27
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 9
|
30
28
|
segments:
|
31
29
|
- 2
|
32
30
|
- 1
|
@@ -125,7 +123,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
123
|
requirements:
|
126
124
|
- - ">="
|
127
125
|
- !ruby/object:Gem::Version
|
128
|
-
hash: 3
|
129
126
|
segments:
|
130
127
|
- 0
|
131
128
|
version: "0"
|
@@ -134,7 +131,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
131
|
requirements:
|
135
132
|
- - ">="
|
136
133
|
- !ruby/object:Gem::Version
|
137
|
-
hash: 3
|
138
134
|
segments:
|
139
135
|
- 0
|
140
136
|
version: "0"
|