How to resolve the algorithm Approximate equality step by step in the Haskell programming language
How to resolve the algorithm Approximate equality step by step in the Haskell 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 Haskell programming language
1. Custom Equality Operator for Near Equality
The code defines a type class AlmostEq
that provides a way to compare two values of type a
for near equality (approximate equality). This is useful when comparing floating-point numbers or other values where exact equality may not be possible due to rounding errors or other factors.
2. Components of AlmostEq
The AlmostEq
type class requires the following constraints on its argument a
:
Num a
:a
must be a numeric type that supports basic arithmetic operations.Ord a
:a
must be an ordered type, meaning values of typea
can be compared using<
,<=
, etc.Eq a
:a
must be an equality type, meaning values of typea
can be tested for equality using==
.
3. eps
Member Function
The AlmostEq
type class includes a member function eps
that returns an epsilon value which represents the maximum difference allowed between two values for them to be considered nearly equal.
4. ~=
Operator for Near Equality
The ~=
operator is defined as an infix operator with a precedence of 4. It is used to test whether two values of type a
are nearly equal. The operator returns True
if any of the following conditions are met:
- The values are exactly equal (
a == b
). - The absolute difference between the values is less than the
eps
value multiplied by the absolute sum of the values (abs (a - b) < eps * abs(a + b)
). - The absolute difference between the values is less than the
eps
value (abs (a - b) < eps
).
5. Instances of AlmostEq
The code also provides instances of the AlmostEq
type class for the following types:
Int
witheps
set to 0.Integer
witheps
set to 0.Double
witheps
set to 1e-14.Float
witheps
set to 1e-5.
6. test
List
The test
list contains several pairs of floating-point numbers to be tested for near equality.
7. main
Function
The main
function runs the tests by iterating through the test
list and calling the runTest
function for each pair of numbers.
8. runTest
Function
The runTest
function prints the following information for each pair of numbers:
- The original values
a
andb
. - The result of the exact equality test (
a == b
). - The result of the near equality test (
a~=b
).
The code is a Haskell program that defines a function main
, which is the entry point of the program. The function main
takes a list of tuples of pairs of floating point numbers as input and for each pair it prints if the two numbers are equal or if they are almost equal.
The definition of main
is as follows:
main = mapM_ runTest test
where
runTest (a, b) = do
printf "%f == %f %v\n" a b (show $ a==b) :: IO ()
printf "%f ~= %f %v\n\n" a b (show $ a~=b)
The function mapM_
applies the function runTest
to each element of the list test
and returns a list of the results. The function runTest
takes a pair of floating point numbers as input and prints if the two numbers are equal or if they are almost equal. The function printf
is used to format the output.
The definition of the function runTest
is as follows:
runTest (a, b) = do
printf "%f == %f %v\n" a b (show $ a==b) :: IO ()
printf "%f ~= %f %v\n\n" a b (show $ a~=b)
The function printf
is used to format the output. The format string "%f == %f %v\n"
expects three arguments: two floating point numbers and a boolean value. The format string "%f ~= %f %v\n"
expects three arguments: two floating point numbers and a boolean value.
The function show
is used to convert the boolean value to a string. The boolean value is True
if the two numbers are equal or if they are almost equal, and False
otherwise.
The definition of the function ~=
is as follows:
infix 4 ~=
(~=) :: AlmostEq a => a -> a -> Bool
a ~= b = or [ a == b
, abs (a - b) < eps * abs(a + b)
, abs (a - b) < eps ]
The infix operator ~=
is defined for any type a
that implements the AlmostEq
type class. The type class AlmostEq
requires the type a
to implement the Num
, Ord
, and Eq
type classes. The function eps
returns the epsilon value for the type a
. The epsilon value is used to determine if two numbers are almost equal.
The function ~=
returns True
if the two numbers are equal, if the absolute value of the difference between the two numbers is less than the epsilon value multiplied by the absolute value of the sum of the two numbers, or if the absolute value of the difference between the two numbers is less than the epsilon value. Otherwise, the function returns False
.
The definition of the AlmostEq
type class is as follows:
class (Num a, Ord a, Eq a) => AlmostEq a where
eps :: a
The AlmostEq
type class has one method, eps
, which returns the epsilon value for the type a
. The epsilon value is used to determine if two numbers are almost equal.
The following instances of the AlmostEq
type class are defined:
instance AlmostEq Int where eps = 0
instance AlmostEq Integer where eps = 0
instance AlmostEq Double where eps = 1e-14
instance AlmostEq Float where eps = 1e-5
The instance of the AlmostEq
type class for the type Int
sets the epsilon value to 0. The instance of the AlmostEq
type class for the type Integer
sets the epsilon value to 0. The instance of the AlmostEq
type class for the type Double
sets the epsilon value to 1e-14. The instance of the AlmostEq
type class for the type Float
sets the epsilon value to 1e-5.
The following is an example of how to use the ~=
operator:
>>> 10 ~= 10.0
True
>>> 10 ~= 10.001
True
>>> 10 ~= 11
False
Source code in the haskell programming language
class (Num a, Ord a, Eq a) => AlmostEq a where
eps :: a
infix 4 ~=
(~=) :: AlmostEq a => a -> a -> Bool
a ~= b = or [ a == b
, abs (a - b) < eps * abs(a + b)
, abs (a - b) < eps ]
instance AlmostEq Int where eps = 0
instance AlmostEq Integer where eps = 0
instance AlmostEq Double where eps = 1e-14
instance AlmostEq Float where eps = 1e-5
test :: [(Double, Double)]
test = [(100000000000000.01, 100000000000000.011)
,(100.01, 100.011)
,(10000000000000.001 / 10000.0, 1000000000.0000001000)
,(0.001, 0.0010000001)
,(0.000000000000000000000101, 0.0)
,(sqrt 2 * sqrt 2, 2.0)
,(-sqrt 2 * sqrt 2, -2.0)
,(3.141592653589793, 3.141592653589794)
,(3.141592653589, 3.141592653589794)]
-- requires import Text.Printf
main = mapM_ runTest test
where
runTest (a, b) = do
printf "%f == %f %v\n" a b (show $ a==b) :: IO ()
printf "%f ~= %f %v\n\n" a b (show $ a~=b)
You may also check:How to resolve the algorithm One-dimensional cellular automata step by step in the ALGOL W programming language
You may also check:How to resolve the algorithm Elementary cellular automaton/Infinite length step by step in the Wren programming language
You may also check:How to resolve the algorithm Sequence of primorial primes step by step in the Perl programming language
You may also check:How to resolve the algorithm Loops/For step by step in the AppleScript programming language
You may also check:How to resolve the algorithm Strip whitespace from a string/Top and tail step by step in the Elixir programming language