flt 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+