nio 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,10 +7,8 @@
7
7
  # as published by the Free Software Foundation; either version 2
8
8
  # of the License, or (at your option) any later version.
9
9
 
10
- #require File.dirname(__FILE__) + '/test_helper.rb'
10
+ #require File.dirname(__FILE__) + '/helper.rb'
11
11
  require 'test/unit'
12
-
13
- require 'nio/repdec'
14
12
  include Nio
15
13
  require 'yaml'
16
14
 
@@ -81,8 +79,8 @@ class TestRepdec < Test::Unit::TestCase
81
79
  assert_equal [1, 0], r.setS("Infinity").getQ
82
80
 
83
81
  assert_equal "-Infinity", r.setS("-Infinity").getS(0)
84
- assert_equal [-1, 0], r.setS("-Infinity").getQ
82
+ assert_equal [-1, 0], r.setS("-Infinity").getQ
85
83
  end
86
-
84
+
87
85
  end
88
86
 
@@ -1,30 +1,30 @@
1
1
 
2
- # Copyright (C) 2003-2005, Javier Goizueta <javier@goizueta.info>
3
- #
4
- # This program is free software; you can redistribute it and/or
5
- # modify it under the terms of the GNU General Public License
6
- # as published by the Free Software Foundation; either version 2
7
- # of the License, or (at your option) any later version.
8
- require 'test/unit'
9
-
10
- require 'nio/rtnlzr'
11
- require 'nio/sugar'
2
+
3
+ require File.dirname(__FILE__) + '/helper.rb'
12
4
  include Nio
13
5
  require 'yaml'
6
+ require 'flt'
7
+ require 'flt/float'
8
+ require 'flt/math'
9
+ require 'flt/bigdecimal'
14
10
  require 'bigdecimal/math'
15
11
 
16
- class TestRtnlzr < Test::Unit::TestCase
17
12
 
18
- class BgMth
19
- extend BigMath
20
- end
13
+ require 'bigdecimal/math'
14
+
15
+ module BgMth
16
+ extend BigMath
17
+ end
18
+
19
+
20
+ class TestRtnlzr < Test::Unit::TestCase
21
21
 
22
22
  def setup
23
23
 
24
24
  $data = YAML.load(File.read(File.join(File.dirname(__FILE__) ,'data.yaml'))).collect{|x| [x].pack('H*').unpack('E')[0]}
25
25
 
26
26
  end
27
-
27
+
28
28
 
29
29
  def test_basic_rtnlzr
30
30
  # basic Rtnlzr tests
@@ -34,7 +34,9 @@ class TestRtnlzr < Test::Unit::TestCase
34
34
  assert_equal [13,10], Rtnlzr.max_denominator(BigDecimal('1.3'),10)
35
35
  assert_equal [1,3], Rtnlzr.max_denominator(1.0/3,10)
36
36
  assert_equal [1,3], Rtnlzr.max_denominator(BigDecimal('1')/3,10)
37
-
37
+ assert_equal [13,10], Rtnlzr.max_denominator(Flt.DecNum('1.3'),10)
38
+ assert_equal [1,3], Rtnlzr.max_denominator(Flt.DecNum('1')/3,10)
39
+
38
40
  # basic tests of Float#nio_r
39
41
  assert_equal Rational(1,3), (1.0/3.0).nio_r
40
42
  assert_equal Rational(2,3), (2.0/3.0).nio_r
@@ -42,57 +44,77 @@ class TestRtnlzr < Test::Unit::TestCase
42
44
  assert_equal Rational(89,217), (89.0/217.0).nio_r
43
45
 
44
46
  # rationalization of Floats using a tolerance
45
- t = Tolerance.new(1e-15,:sig)
47
+ t = Flt.Tolerance(1e-15/2,:floating)
46
48
  assert_equal Rational(540429, 12500),43.23432.nio_r(t)
47
49
  assert_equal Rational(6636649, 206596193),0.032123772.nio_r(t)
48
50
  assert_equal Rational(280943, 2500000), 0.1123772.nio_r(t)
49
51
  assert_equal Rational(39152929, 12500), 3132.23432.nio_r(t)
50
52
  assert_equal Rational(24166771439, 104063), 232232.123223432.nio_r(t)
51
- assert_equal Rational(792766404965, 637), 1244531247.98273123.nio_r(t)
53
+ assert_equal Rational(792766404965, 637), 1244531247.98273123.nio_r(t)
52
54
  #$data.each do |x|
53
55
  # assert t.equals?(x, x.nio_r(t).to_f), "out of tolerance: #{x.inspect} #{x.nio_r(t).inspect}"
54
56
  #end
55
-
56
- # rationalization with maximum denominator
57
- assert_equal Rational(9441014047197, 7586), (1244531247.98273123.nio_r(10000))
57
+
58
+ # rationalization with maximum denominator
59
+ assert_equal Rational(9441014047197, 7586), (1244531247.98273123.nio_r(10000))
58
60
  assert_equal Rational(11747130449709, 9439), BigDecimal('1244531247.982731230').nio_r(10000)
