# Compare numbers at the stated precision

**URL:** <https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719>\
**Category:** General Usage\
**Tags:** numbers, precision\
**Created:** [September 3, 2022, 6:45am UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719 "2022-09-03T06:45:15Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [September 3, 2022, 6:45am UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/1 "2022-09-03T06:45:15Z")

</div>

In tests I’ll like to be able to write the following and the test to pass:

```julia

@test aresame(pi, 3.14)

```

The following works:

```julia

@test isapprox(pi, 3.14, atol = 0.005)

```

But then I need to adjust the absolute tolerance manually.

I need a function to find the “number of significant digits” of a numeric literal and use that.

The following apparently works, but I’m wondering if this already exists?

```julia

function sigdigs(x)
    x_string = string(convert(Float64,x))
    length(x_string) - findlast('.',x_string)
end

function aresame(x,y)
    tol_digits = min(sigdigs(x), sigdigs(y))
    tol = .49*0.1^(tol_digits)
    isapprox(x,y,atol=tol)
end

julia> aresame(pi,3.1)
true

julia> aresame(pi,3.14)
true

julia> aresame(pi,3.141)
false

julia> aresame(pi,3.1415)
false

julia> aresame(pi,3.14159)
true

```

Are there standard functions or a package that does this?

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [September 3, 2022, 7:44am UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/2 "2022-09-03T07:44:50Z")

</div>

Can this be adapted to make use of the `rtol` keyword in `isapprox`?

---

<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:** [September 3, 2022, 12:23pm UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/3 "2022-09-03T12:23:46Z")

</div>

> [@tp2750](#):
>
> The following apparently works

Nope:

```julia
julia> sigdigs(1.00000000)
1

```

The basic problem here is that the Julia parser does not preserve the number of digits that were used when a literal floating-point value was entered.

The only way I can think of to do this is to define a new type of numeric literal that you construct with a string macro. e.g. you could define a type such that:

```julia
@test pi ≈ t"3.14"

```

works, i.e. `t"3.14"` constructs a type `TestNumber(3.14, 0.005)` and there is an overloaded `isapprox` for `TestNumber`.

---

<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:** [September 3, 2022, 12:40pm UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/4 "2022-09-03T12:40:09Z")

</div>

> [@stevengj](#):
>
> The only way I can think of to do this is to define a new type of numeric literal that you construct with a string macro.

For example:

```julia
struct TestNumber{T<:Number}
    val::T
    atol::Float64
end
macro t_str(s)
    val = parse(Float64, s)
    parts = split(s, r"\.|[Ee]")
    atol = exp10(length(parts) > 1 ? -length(parts[2]) : 0) * 0.5 *
           (length(parts) > 2 ? exp10(parse(Int, parts[3])) : 1.0)
    return TestNumber(val, atol)
end
Base.isapprox(x::Number, t::TestNumber) = isapprox(x, t.val, atol=t.atol)
Base.isapprox(t::TestNumber, x::Number) = isapprox(x, t)
Base.show(io::IO, t::TestNumber) = print(io, t.val, " ± ", t.atol)

```

So that e.g.

```julia
julia> t"3.14"
3.14 ± 0.005

julia> t"3.1400"
3.14 ± 5.0e-5

julia> t"3.1400e-10"
3.14e-10 ± 5.000000000000001e-15

julia> pi ≈ t"3.14"
true

julia> pi ≈ t"3.140"
false

```

---

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [September 4, 2022, 1:33pm UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/5 "2022-09-04T13:33:50Z")

</div>

Thank you @stevengj .  
Looks like it is a bit more complicated than I imagined.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [September 4, 2022, 4:21pm UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/6 "2022-09-04T16:21:28Z")

</div>

Could using the `sigdigits` parameter of the `round` function be useful?  
I ask this because I have not understood what exactly the need is.

---

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [September 4, 2022, 5:05pm UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/7 "2022-09-04T17:05:10Z")

</div>

I would like to “automatically” get the number of significant digits of a numeric literal.  
As @stevengj has shown, that is probably not possible in general without using strings or string macros.  
Sorry for not being precise.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [September 4, 2022, 5:42pm UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/8 "2022-09-04T17:42:56Z")

</div>

Could you give some examples of expected result (negative = false or positive = true)?  
I have tried the following examples and I don’t know I can’t understand why one is true and one is false.

```julia
julia> pi ≈ t"3.1415"
false

julia> pi ≈ t"3.14159"
true

```

**edit**  
ok. understood. depends on whether the next digit is less than or greater than 5

is this equivalent?

```julia
aresame(x,s)=isapprox(round(x,sigdigits=length(strip(s,'0'))-1),parse(Float64, s))

```

---

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [September 5, 2022, 4:44am UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/9 "2022-09-05T04:44:35Z")

</div>

Thank you for the suggestion @rocco_sprmnt21 .  
Your function captures the idea well. I would prefer it to be symmetric, but that should not be too hard to fix.

Clearly my original post was not precise enough. My main question is if there is already some package (or standard function) that does this.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [September 5, 2022, 9:29am UTC](https://discourse.julialang.org/t/compare-numbers-at-the-stated-precision/86719/10 "2022-09-05T09:29:10Z")

</div>

well … then @steveng’sj solution is right for you, in the absence of a library solution?

maybe something like that if it were available working would be closer to your expectations?

```julia
Base.isapprox(x::Number, y::Number, sigdigits:: Bool) = 
if sigdigits
# here the expressions you used in 
# sigdigs
# and
# aresame
   return isapprox(x, y, atol = .49*0.1^(tol_digits))`
end

```
