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
@@ -0,0 +1,561 @@
1
+ # Tolerance for floating-point types (Float, Flt::BinNum, Flt::DecNum)
2
+ #
3
+ # Tolerance can be used to allow for a tolerance in floating-point comparisons.
4
+ #
5
+ # A Tolerance can be defined independently of the type (floating-point numeric class)
6
+ # it will be used with; The actual tolerance value will be compute for a particular reference value:
7
+ #
8
+ # tol = Tolerance(3, :decimals)
9
+ # puts tol.value(DecNum('10.0')).inspect
10
+ # puts tol.value(10.0).inspect
11
+ # puts tol.value.inspect
12
+ #
13
+ # tol = Tolerance(:epsilon)
14
+ # puts tol.value(DecNum('10.0')).inspect
15
+ # puts tol.value(10.0).inspect
16
+ # puts tol.value.inspect
17
+ #
18
+ # Tolerances can be:
19
+ # * Absolute: the tolerance value is a fixed value independent of the values to be compared.
20
+ # * Relative: the tolerance value is adjusted (scaled) to the magnitude of the numbers to be compared,
21
+ # so that it specifies admisible relative error values.
22
+ # Particular cases of relative tolerance are Percent and Permille tolerance.
23
+ # * Floating: tolerance is scaled along with the floating-point values. Floating tolerances can be
24
+ # :native (the scaling is done with the same base as the floating point radix), or have a specific base.
25
+ # Currently floating tolerances use the :low convention at the powers of the radix (as ulps). Floating
26
+ # tolerances should be computed at the correct or exact value to be compared, not at an approximation, but
27
+ # note that binary tolerance operations (equals?, less_than?, ...) consider both arguments as approximations.
28
+ # A special case of a floating tolerance are tolerances specified in ULPs.
29
+ #
30
+ # Tolerances can be specified as:
31
+ # * A specific value (valid for any type of tolerance: absolute, relative & floating)
32
+ # * A number of digits, or, for specific bases, decimals or bits, available for absolute and floating (significant).
33
+ # * Epsilon (or Big epsilon), optionally multiplied by a factor, available for all types of tolerances
34
+ # * A number of ULPs, which implies a floating tolerance.
35
+ # * A percent or permille value, only for relative tolerances.
36
+ #
37
+ # There exists a Tolerance-derived class for each valid combination of type of tolerance and specification mode,
38
+ # but they all can be defined with the Tolerance() constructor.
39
+ # The first parameter to the constructor is the tolerance value, and in some kinds of tolerance it can be
40
+ # omitted. Next, the kind of tolerance is passed as a symbol; valid values are:
41
+ # * :absolute
42
+ # * :relative
43
+ # * :floating Generic floating decimal; another parameter can be passed for a specific base
44
+ # * :percent a particular kind of relative tolerance
45
+ # * :permille a particular kind of relative tolerance
46
+ # * :ulps a particular kind of floating tolerance
47
+ # * :sig_decimals (significative rounded decimals) a particular kind of floating tolerance; another parameter specifies if rounded
48
+ # * :decimals a particular kind of absolute tolerance
49
+ # * :sig_bits (significative bits) a particular kind of floating tolerance; another parameter specifies if rouded
50
+ # * :epsilon relative tolerance given as a multiple of epsilon (1 by default)
51
+ # * :abs_epsilon absolute tolerance given as a multiple of epsilon (1 by default)
52
+ # * :flt_epsilon floating tolerance given as a multiple of epsilon (1 by default)
53
+ # * :big_epsilon relative tolerance given as a multiple of big-epsilon (1 by default)
54
+ # * :abs_big_epsilon absolute tolerance given as a multiple of big-epsilon (1 by default)
55
+ # * :flt_big_epsilon floating tolerance given as a multiple of big-epsilon (1 by default)
56
+ #
57
+ # Examples:
58
+ #
59
+ # tol = Tolerance(100, :absolute)
60
+ # puts tol.value(1.0)
61
+ # puts tol.value(1.5)
62
+ # puts tol.value(1.0E10)
63
+ # puts tol.eq?(11234.0, 11280.0)
64
+ #
65
+ # tol = Tolerance(100, :relative)
66
+ # puts tol.value(1.0)
67
+ # puts tol.value(1.5)
68
+ # puts tol.value(1.0E10)
69
+ # puts tol.eq?(11234.0, 11280.0)
70
+ #
71
+ # tol = Tolerance(100, :floating)
72
+ # puts tol.value(1.0)
73
+ # puts tol.value(1.5)
74
+ # puts tol.value(1.0E10)
75
+ # puts tol.eq?(11234.0, 11280.0)
76
+ #
77
+ # tol = Tolerance(3, :sig_decimals)
78
+ # puts tol.eq?(1.234,1.23)
79
+ #
80
+ # tol = Tolerance(1, :ulps)
81
+ # puts tol.eq?(3.3433, 3.3433.next)
82
+ # puts tol.eq?(DecNum('1.1'), DecNum('1.1').next)
83
+ #
84
+ # tol = Tolerance(1, :percent)
85
+ # puts tol.equal_to?(3.14159, Math::PI)
86
+ #
87
+
88
+ require 'flt'
89
+ require 'flt/float'
90
+
91
+ module Flt
92
+
93
+ # The Tolerance class is a base class for all tolerances.
94
+ #
95
+ # Particular tolerance *kinds* (defined by a type of tolerance and the way to specify its value) are
96
+ # implemented in separate classes derived from Tolerance.
97
+ #
98
+ # Derived classes must implement at least one of the methods relative_to() or relative_to_many()
99
+ # and may also redefine cast_value() and descr_value()
100
+ class Tolerance
101
+
102
+ def initialize(value)
103
+ @value = value
104
+ end
105
+
106
+ # Value of the tolerance for a given (floating-point) quantity
107
+ def value(x=nil)
108
+ if x
109
+ relative_to(x)
110
+ else
111
+ @value
112
+ end
113
+ end
114
+
115
+ # Shorthand for value()
116
+ def [](x)
117
+ value(x)
118
+ end
119
+
120
+ # Description of the tolerance
121
+ def to_s
122
+ descr_value
123
+ end
124
+
125
+ # Is x nearly zero? (zero within tolerance); if a second argument y is specified:
126
+ # is x nearly zero? compared to y?
127
+ def zero?(x, y=nil)
128
+ x.zero? || x.abs < value(y || x)
129
+ end
130
+
131
+ # Returns true if the argument is approximately an integer
132
+ def integer?(x)
133
+ # Computing the tolerance at x seems the best option here
134
+ (x-x.round).abs <= relative_to(x)
135
+ end
136
+
137
+ # If the argument is close to an integer it rounds it
138
+ def integer(x)
139
+ # return integer?(x) ? x.round : nil
140
+ r = x.round
141
+ ((x-r).abs <= relative_to(x)) ? r : nil
142
+ end
143
+
144
+ # Binary comparison operations that treat both arguments equally;
145
+
146
+ # less-than: x < y within tolerance
147
+ def lt?(x,y)
148
+ y-x > relative_to_many(:max, x, y)
149
+ end
150
+
151
+ # greater_than: x > y within tolerance
152
+ def gt?(x,y)
153
+ x-y > relative_to_many(:max, x, y)
154
+ end
155
+
156
+ # equals: x == y within tolerance (relaxed)
157
+ def eq?(x, y)
158
+ (x-y).abs <= relative_to_many(:max, x, y)
159
+ end
160
+
161
+ # strongly equals: x == y within tolerance (strict)
162
+ def seq?
163
+ (x-y).abs <= relative_to_many(:min, x, y)
164
+ end
165
+
166
+ # Binary operations that consider the second value the correct or exact value
167
+
168
+ # x < correct value y within tolerance
169
+ def less_than?(x,y)
170
+ y-x > relative_to(y)
171
+ end
172
+
173
+ # x > correct value y within tolerance
174
+ def greater_than?(x,y)
175
+ x-y > relative_to(y)
176
+ end
177
+
178
+ # x == correct value y within tolerance
179
+ def equal_to?(x, y)
180
+ (x-y).abs <= relative_to(y)
181
+ end
182
+
183
+ # This method is redefined in derived classes to compute the tolerance value in relation to the value x;
184
+ #
185
+ # If not redefined, relative_to_many will be used.
186
+ def relative_to(x)
187
+ relative_to_many(:max, x)
188
+ end
189
+
190
+ # This method is redefined in derived classes to compute the tolerance value in relation to the values xs;
191
+ # mode must be either :max or :min, and determines if the largerst (relaxed condition) or smallest
192
+ #(strict condition) of the relative tolerances is returned.
193
+ #
194
+ # If not redefined, relative_to will be used, but redefining this method can be used to optimize the
195
+ # performance
196
+ def relative_to_many(mode, *xs)
197
+ xs.map{|x| relative_to(x)}.send(mode)
198
+ end
199
+
200
+ # Returns the tolerance reference value for a numeric class; in derived classes this
201
+ # can be redefined to allow for values which change in value or precision depending
202
+ # on the numeric class or context.
203
+ def cast_value(num_class)
204
+ num_class.context.Num(@value)
205
+ end
206
+
207
+ # Description of the reference value (can be specialized in derived classes)
208
+ def descr_value
209
+ @value.to_s
210
+ end
211
+
212
+ # Class methods
213
+ class <<self
214
+
215
+ # Define a tolerance magnitude as a number of digits of the given base. If rounded is true
216
+ # it is assumed that results are rounded to n digits; otherwise truncation or directed rounding
217
+ # may occur and the tolerance will be larger.
218
+ def digits(base, n, rounded=true)
219
+ v = base**(-n)
220
+ v /= 2 if rounded
221
+ v
222
+ end
223
+
224
+ # Define a tolerance magnitude as a number of decimal digits. If rounded is true
225
+ # it is assumed that results are rounded to n digits; otherwise truncation or directed rounding
226
+ # may occur and the tolerance will be larger.
227
+ def decimals(n, rounded=true)
228
+ digits 10, n, rounded
229
+ end
230
+
231
+ # Define a tolerance magnitude as a number of binary digits. If rounded is true
232
+ # it is assumed that results are rounded to n digits; otherwise truncation or directed rounding
233
+ # may occur and the tolerance will be larger.
234
+ def bits(n, rounded=true)
235
+ digits 10, n, rounded
236
+ end
237
+
238
+ # Define a tolerance magnitude in relation to the 'epsilon' of the floating-point type and context.
239
+ # A multiplier may be specified to scale the epsilon.
240
+ def epsilon(num_class, mult=1)
241
+ num_class.context.epsilon*mult
242
+ end
243
+
244
+ # Define a tolerance magnitude in relation to the 'big epsilon' of the floating-point type and context.
245
+ # A multiplier may be specified to scale the big epsilon.
246
+ #
247
+ # This is a tolerance that makes multiplication associative when used with FloatingTolerance.
248
+ def big_epsilon(num_class, mult=1)
249
+ context = num_class.context
250
+ e0 = context.epsilon
251
+ # we could compute with round-up instead of using next_plus, but we can't do that with Float
252
+ den = (context.Num(1)-e0/2)
253
+ big_eps = context.next_plus(e0*2/(den*den))
254
+ big_eps*mult
255
+ end
256
+
257
+ end
258
+
259
+ end
260
+
261
+ # Implementation of absolute tolerances
262
+ class AbsoluteTolerance < Tolerance
263
+ def initialize(value)
264
+ super
265
+ end
266
+ def relative_to(x)
267
+ cast_value(x.class)
268
+ end
269
+ def relative_to_many(mode, *xs)
270
+ cast_value(xs.first.class)
271
+ end
272
+ end
273
+
274
+ # Implementation of relative tolerances
275
+ class RelativeTolerance < Tolerance
276
+ def initialize(value)
277
+ super
278
+ end
279
+ def relative_to(x)
280
+ x.abs*cast_value(x.class)
281
+ end
282
+ def to_s
283
+ "#{descr_value}/1"
284
+ end
285
+ end
286
+
287
+ # Implementation of percent (relative) tolerances
288
+ class PercentTolerance < RelativeTolerance
289
+ def initialize(value)
290
+ super
291
+ end
292
+ def to_s
293
+ "#{descr_value}%"
294
+ end
295
+ def cast_value(num_class)
296
+ num_class.Num(@value)/num_class.Num(100)
297
+ end
298
+ end
299
+
300
+ # Implementation of permille (relative) tolerances
301
+ class PermilleTolerance < RelativeTolerance
302
+ def initialize(value)
303
+ super
304
+ end
305
+ def to_s
306
+ "#{descr_value}/1000"
307
+ end
308
+ def cast_value(num_class)
309
+ num_class.Num(@value)/num_class.Num(1000)
310
+ end
311
+ end
312
+
313
+ # Implementation of floating tolerances
314
+ class FloatingTolerance < Tolerance
315
+ def initialize(value, radix=:native)
316
+ super(value)
317
+ @radix = radix
318
+ end
319
+
320
+ def to_s
321
+ if @radix==:native
322
+ "#{descr_value} flt."
323
+ else
324
+ "#{descr_value} flt.(#{radix})"
325
+ end
326
+ end
327
+
328
+ @float_minimum_normalized_fraction = Math.ldexp(1,-1)
329
+ def self.float_minimum_normalized_fraction
330
+ @float_minimum_normalized_fraction
331
+ end
332
+
333
+ def self.ref_adjusted_exp
334
+ -1
335
+ end
336
+
337
+ def relative_to_many(mode, *xs)
338
+ exp = nil
339
+
340
+ num_class = xs.first.class
341
+ context = num_class.context
342
+ xs = xs.map{|x| context.Num(x)}
343
+ v = cast_value(num_class)
344
+
345
+ # TODO: simplify using context
346
+ case xs.first
347
+ when Flt::Num
348
+ # TODO: handle special values
349
+ if @radix == :native || @radix == num_class.radix
350
+ exp = xs.map do |x|
351
+ x = x.normalize
352
+ exp = x.adjusted_exponent
353
+ exp -= 1 if x.coefficient == x.num_class.context.minimum_normalized_coefficient # if :low mode
354
+ exp -= FloatingTolerance.ref_adjusted_exp
355
+ exp
356
+ end.send(mode)
357
+ r = num_class.Num(+1, v.coefficient, v.exponent+exp)
358
+ r = r.normalize if num_class.radix == 2
359
+ r
360
+ elsif @radix==10
361
+ # assert x.class==BinNum
362
+ # TODO: optimize (implement log10 for BinNum)
363
+ exp = xs.map do |x|
364
+ x = x.to_decimal_exact(:exact=>true).normalize
365
+ exp = x.adjusted_exponent
366
+ exp -= 1 if x.coefficient == x.num_class.context.minimum_normalized_coefficient # if :low mode
367
+ exp -= FloatingTolerance.ref_adjusted_exp
368
+ exp
369
+ end.send(mode)
370
+ num_class.from_decimal(Flt.DecNum(+1, 1, exp)*v.to_decimal_exact)
371
+ else
372
+ # assert num_class==DecNum && @radix==2
373
+ exp = xs.map do |x|
374
+ exp = (x.ln/DecNum(2).ln).ceil.to_i - 1 # (x.ln/DecNum(2).ln).floor+1 - 1 if :high mode
375
+ exp -= FloatingTolerance.ref_adjusted_exp
376
+ exp
377
+ end.send(mode)
378
+ v*num_class.Num(2)**exp
379
+ end
380
+ when Float
381
+ if @radix == :native || @radix == Float::RADIX
382
+ exp = xs.map do |x|
383
+ f,e = Math.frexp(x)
384
+ exp = e-1
385
+ exp -= 1 if f==FloatingTolerance.float_minimum_normalized_fraction # if :low mode
386
+ exp -= FloatingTolerance.ref_adjusted_exp
387
+ end.send(mode)
388
+ Math.ldexp(v.to_f, exp)
389
+ else
390
+ # assert @radix==10
391
+ exp = xs.map do |x|
392
+ exp = Math.log10(x.abs).ceil - 1 # Math.log10(x.abs).floor+1 - 1 if :high mode
393
+ exp -= FloatingTolerance.ref_adjusted_exp
394
+ end.send(mode)
395
+ v*10.0**exp
396
+ end
397
+ when BigDecimal
398
+ if @radix == :native || @radix == 10
399
+ exp = xs.map do |x|
400
+ sign,digits,base,exp = x.split
401
+ exp -= 1
402
+ exp -= 1 if digits=="1" # if :low mode
403
+ exp -= FloatingTolerance.ref_adjusted_exp
404
+ exp
405
+ end.send(mode)
406
+ sign, digits, base, vexp = v.split
407
+ BigDecimal.new("0.#{digits}E#{vexp+exp}")
408
+ else
409
+ # assert num_class==BigDecimal && @radix==2
410
+ prec = 10
411
+ exp = xs.map do |x|
412
+ exp = (Flt::DecNum(x.to_s).ln/Flt::DecNum(2).ln).ceil - 1 # ... if :high mode
413
+ exp -= FloatingTolerance.ref_adjusted_exp
414
+ exp
415
+ end.send(mode)
416
+ context.Num(v)*context.Num(2)**exp
417
+ end
418
+ end
419
+ end
420
+
421
+ end
422
+
423
+ # Implementation of (floating) tolerances given in ULPs (units in the last place)
424
+ class UlpsTolerance < FloatingTolerance
425
+ def initialize(n=nil, num_class=nil)
426
+ @ulps = n || 1
427
+ num_class ||= Float
428
+ context = num_class.context
429
+ unit = context.Num(1)
430
+ n = context.Num(@ulps)
431
+ super(context.ulp(unit)*n)
432
+ end
433
+ def to_s
434
+ "#{@ulps} ulp#{(!@ulps.kind_of?(Numeric) || (@ulps > 1)) ? 's' : ''}"
435
+ end
436
+ def relative_to(x)
437
+ context = x.class.context
438
+ n = context.Num(@ulps)
439
+ context.ulp(x)*n
440
+ end
441
+ def relative_to_many(mode, *xs)
442
+ xs.map{|x| relative_to(x)}.send(mode)
443
+ end
444
+ end
445
+
446
+ # Implementation of (floating) tolerances given in number of significant decimal digits
447
+ class SigDecimalsTolerance < FloatingTolerance
448
+ def initialize(ndec, rounded = true)
449
+ super Tolerance.decimals(ndec, rounded), 10
450
+ @decimals = ndec
451
+ @rounded = rounded
452
+ end
453
+ def to_s
454
+ "#{@decimals} sig. #{@rounded ? 'r.' : 'r'}dec."
455
+ end
456
+ end
457
+
458
+ # Implementation of (absolute) tolerances given in number of decimal digits
459
+ class DecimalsTolerance < AbsoluteTolerance
460
+ def initialize(ndec, rounded = true)
461
+ super Tolerance.decimals(ndec, rounded)
462
+ @decimals = ndec
463
+ @rounded = rounded
464
+ end
465
+ def to_s
466
+ "#{@decimals} #{@rounded ? 'r.' : 'r'}dec."
467
+ end
468
+ end
469
+
470
+ # Implementation of (floating) tolerances given in number of significant bits
471
+ class SigBitsTolerance < FloatingTolerance
472
+ def initialize(ndec, rounded = true)
473
+ super Tolerance.bits(ndec, rounded), 2
474
+ @bits = ndec
475
+ @rounded = rounded
476
+ end
477
+ def to_s
478
+ "#{@bits} sig. #{@rounded ? 'r.' : 'r'}bits"
479
+ end
480
+ end
481
+
482
+ # Mixin for tolerances defined by Epsilon or a multiple of it
483
+ module EpsilonMixin
484
+ def initialize(mult=nil)
485
+ @mult = mult || 1
486
+ super nil
487
+ end
488
+ def cast_value(num_class)
489
+ Tolerance.epsilon(num_class, @mult)
490
+ end
491
+ def descr_value
492
+ "#{@mult==1 ? '' : "#{@mult} "} eps."
493
+ end
494
+ end
495
+
496
+ # Implementation of (relative) tolerances given as a multiple of Epsilon
497
+ class EpsilonTolerance < RelativeTolerance
498
+ include EpsilonMixin
499
+ end
500
+
501
+ # Implementation of (absolute) tolerances given as a multiple of Epsilon
502
+ class AbsEpsilonTolerance < AbsoluteTolerance
503
+ include EpsilonMixin
504
+ end
505
+
506
+ # Implementation of (floating) tolerances given as a multiple of Epsilon
507
+ class FltEpsilonTolerance < FloatingTolerance
508
+ include EpsilonMixin
509
+ end
510
+
511
+ # Mixin for tolerances defined by Big Epsilon or a multiple of it
512
+ module BigEpsilonMixin
513
+ def initialize(mult=nil)
514
+ @mult = mult || 1
515
+ super nil
516
+ end
517
+ def cast_value(num_class)
518
+ Tolerance.big_epsilon(num_class, @mult)
519
+ end
520
+ def descr_value
521
+ "#{@mult==1 ? '' : "#{@mult} "} big eps."
522
+ end
523
+ end
524
+
525
+ # Implementation of (relative) tolerances given as a multiple of Big Epsilon
526
+ class BigEpsilonTolerance < RelativeTolerance
527
+ include BigEpsilonMixin
528
+ end
529
+
530
+ # Implementation of (absolute) tolerances given as a multiple of Big Epsilon
531
+ class AbsBigEpsilonTolerance < AbsoluteTolerance
532
+ include EpsilonMixin
533
+ end
534
+
535
+ # Implementation of (floating) tolerances given as a multiple of Big Epsilon
536
+ class FltBigEpsilonTolerance < FloatingTolerance
537
+ include BigEpsilonMixin
538
+ end
539
+
540
+ module_function
541
+ # Tolerance constructor.
542
+ #
543
+ # The first parameter is the value (magnitude) of the tolerance, and is optional for some tolerances.
544
+ #
545
+ # The next parameter is the kind of tolerance as a symbol. It corresponds to the name of the
546
+ # implementation class minus the Tolerance suffix, and converted to snake-case (lowercase with underscores to
547
+ # separate words.)
548
+ #
549
+ # Finally any additional parameters admitted by the class constructor can be passed.
550
+ def Tolerance(*args)
551
+ if args.first.is_a?(Symbol)
552
+ value = nil
553
+ else
554
+ value = args.shift
555
+ end
556
+ cls_name = (args.shift || :absolute).to_s.gsub(/(^|_)(.)/){$2.upcase} + "Tolerance"
557
+ Flt.const_get(cls_name).new(value, *args)
558
+ end
559
+
560
+ end # Flt
561
+