Class: Flt::Tolerance

Inherits:
Object show all
Defined in:
lib/flt/tolerance.rb

Overview

The Tolerance class is a base class for all tolerances.

Particular tolerance kinds (defined by a type of tolerance and the way to specify its value) are implemented in separate classes derived from Tolerance.

Derived classes must implement at least one of the methods relative_to() or relative_to_many() and may also redefine cast_value() and descr_value()

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value) ⇒ Tolerance

Returns a new instance of Tolerance.


99
100
101
# File 'lib/flt/tolerance.rb', line 99

def initialize(value)
  @value = value
end

Class Method Details

.big_epsilon(num_class, mult = 1) ⇒ Object

Define a tolerance magnitude in relation to the 'big epsilon' of the floating-point type and context. A multiplier may be specified to scale the big epsilon.

This is a tolerance that makes multiplication associative when used with FloatingTolerance.


245
246
247
248
249
250
251
252
# File 'lib/flt/tolerance.rb', line 245

def big_epsilon(num_class, mult=1)
  context = num_class.context
  e0 = context.epsilon
  # we could compute with round-up instead of using next_plus, but we can't do that with Float
  den = (context.Num(1)-e0/2)
  big_eps = context.next_plus(e0*2/(den*den))
  big_eps*mult
end

.bits(n, rounded = true) ⇒ Object

Define a tolerance magnitude as a number of binary digits. If rounded is true it is assumed that results are rounded to n digits; otherwise truncation or directed rounding may occur and the tolerance will be larger.


231
232
233
# File 'lib/flt/tolerance.rb', line 231

def bits(n, rounded=true)
  digits 10, n, rounded
end

.decimals(n, rounded = true) ⇒ Object

Define a tolerance magnitude as a number of decimal digits. If rounded is true it is assumed that results are rounded to n digits; otherwise truncation or directed rounding may occur and the tolerance will be larger.


224
225
226
# File 'lib/flt/tolerance.rb', line 224

def decimals(n, rounded=true)
  digits 10, n, rounded
end

.define_sugar(value_class, *tol_classes) ⇒ Object

:nodoc:


15
16
17
18
19
20
21
22
23
24
# File 'lib/flt/tolerance/sugar.rb', line 15

def Tolerance.define_sugar(value_class, *tol_classes) #:nodoc:
  tol_classes.each do |tol_class|
    suffix = tol_class.to_s.split('::').last.
      gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
      gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
    value_class.send(:define_method, suffix) do
      tol_class.new(self)
    end
  end
end

.digits(base, n, rounded = true) ⇒ Object

Define a tolerance magnitude as a number of digits of the given base. If rounded is true it is assumed that results are rounded to n digits; otherwise truncation or directed rounding may occur and the tolerance will be larger.


215
216
217
218
219
# File 'lib/flt/tolerance.rb', line 215

def digits(base, n, rounded=true)
  v = base**(-n)
  v /= 2 if rounded
  v
end

.epsilon(num_class, mult = 1) ⇒ Object

Define a tolerance magnitude in relation to the 'epsilon' of the floating-point type and context. A multiplier may be specified to scale the epsilon.


237
238
239
# File 'lib/flt/tolerance.rb', line 237

def epsilon(num_class, mult=1)
  num_class.context.epsilon*mult
end

Instance Method Details

#[](x) ⇒ Object

Shorthand for value()


113
114
115
# File 'lib/flt/tolerance.rb', line 113

def [](x)
  value(x)
end

#cast_value(num_class) ⇒ Object

Returns the tolerance reference value for a numeric class; in derived classes this can be redefined to allow for values which change in value or precision depending on the numeric class or context.


200
201
202
# File 'lib/flt/tolerance.rb', line 200

def cast_value(num_class)
  num_class.context.Num(@value)
end

#descr_valueObject

Description of the reference value (can be specialized in derived classes)


205
206
207
# File 'lib/flt/tolerance.rb', line 205

def descr_value
  @value.to_s
end

#eq?(x, y) ⇒ Boolean

