# [R] The effect of tolerance in all.equal()

Duncan Murdoch murdoch.duncan at gmail.com
Sun Apr 30 18:35:44 CEST 2017

```On 30/04/2017 12:26 PM, Ashim Kapoor wrote:
> Dear All,
>
> This answer is very clear. Many thanks.
>
> when does it  return language / logical / chr ? I would want to read that
> so I can interpret the result of structure. I don't think ?str contains
> this.To me, logical and chr make sense, what does language mean? I think I
> need to read some more.

I would read the R Language Definition manual, and then bits and pieces
of R Internals, as necessary.  These are both included with R.  There
are also books separate from R that talk about these things, but I don't
know which to recommend.

Duncan Murdoch

>
> Many thanks,
> Ashim
>
> On Tue, Apr 25, 2017 at 3:14 PM, Martin Maechler <maechler at stat.math.ethz.ch
>> wrote:
>
>>>>>>> Ashim Kapoor <ashimkapoor at gmail.com>
>>>>>>>     on Tue, 25 Apr 2017 14:02:18 +0530 writes:
>>
>>     > Dear all,
>>     > I am not able to understand the interplay of absolute vs relative and
>>     > tolerance in the use of all.equal
>>
>>     > If I want to find out if absolute differences between 2
>> numbers/vectors are
>>     > bigger than a given tolerance I would do:
>>
>>     > all.equal(1,1.1,scale=1,tol= .1)
>>
>>     > If I want to find out if relative differences between 2
>> numbers/vectors are
>>     > bigger than a given tolerance I would do :
>>
>>     > all.equal(1,1.1,tol=.1)
>>
>>     > ############################################################
>> ######################################################################
>>
>>     > I can also do :
>>
>>     > all.equal(1,3,tol=1)
>>
>>     > to find out if the absolute difference is bigger than 1.But here I
>> won't be
>>     > able to detect absolute differences smaller than 1 in this case,so I
>> don't
>>     > think that this is a good way.
>>
>>     > My query is: what is the reasoning behind all.equal returning the
>> absolute
>>     > difference if the tolerance >= target and relative difference if
>> tolerance
>>     > < target?
>> (above, it is    tol  >/<=  |target|  ie. absolute value)
>>
>>
>> The following are desiderata / restrictions :
>>
>> 1) Relative tolerance is needed to keep things scale-invariant
>>    i.e.,  all.equal(x, y)  and  all.equal(1000 * x, 1000 * y)
>>    should typically be identical for (almost) all (x,y).
>>
>>    ==> "the typical behavior should use relative error tolerance"
>>
>> 2) when x or y (and typically both!) are very close to zero it
>>    is typically undesirable to keep relative tolerances (in the
>>    boundary case, they _are_ zero exactly, and "relative error" is
>> undefined).
>>    E.g., for most purposes, 3.45e-15 and 1.23e-17 should be counted as
>>    equal to zero and hence to themselves.
>>
>> 1) and 2) are typically reconciled by switching from relative to absolute
>> when the arguments are close to zero (*).
>>
>> The exact cutoff at which to switch from relative to absolute
>> (or a combination of the two) is somewhat arbitrary(*2) and for
>> all.equal() has been made in the 1980's (or even slightly
>> earlier?) when all.equal() was introduced into the S language at
>> Bell labs AFAIK. Maybe John Chambers (or Rick Becker or ...,
>> but they may not read R-help) knows more.
>> *2) Then, the choice for all.equal() is in some way "least arbitrary",
>>     using c = 1 in the more general   tolerance >= c*|target|  framework.
>>
>> *) There have been alternatives in "the (applied numerical
>>  analysis / algorithm) literature" seen in published algorithms,
>>  but I don't have any example ready.
>>  Notably some of these alternatives are _symmetric_ in (x,y)
>>  where all.equal() was designed to be asymmetric using names
>>  'target' and 'current'.
>>
>> The alternative idea is along the following thoughts:
>>
>> Assume that for "equality" we want _both_ relative and
>> absolute (e := tolerance) "equality"
>>
>>    |x - y| < e (|x|+|y|)/2  (where you could use |y| or |x|
>>                              instead of their mean; all.equal()
>>                              uses |target|)
>>    |x - y| < e * e1          (where e1 = 1, or e1 = 10^-7..)
>>
>> If you add the two inequalities you get
>>
>>    |x - y| < e (e1 + |x+y|/2)
>>
>> as check which is a "mixture" of relative and absolute tolerance.
>>
>> With a somewhat long history, my gut feeling would nowadays
>> actually prefer this (I think with a default of e1 = e) - which
>> does treat x and y symmetrically.
>>
>> Note that convergence checks in good algorithms typically check
>> for _both_ relative and absolute difference (each with its
>> tolerance providable by the user), and the really good ones for
>> minimization do  check for (approximate) gradients also being
>> close to zero - as old timers among us should have learned from
>> Doug Bates ... but now I'm really diverging.
>>
>> Last but not least some  R  code at the end,  showing that the *asymmetric*
>> nature of all.equal() may lead to somewhat astonishing (but very
>> logical and as documented!) behavior.
>>
>> Martin
>>
>>     > Best Regards,
>>     > Ashim
>>
>>
>>> ## The "data" to use:
>>> epsQ <- lapply(seq(12,18,by=1/2), function(P) bquote(10^-.(P)));
>> names(epsQ) <- sapply(epsQ, deparse); str(epsQ)
>> List of 13
>>  \$ 10^-12  : language 10^-12
>>  \$ 10^-12.5: language 10^-12.5
>>  \$ 10^-13  : language 10^-13
>>  \$ 10^-13.5: language 10^-13.5
>>  \$ 10^-14  : language 10^-14
>>  \$ 10^-14.5: language 10^-14.5
>>  \$ 10^-15  : language 10^-15
>>  \$ 10^-15.5: language 10^-15.5
>>  \$ 10^-16  : language 10^-16
>>  \$ 10^-16.5: language 10^-16.5
>>  \$ 10^-17  : language 10^-17
>>  \$ 10^-17.5: language 10^-17.5
>>  \$ 10^-18  : language 10^-18
>>
>>> str(lapply(epsQ, function(tl) all.equal(3.45e-15, 1.23e-17, tol =
>> eval(tl))))
>> List of 13
>>  \$ 10^-12  : logi TRUE
>>  \$ 10^-12.5: logi TRUE
>>  \$ 10^-13  : logi TRUE
>>  \$ 10^-13.5: logi TRUE
>>  \$ 10^-14  : logi TRUE
>>  \$ 10^-14.5: chr "Mean relative difference: 0.9964348"
>>  \$ 10^-15  : chr "Mean relative difference: 0.9964348"
>>  \$ 10^-15.5: chr "Mean relative difference: 0.9964348"
>>  \$ 10^-16  : chr "Mean relative difference: 0.9964348"
>>  \$ 10^-16.5: chr "Mean relative difference: 0.9964348"
>>  \$ 10^-17  : chr "Mean relative difference: 0.9964348"
>>  \$ 10^-17.5: chr "Mean relative difference: 0.9964348"
>>  \$ 10^-18  : chr "Mean relative difference: 0.9964348"
>>
>>> ## Now swap `target` and `current` :
>>> str(lapply(epsQ, function(tl) all.equal(1.23e-17, 3.45e-15, tol =
>> eval(tl))))
>> List of 13
>>  \$ 10^-12  : logi TRUE
>>  \$ 10^-12.5: logi TRUE
>>  \$ 10^-13  : logi TRUE
>>  \$ 10^-13.5: logi TRUE
>>  \$ 10^-14  : logi TRUE
>>  \$ 10^-14.5: chr "Mean absolute difference: 3.4377e-15"
>>  \$ 10^-15  : chr "Mean absolute difference: 3.4377e-15"
>>  \$ 10^-15.5: chr "Mean absolute difference: 3.4377e-15"
>>  \$ 10^-16  : chr "Mean absolute difference: 3.4377e-15"
>>  \$ 10^-16.5: chr "Mean absolute difference: 3.4377e-15"
>>  \$ 10^-17  : chr "Mean relative difference: 279.4878"
>>  \$ 10^-17.5: chr "Mean relative difference: 279.4878"
>>  \$ 10^-18  : chr "Mean relative difference: 279.4878"
>>
>>>
>>
>
> 	[[alternative HTML version deleted]]
>
> ______________________________________________
> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
> https://stat.ethz.ch/mailman/listinfo/r-help