59
-
60
-
61
+ assert_equal Rational(11747130449709, 9439), Flt.DecNum('1244531247.982731230').nio_r(10000)
62
+
63
+
61
64
  # approximate a value in [0.671,0.672];
62
65
  # Float
63
- assert_equal [43,64], Rtnlzr.new(Tolerance.new(0.0005)).rationalize(0.6715)
64
- assert_equal [43,64], Rtnlzr.new(Tol(0.0005)).rationalize(0.6715)
66
+ assert_equal [43,64], Rtnlzr.new(Flt.Tolerance(0.0005)).rationalize(0.6715)
65
67
  assert_equal [43,64], Rtnlzr.new(Rational(5,10000)).rationalize(0.6715)
68
+ # BinNum
69
+ assert_equal [43,64], Rtnlzr.new(Flt.Tolerance(Flt.BinNum('0.0005'))).rationalize(Flt::BinNum('0.6715'))
70
+ assert_equal [43,64], Rtnlzr.new(Flt.Tolerance(Rational(5,10000))).rationalize(Flt::BinNum('0.6715'))
66
71
  # BigDecimal
67
- assert_equal [43,64], Rtnlzr.new(BigTolerance.new(BigDecimal('0.0005'))).rationalize(BigDecimal('0.6715'))
68
- assert_equal [43,64], Rtnlzr.new(Tol(BigDecimal('0.0005'))).rationalize(BigDecimal('0.6715'))
72
+ assert_equal [43,64], Rtnlzr.new(Flt.Tolerance('0.0005')).rationalize(BigDecimal('0.6715'))
69
73
  assert_equal [43,64], Rtnlzr.new(Rational(5,10000)).rationalize(BigDecimal('0.6715'))
70
- #
74
+ # DecNum
75
+ assert_equal [43,64], Rtnlzr.new(Flt.Tolerance(Flt.DecNum('0.0005'))).rationalize(Flt::DecNum('0.6715'))
76
+ assert_equal [43,64], Rtnlzr.new(Flt.Tolerance(Rational(5,10000))).rationalize(Flt::DecNum('0.6715'))
77
+ #
71
78
  assert_equal Rational(43,64), 0.6715.nio_r(0.0005)
72
79
  assert_equal Rational(43,64), 0.6715.nio_r(Rational(5,10000))
73
80
  assert_equal Rational(47,70), 0.6715.nio_r(70)
74
81
  assert_equal Rational(45,67), 0.6715.nio_r(69)
75
82
  assert_equal Rational(2,3), 0.6715.nio_r(10)
76
-
83
+
77
84
  # some PI tests
78
- assert_equal Rational(899125804609,286200632530), BgMth.PI(64).nio_r(BigTolerance.new(BigDec('261E-24')))
79
- assert_equal Rational(899125804609,286200632530), BgMth.PI(64).nio_r(Tol(BigDec('261E-24')))
80
- assert_equal Rational(899125804609,286200632530), BgMth.PI(64).nio_r(BigDec('261E-24'))
81
- assert_equal Rational(899125804609,286200632530), BgMth.PI(64).nio_r(BigDec(261E-24))
82
- assert_equal Rational(899125804609,286200632530), BgMth.PI(64).nio_r(261E-24)
83
-
84
- # BigDecimal tests
85
- #t = BigTolerance.new(BigDecimal('1e-15'),:sig)
86
- t = BigTolerance.decimals(20,:sig)
85
+ assert_equal Rational(899125804609,286200632530), BgMth.PI(64).nio_r(Flt.Tolerance(Flt.DecNum('261E-24')))
86
+ assert_equal Rational(899125804609,286200632530), BgMth.PI(64).nio_r(Flt.Tolerance(Flt.DecNum('261E-24')))
87
+ assert_equal Rational(899125804609,286200632530), BgMth.PI(64).nio_r(Flt.DecNum('261E-24'))
88
+ assert_equal Rational(899125804609,286200632530), BgMth.PI(64).nio_r(261E-24)
89
+
90
+ assert_equal Rational(899125804609,286200632530), Flt::DecNum::Math.pi(64).nio_r(Flt.Tolerance(Flt.DecNum('261E-24')))
91
+ assert_equal Rational(899125804609,286200632530), Flt::DecNum::Math.pi(64).nio_r(Flt.Tolerance(Flt.DecNum('261E-24')))
92
+ assert_equal Rational(899125804609,286200632530), Flt::DecNum::Math.pi(64).nio_r(Flt.DecNum('261E-24'))
93
+ assert_equal Rational(899125804609,286200632530), Flt::DecNum::Math.pi(64).nio_r(261E-24)
94
+
95
+ # DecNum tests
96
+ #t = Flt.Tolerance(Flt.DecNum('1e-15'),:floating)
97
+ t = Flt.Tolerance(20,:sig_decimals)
87
98
  $data.each do |x|
