How to resolve the algorithm Approximate equality step by step in the Ruby programming language

Published on 12 May 2024 09:40 PM

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 the close_to? method.

  • The close_to? method takes two numeric arguments, num and an optional tol (tolerance) parameter, which defaults to Float::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) or Float::INFINITY. These values are considered not close to anything, so false is returned.

  • If neither value is NaN or Float::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 returns false.

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