Skip to content

Commit

Permalink
Merge pull request #12472 from stevengj/isapprox2
Browse files Browse the repository at this point in the history
add isapprox for arrays, with ≈ and ≉ synonyms
  • Loading branch information
stevengj committed Aug 10, 2015
2 parents 5c9d178 + 9ccdbff commit 80be6dc
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 19 deletions.
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ Library improvements

* The `MathConst` type has been renamed `Irrational` ([#11922]).

* `isapprox` now has simpler and more sensible default tolerances ([#12393]).
* `isapprox` now has simpler and more sensible default tolerances ([#12393]), supports arrays, and has synonyms `≈` ([U+2248](http://www.fileformat.info/info/unicode/char/2248/index.htm), LaTeX `\approx`) and `≉` ([U+2249](http://www.fileformat.info/info/unicode/char/2249/index.htm), LaTeX `\napprox`) for `isapprox` and `!isapprox`, respectively ([#12472]).

* Numbers

Expand Down Expand Up @@ -1563,11 +1563,13 @@ Too numerous to mention.
[#11891]: https://github.com/JuliaLang/julia/issues/11891
[#11922]: https://github.com/JuliaLang/julia/issues/11922
[#11985]: https://github.com/JuliaLang/julia/issues/11985
[#12025]: https://github.com/JuliaLang/julia/issues/12025
[#12031]: https://github.com/JuliaLang/julia/issues/12031
[#12034]: https://github.com/JuliaLang/julia/issues/12034
[#12087]: https://github.com/JuliaLang/julia/issues/12087
[#12137]: https://github.com/JuliaLang/julia/issues/12137
[#12162]: https://github.com/JuliaLang/julia/issues/12162
[#12393]: https://github.com/JuliaLang/julia/issues/12393
[#12458]: https://github.com/JuliaLang/julia/issues/12458
[#12472]: https://github.com/JuliaLang/julia/issues/12472
[#12491]: https://github.com/JuliaLang/julia/issues/12491
11 changes: 9 additions & 2 deletions base/docs/helpdb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2935,11 +2935,18 @@ cis
doc"""
```rst
::
isapprox(x::Number, y::Number; rtol::Real=sqrt(eps), atol::Real=0)
isapprox(x, y; rtol::Real=sqrt(eps), atol::Real=0)
Inexact equality comparison: ``true`` if ``abs(x-y) <= atol + rtol*max(abs(x), abs(y))``. The default ``atol`` is zero and the default ``rtol`` depends on the types of ``x`` and ``y``.
Inexact equality comparison: ``true`` if ``norm(x-y) <= atol + rtol*max(norm(x), norm(y))``. The default ``atol`` is zero and the default ``rtol`` depends on the types of ``x`` and ``y``.
For real or complex floating-point values, ``rtol`` defaults to ``sqrt(eps(typeof(real(x-y))))``. This corresponds to requiring equality of about half of the significand digits. For other types, ``rtol`` defaults to zero.
``x`` and ``y`` may also be arrays of numbers, in which case ``norm``
defaults to ``vecnorm`` but may be changed by passing a
``norm::Function`` keyword argument. (For numbers, ``norm`` is the
same thing as ``abs``.)
The binary operator ``≈`` is equivalent to ``isapprox`` with the default arguments, and ``x ≉ y`` is equivalent to ``!isapprox(x,y)``.
```
"""
isapprox
Expand Down
2 changes: 2 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ export
zero,
,
,
,
,

# specfun
airy,
Expand Down
8 changes: 6 additions & 2 deletions base/floatfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,14 @@ for f in (:round, :ceil, :floor, :trunc)
end

# isapprox: approximate equality of numbers
isapprox(x::Number, y::Number; rtol::Real=rtoldefault(x,y), atol::Real=0) =
function isapprox(x::Number, y::Number; rtol::Real=rtoldefault(x,y), atol::Real=0)
x == y || (isfinite(x) && isfinite(y) && abs(x-y) <= atol + rtol*max(abs(x), abs(y)))
end

const = isapprox
(x,y) = !(x y)

# default tolerance arguments
rtoldefault{T<:AbstractFloat}(::Type{T}) = sqrt(eps(T))
rtoldefault{T<:Real}(::Type{T}) = 0
rtoldefault{T<:Number,S<:Number}(x::T, y::S) = rtoldefault(promote_type(real(T),real(S)))
rtoldefault{T<:Number,S<:Number}(x::Union(T,Type{T}), y::Union(S,Type{S})) = rtoldefault(promote_type(real(T),real(S)))
3 changes: 2 additions & 1 deletion base/linalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ module LinAlg
importall Base
importall ..Base.Operators
import Base: USE_BLAS64, size, copy, copy_transpose!, power_by_squaring,
print_matrix, transpose!, unsafe_getindex, unsafe_setindex!
print_matrix, transpose!, unsafe_getindex, unsafe_setindex!,
isapprox

export
# Modules
Expand Down
5 changes: 5 additions & 0 deletions base/linalg/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -535,3 +535,8 @@ det(x::Number) = x
logdet(A::AbstractMatrix) = logdet(lufact(A))
logabsdet(A::AbstractMatrix) = logabsdet(lufact(A))

# isapprox: approximate equality of arrays [like isapprox(Number,Number)]
function isapprox{T<:Number,S<:Number}(x::AbstractArray{T}, y::AbstractArray{S}; rtol::Real=Base.rtoldefault(T,S), atol::Real=0, norm::Function=vecnorm)
d = norm(x - y)
return isfinite(d) ? d <= atol + rtol*max(norm(x), norm(y)) : x == y
end
39 changes: 26 additions & 13 deletions test/floatapprox.jl
Original file line number Diff line number Diff line change
@@ -1,33 +1,40 @@
# This file is a part of Julia. License is MIT: http://julialang.org/license

# Floating point numbers - basic tests
@test isapprox(4.00000000000001, 4.0)
@test isapprox(5.0,4.999999999999993)
@test !isapprox(4.000000002, 4.00300002)
@test 4.00000000000001 4.0
@test 5.0 4.999999999999993
@test 4.000000002 4.00300002

# Other tolerance levels
@test isapprox(4.32, 4.3; rtol=0.1, atol=0.01)
@test isapprox(1.001, 1.002; rtol=0.001, atol=0.0001)
@test !isapprox(4.5, 4.9; rtol=0.001, atol=0.001)

# Complex numbers
@test isapprox(1.0 + 1.0im, 1.0 + 1.00000000000001im)
@test isapprox(0.9999999999999 + 1.0im, 1.0 + 1.000000000000001im)
@test 1.0 + 1.0im 1.0 + 1.00000000000001im
@test 0.9999999999999 + 1.0im 1.0 + 1.000000000000001im
@test isapprox(0.9999 + 1.0im, 1.0 + 1.1im; rtol = 0.0001, atol=1.1)

# Complex <-> reals
@test isapprox(1.0 + 0im, 1.0000000000001)
@test 1.0 + 0im 1.0000000000001
@test isapprox(0.9999999999999, 1.0 + 0im)
@test !isapprox(1.0+1im, 1.000000000000001)

# Comparing NaNs
@test !isapprox(4.0,NaN)
@test !isapprox(NaN,4.0)
@test !isapprox(complex(2.3,NaN), complex(NaN,2.3))
@test !isapprox(NaN, NaN)
@test !isapprox(complex(NaN,NaN), complex(NaN,NaN))
@test !isapprox(complex(NaN,2.3), complex(NaN,2.3))
@test !isapprox(complex(2.3,NaN), complex(2.3,NaN))
@test 4.0 NaN
@test NaN 4.0
@test complex(2.3,NaN) complex(NaN,2.3)
@test NaN NaN
@test complex(NaN,NaN) complex(NaN,NaN)
@test complex(NaN,2.3) complex(NaN,2.3)
@test complex(2.3,NaN) complex(2.3,NaN)

# Comparing Infs
@test Inf Inf
@test Inf 1
@test Inf -Inf
@test complex(0.0,Inf) complex(0.0,Inf)
@test complex(0.0,Inf) complex(0.0,-Inf)

# Tests for integers and rationals
@test isapprox(4,4)
Expand All @@ -46,3 +53,9 @@

# issue #12375:
@test !isapprox(1e17, 1)

# Tests for arrays:
@test [1,2,3] [1,2,3+1e-9]
@test [0,1] [1e-9, 1]
@test [0,Inf] [0,Inf]
@test [0,Inf] [0,-Inf]

0 comments on commit 80be6dc

Please sign in to comment.