88
- x = BigDec(x,:exact)
99
+ x = Flt.BinNum(x).to_decimal_exact
89
100
  q = x.nio_r(t)
90
- assert t.equals?(x, BigDec(q)), "out of tolerance: #{x.inspect} #{BigDec(q)}"
101
+ assert t.eq?(x, Flt.DecNum(q)), "out of tolerance: #{x.inspect} #{Flt.DecNum(q)}"
91
102
  end
103
+
104
+ # Flt tests
105
+ #t = Flt.Tolerance(Flt.DecNum('1e-15'),:floating)
106
+ t = Flt.Tolerance(20,:sig_decimals)
107
+ $data.each do |x|
108
+ x = Flt.BinNum(x)
109
+ q = x.nio_r(t)
110
+ assert t.eq?(x, Flt.BinNum(q)), "out of tolerance: #{x.inspect} #{Flt.BinNum(q)}"
111
+ end
112
+
113
+
92
114
  end
93
115
 
94
116
  def test_compare_algorithms
95
- r = Rtnlzr.new(Tolerance.new(1e-5,:sig))
117
+ r = Rtnlzr.new(Flt.Tolerance(1e-5,:floating))
96
118
  ($data + $data.collect{|x| -x}).each do |x|
97
119
  q1 = r.rationalize_Knuth(x)
98
120
  q2 = r.rationalize_Horn(x)
@@ -105,7 +127,7 @@ class TestRtnlzr < Test::Unit::TestCase
105
127
  assert_equal q1, q3
106
128
  #assert_equal q1, q4
107
129
  end
108
- r = Rtnlzr.new(Tolerance.epsilon)
130
+ r = Rtnlzr.new(Flt.Tolerance(:epsilon))
109
131
  ($data + $data.collect{|x| -x}).each do |x|
110
132
  q1 = r.rationalize_Knuth(x)
111
133
  q2 = r.rationalize_Horn(x)
@@ -118,8 +140,8 @@ class TestRtnlzr < Test::Unit::TestCase
118
140
  assert_equal q1, q3
119
141
  #assert_equal q1, q4
120
142
  end
121
-
143
+
122
144
  end
123
-
124
145
 
146
+
125
147
  end
@@ -1,5 +1,5 @@
1
1
 
2
- #require File.dirname(__FILE__) + '/test_helper.rb'
2
+ #require File.dirname(__FILE__) + '/helper.rb'
3
3
  require 'test/unit'
4
4
 
5
5
  require 'nio/repdec'
@@ -35,6 +35,6 @@ class TestTools < Test::Unit::TestCase
35
35
  assert_equal(x.hash,y.hash)
36
36
  assert_equal(false,x.hash==z.hash)
37
37
  end
38
-
38
+
39
39
  end
40
40
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Javier Goizueta
@@ -9,9 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-12-24 00:00:00 +01:00
12
+ date: 2009-08-05 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: flt
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.0
24
+ version:
15
25
  - !ruby/object:Gem::Dependency
16
26
  name: bones
17
27
  type: :development
@@ -41,7 +51,6 @@ files:
41
51
  - Rakefile
42
52
  - SOURCE.txt
43
53
  - lib/nio.rb
44
- - lib/nio/flttol.rb
45
54
  - lib/nio/fmt.rb
46
55
  - lib/nio/repdec.rb
47
56
  - lib/nio/rtnlzr.rb
@@ -64,13 +73,15 @@ files:
64
73
  - tasks/svn.rake
65
74
  - tasks/test.rake
66
75
  - test/data.yaml
76
+ - test/helper.rb
67
77
  - test/test_fmt.rb
68
- - test/test_helper.rb
69
78
  - test/test_repdec.rb
70
79
  - test/test_rtnlzr.rb
71
80
  - test/test_tools.rb
72
81
  has_rdoc: true
73
82
  homepage: http://nio.rubyforge.org
83
+ licenses: []
84
+
74
85
  post_install_message:
75
86
  rdoc_options:
76
87
  - --main
@@ -100,13 +111,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
111
  requirements: []
101
112
 
102
113
  rubyforge_project: nio
103
- rubygems_version: 1.2.0
114
+ rubygems_version: 1.3.3
104
115
  signing_key:
105
- specification_version: 2
116
+ specification_version: 3
106
117
  summary: Numeric input/output
107
118
  test_files:
108
119
  - test/test_fmt.rb
109
- - test/test_helper.rb
110
120
  - test/test_repdec.rb
111
121
  - test/test_rtnlzr.rb
112
122
  - test/test_tools.rb
@@ -1,669 +0,0 @@
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) ? Nio.numeric_cast(r,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) ? Nio.numeric_cast(r,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
- def numeric_cast(value, type)
658
- if value.respond_to?(:prec)
659
- value.prec(type)
660
- else
661
- if type.kind_of?(BigDecimal)
662
- BigDec(value)
663
- else
664
- Object.send type.to_s, value
665
- end
666
- end
667
- end
668
-
669
- end