# Approximate equality

**URL:** <https://discourse.julialang.org/t/approximate-equality/8952>\
**Category:** General Usage\
**Tags:** question, bug\
**Created:** [February 9, 2018, 3:10pm UTC](https://discourse.julialang.org/t/approximate-equality/8952 "2018-02-09T15:10:51Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [February 10, 2018, 2:45pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/21 "2018-02-10T14:45:48Z")

</div>

> [@simonbyrne](#):
>
> `abs(x-y) ≤ atol + rtol*max(abs(x), abs(y), realmin(typeof(x)), realmin(typeof(y)))`

I don’t know what problem this would actually solve. People doing `x ≈ 0` in practice are invariably like the original poster: they are expecting a tolerance much much greater than `realmin`.

That is, they are expecting `≈` to either magically know an absolute tolerance that is appropriate to how they computed `x` (which is impossible) or they are expecting `≈` to use an absolute tolerance assuming all quantities are of order unity (which is wrong). They just need to learn to pass an absolute tolerance for comparison of numbers to zero, or to simply check `abs(x) ≤ atol`.

Using `realmin` here makes `isapprox` harder to understand (now you’re asking the reader to know what `realmin` and subnormal numbers mean) for no benefit.

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [February 10, 2018, 2:53pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/22 "2018-02-10T14:53:28Z")

</div>

I agree entirely. Better to warn or error that it is invalid and to use `norm(x) <tol ` or if they are going `a - b`\approx `0` that they should instead use `a`\approx `b`.

The is especially important to warn them about because a whole bunch of code would would be easily reorganized… People are yin the habit of writing code like

```julia
error = abs(a-b) 
Converted = error \approx 0

```

---

<div class="post-metadata">

**Author:** ![Stephen\_Vavasis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stephen_vavasis/32/3389_2.png) [@Stephen\_Vavasis](https://discourse.julialang.org/u/Stephen_Vavasis)\
**Post date:** [February 10, 2018, 5:18pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/23 "2018-02-10T17:18:37Z")

</div>

I see that many smart people have posted on this site opinions on how `isapprox` ought to behave, and the opinions are mutually contradictory. This is strong evidence that this function should be dropped from Base. There is no such function in Matlab, and I have never heard anyone express a desire for it to be added to Matlab.

Let me ask the following: is there any author of a serious numerical package reading this discussion who uses `isapprox` in his/her code?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [February 10, 2018, 5:31pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/24 "2018-02-10T17:31:26Z")

</div>

> [@Stephen\_Vavasis](#):
>
> This is strong evidence that this function should be dropped from Base.

What, why? The relative tolerance is uncontroversial. The absolute tolerance choice is justified, though jarring at first. With `@test` and `atol` it’s a very nice convenience.

> [@Stephen\_Vavasis](#):
>
> There is no such function in Matlab, and I have never heard anyone express a desire for it to be added to Matlab.

MATLAB packages typically aren’t doing a bunch of unit tests and CI to care about easily testing for accuracy. That’s largely due to the fact that CI testing a language which needs a license is… (how do you even do it?). Everyone has to write tests in Julia in order to register a package, and if you do floating point calculations, you will want `isapprox`.

> [@Stephen\_Vavasis](#):
>
> Let me ask the following: is there any author of a serious numerical package reading this discussion who uses isapprox in his/her code?

Yes, in DiffEq’s tests because you cannot test equality of floating point calculations for anything serious.

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [February 10, 2018, 5:32pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/25 "2018-02-10T17:32:16Z")

</div>

I think is used in test cases more so than in the middle of algorithms? I really like having the function,… Just want it to fail or warn clearly or not even compile if it isnt doing something the user thinks it is.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 10, 2018, 5:33pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/26 "2018-02-10T17:33:29Z")

</div>

> [@Stephen\_Vavasis](#):
>
> serious numerical package reading this discussion who uses isapprox in his/her code?

I don’t know what counts as serious, but among the packages I have installed,

```sh
$ grep isapprox ~/.julia/v0.6/**/*.jl | wc -l
1442

```

Most of these are tests. So I would argue that it is useful.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 10, 2018, 5:35pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/27 "2018-02-10T17:35:32Z")

</div>

> [@jlperla](#):
>
> fail or warn clearly or not even compile if it isnt doing something the user thinks it is

That should be quite hard to do consistently, until LLVM implements an interface for mind reading. 😄

---

<div class="post-metadata">

**Author:** ![Ralph\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ralph_smith/32/10344_2.png) [@Ralph\_Smith](https://discourse.julialang.org/u/Ralph_Smith)\
**Post date:** [February 10, 2018, 5:35pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/28 "2018-02-10T17:35:39Z")

</div>

> [@Stephen\_Vavasis](#):
>
> There is no such function in Matlab, and I have never heard anyone express a desire for it to be added to Matlab.

Actually, it’s there in Matlab, and it’s called `verifyEqual` (tolerances are optional parameters). Also intended for ~~CI~~ unit testing.

Edit: as Chris points out, CI is awkward for Matlab.

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [February 10, 2018, 5:37pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/29 "2018-02-10T17:37:06Z")

</div>

But isn’t the issue just the comparison when onr of the things are 0? Everything else is mathematically sound

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [February 10, 2018, 5:37pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/30 "2018-02-10T17:37:59Z")

</div>

Yes, I have used it. Try out the matlab unit testing framework something for some good head smashing on your computer

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [February 10, 2018, 5:38pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/31 "2018-02-10T17:38:29Z")

</div>

> [@jlperla](#):
>
> Yes, I have used it. Try out the matlab unit testing framework something for some good head smashing on your computer

Just curious, were you able to set it up with Travis or AppVeyor? I’ve never seen that.

---

<div class="post-metadata">

**Author:** ![mvhulten](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mvhulten/32/2444_2.png) [@mvhulten](https://discourse.julialang.org/u/mvhulten)\
**Post date:** [February 10, 2018, 5:39pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/32 "2018-02-10T17:39:56Z")

</div>

I agree with @ChrisRackauckas in that the relative case is very sensible, both in the light of floating point precision and, as I argued before, it is consistent with the idea how physicists perceive what approximation is.

We should be careful with adding something like the absolute case (comparison with zero). I would say that one should do `isapprox(myvar+1, 1)` (or replace 1 for something that is sensible in that case).

My current point of view is not to change anything to the behaviour.

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [February 10, 2018, 5:40pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/33 "2018-02-10T17:40:45Z")

</div>

Never bothered…would need to have a custom docker image for it the be especially useful for CI on github due to licensing.

One of the MANY reasons to use jylia

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [February 10, 2018, 5:41pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/34 "2018-02-10T17:41:42Z")

</div>

But why is 1 special as a reference scale? Better to just throw an assert or ugly warning

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [February 10, 2018, 5:44pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/35 "2018-02-10T17:44:03Z")

</div>

> [@jlperla](#):
>
> But why is 1 special as a reference scale? Better to just throw an assert or ugly warning

Well, `atol=0` is essentially the same as throwing an error if used in a test, since that will fail unless you have equality when near zero. You can then up the tolerance so the test passes if you want.

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [February 10, 2018, 5:45pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/36 "2018-02-10T17:45:31Z")

</div>

Moreover: there is a discontinuity in the comparison as the minimum of the two numbers goes towards zero

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 10, 2018, 5:49pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/37 "2018-02-10T17:49:51Z")

</div>

As I said above: this is not a good comparison for all cases, but nothing is. It is at least conceptually clear and has a simple mental model. Also, it is easy to customize: setting `atol` and `rtol` covers a lot of usual cases.

I curious what you would replace it with. As it was [pointed out](https://discourse.julialang.org/t/approximate-equality/8952/21) above: just set `atol` if you want to compare near-`0`s. An update to the simple statistic above:

```julia
$ grep isapprox ~/.julia/v0.6/**/src/*.jl | wc -l
137
$ grep isapprox ~/.julia/v0.6/**/test/*.jl | wc -l
1284

```

so the majority are using it for tests, for which it is fine that `isapprox(0, ϵ)` are rejected. Then you just set `atol`.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [February 10, 2018, 6:59pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/38 "2018-02-10T18:59:54Z")

</div>

> [@Stephen\_Vavasis](#):
>
> I see that many smart people have posted on this site opinions on how isapprox ought to behave, and the opinions are mutually contradictory.

I think the basic issue is that many people don’t have a good mental model for floating-point comparisons. (This seems to be one of the eternal verities of floating-point arithmetic, not specific to Julia.) Once the issue is explained, objections to the `atol=0` default almost invariably melt away.

It’s important to have this in Base for testing, and is also important because it is so easy to get wrong (especially in the array case, where you really want to use some norm of the whole array as a reference magnitude in most applications, but people’s first attempts almost always involve elementwise comparisons).

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [February 10, 2018, 7:16pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/39 "2018-02-10T19:16:13Z")

</div>

> [@Stephen\_Vavasis](#):
>
> Let me ask the following: is there any author of a serious numerical package reading this discussion who uses isapprox in his/her code?

> **[Steven G. Johnson](https://en.wikipedia.org/wiki/Steven_G._Johnson)**
>
> Steven Glenn Johnson (born 1973) is an American mathematician known for being a co-creator of the FFTW library for software-based fast Fourier transforms and for his work on photonic crystals. He is professor of Applied Mathematics and Physics at MIT where he leads a group on Nanostructures and Computation.
> While working on his PhD at MIT, he developed the Fastest Fourier Transform in the West (FFTW) library with funding from the DoD NDSEG Fellowship. Steven Johnson and his colleague Matteo Frig...

> **[FFTW](https://en.wikipedia.org/wiki/FFTW)**
>
> The Fastest Fourier Transform in the West (FFTW) is a software library for computing discrete Fourier transforms (DFTs) developed by Matteo Frigo and Steven G. Johnson at the Massachusetts Institute of Technology.
> FFTW is one of the fastest free software implementations of the fast Fourier transform (FFT). It implements the FFT algorithm for real and complex-valued arrays of arbitrary size and dimension.
> FFTW expeditiously transforms data by supporting a variety of algorithms and choosing the o...

> <https://github.com/JuliaMath/FFTW.jl/blob/6e26a1ee12c5f05a9c8eb5f653b56f04ab568b80/test/runtests.jl#L113-L142>

---

<div class="post-metadata">

**Author:** ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)\
**Post date:** [February 10, 2018, 11:00pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/40 "2018-02-10T23:00:43Z")

</div>

I think the issue here even goes back to people (myself certainly included) that weren’t mentally thinking about what a \approx b means properly. Undergraduates and RAs who are often writing test cases are also unlikely to think through the nuances of relative comparisons and will probably just pull a tolerance out of thin air. On benefit of the current \approx is that is does the relative tolerance calculation for people properly.

From the model of this, it seems that it is,  
 a \approx b\quad \text{iff} \quad \frac{a}{b}\approx 1 \approx \frac{b}{a}

If this is indeed true, then the real issue is not even floating point math, but rather that this is undefined if either a=0 and b=0. We wouldn’t have a division by 0 silently ignored, so why would we here?

As for redefining this as  
 a \approx b\quad \text{iff} \quad \frac{a+ \mathbf{1}(a = 0 || b = 0)}{b + \mathbf{1}(a = 0 || b = 0)} \approx 1 there is an ugly discontinuity in whether the operation is true as a \to 0 or b\to 0.

More importantly, I am betting that 90% of the uses of `a ≈ 0` comes to two cases (this is a dogmatic prior, no evidence!):

1. People get in the habit of checking scalars `a - b ≈ 0` because they used to do `abs(a - b) < tol`. Here they could just have easily done `a ≈ b` with a small code rearrangement, which might even be cleaner in notation.
2. Testing whether two vectors are similar by checking ||A - B||\_K \approx 0 for some K norm, and calling it with `norm(A-B,Inf)≈0` or something like that. But the fallback for abstract arrays with `isapprox` basically does the ∞ norm. So in that case I think the warning should also be to call it with `a ≈ b` for vectors if the infinity norm is good enough. It will broadcast to the correct scalar version.

Here is a starting point for the `isapprox` that could be useful (where the array version doesn’t need to change)

```julia
function isapprox(x::Number, y::Number; rtol::Real=rtoldefault(x,y), atol::Real=0, nans::Bool=false)
     if(x != y && (x==zero(Number) || y==zero(Number)))
        warn("isapprox(x,y) cannot be called with x=0 or y=0. If you are using isapprox(x - y, 0) or isapprox(norm(x-y),0) the rearrange code to be isapprox(x,y) for either scalars or vectors")
        throw(DomainError())
    else
        return x == y || (isfinite(x) && isfinite(y) && abs(x-y) <= atol + rtol*max(abs(x), abs(y))) || (nans && isnan(x) && isnan(y))
    end
end

```

Try it with

```julia
isapprox(1.0,1.000000001)
isapprox(1.0 - 1.000000001,0)
isapprox([1.0;0.1], [1.00000001;0.10000001])

```

[Previous page](https://discourse.julialang.org/t/approximate-equality/8952.md?page=1)

[Next page](https://discourse.julialang.org/t/approximate-equality/8952.md?page=3)
