Module: Philiprehberger::Approx
- Defined in:
- lib/philiprehberger/approx.rb,
lib/philiprehberger/approx/version.rb,
lib/philiprehberger/approx/comparator.rb,
lib/philiprehberger/approx/rspec_matchers.rb
Defined Under Namespace
Modules: RSpecMatchers Classes: Comparator, Error
Constant Summary collapse
- VERSION =
'0.6.0'
Class Method Summary collapse
-
.assert_near(a, b, epsilon: 1e-9) ⇒ Object
Assert that two values are approximately equal, raising on mismatch.
-
.assert_within(a, b, abs: nil, rel: nil) ⇒ Object
Assert that two values pass within?, raising on mismatch.
-
.between?(value, min, max, epsilon: 1e-9) ⇒ Boolean
Check if a numeric value lies within [min, max] with epsilon slack on both ends.
-
.clamp(value, target, epsilon: 1e-9) ⇒ Numeric
Snap a value to target if approximately equal, otherwise return unchanged.
-
.diff(a, b, epsilon: Float::EPSILON) ⇒ Hash
Return a diagnostic hash showing why values do or do not match.
-
.equal?(a, b, epsilon: 1e-9) ⇒ Boolean
Check if two values are approximately equal within epsilon.
-
.near?(a, b, epsilon: 1e-9) ⇒ Boolean
Alias for equal? with explicit epsilon.
-
.percent_equal?(a, b, percent:) ⇒ Boolean
Check if two values are approximately equal within a percentage tolerance.
-
.relative_equal?(a, b, tolerance: 1e-6) ⇒ Boolean
Check if two values are approximately equal using relative tolerance.
-
.within?(a, b, abs: nil, rel: nil) ⇒ Boolean
Check if two values are approximately equal using combined tolerance.
-
.zero?(value, epsilon: 1e-9) ⇒ Boolean
Check if a numeric value is approximately zero.
Class Method Details
.assert_near(a, b, epsilon: 1e-9) ⇒ Object
Assert that two values are approximately equal, raising on mismatch
79 80 81 82 83 |
# File 'lib/philiprehberger/approx.rb', line 79 def self.assert_near(a, b, epsilon: 1e-9) return if equal?(a, b, epsilon: epsilon) raise Error, "expected #{a.inspect} to be near #{b.inspect} (epsilon: #{epsilon})" end |
.assert_within(a, b, abs: nil, rel: nil) ⇒ Object
Assert that two values pass within?, raising on mismatch
At least one of abs: or rel: must be provided.
114 115 116 117 118 |
# File 'lib/philiprehberger/approx.rb', line 114 def self.assert_within(a, b, abs: nil, rel: nil) return if within?(a, b, abs: abs, rel: rel) raise Error, "expected #{a.inspect} to be within #{b.inspect} (abs: #{abs}, rel: #{rel})" end |
.between?(value, min, max, epsilon: 1e-9) ⇒ Boolean
Check if a numeric value lies within [min, max] with epsilon slack on both ends
101 102 103 |
# File 'lib/philiprehberger/approx.rb', line 101 def self.between?(value, min, max, epsilon: 1e-9) value.between?(min - epsilon, max + epsilon) end |
.clamp(value, target, epsilon: 1e-9) ⇒ Numeric
Snap a value to target if approximately equal, otherwise return unchanged
Returns target when value is within epsilon of target. Useful for snapping near-values to an exact canonical value.
69 70 71 |
# File 'lib/philiprehberger/approx.rb', line 69 def self.clamp(value, target, epsilon: 1e-9) equal?(value, target, epsilon: epsilon) ? target : value end |
.diff(a, b, epsilon: Float::EPSILON) ⇒ Hash
Return a diagnostic hash showing why values do or do not match
136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/philiprehberger/approx.rb', line 136 def self.diff(a, b, epsilon: Float::EPSILON) actual_diff = (a - b).abs.to_f allowed = epsilon.to_f ratio = allowed.zero? ? Float::INFINITY : actual_diff / allowed { match: actual_diff <= allowed, actual_diff: actual_diff, allowed: allowed, ratio: ratio } end |
.equal?(a, b, epsilon: 1e-9) ⇒ Boolean
Check if two values are approximately equal within epsilon
17 18 19 |
# File 'lib/philiprehberger/approx.rb', line 17 def self.equal?(a, b, epsilon: 1e-9) compare(a, b, epsilon) end |
.near?(a, b, epsilon: 1e-9) ⇒ Boolean
Alias for equal? with explicit epsilon
27 28 29 |
# File 'lib/philiprehberger/approx.rb', line 27 def self.near?(a, b, epsilon: 1e-9) equal?(a, b, epsilon: epsilon) end |
.percent_equal?(a, b, percent:) ⇒ Boolean
Check if two values are approximately equal within a percentage tolerance
126 127 128 |
# File 'lib/philiprehberger/approx.rb', line 126 def self.percent_equal?(a, b, percent:) compare_percent(a, b, percent) end |
.relative_equal?(a, b, tolerance: 1e-6) ⇒ Boolean
Check if two values are approximately equal using relative tolerance
Relative tolerance: |a - b| / max(|a|, |b|) <= tolerance Falls back to absolute comparison when both values are zero.
40 41 42 |
# File 'lib/philiprehberger/approx.rb', line 40 def self.relative_equal?(a, b, tolerance: 1e-6) compare_relative(a, b, tolerance) end |
.within?(a, b, abs: nil, rel: nil) ⇒ Boolean
Check if two values are approximately equal using combined tolerance
Passes if either absolute or relative tolerance is met. At least one of abs: or rel: must be provided.
54 55 56 57 58 |
# File 'lib/philiprehberger/approx.rb', line 54 def self.within?(a, b, abs: nil, rel: nil) raise ArgumentError, 'at least one of abs: or rel: must be provided' if abs.nil? && rel.nil? compare_within(a, b, abs, rel) end |
.zero?(value, epsilon: 1e-9) ⇒ Boolean
Check if a numeric value is approximately zero
90 91 92 |
# File 'lib/philiprehberger/approx.rb', line 90 def self.zero?(value, epsilon: 1e-9) value.abs <= epsilon end |