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.



103
104
105
# File 'lib/flt/tolerance.rb', line 103

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.



249
250
251
252
253
254
255
256
# File 'lib/flt/tolerance.rb', line 249

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.



235
236
237
# File 'lib/flt/tolerance.rb', line 235

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.



228
229
230
# File 'lib/flt/tolerance.rb', line 228

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.



219
220
221
222
223
# File 'lib/flt/tolerance.rb', line 219

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.



241
242
243
# File 'lib/flt/tolerance.rb', line 241

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

Instance Method Details

#[](x) ⇒ Object

Shorthand for value()



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

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.



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

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

#descr_valueObject

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



209
210
211
# File 'lib/flt/tolerance.rb', line 209

def descr_value
  @value.to_s
end

#eq?(x, y) ⇒ Boolean

equals: x == y within tolerance (relaxed)

Returns:

  • (Boolean)


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

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)


180
181
182
# File 'lib/flt/tolerance.rb', line 180

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)


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

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

#gt?(x, y) ⇒ Boolean

greater_than: x > y within tolerance

Returns:

  • (Boolean)


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

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



139
140
141
142
143
# File 'lib/flt/tolerance.rb', line 139

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)


133
134
135
136
# File 'lib/flt/tolerance.rb', line 133

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)


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

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

#lt?(x, y) ⇒ Boolean

less-than: x < y within tolerance

Returns:

  • (Boolean)


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

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.



187
188
189
# File 'lib/flt/tolerance.rb', line 187

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



197
198
199
# File 'lib/flt/tolerance.rb', line 197

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)


163
164
165
# File 'lib/flt/tolerance.rb', line 163

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

#to_sObject

Description of the tolerance



122
123
124
# File 'lib/flt/tolerance.rb', line 122

def to_s
  descr_value
end

#value(x = nil) ⇒ Object

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



108
109
110
111
112
113
114
# File 'lib/flt/tolerance.rb', line 108

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)


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

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