nio 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,10 @@
1
+ == 0.2.2 2008-03-04
2
+
3
+ * Minor enhancements
4
+ - show_plus can be passed a string (e.g. ' ') that is used as the plus sign;
5
+ added new show_exp_plus to control the sign display of the exponent in
6
+ scientific notation.
7
+
1
8
  == 0.2.1 2007-12-15
2
9
 
3
10
  * Minor enhancements
@@ -1,20 +1,19 @@
1
1
  History.txt
2
2
  License.txt
3
3
  Manifest.txt
4
- README.txt
4
+ README.txt
5
5
  SOURCE.txt
6
6
  Rakefile
7
7
  config/hoe.rb
8
8
  config/requirements.rb
9
9
  lib/nio.rb
10
- lib/nio/version.rb
11
- lib/nio/repdec.rb
12
- lib/nio/flttol.rb
13
- lib/nio/tools.rb
14
- lib/nio/rtnlzr.rb
15
- lib/nio/fmt.rb
16
- lib/nio/sugar.rb
17
- log/debug.log
10
+ lib/nio/version.rb
11
+ lib/nio/repdec.rb
12
+ lib/nio/flttol.rb
13
+ lib/nio/tools.rb
14
+ lib/nio/rtnlzr.rb
15
+ lib/nio/fmt.rb
16
+ lib/nio/sugar.rb
18
17
  script/destroy
19
18
  script/destroy.cmd
20
19
  script/generate
@@ -23,12 +22,12 @@ script/txt2html
23
22
  script/txt2html.cmd
24
23
  setup.rb
25
24
  tasks/nuweb.rake
26
- tasks/deployment.rake
25
+ tasks/deployment.rake
27
26
  tasks/environment.rake
28
- tasks/website.rake
29
- test/data.yaml
27
+ tasks/website.rake
28
+ test/data.yaml
30
29
  test/test_helper.rb
31
- test/test_tools.rb
30
+ test/test_tools.rb
32
31
  test/test_repdec.rb
33
- test/test_rtnlzr.rb
34
- test/test_fmt.rb
32
+ test/test_rtnlzr.rb
33
+ test/test_fmt.rb
data/Rakefile CHANGED
@@ -1,4 +1,4 @@
1
1
  require 'config/requirements'
2
2
  require 'config/hoe' # setup Hoe + all gem configuration
3
3
 
4
- Dir['tasks/**/*.rake'].each { |rake| load rake }
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -1,4 +1,4 @@
1
- require 'nio/version'
1
+ require File.join(File.dirname(__FILE__),'../source/lib/nio/version')
2
2
 
3
3
  AUTHOR = 'Javier Goizueta' # can also be an array of Authors
4
4
  EMAIL = "javier@goizueta.info"
@@ -8,6 +8,7 @@ RUBYFORGE_PROJECT = 'nio' # The unix name for your project
8
8
  HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
9
  DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
10
 
11
+ =begin
11
12
  @config_file = "C:/Documents and Settings/jgoizueta/.rubyforge/user-config.yml"
12
13
  @config = nil
13
14
  RUBYFORGE_USERNAME = "jgoizueta"
@@ -31,7 +32,6 @@ end
31
32
  REV = nil
32
33
  # UNCOMMENT IF REQUIRED:
33
34
  # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
