How to resolve the algorithm Approximate equality step by step in the Ruby programming language
How to resolve the algorithm Approximate equality step by step in the Ruby programming language
Table of Contents
Problem Statement
Sometimes, when testing whether the solution to a task (for example, here on Rosetta Code) is correct, the difference in floating point calculations between different language implementations becomes significant. For example, a difference between 32 bit and 64 bit floating point calculations may appear by about the 8th significant digit in base 10 arithmetic.
Create a function which returns true if two floating point numbers are approximately equal.
The function should allow for differences in the magnitude of numbers, so that, for example, 100000000000000.01 may be approximately equal to 100000000000000.011, even though 100.01 is not approximately equal to 100.011. If the language has such a feature in its standard library, this may be used instead of a custom function. Show the function results with comparisons on the following pairs of values:
Answers should be true for the first example and false in the second, so that just rounding the numbers to a fixed number of decimals should not be enough. Otherwise answers may vary and still be correct. See the Python code for one type of solution.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Approximate equality step by step in the Ruby programming language
Explanation of the Provided Ruby Code:
This Ruby code defines a method close_to?
on the Numeric
class, which checks if two numeric values are close to each other within a specified tolerance. The code also includes a series of test cases to demonstrate the usage of this method.
Implementation Details:
-
The
Numeric
class is extended to add theclose_to?
method. -
The
close_to?
method takes two numeric arguments,num
and an optionaltol
(tolerance) parameter, which defaults toFloat::EPSILON
. -
The method first checks if the two values are exactly equal, returning
true
if they are. -
If the values are not equal, it checks if either of them is either
NaN
(Not a Number) orFloat::INFINITY
. These values are considered not close to anything, sofalse
is returned. -
If neither value is
NaN
orFloat::INFINITY
, the absolute difference between the two values is calculated and compared to the tolerance. The tolerance is multiplied by the maximum absolute value of the two numbers to account for different scales. -
If the absolute difference is less than or equal to the tolerance, the method returns
true
, indicating that the two values are close; otherwise, it returnsfalse
.
Test Cases:
The testvalues
array contains several pairs of numeric values to be tested, including values with precision errors, NaN, infinity, and square root of 2.
Output:
After running the code, the following output is displayed:
1.0e+15 ≈ 1.0000000000000001e+15
100.01 ≈ 100.011
1.0e+11 ≈ 1000000000.0000001
0.001 ≈ 0.0010000001
1.01e-22 ≈ 0.0
2.0 ≈ 2.0
-2.0 ≈ -2.0
3.141592653589793 ≈ 3.141592653589793
nan ≈ nan
inf ≈ inf
Conclusion:
This code demonstrates a useful close_to?
method for comparing numeric values while allowing for a specified tolerance. The test cases illustrate its behavior with various types of numeric values, including those with precision errors and special values like NaN
and Infinity
.
Source code in the ruby programming language
require "bigdecimal"
testvalues = [[100000000000000.01, 100000000000000.011],
[100.01, 100.011],
[10000000000000.001 / 10000.0, 1000000000.0000001000],
[0.001, 0.0010000001],
[0.000000000000000000000101, 0.0],
[(2**0.5) * (2**0.5), 2.0],
[-(2**0.5) * (2**0.5), -2.0],
[BigDecimal("3.14159265358979323846"), 3.14159265358979324],
[Float::NAN, Float::NAN,],
[Float::INFINITY, Float::INFINITY],
]
class Numeric
def close_to?(num, tol = Float::EPSILON)
return true if self == num
return false if (self.to_f.nan? or num.to_f.nan?) # NaN is not even close to itself
return false if [self, num].count( Float::INFINITY) == 1 # Infinity is only close to itself
return false if [self, num].count(-Float::INFINITY) == 1
(self-num).abs <= tol * ([self.abs, num.abs].max)
end
end
testvalues.each do |a,b|
puts "#{a} #{a.close_to?(b) ? '≈' : '≉'} #{b}"
end
You may also check:How to resolve the algorithm Fractran step by step in the Python programming language
You may also check:How to resolve the algorithm 100 doors step by step in the Coq programming language
You may also check:How to resolve the algorithm Square but not cube step by step in the APL programming language
You may also check:How to resolve the algorithm Null object step by step in the Visual Basic programming language
You may also check:How to resolve the algorithm Hamming numbers step by step in the FunL programming language