# 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:** 1

<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 9, 2018, 3:10pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/1 "2018-02-09T15:10:51Z")

</div>

I read somewhere that the approximation binary operator (\approx) checks if the number is within machine precision. Whatever it does exactly, it does not appear to behave consistently:

```julia
julia> ℯ^(-π*im)
-1.0 - 1.2246467991473532e-16im

julia> ℯ^(-π*im) == -1
false

```

This is probably normal behaviour, and I guess that \sim 10^{-16} is machine or type precision. So I will use \approx to get a `true`th, but reordening of symbols, or considering only the imaginary part, results in a `false`hood:

```julia
julia> ℯ^(-π*im) ≈ -1
true

julia> ℯ^(-π*im) + 1 ≈ 0
false

julia> imag(ℯ^(-π*im))
-1.2246467991473532e-16

julia> imag(ℯ^(-π*im)) ≈ 0
false

```

Tip: typing `\app[Tab][Tab]` in the interpreter results in TeX’s \approx and then Unicode.

Most of the above numerical expressions are of the same type `Complex{Float64}`, so precision should be the same for everything. The last two `imag()` expressions are `Float64` and shows the problem as well. What happens here?

I am using Julia 0.7.0-DEV.3686, same on 0.6.2.

---

<div class="post-metadata">

**Author:** ![vvjn](https://avatars.discourse-cdn.com/v4/letter/v/5f9b8f/32.png) [@vvjn](https://discourse.julialang.org/u/vvjn)\
**Post date:** [February 9, 2018, 3:47pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/2 "2018-02-09T15:47:10Z")

</div>

What is happening is shown in the docs for `isapprox`.

```julia
isapprox(x, y; rtol::Real=sqrt(eps), atol::Real=0, nans::Bool=false, norm::Function)

  Inexact equality comparison: true if norm(x-y) <= atol + rtol*max(norm(x), norm(y))

```

Why the rules are set like that, I’m not sure.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [February 9, 2018, 4:07pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/3 "2018-02-09T16:07:13Z")

</div>

There was much discussion about this at one time. For isapprox to work reasonably over pairs that may be very close, close, far or very far from each other , it is necessary to combine both the absolute difference and the relative inexactness and that is usually done additively. Norms are taken to normalize the metric over various kinds of input.

---

<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 9, 2018, 4:38pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/4 "2018-02-09T16:38:05Z")

</div>

I have been breaking my head over Julia’s definition of `isapprox()`. I was missing an important ingredient, namely the fact that computers approximate real numbers by floats! For floats the precision depends on the magnitude of the number (and it depends on how many bits the float has). For instance,

```julia
julia> isapprox(1 + 1.2e-16, 1)
true

julia> isapprox(1.2e-16, 0)
false

```

To some extend, this is consistent how for instance physicists think about approximation. Something like a \approx b \Leftrightarrow a/b \approx 1. Approximation is relative. This implies that “approximately zero” doesn’t make sense (ratio is ill-defined), also not in Julia:

```julia
julia> isapprox(1.2e-300, 0)
false

```

---

<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 9, 2018, 4:45pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/5 "2018-02-09T16:45:11Z")

</div>

I didn’t know that Julia has such a function, and I propose that it should be dropped from the language. For users with experience and understanding of floating-point, this function is superfluous since they can use `norm` and `abs` appropriately. For users lacking experience, this function gives them a false sense of security as they enter a mine-field.

---

<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 9, 2018, 4:55pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/6 "2018-02-09T16:55:51Z")

</div>

I’m not sure if I agree. If I see an “\approx” somewhere of which I don’t know its definition yet, I won’t assume any type of security at all. If I don’t know what it means I either don’t use it, or I try to understand what it means first.

If Julia’s `isapprox(a, b)` is indeed consistent with what is usually understood by a/b\approx 1, I propose to leave it as-is. Otherwise, I don’t know (it may be there for a different reason).

---

<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 9, 2018, 5:20pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/7 "2018-02-09T17:20:48Z")

</div>

I understand the mathematical justification for `isapprox(a,0.0)` being ill-defined, but it is pretty confusing for users.

Is there a meaningful way to define  
`isapproxzero(a)`? and if so could the a \approx 0 be written to support that particular form for the integer 0 literal?. i.e. something like

```julia
function isapprox(x, zero_literal???; rtol::Real=sqrt(eps), atol::Real=0, nans::Bool=false, norm::Function)
   return norm(x) < rtol
end

```

At this point, since `x` \approx `0` is pretty much useless, I don’t see what the harm is?