- VERS = Nio::VERSION::STRING + (REV ? ".#{REV}" : "")
35
35
  RDOC_OPTS = ['--quiet', '--title', 'Nio documentation',
36
36
  "--opname", "index.html",
37
37
  "--line-numbers",
@@ -44,30 +44,32 @@ class Hoe
44
44
  @extra_deps
45
45
  end
46
46
  end
47
+ =end
47
48
 
48
49
  # Generate all the Rake tasks
49
50
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
- hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
- p.author = AUTHOR
51
+ $hoe = Hoe.new(GEM_NAME, Nio::VERSION::STRING) do |p|
52
+ p.developer AUTHOR, EMAIL
52
53
  p.description = DESCRIPTION
53
- p.email = EMAIL
54
54
  p.summary = DESCRIPTION
55
55
  p.url = HOMEPATH
56
56
  p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
57
57
  p.test_globs = ["test/**/test_*.rb"]
58
58
  p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
59
59
 
60
- # == Optional
60
+
61
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
62
+ #p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
63
+ p.remote_rdoc_dir = '' # we start using the rdoc as the project home-page, later we'll setup separate page
64
+ p.rsync_args = '-av --delete --ignore-errors'
61
65
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\\n\\n")
66
+
62
67
  #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
63
68
 
64
- #p.spec_extras = {} # A hash of extra values to set in the gemspec.
65
-
69
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
70
+
66
71
  #p.spec_extras = { :autorequire=>'nio' }
67
72
 
68
73
  end
69
74
 
70
- CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
71
- PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
72
- #hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
73
- hoe.remote_rdoc_dir = '' # we start using the rdoc as the project home-page, later we'll setup separate page
75
+ require 'newgem/tasks' # load /tasks/*.rake
@@ -2,7 +2,7 @@ require 'fileutils'
2
2
  include FileUtils
3
3
 
4
4
  require 'rubygems'
5
- %w[rake hoe newgem rubigen].each do |req_gem|
5
+ %w[rubygems rake newgem rubigen].each do |req_gem|
6
6
  begin
7
7
  require req_gem
8
8
  rescue LoadError
@@ -14,4 +14,4 @@ end
14
14
 
15
15
  $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
16
16
 
17
- #require 'nio'
17
+ #require 'nio'
@@ -1,657 +1,657 @@
1
- # Floating point tolerance
2
- #--
3
- # Copyright (C) 2003-2005, Javier Goizueta <javier@goizueta.info>
4
- #
5
- # This program is free software; you can redistribute it and/or
6
- # modify it under the terms of the GNU General Public License
7
- # as published by the Free Software Foundation; either version 2
8
- # of the License, or (at your option) any later version.
9
- #++
10
- #
11
- # Author:: Javier Goizueta (mailto:javier@goizueta.info)
12
- # Copyright:: Copyright (c) 2002-2004 Javier Goizueta
13
- # License:: Distributes under the GPL license
14
- #
15
- # This module provides a numeric tolerance class for Float and BigDecimal.
16
-
17
- require 'bigdecimal'
18
- require 'bigdecimal/math' if ::VERSION>='1.8.1'
19
- require 'nio/tools'
20
-
21
-
22
- class Float
23
- unless const_defined?(:RADIX) # old Ruby versions didn't have this
24
- # Base of the Float representation
25
- RADIX = 2
26
-
27
- x = 1.0
28
- _bits_ = 0
29
- while 1!=x+1
30
- _bits_ += 1
31
- x /= 2
32
- end
33
- if ((1.0+2*x)-1.0)>2*x
34
- _bits_ -= 1
35
- end
36
-
37
- # Number of RADIX-base digits of precision in a Float
38
- MANT_DIG = _bits_
39
- # Number of decimal digits that can be stored in a Float and recovered
40
- DIG = ((MANT_DIG-1)*Math.log(RADIX)/Math.log(10)).floor
41
- # Smallest value that added to 1.0 produces something different from 1.0
42
- EPSILON = Math.ldexp(*Math.frexp(1).collect{|e| e.kind_of?(Integer) ? e-(MANT_DIG-1) : e})
43
- end
44
- # Decimal precision required to represent a Float and be able to recover its value
45
- DECIMAL_DIG = (MANT_DIG*Math.log(RADIX)/Math.log(10)).ceil+1
46
- end
47
-
48
- # :stopdoc:
49
- # A problem has been detected with Float#to_i() in some Ruby versiones
50
- # (it has been found in Ruby 1.8.4 compiled for x86_64_linux|)
51
- # This problem makes to_i produce an incorrect sign on some cases.
52
- # Here we try to detect the problem and apply a quick patch,
53
- # although this will slow down the method.
54
- if 4.611686018427388e+018.to_i < 0
55
- class Float
56
- alias _to_i to_i
57
- def to_i
58
- neg = (self < 0)
59
- i = _to_i
60
- i_neg = (i < 0)
61
- i = -i if neg != i_neg
62
- i
63
- end
64
- end
65
- end
66
- # :startdoc:
67
-
68
-
69
- # This module contains some constructor-like module functions
70
- # to help with the creation of tolerances and big-decimals.
71
- #
72
- # =BigDec
73
- # BigDec(x) -> a BigDecimal
74
- # BigDec(x,precision) -> a BigDecimal
75
- # BigDec(x,:exact) -> a BigDecimal
76
- # This is a shortcut to define a BigDecimal without using quotes
77
- # and a general conversion to BigDecimal method.
78
- #
79
- # The second parameter can be :exact to try for an exact conversion
80
- #
81
- # Conversions from Float have issues that should be understood; :exact
82
- # conversion will use the exact internal value of the Float, and when
83
- # no precision is specified, a value as simple as possible expressed as
84
- # a fraction will be used.
85
- #
86
- # =Tol
87
- # Tol(x) -> a Tolerance
88
- # This module function will convert its argument to a Noi::Tolerance
89
- # or a Noi::BigTolerance depending on its argument;
90
- #
91
- # Values of type Tolerance,Float,Integer (for Tolerance) or
92
- # BigTolerance,BigDecimal (for BigTolerance) are accepted.
93
- #
94
- # =BigTol
95
- # BigTol(x) -> a BigTolerance
96
- # This module function will convert its argument to a Noi::BigTolerance
97
- #
98
- # Values of type BigTolerance or Numeric are accepted.
99
- module Nio
100
-
101
- # This class represents floating point tolerances for Float numbers
102
- # and allows comparison within the specified tolerance.
103
- class Tolerance
104
- include StateEquivalent
105
-
106
- # The numeric class this tolerance applies to.
107
- def num_class
108
- Float
109
- end
110
-
111
- # The tolerance mode is either :abs (absolute) :rel (relative) or :sig (significant).
112
- # The last parameter is a flag to specify decimal mode for the :sig mode
113
- def initialize(t=0.0, mode=:abs, decmode=false)
114
- set t, mode, decmode
115
- end
116
-
117
-
118
- #This initializes a Tolerance with a given number of decimals
119
- def decimals(d, mode=:abs, rounded=true)
120
-
121
- @mode = mode
122
- @decimal_mode = true
123
- @d = (d<=0 || d>Float::DIG) ? Float::DIG : d
124
- @t = 10**(-@d)
125
- @t *= 0.5 if rounded
126
-
127
- self
128
- end
129
-
130
- #This initializes a Tolerance with a number of significant decimal digits
131
- def sig_decimals(d, rounded=true)
132
- decimals d, :sig, rounded
133
- end
134
-
135
- #Initialize with a multiple of the internal floating-point precision.
136
- def epsilon(times_epsilon=1, mode=:sig)
137
- set Float::EPSILON*times_epsilon, mode
138
- end
139
-
140
- # As #epsilon but using a somewhat bigger (about twice) precision that
141
- # assures associative multiplication.
142
- def big_epsilon(n=1, mode=:sig)
143
- t = Math.ldexp(0.5*n,3-Float::MANT_DIG) # n*(2*Float::EPSILON/(1-0.5*Float::EPSILON)**2)
144
- set t, mode
145
- end
146
-
147
- # Initialize with a relative fraction
148
- def fraction(f)
149
- set f, :rel
150
- end
151
- # Initialize with a percentage
152
- def percent(x)
153
- fraction x/100.0
154
- end
155
- # Initialize with a per-mille value
156
- def permille(x)
157
- fraction x/1000.0
158
- end
159
-
160
-
161
- #Shortcut notation for get_value
162
- def [](x)
163
- return x.nil? ? @t : get_value(x)
164
- end
165
- #Return tolerance relative to a magnitude
166
- def get_value(x)
167
- rel(x)
168
- end
169
- #Essential equality within tolerance
170
- def equals?(x,y)
171
-
172
- case @mode
173
- when :sig
174
-
175
- if @decimal_mode
176
- begin
177
- x_exp = Math.log10(x.abs)
178
- #x_exp = x_exp.finite? ? x_exp.ceil : 0
179
- x_exp = x_exp.finite? ? x_exp.floor+1 : 0
180
- rescue
181
- x_exp = 0
182
- end
183
- begin
184
- y_exp = Math.log10(y.abs)
185
- #y_exp = y_exp.finite? ? y_exp.ceil : 0
186
- y_exp = y_exp.finite? ? y_exp.floor+1 : 0
187
- rescue
188
- y_exp = 0
189
- end
190
- (y-x).abs <= @t*(10**([x_exp,y_exp].min-@@dec_ref_exp))
191
- else
192
- z,x_exp = Math.frexp(x)
193
- z,y_exp = Math.frexp(y)
194
- (y-x).abs <= Math.ldexp(@t,[x_exp,y_exp].min-@@ref_exp) # (y-x).abs <= @t*(2**([x_exp,y_exp].min-@@ref_exp))
195
- end
196
-
197
- when :rel
198
-
199
- (y-x).abs <= @t*([x.abs,y.abs].min) #reference value is 1
200
-
201
- when :abs
202
- (x-y).abs<@t
203
- end
204
-
205
- end
206
- #Approximate equality within tolerance
207
- def aprx_equals?(x,y)
208
-
209
- case @mode
210
- when :sig
211
-
212
- if @decimal_mode
213
- begin
214
- x_exp = Math.log10(x.abs)
215
- #x_exp = x_exp.finite? ? x_exp.ceil : 0
216
- x_exp = x_exp.finite? ? x_exp.floor+1 : 0
217
- rescue
218
- x_exp = 0
219
- end
220
- begin
221
- y_exp = Math.log10(y.abs)
222
- #y_exp = y_exp.finite? ? y_exp.ceil : 0
223
- y_exp = y_exp.finite? ? y_exp.floor+1 : 0
224
- rescue
225
- y_exp = 0
226
- end
227
- (y-x).abs <= @t*(10**([x_exp,y_exp].max-@@dec_ref_exp))
228
- else
229
- z,x_exp = Math.frexp(x)
230
- z,y_exp = Math.frexp(y)
231
- (y-x).abs <= Math.ldexp(@t,[x_exp,y_exp].max-@@ref_exp) # (y-x).abs <= @t*(2**([x_exp,y_exp].max-@@ref_exp))
232
- end
233
-
234
- when :rel
235
-
236
- (y-x).abs <= @t*([x.abs,y.abs].max) #reference value is 1
237
-
238
- when :abs
239
- (x-y).abs<=@t
240
- end
241
-
242
- end
243
- #Comparison within tolerance
244
- def greater_than?(x,y)
245
- less_than?(y,x)
246
- end
247
- #Comparison within tolerance
248
- def less_than?(x,y)
249
-
250
- case @mode
251
- when :sig
252
-
253
- if @decimal_mode
254
- begin
255
- x_exp = Math.log10(x.abs)
256
- #x_exp = x_exp.finite? ? x_exp.ceil : 0
257
- x_exp = x_exp.finite? ? x_exp.floor+1 : 0
258
- rescue
259
- x_exp = 0
260
- end
261
- begin
262
- y_exp = Math.log10(y.abs)
263
- #y_exp = y_exp.finite? ? y_exp.ceil : 0
264
- y_exp = y_exp.finite? ? y_exp.floor+1 : 0
265
- rescue
266
- y_exp = 0
267
- end
268
- y-x > @t*(10**([x_exp,y_exp].max-@@dec_ref_exp))
269
- else
270
- z,x_exp = Math.frexp(x)
271
- z,y_exp = Math.frexp(y)
272
- y-x > Math.ldexp(@t,[x_exp,y_exp].max-@@ref_exp) # y-x > @t*(2**([x_exp,y_exp].max-@@ref_exp))
273
- end
274
-
275
- when :rel
276
-
277
- y-x > @t*([x.abs,y.abs].max) #reference value is 1
278
-
279
- when :abs
280
- x-y<@t
281
- end
282
-
283
- end
284
- #Comparison within tolerance
285
- def zero?(x,compared_with=nil)
286
- compared_with.nil? ? x.abs<@t : x.abs<rel(compared_with)
287
- end
288
-
289
-
290
- # Returns true if the argument is approximately an integer
291
- def apprx_i?(x)
292
- equals?(x,x.round)
293
- end
294
- # If the argument is close to an integer it rounds it
295
- # and returns it as an object of the specified class (by default, Integer)
296
- def apprx_i(x,result=Integer)
297
- r = x.round
298
- return equals?(x,r) ? r.prec(result) : x
299
- end
300
-
301
-
302
- # Returns the magnitude of the tolerance
303
- def magnitude
304
- @t
305
- end
306
- # Returns the number of decimal digits of the tolerance
307
- def num_decimals
308
- @d
309
- end
310
- # Returns true for decimal-mode tolerance
311
- def decimal?
312
- @decimal_mode
313
- end
314
- # Returns the mode (:abs, :rel, :sig) of the tolerance
315
- def mode
316
- @mode
317
- end
318
-
319
-
320
- private
321
-
322
- def set(t=0.0, mode=:abs, decmode=false)
323
-
324
- @t = t==0 ? Float::EPSILON : t.abs
325
- @t = 0.5 if @t > 0.5
326
- @mode = mode
327
- @t = Float::EPSILON if @mode!=:abs && @t<Float::EPSILON
328
- @decimal_mode = decmode
329
- @d = @t==0 ? 0 : (-Math.log10(2*@t).floor).to_i
330
-
331
- self
332
- end
333
-
334
- @@ref_exp = 1 # Math.frexp(1)[1] => tol. relative to [1,2)
335
-
336
- @@dec_ref_exp = 0 # tol. relative to [0.1,1)
337
-
338
- def rel(x)
339
- r = @t
340
- case @mode
341
- when :sig
342
- if @decimal_mode
343
- d = x==0 ? 0 : (Math.log10(x.abs).floor+1).to_i
344
- r = @t*(10**(d-@@dec_ref_exp))
345
- else
346
- x,exp = Math.frexp(x)
347
- r = Math.ldexp(@t,exp-@@ref_exp)
348
- end
349
- when :rel
350
- r = @t*x.abs
351
- end
352
- r
353
- end
354
-
355
- end
356
-
357
- def Tolerance.decimals(d=0, mode=:abs,rounded=true)
358
- Tolerance.new.decimals(d,mode,rounded)
359
- end
360
- def Tolerance.sig_decimals(d=0, mode=:abs,rounded=true)
361
- Tolerance.new.sig_decimals(d,rounded)
362
- end
363
- def Tolerance.epsilon(n=1, mode=:sig)
364
- Tolerance.new.epsilon(n, mode)
365
- end
366
- def Tolerance.big_epsilon(n=1, mode=:sig)
367
- Tolerance.new.big_epsilon(n, mode)
368
- end
369
- def Tolerance.fraction(f)
370
- Tolerance.new.fraction(f)
371
- end
372
- def Tolerance.percent(p)
373
- Tolerance.new.percent(p)
374
- end
375
- def Tolerance.permille(p)
376
- Tolerance.new.permille(p)
377
- end
378
-
379
- # This class represents floating point tolerances for BigDecimal numbers
380
- # and allows comparison within the specified tolerance.
381
- class BigTolerance
382
- include StateEquivalent
383
- module BgMth # :nodoc:
384
- extend BigMath if ::RUBY_VERSION>='1.8.1'
385
- end
386
-
387
- # The numeric class this tolerance applies to.
388
- def num_class
389
- BigDecimal
390
- end
391
-
392
- #The tolerance mode is either :abs (absolute) :rel (relative) or :sig
393
- def initialize(t=BigDecimal('0'), mode=:abs, decmode=false)
394
- set t, mode, decmode
395
- end
396
-
397
-
398
- #This initializes a BigTolerance with a given number of decimals
399
- def decimals(d, mode=:abs, rounded=true)
400
-
401
- @mode = mode
402
- @decimal_mode = true
403
- @d = d==0 ? 16 : d
404
- if rounded
405
- @t = BigDecimal("0.5E#{-d}") # HALF*(BigDecimal(10)**(-d))
406
- else
407
- @t = BigDecimal("1E#{-d}") # BigDecimal(10)**(-d)
408
- end
409
- @ref_exp = BigDecimal('0.1').exponent # reference for significative mode: [0.1,1)
410
-
411
- self
412
- end
413
-
414
- #This initializes a BigTolerance with a number of significative decimal digits
415
- def sig_decimals(d, rounded=true)
416
- decimals d, :sig, rounded
417
- end
418
-
419
- def fraction(f)
420
- set f, :rel
421
- end
422
- def percent(x)
423
- fraction x*BigDecimal('0.01')
424
- end
425
- def permille(x)
426
- fraction x*BigDecimal('0.001')
427
- end
428
-
429
-
430
- #Shortcut notation for get_value
431
- def [](x)
432
- return x.nil? ? @t : get_value(x)
433
- end
434
- #Return tolerance relative to a magnitude
435
- def get_value(x)
436
- rel(x)
437
- end
438
- #Essential equality within tolerance
439
- def equals?(x,y)
440
-
441
- case @mode
442
- when :sig
443
-
444
- x_exp = x.exponent
445
- y_exp = y.exponent
446
- (y-x).abs <= @t*BigDecimal("1E#{[x_exp,y_exp].min-@ref_exp}")
447
-
448
- when :rel
449
-
450
- (y-x).abs <= @t*([x.abs,y.abs].min) #reference value is 1
451
-
452
- when :abs
453
- (x-y).abs<@t
454
- end
455
-
456
- end
457
- #Approximate equality within tolerance
458
- def aprx_equals?(x,y)
459
-
460
- case @mode
461
- when :sig
462
-
463
- x_exp = x.exponent
464
- y_exp = y.exponent
465
- (y-x).abs <= @t*BigDecimal("1E#{[x_exp,y_exp].max-@ref_exp}")
466
-
467
- when :rel
468
-
469
- (y-x).abs <= @t*([x.abs,y.abs].max) #reference value is 1
470
-
471
- when :abs
472
- (x-y).abs<=@t
473
- end
474
-
475
- end
476
- #Comparison within tolerance
477
- def greater_than?(x,y)
478
- less_than?(y,x)
479
- end
480
- #Comparison within tolerance
481
- def less_than?(x,y)
482
-
483
- case @mode
484
- when :sig
485
-
486
- x_exp = x.exponent
487
- y_exp = y.exponent
488
- y-x > @t*BigDecimal("1E#{[x_exp,y_exp].max-@ref_exp}")
489
-
490
- when :rel
491
-
492
- y-x > @t*([x.abs,y.abs].max) #reference value is 1
493
-
494
- when :abs
495
- x-y<@t
496
- end
497
-
498
- end
499
- #Comparison within tolerance
500
- def zero?(x,compared_with=nil)
501
- compared_with.nil? ? x.abs<@t : x.abs<rel(compared_with)
502
- end
503
-
504
-
505
- # Returns true if the argument is approximately an integer
506
- def apprx_i?(x)
507
- equals?(x,x.round)
508
- end
509
- # If the argument is close to an integer it rounds it
510
- # and returns it as an object of the specified class (by default, Integer)
511
- def apprx_i(x,result=Integer)
512
- r = x.round
513
- return equals?(x,r) ? r.prec(result) : x
514
- end
515
-
516
-
517
- # Returns the magnitude of the tolerance
518
- def magnitude
519
- @t
520
- end
521
- # Returns the number of decimal digits of the tolerance
522
- def num_decimals
523
- @d
524
- end
525
- # Returns true for decimal-mode tolerance
526
- def decimal?
527
- @decimal_mode
528
- end
529
- # Returns the mode (:abs, :rel, :sig) of the tolerance
530
- def mode
531
- @mode
532
- end
533
-
534
-
535
- private
536
-
537
- HALF = BigDecimal('0.5')
538
-
539
- def set(t=BigDecimal('0'), mode=:abs, decmode=false)
540
-
541
- @t = t
542
- @t = HALF if @t > HALF
543
- raise TypeError,"El valor de tolerancia debe ser de tipo BigDecimal" if @t.class!=BigDecimal
544
- @mode = mode
545
- @decimal_mode = decmode
546
- @d = @t.zero? ? 0 : -(@t*2).exponent+1
547
- @ref_exp = BigDecimal('1').exponent # reference for significative mode: [1,10)
548
-
549
- self
550
- end
551
-
552
- def rel(x)
553
- r = @t
554
- case @mode
555
- when :sig
556
- d = x==0 ? 0 : x.exponent
557
- r = @t*BigDecimal("1E#{d-@ref_exp}")
558
- when :rel
559
- r = @t*x.abs
560
- end
561
- r
562
- end
563
-
564
- end
565
-
566
- def BigTolerance.decimals(d=0, mode=:abs)
567
- BigTolerance.new.decimals(d,mode)
568
- end
569
- def BigTolerance.sig_decimals(d=0, mode=:abs)
570
- BigTolerance.new.sig_decimals(d)
571
- end
572
- def BigTolerance.fraction(f)
573
- BigTolerance.new.fraction(f)
574
- end
575
- def BigTolerance.percent(p)
576
- BigTolerance.new.percent(p)
577
- end
578
- def BigTolerance.permille(p)
579
- BigTolerance.new.permille(p)
580
- end
581
-
582
- module_function
583
-
584
- # Tol(x) -> a Tolerance
585
- # This module function will convert its argument to a Noi::Tolerance
586
- # or a Noi::BigTolerance depending on its argument;
587
- #
588
- # Values of type Tolerance,Float,Integer (for Tolerance) or
589
- # BigTolerance,BigDecimal (for BigTolerance) are accepted.
590
- def Tol(x) # :doc:
591
- case x
592
- when Tolerance
593
- x
594
- when BigTolerance
595
- x
596
- when BigDecimal
597
- BigTolerance.new(x)
598
- when Float
599
- Tolerance.new(x)
600
- when Integer
601
- Tolerance.sig_decimals(x)
602
- else # e.g. Rational
603
- x
604
- end
605
- end
606
-
607
- # BigTol(x) -> a BigTolerance
608
- # This module function will convert its argument to a Noi::BigTolerance
609
- #
610
- # Values of type BigTolerance or Numeric are accepted.
611
- def BigTol(x) # :doc:
612
- case x
613
- when BigTolerance
614
- x
615
- when Integer
616
- BigTolerance.sig_decimals(x)
617
- when Rational
618
- x
619
- else
620
- BigTolerance.new(BigDec(x))
621
- end
622
- end
623
-
624
- # BigDec(x) -> a BigDecimal
625
- # BigDec(x,precision) -> a BigDecimal
626
- # BigDec(x,:exact) -> a BigDecimal
627
- # This is a shortcut to define a BigDecimal without using quotes
628
- # and a general conversion to BigDecimal method.
629
- #
630
- # The second parameter can be :exact to try for an exact conversion
631
- #
632
- # Conversions from Float have issues that should be understood; :exact
633
- # conversion will use the exact internal value of the Float, and when
634
- # no precision is specified, a value as simple as possible expressed as
635
- # a fraction will be used.
636
- def BigDec(x,prec=nil) # :doc:
637
- if x.respond_to?(:to_str)
638
- x = BigDecimal(x.to_str, prec||0)
639
- else
640
- case x
641
- when Integer
642
- x = BigDecimal(x.to_s)
643
- when Rational
644
- if prec && prec!=:exact
645
- x = BigDecimal.new(x.numerator.to_s).div(x.denominator,prec)
646
- else
647
- x = BigDecimal.new(x.numerator.to_s)/BigDecimal.new(x.denominator.to_s)
648
- end
649
- when BigDecimal
650
- when Float
651
- x = nio_float_to_bigdecimal(x,prec)
652
- end
653
- end
654
- x
655
- end
656
-
657
- end
1
+ # Floating point tolerance
2
+ #--
3
+ # Copyright (C) 2003-2005, Javier Goizueta <javier@goizueta.info>
4
+ #
5
+ # This program is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU General Public License
7
+ # as published by the Free Software Foundation; either version 2
8
+ # of the License, or (at your option) any later version.
9
+ #++
10
+ #
11
+ # Author:: Javier Goizueta (mailto:javier@goizueta.info)
12
+ # Copyright:: Copyright (c) 2002-2004 Javier Goizueta
13
+ # License:: Distributes under the GPL license
14
+ #
15
+ # This module provides a numeric tolerance class for Float and BigDecimal.
16
+
17
+ require 'bigdecimal'
18
+ require 'bigdecimal/math' if RUBY_VERSION>='1.8.1'
19
+ require 'nio/tools'
20
+
21
+
22
+ class Float
23
+ unless const_defined?(:RADIX) # old Ruby versions didn't have this
24
+ # Base of the Float representation
25
+ RADIX = 2
26
+
27
+ x = 1.0
28
+ _bits_ = 0
29
+ while 1!=x+1
30
+ _bits_ += 1
31
+ x /= 2
32
+ end
33
+ if ((1.0+2*x)-1.0)>2*x
34
+ _bits_ -= 1
35
+ end
36
+
37
+ # Number of RADIX-base digits of precision in a Float
38
+ MANT_DIG = _bits_
39
+ # Number of decimal digits that can be stored in a Float and recovered
40
+ DIG = ((MANT_DIG-1)*Math.log(RADIX)/Math.log(10)).floor
41
+ # Smallest value that added to 1.0 produces something different from 1.0
42
+ EPSILON = Math.ldexp(*Math.frexp(1).collect{|e| e.kind_of?(Integer) ? e-(MANT_DIG-1) : e})
43
+ end
44
+ # Decimal precision required to represent a Float and be able to recover its value
45
+ DECIMAL_DIG = (MANT_DIG*Math.log(RADIX)/Math.log(10)).ceil+1
46
+ end
47
+
48
+ # :stopdoc:
49
+ # A problem has been detected with Float#to_i() in some Ruby versiones
50
+ # (it has been found in Ruby 1.8.4 compiled for x86_64_linux|)
51
+ # This problem makes to_i produce an incorrect sign on some cases.
52
+ # Here we try to detect the problem and apply a quick patch,
53
+ # although this will slow down the method.
54
+ if 4.611686018427388e+018.to_i < 0
55
+ class Float
56
+ alias _to_i to_i
57
+ def to_i
58
+ neg = (self < 0)
59
+ i = _to_i
60
+ i_neg = (i < 0)
61
+ i = -i if neg != i_neg
62
+ i
63
+ end
64
+ end
65
+ end
66
+ # :startdoc:
67
+
68
+
69
+ # This module contains some constructor-like module functions
70
+ # to help with the creation of tolerances and big-decimals.
71
+ #
72
+ # =BigDec
73
+ # BigDec(x) -> a BigDecimal
74
+ # BigDec(x,precision) -> a BigDecimal
75
+ # BigDec(x,:exact) -> a BigDecimal
76
+ # This is a shortcut to define a BigDecimal without using quotes
77
+ # and a general conversion to BigDecimal method.
78
+ #
79
+ # The second parameter can be :exact to try for an exact conversion
80
+ #
81
+ # Conversions from Float have issues that should be understood; :exact
82
+ # conversion will use the exact internal value of the Float, and when
83
+ # no precision is specified, a value as simple as possible expressed as
84
+ # a fraction will be used.
85
+ #
86
+ # =Tol
87
+ # Tol(x) -> a Tolerance
88
+ # This module function will convert its argument to a Noi::Tolerance
89
+ # or a Noi::BigTolerance depending on its argument;
90
+ #
91
+ # Values of type Tolerance,Float,Integer (for Tolerance) or
92
+ # BigTolerance,BigDecimal (for BigTolerance) are accepted.
93
+ #
94
+ # =BigTol
95
+ # BigTol(x) -> a BigTolerance
96
+ # This module function will convert its argument to a Noi::BigTolerance
97
+ #
98
+ # Values of type BigTolerance or Numeric are accepted.
99
+ module Nio
100
+
101
+ # This class represents floating point tolerances for Float numbers
102
+ # and allows comparison within the specified tolerance.
103
+ class Tolerance
104
+ include StateEquivalent
105
+
106
+ # The numeric class this tolerance applies to.
107
+ def num_class
108
+ Float
109
+ end
110
+
111
+ # The tolerance mode is either :abs (absolute) :rel (relative) or :sig (significant).
112
+ # The last parameter is a flag to specify decimal mode for the :sig mode
113
+ def initialize(t=0.0, mode=:abs, decmode=false)
114
+ set t, mode, decmode
115
+ end
116
+
117
+
118
+ #This initializes a Tolerance with a given number of decimals
119
+ def decimals(d, mode=:abs, rounded=true)
120
+
121
+ @mode = mode
122
+ @decimal_mode = true
123
+ @d = (d<=0 || d>Float::DIG) ? Float::DIG : d
124
+ @t = 10**(-@d)
125
+ @t *= 0.5 if rounded
126
+
127
+ self
128
+ end
129
+
130
+ #This initializes a Tolerance with a number of significant decimal digits
131
+ def sig_decimals(d, rounded=true)
132
+ decimals d, :sig, rounded
133
+ end
134
+
135
+ #Initialize with a multiple of the internal floating-point precision.
136
+ def epsilon(times_epsilon=1, mode=:sig)
137
+ set Float::EPSILON*times_epsilon, mode
138
+ end
139
+
140
+ # As #epsilon but using a somewhat bigger (about twice) precision that
141
+ # assures associative multiplication.
142
+ def big_epsilon(n=1, mode=:sig)
143
+ t = Math.ldexp(0.5*n,3-Float::MANT_DIG) # n*(2*Float::EPSILON/(1-0.5*Float::EPSILON)**2)
144
+ set t, mode
145
+ end
146
+
147
+ # Initialize with a relative fraction
148
+ def fraction(f)
149
+ set f, :rel
150
+ end
151
+ # Initialize with a percentage
152
+ def percent(x)
153
+ fraction x/100.0
154
+ end
155
+ # Initialize with a per-mille value
156
+ def permille(x)
157
+ fraction x/1000.0
158
+ end
159
+
160
+
161
+ #Shortcut notation for get_value
162
+ def [](x)
163
+ return x.nil? ? @t : get_value(x)
164
+ end
165
+ #Return tolerance relative to a magnitude
166
+ def get_value(x)
167
+ rel(x)
168
+ end
169
+ #Essential equality within tolerance
170
+ def equals?(x,y)
171
+
172
+ case @mode
173
+ when :sig
174
+
175
+ if @decimal_mode
176
+ begin
177
+ x_exp = Math.log10(x.abs)
178
+ #x_exp = x_exp.finite? ? x_exp.ceil : 0
179
+ x_exp = x_exp.finite? ? x_exp.floor+1 : 0
180
+ rescue
181
+ x_exp = 0
182
+ end
183
+ begin
184
+ y_exp = Math.log10(y.abs)
185
+ #y_exp = y_exp.finite? ? y_exp.ceil : 0
186
+ y_exp = y_exp.finite? ? y_exp.floor+1 : 0
187
+ rescue
188
+ y_exp = 0
189
+ end
190
+ (y-x).abs <= @t*(10**([x_exp,y_exp].min-@@dec_ref_exp))
191
+ else
192
+ z,x_exp = Math.frexp(x)
193
+ z,y_exp = Math.frexp(y)
194
+ (y-x).abs <= Math.ldexp(@t,[x_exp,y_exp].min-@@ref_exp) # (y-x).abs <= @t*(2**([x_exp,y_exp].min-@@ref_exp))
195
+ end
196
+
197
+ when :rel
198
+
199
+ (y-x).abs <= @t*([x.abs,y.abs].min) #reference value is 1
200
+
201
+ when :abs
202
+ (x-y).abs<@t
203
+ end
204
+
205
+ end
206
+ #Approximate equality within tolerance
207
+ def aprx_equals?(x,y)
208
+
209
+ case @mode
210
+ when :sig
211
+
212
+ if @decimal_mode
213
+ begin
214
+ x_exp = Math.log10(x.abs)
215
+ #x_exp = x_exp.finite? ? x_exp.ceil : 0
216
+ x_exp = x_exp.finite? ? x_exp.floor+1 : 0
217
+ rescue
218
+ x_exp = 0
219
+ end
220
+ begin
221
+ y_exp = Math.log10(y.abs)
222
+ #y_exp = y_exp.finite? ? y_exp.ceil : 0
223
+ y_exp = y_exp.finite? ? y_exp.floor+1 : 0
224
+ rescue
225
+ y_exp = 0
226
+ end
227
+ (y-x).abs <= @t*(10**([x_exp,y_exp].max-@@dec_ref_exp))
228
+ else
229
+ z,x_exp = Math.frexp(x)
230
+ z,y_exp = Math.frexp(y)
231
+ (y-x).abs <= Math.ldexp(@t,[x_exp,y_exp].max-@@ref_exp) # (y-x).abs <= @t*(2**([x_exp,y_exp].max-@@ref_exp))
232
+ end
233
+
234
+ when :rel
235
+
236
+ (y-x).abs <= @t*([x.abs,y.abs].max) #reference value is 1
237
+
238
+ when :abs
239
+ (x-y).abs<=@t
240
+ end
241
+
242
+ end
243
+ #Comparison within tolerance
244
+ def greater_than?(x,y)
245
+ less_than?(y,x)
246
+ end
247
+ #Comparison within tolerance
248
+ def less_than?(x,y)
249
+
250
+ case @mode
251
+ when :sig
252
+
253
+ if @decimal_mode
254
+ begin
255
+ x_exp = Math.log10(x.abs)
256
+ #x_exp = x_exp.finite? ? x_exp.ceil : 0
257
+ x_exp = x_exp.finite? ? x_exp.floor+1 : 0
258
+ rescue
259
+ x_exp = 0
260
+ end
261
+ begin
262
+ y_exp = Math.log10(y.abs)
263
+ #y_exp = y_exp.finite? ? y_exp.ceil : 0
264
+ y_exp = y_exp.finite? ? y_exp.floor+1 : 0
265
+ rescue
266
+ y_exp = 0
267
+ end
268
+ y-x > @t*(10**([x_exp,y_exp].max-@@dec_ref_exp))
269
+ else
270
+ z,x_exp = Math.frexp(x)
271
+ z,y_exp = Math.frexp(y)
272
+ y-x > Math.ldexp(@t,[x_exp,y_exp].max-@@ref_exp) # y-x > @t*(2**([x_exp,y_exp].max-@@ref_exp))
273
+ end
274
+
275
+ when :rel
276
+
277
+ y-x > @t*([x.abs,y.abs].max) #reference value is 1
278
+
279
+ when :abs
280
+ x-y<@t
281
+ end
282
+
283
+ end
284
+ #Comparison within tolerance
285
+ def zero?(x,compared_with=nil)
286
+ compared_with.nil? ? x.abs<@t : x.abs<rel(compared_with)
287
+ end
288
+
289
+
290
+ # Returns true if the argument is approximately an integer
291
+ def apprx_i?(x)
292
+ equals?(x,x.round)
293
+ end
294
+ # If the argument is close to an integer it rounds it
295
+ # and returns it as an object of the specified class (by default, Integer)
296
+ def apprx_i(x,result=Integer)
297
+ r = x.round
298
+ return equals?(x,r) ? r.prec(result) : x
299
+ end
300
+
301
+
302
+ # Returns the magnitude of the tolerance
303
+ def magnitude
304
+ @t
305
+ end
306
+ # Returns the number of decimal digits of the tolerance
307
+ def num_decimals
308
+ @d
309
+ end
310
+ # Returns true for decimal-mode tolerance
311
+ def decimal?
312
+ @decimal_mode
313
+ end
314
+ # Returns the mode (:abs, :rel, :sig) of the tolerance
315
+ def mode
316
+ @mode
317
+ end
318
+
319
+
320
+ private
321
+
322
+ def set(t=0.0, mode=:abs, decmode=false)
323
+
324
+ @t = t==0 ? Float::EPSILON : t.abs
325
+ @t = 0.5 if @t > 0.5
326
+ @mode = mode
327
+ @t = Float::EPSILON if @mode!=:abs && @t<Float::EPSILON
328
+ @decimal_mode = decmode
329
+ @d = @t==0 ? 0 : (-Math.log10(2*@t).floor).to_i
330
+
331
+ self
332
+ end
333
+
334
+ @@ref_exp = 1 # Math.frexp(1)[1] => tol. relative to [1,2)
335
+
336
+ @@dec_ref_exp = 0 # tol. relative to [0.1,1)
337
+
338
+ def rel(x)
339
+ r = @t
340
+ case @mode
341
+ when :sig
342
+ if @decimal_mode
343
+ d = x==0 ? 0 : (Math.log10(x.abs).floor+1).to_i
344
+ r = @t*(10**(d-@@dec_ref_exp))
345
+ else
346
+ x,exp = Math.frexp(x)
347
+ r = Math.ldexp(@t,exp-@@ref_exp)
348
+ end
349
+ when :rel
350
+ r = @t*x.abs
351
+ end
352
+ r
353
+ end
354
+
355
+ end
356
+
357
+ def Tolerance.decimals(d=0, mode=:abs,rounded=true)
358
+ Tolerance.new.decimals(d,mode,rounded)
359
+ end
360
+ def Tolerance.sig_decimals(d=0, mode=:abs,rounded=true)
361
+ Tolerance.new.sig_decimals(d,rounded)
362
+ end
363
+ def Tolerance.epsilon(n=1, mode=:sig)
364
+ Tolerance.new.epsilon(n, mode)
365
+ end
366
+ def Tolerance.big_epsilon(n=1, mode=:sig)
367
+ Tolerance.new.big_epsilon(n, mode)
368
+ end
369
+ def Tolerance.fraction(f)
370
+ Tolerance.new.fraction(f)
371
+ end
372
+ def Tolerance.percent(p)
373
+ Tolerance.new.percent(p)
374
+ end
375
+ def Tolerance.permille(p)
376
+ Tolerance.new.permille(p)
377
+ end
378
+
379
+ # This class represents floating point tolerances for BigDecimal numbers
380
+ # and allows comparison within the specified tolerance.
381
+ class BigTolerance
382
+ include StateEquivalent
383
+ module BgMth # :nodoc:
384
+ extend BigMath if ::RUBY_VERSION>='1.8.1'
385
+ end
386
+
387
+ # The numeric class this tolerance applies to.
388
+ def num_class
389
+ BigDecimal
390
+ end
391
+
392
+ #The tolerance mode is either :abs (absolute) :rel (relative) or :sig
393
+ def initialize(t=BigDecimal('0'), mode=:abs, decmode=false)
394
+ set t, mode, decmode
395
+ end
396
+
397
+
398
+ #This initializes a BigTolerance with a given number of decimals
399
+ def decimals(d, mode=:abs, rounded=true)
400
+
401
+ @mode = mode
402
+ @decimal_mode = true
403
+ @d = d==0 ? 16 : d
404
+ if rounded
405
+ @t = BigDecimal("0.5E#{-d}") # HALF*(BigDecimal(10)**(-d))
406
+ else
407
+ @t = BigDecimal("1E#{-d}") # BigDecimal(10)**(-d)
408
+ end
409
+ @ref_exp = BigDecimal('0.1').exponent # reference for significative mode: [0.1,1)
410
+
411
+ self
412
+ end
413
+
414
+ #This initializes a BigTolerance with a number of significative decimal digits
415
+ def sig_decimals(d, rounded=true)
416
+ decimals d, :sig, rounded
417
+ end
418
+
419
+ def fraction(f)
420
+ set f, :rel
421
+ end
422
+ def percent(x)
423
+ fraction x*BigDecimal('0.01')
424
+ end
425
+ def permille(x)
426
+ fraction x*BigDecimal('0.001')
427
+ end
428
+
429
+
430
+ #Shortcut notation for get_value
431
+ def [](x)
432
+ return x.nil? ? @t : get_value(x)
433
+ end
434
+ #Return tolerance relative to a magnitude
435
+ def get_value(x)
436
+ rel(x)
437
+ end
438
+ #Essential equality within tolerance
439
+ def equals?(x,y)
440
+
441
+ case @mode
442
+ when :sig
443
+
444
+ x_exp = x.exponent
445
+ y_exp = y.exponent
446
+ (y-x).abs <= @t*BigDecimal("1E#{[x_exp,y_exp].min-@ref_exp}")
447
+
448
+ when :rel
449
+
450
+ (y-x).abs <= @t*([x.abs,y.abs].min) #reference value is 1
451
+
452
+ when :abs
453
+ (x-y).abs<@t
454
+ end
455
+
456
+ end
457
+ #Approximate equality within tolerance
458
+ def aprx_equals?(x,y)
459
+
460
+ case @mode
461
+ when :sig
462
+
463
+ x_exp = x.exponent
464
+ y_exp = y.exponent
465
+ (y-x).abs <= @t*BigDecimal("1E#{[x_exp,y_exp].max-@ref_exp}")
466
+
467
+ when :rel
468
+
469
+ (y-x).abs <= @t*([x.abs,y.abs].max) #reference value is 1
470
+
471
+ when :abs
472
+ (x-y).abs<=@t
473
+ end
474
+
475
+ end
476
+ #Comparison within tolerance
477
+ def greater_than?(x,y)
478
+ less_than?(y,x)
479
+ end
480
+ #Comparison within tolerance
481
+ def less_than?(x,y)
482
+
483
+ case @mode
484
+ when :sig
485
+
486
+ x_exp = x.exponent
487
+ y_exp = y.exponent
488
+ y-x > @t*BigDecimal("1E#{[x_exp,y_exp].max-@ref_exp}")
489
+
490
+ when :rel
491
+
492
+ y-x > @t*([x.abs,y.abs].max) #reference value is 1
493
+
494
+ when :abs
495
+ x-y<@t
496
+ end
497
+
498
+ end
499
+ #Comparison within tolerance
500
+ def zero?(x,compared_with=nil)
501
+ compared_with.nil? ? x.abs<@t : x.abs<rel(compared_with)
502
+ end
503
+
504
+
505
+ # Returns true if the argument is approximately an integer
506
+ def apprx_i?(x)
507
+ equals?(x,x.round)
508
+ end
509
+ # If the argument is close to an integer it rounds it
510
+ # and returns it as an object of the specified class (by default, Integer)
511
+ def apprx_i(x,result=Integer)
512
+ r = x.round
513
+ return equals?(x,r) ? r.prec(result) : x
514
+ end
515
+
516
+
517
+ # Returns the magnitude of the tolerance
518
+ def magnitude
519
+ @t
520
+ end
521
+ # Returns the number of decimal digits of the tolerance
522
+ def num_decimals
523
+ @d
524
+ end
525
+ # Returns true for decimal-mode tolerance
526
+ def decimal?
527
+ @decimal_mode
528
+ end
529
+ # Returns the mode (:abs, :rel, :sig) of the tolerance
530
+ def mode
531
+ @mode
532
+ end
533
+
534
+
535
+ private
536
+
537
+ HALF = BigDecimal('0.5')
538
+
539
+ def set(t=BigDecimal('0'), mode=:abs, decmode=false)
540
+
541
+ @t = t
542
+ @t = HALF if @t > HALF
543
+ raise TypeError,"El valor de tolerancia debe ser de tipo BigDecimal" if @t.class!=BigDecimal
544
+ @mode = mode
545
+ @decimal_mode = decmode
546
+ @d = @t.zero? ? 0 : -(@t*2).exponent+1
547
+ @ref_exp = BigDecimal('1').exponent # reference for significative mode: [1,10)
548
+
549
+ self
550
+ end
551
+
552
+ def rel(x)
553
+ r = @t
554
+ case @mode
555
+ when :sig
556
+ d = x==0 ? 0 : x.exponent
557
+ r = @t*BigDecimal("1E#{d-@ref_exp}")
558
+ when :rel
559
+ r = @t*x.abs
560
+ end
561
+ r
562
+ end
563
+
564
+ end
565
+
566
+ def BigTolerance.decimals(d=0, mode=:abs)
567
+ BigTolerance.new.decimals(d,mode)
568
+ end
569
+ def BigTolerance.sig_decimals(d=0, mode=:abs)
570
+ BigTolerance.new.sig_decimals(d)
571
+ end
572
+ def BigTolerance.fraction(f)
573
+ BigTolerance.new.fraction(f)
574
+ end
575
+ def BigTolerance.percent(p)
576
+ BigTolerance.new.percent(p)
577
+ end
578
+ def BigTolerance.permille(p)
579
+ BigTolerance.new.permille(p)
580
+ end
581
+
582
+ module_function
583
+
584
+ # Tol(x) -> a Tolerance
585
+ # This module function will convert its argument to a Noi::Tolerance
586
+ # or a Noi::BigTolerance depending on its argument;
587
+ #
588
+ # Values of type Tolerance,Float,Integer (for Tolerance) or
589
+ # BigTolerance,BigDecimal (for BigTolerance) are accepted.
590
+ def Tol(x) # :doc:
591
+ case x
592
+ when Tolerance
593
+ x
594
+ when BigTolerance
595
+ x
596
+ when BigDecimal
597
+ BigTolerance.new(x)
598
+ when Float
599
+ Tolerance.new(x)
600
+ when Integer
601
+ Tolerance.sig_decimals(x)
602
+ else # e.g. Rational
603
+ x
604
+ end
605
+ end
606
+
607
+ # BigTol(x) -> a BigTolerance
608
+ # This module function will convert its argument to a Noi::BigTolerance
609
+ #
610
+ # Values of type BigTolerance or Numeric are accepted.
611
+ def BigTol(x) # :doc:
612
+ case x
613
+ when BigTolerance
614
+ x
615
+ when Integer
616
+ BigTolerance.sig_decimals(x)
617
+ when Rational
618
+ x
619
+ else
620
+ BigTolerance.new(BigDec(x))
621
+ end
622
+ end
623
+
624
+ # BigDec(x) -> a BigDecimal
625
+ # BigDec(x,precision) -> a BigDecimal
626
+ # BigDec(x,:exact) -> a BigDecimal
627
+ # This is a shortcut to define a BigDecimal without using quotes
628
+ # and a general conversion to BigDecimal method.
629
+ #
630
+ # The second parameter can be :exact to try for an exact conversion
631
+ #
632
+ # Conversions from Float have issues that should be understood; :exact
633
+ # conversion will use the exact internal value of the Float, and when
634
+ # no precision is specified, a value as simple as possible expressed as
635
+ # a fraction will be used.
636
+ def BigDec(x,prec=nil) # :doc:
637
+ if x.respond_to?(:to_str)
638
+ x = BigDecimal(x.to_str, prec||0)
639
+ else
640
+ case x
641
+ when Integer
642
+ x = BigDecimal(x.to_s)
643
+ when Rational
644
+ if prec && prec!=:exact
645
+ x = BigDecimal.new(x.numerator.to_s).div(x.denominator,prec)
646
+ else
647
+ x = BigDecimal.new(x.numerator.to_s)/BigDecimal.new(x.denominator.to_s)
648
+ end
649
+ when BigDecimal
650
+ when Float
651
+ x = nio_float_to_bigdecimal(x,prec)
652
+ end
653
+ end
654
+ x
655
+ end
656
+
657
+ end