I had a vague idea about an operator that would ease working with value tolerances and ranges. During our ride up Mount Etna, I by chance had the pleasure of sitting next to Geoff Streeter. We started discussing some things, and before long I had my laptop out and we were prototyping a new operator.
I discussed my idea with Nick Nickolov, who told me that being a fan of ⎕CT←0
, he has considered ≈
to denote tolerant equality. I think we then naturally would want ≉
, and ≲
, and ≳
, and so on.. It is clear that we are dealing with a whole concept here, namely the allowing for deviation in comparisons.
There is a long-standing disagreement on whether ⎕CT
is a mathematical concept of tolerance (Geoff Streeter's position) or just a patch for binary machines' problems with floating point calculations (Morten Kromberg's position). By introducing a specific operator to denote allowed range in comparison, even Geoff (he told me so!) would agree that ⎕CT
remains nothing but a computing tool. ⎕CT
would continue to apply in comparisons with allowed range, only further expanding the allowance, but the user could set ⎕CT←0
and use his own code to get exactly the precision he wants.
Later, I had the honour of discussing the idea in an informal group including Nick, Geoff, Aaron Hsu, Roger Hui, and other bright minds. During a meal, I also discussed the idea with Brian Becker. After drafting this blog post, Geoff came up with a significant improvement, which I could extend even further:
A whole aspect of tolerant comparison could easily be added to the proposed operator by allowing a vector right-operand, where the first element represents relative deviance (⎕CT
style), and the second element represents absolute deviance. For example, =±0.1 2
would mean comparison with a deviance of up to 10% or 2 units. For 100 it would mean 90 ≤ x ≤ 110, for 10 it would mean 8 ≤ x ≤ 12, and for 0 it would mean −2 ≤ x ≤ 2. This solves the often encountered problem that ⎕CT
is not used in comparisons with zero, and opens up applications like neutral joystick input with a bit of play.
Furthermore, the right-operand could be expanded to the complex domain allowing different deviance in the real and imaginary dimensions: 0 (=±0.1J0.1) f x
flags all approximate roots of f
, while 0 (=±0.1) f x
flags only the real approximate roots.
Currently in Dyalog APL we have to use the rather cumbersome expression (¯1≤x)∧(x≤2)
because the equality in essence is ternary (has three arguments; x
, ¯1
, and 2
). Unfortunately, this APL expression is not a good tool for thought, because the ±
really conceptually denotes that the =
is modified to allow for a certain deviation. In other words, we have a modified function. This calls for an operator! Now consider
x (=±2) 1
where it is clear that =
is modified by ±
to allow a deviation of 2
:
¯5 ¯1 1 3 4 5 (=±2) 1
0 1 1 1 0 0
Where could a range be allowed in an otherwise precise (save for ⎕CT
) comparison? Well, everywhere where ⎕CT
is an implicit argument of course! That is, the monadic primitive functions Ceiling (⌈
), Floor (⌊
) and Unique (∪
) and the dyadic functions Equal (=
), Excluding (~
), Find (⍷
), Greater (>
), Greater or Equal (≥
), Index of (⍳
), Intersection (∩
), Less (<
), Less or Equal (≤
), Match (≡
), Membership (∊
), Not Match (≢
), Not Equal (≠
), Residue (|
) and Union (∪
), as well as ⎕FMT
's O
-format.
There are several real-world examples where the equivalent current-APL code would be much simpler using this operator. Here are a few examples:
Round up if much above lower integer:
(⌈±0 0.2) 1.6 1.9 2 2.2 2.3
2 2 2 2 3
Elements that far from each other:
(∪±0 0.2) 1.6 1.9 2 2.2 2.3
1.6 1.9 2.2
Remove elements ≈ 2:
1.6 1.9 2 2.2 2.3 (~±0 0.2) 2
1.6 2.3
Index of first element ≈ 2:
1.6 1.9 2 2.2 2.3 (⍳±0 0.2) 2
2
Close-enough match?
1.6 1.9 2 2.2 2.3 (≡±0 0.2) 1.5 2 2 2 1.5
1
Within 5% of any element?
1.7 2.4 (∊±0.05) 1.6 1.9 2 2.2 2.3
0 1
With a set of tiles that are 4 cm long, can the given walls be covered if we allow 5% fuzziness through varying the amount of grout?
0 = 4 (|±0.05) 16 19 20 22 23
1 0 1 0 1
Is the joystick input neutral or within 10% of 1000?
heading (∊±1 0.1) 0 request
1 0 1 0 1
- As so much in regular mathematics, the notation x = 1 ± 2 is ambiguous. An identical notation is used for the roots of p = 2x² − 4x – 6, namely x = 1 ± 2, that is, both x = −1 and x = 3, but of course not any value in between them. See Wikipedia.