---

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [February 9, 2018, 6:26pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/8 "2018-02-09T18:26:50Z")

</div>

This was discussed in [https://github.com/JuliaLang/julia/issues/23376](https://github.com/JuliaLang/julia/issues/23376) and the consensus was not to do it.

---

<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 9, 2018, 6:37pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/9 "2018-02-09T18:37:39Z")

</div>

I think I understand. So the issue is that the units of the default tolerance only make sense for the particular norm you are interested in?

---

<div class="post-metadata">

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

</div>

The issue is that when you say that a is approximately equal to b, it means that |b-a| is small compared to the characteristic magnitude of a and b, which is taken to be max(a,b) for lack of a better way. If b is zero, then that procedure fails. The alternative would be to define the smallness absolutely (which you can do by yourself with isapprox(rtol=Inf, atol=your\_tol)), but this really assumes that the quantities you’re interested in have a natural unit of about one, which might or might not be true. 1e-10 meters is small when you’re comparing the length of an atom to the length of your arm, it’s not so small when you’re comparing the length of an atom to the Planck length or something like that. Really in any well-behaved computation you should normalize everything to a relevant set of units, and everything will be about unity, so this would make sense, but it’s probably not a decision that the base language should make (see stevengj’s comment in the linked issue)

---

<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 9, 2018, 6:59pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/11 "2018-02-09T18:59:45Z")

</div>

Makes complete sense. Is there ever a time when `a` \approx `0` or `a` \approx `0.0` is meaningful? If not, is there a way to give a warning to users who may not have thought this through, so it silently fail? I have personally made the mistake before

---

<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 9, 2018, 7:31pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/12 "2018-02-09T19:31:25Z")

</div>

My understanding is that `isapprox(a, 0.0) == false` for an `a != 0.0`. I prefer |y - x| \le \epsilon\cdot(1+|x|+|y|) in practice. But no single predicate will satisfy all expectations, and it is useful to have _something_ in `Base`.

---

<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 9, 2018, 7:42pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/13 "2018-02-09T19:42:10Z")

</div>

If it is not _something_ then at least it should warn the user that it is not doing what they think it is doing. i.e. sounds like if `min(abs(a),abs(b)) == 0` but `a != b` EXACTLY (which often fails for floating point operations) then the function should do a warning or error

---

<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 9, 2018, 8:02pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/14 "2018-02-09T20:02:17Z")

</div>

Approximate comparison to an explicit zero is equivalent to exact comparison but you can have `x ≈ y` where both end up being exactly zero and it will succeed.

Idle thought: would it make any sense to consider subnormal floats to be approximately zero? Or some subset of subnormal floats?

---

<div class="post-metadata">

**Author:** ![simonbyrne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simonbyrne/32/19_2.png) [@simonbyrne](https://discourse.julialang.org/u/simonbyrne)\
**Post date:** [February 9, 2018, 8:30pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/15 "2018-02-09T20:30:06Z")

</div>

We could tweak it to be something like

```julia
abs(x-y) <= atol + rtol*max(abs(x), abs(y), realmin(typeof(x)), realmin(typeof(y)))

```

That way by default any `Float64` of magnitude less than `realmin()*sqrt(eps()) == 3.3156184e-316` would be approximately equal to zero.

---

<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 9, 2018, 8:45pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/16 "2018-02-09T20:45:18Z")

</div>

That seems like it would fit the “half the significant digits” criterion.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [February 9, 2018, 9:41pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/17 "2018-02-09T21:41:40Z")

</div>

half the sigdigs when you are focusing on values which by definition are shy some bits of significance (the subnormals) seems overly fine a comb.

any float that is `<` realmin(typeof(float)) is already zeroish given it preceeds the realmin and is \>= 0

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [February 9, 2018, 9:42pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/18 "2018-02-09T21:42:28Z")

</div>

I do agree that the current def is less elegant than it might be.

---

<div class="post-metadata">

**Author:** ![simonbyrne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simonbyrne/32/19_2.png) [@simonbyrne](https://discourse.julialang.org/u/simonbyrne)\
**Post date:** [February 9, 2018, 10:24pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/19 "2018-02-09T22:24:50Z")

</div>

One option would be to make the default value of `atol` to be the `max` of the `realmin`s?

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [February 9, 2018, 11:26pm UTC](https://discourse.julialang.org/t/approximate-equality/8952/20 "2018-02-09T23:26:11Z")

</div>

that sounds decent – if the max(realmin) is conditioned on the type of the values being approxequaled rather than  
maximum(realmin(Float64), realmin(Float32), realmin(Float16))

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