Take an IEC 61131-3 Structured Text function. It compares two REAL
numbers for equality within a specified epsilon tolerance.
FUNCTION REPSILONEQ : BOOL
VAR_INPUT
rLHS : REAL; (* nominal left-hand side *)
rRHS : REAL; (* nominal right-hand side *)
rEpsilon : REAL := REAL#1e-6; (* allowable difference *)
END_VAR
(* Error band is inclusive of the epsilon value.
Less than or equal to is close enough, rather than strict equality. *)
REPSILONEQ := ABS(rLHS - rRHS) <= rEpsilon;
END_FUNCTION
It takes two arguments: two real numbers, nominally the left- and right-hand sides of a function. In reality, the sides do not matter for this function; it computes their absolute difference, hence order does not matter. The sign disappears.
But it begs a question:
Equal To, or Less Than or Equal To?
Should the comparison operator be < or <=? Less than, or less than
or equal to? Put another way, is the epsilon an inclusive or exclusive
upper boundary for the difference comparison? What should happen at the
epsilon boundary?
Ad extremis, as the Romans might say, epsilon is the smallest
meaningful positive difference representable in the system’s
floating-point implementation of a REAL number; C implements two
macros, FLT_EPSILON and DBL_EPSILON, defining these cryptic numbers.
CPUs implement “real” numbers as floating-point numbers which comprise
two signed integer components: an exponent and a mantissa. The smallest
such number amounts to the largest negative exponent combined with the
smallest mantissa—smallest just above zero.
Smallest Epsilon
As shown above, the implementation compares the difference between its two inputs against an inclusive upper boundary.
Suppose that \(\epsilon\) (the rEpsilon argument) is the smallest
possible difference—the actual floating-point unit’s version of epsilon
in real space, whatever that might be. Not zero, that is, but one
floating-point step above zero.
In that case, the REPSILONEQ function answers TRUE only if the
absolute difference computes as an absolute \(lhs-rhs=[0,\epsilon]\)
result. Two possible floating-point numbers satisfy the equality test:
either zero or epsilon.
Only an absolute \(\epsilon\lt0\) would fail for all values of \(lhs\) and
\(rhs\). Negative epsilons always answer FALSE simply because the
absolute difference (always a positive number) can never be less than or
equal to a negative number.
Conclusions
The REPSILONEQ function provides a way to compare two real numbers
with tolerance for small differences.
Using an inclusive epsilon ensures that values within the error tolerance have equality. Call it a pragmatic choice.
Recommended behaviour:
- Reject negative epsilon values. Avoid negative epsilon values, as they
will always result in
FALSE. Clamp its lower boundary to zero usingLIMIT. - Choose an appropriate
rEpsilonvalue based on the usage precision requirements. Use an appropriate inclusive error band to account for small floating-point differences.
Be aware that the function only considers the absolute difference, not relative differences. It does not account for the scale of the numbers being compared.