equals: x == y within tolerance (relaxed)

Returns:

  • (Boolean)

154
155
156
# File 'lib/flt/tolerance.rb', line 154

def eq?(x, y)
  (x-y).abs <= relative_to_many(:max, x, y)
end

#equal_to?(x, y) ⇒ Boolean

x == correct value y within tolerance

Returns:

  • (Boolean)

176
177
178
# File 'lib/flt/tolerance.rb', line 176

def equal_to?(x, y)
  (x-y).abs <= relative_to(y)
end

#greater_than?(x, y) ⇒ Boolean

x > correct value y within tolerance

Returns:

  • (Boolean)

171
172
173
# File 'lib/flt/tolerance.rb', line 171

def greater_than?(x,y)
  x-y > relative_to(y)
end

#gt?(x, y) ⇒ Boolean

greater_than: x > y within tolerance

Returns:

  • (Boolean)

149
150
151
# File 'lib/flt/tolerance.rb', line 149

def gt?(x,y)
  x-y > relative_to_many(:max, x, y)
end

#integer(x) ⇒ Object

If the argument is close to an integer it rounds it


135
136
137
138
139
# File 'lib/flt/tolerance.rb', line 135

def integer(x)
  # return integer?(x) ? x.round : nil
  r = x.round
  ((x-r).abs <= relative_to(x)) ? r : nil
end

#integer?(x) ⇒ Boolean

Returns true if the argument is approximately an integer

Returns:

  • (Boolean)

129
130
131
132
# File 'lib/flt/tolerance.rb', line 129

def integer?(x)
  # Computing the tolerance at x seems the best option here
  (x-x.round).abs <= relative_to(x)
end

#less_than?(x, y) ⇒ Boolean

x < correct value y within tolerance

Returns:

  • (Boolean)

166
167
168
# File 'lib/flt/tolerance.rb', line 166

def less_than?(x,y)
  y-x > relative_to(y)
end

#lt?(x, y) ⇒ Boolean

less-than: x < y within tolerance

Returns:

  • (Boolean)

144
145
146
# File 'lib/flt/tolerance.rb', line 144

def lt?(x,y)
  y-x > relative_to_many(:max, x, y)
end

#relative_to(x) ⇒ Object

This method is redefined in derived classes to compute the tolerance value in relation to the value x;

If not redefined, relative_to_many will be used.


183
184
185
# File 'lib/flt/tolerance.rb', line 183

def relative_to(x)
  relative_to_many(:max, x)
end

#relative_to_many(mode, *xs) ⇒ Object

This method is redefined in derived classes to compute the tolerance value in relation to the values xs; mode must be either :max or :min, and determines if the largerst (relaxed condition) or smallest (strict condition) of the relative tolerances is returned.

If not redefined, relative_to will be used, but redefining this method can be used to optimize the performance


193
194
195
# File 'lib/flt/tolerance.rb', line 193

def relative_to_many(mode, *xs)
  xs.map{|x| relative_to(x)}.send(mode)
end

#seq?(x, y) ⇒ Boolean

strongly equals: x == y within tolerance (strict)

Returns:

  • (Boolean)

159
160
161
# File 'lib/flt/tolerance.rb', line 159

def seq?(x, y)
  (x-y).abs <= relative_to_many(:min, x, y)
end

#to_sObject

Description of the tolerance


118
119
120
# File 'lib/flt/tolerance.rb', line 118

def to_s
  descr_value
end

#value(x = nil) ⇒ Object

Value of the tolerance for a given (floating-point) quantity


104
105
106
107
108
109
110
# File 'lib/flt/tolerance.rb', line 104

def value(x=nil)
  if x
    relative_to(x)
  else
    @value
  end
end

#zero?(x, y = nil) ⇒ Boolean

Is x nearly zero? (zero within tolerance); if a second argument y is specified: is x nearly zero? compared to y?

Returns:

  • (Boolean)

124
125
126
# File 'lib/flt/tolerance.rb', line 124

def zero?(x, y=nil)
  x.zero? || x.abs < value(y || x)
end