diff --git a/NEWS.md b/NEWS.md index 9205c406092b1..de6db9ef68eb3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -38,6 +38,7 @@ New library features Standard library changes ------------------------ * The `nextprod` function now accepts tuples and other array types for its first argument ([#35791]). +* The function `isapprox(x,y)` now accepts the `norm` keyword argument also for numeric (i.e., non-array) arguments `x` and `y` ([#35883]). #### LinearAlgebra diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index f0afe554d1a6e..97f72134c28f4 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -223,7 +223,7 @@ end # isapprox: approximate equality of numbers """ - isapprox(x, y; rtol::Real=atol>0 ? 0 : √eps, atol::Real=0, nans::Bool=false, norm::Function) + isapprox(x, y; atol::Real=0, rtol::Real=atol>0 ? 0 : √eps, nans::Bool=false[, norm::Function]) Inexact equality comparison: `true` if `norm(x-y) <= max(atol, rtol*max(norm(x), norm(y)))`. The default `atol` is zero and the default `rtol` depends on the types of `x` and `y`. The keyword @@ -234,10 +234,9 @@ the square root of [`eps`](@ref) of the type of `x` or `y`, whichever is bigger This corresponds to requiring equality of about half of the significand digits. Otherwise, e.g. for integer arguments or if an `atol > 0` is supplied, `rtol` defaults to zero. -`x` and `y` may also be arrays of numbers, in which case `norm` defaults to the usual -`norm` function in LinearAlgebra, but -may be changed by passing a `norm::Function` keyword argument. (For numbers, `norm` is the -same thing as `abs`.) When `x` and `y` are arrays, if `norm(x-y)` is not finite (i.e. `±Inf` +The `norm` keyword defaults to `abs` for numeric `(x,y)` and to `LinearAlgebra.norm` for +arrays (where an alternative `norm` choice is sometimes useful). +When `x` and `y` are arrays, if `norm(x-y)` is not finite (i.e. `±Inf` or `NaN`), the comparison falls back to checking whether all elements of `x` and `y` are approximately equal component-wise. @@ -273,8 +272,10 @@ julia> isapprox(1e-10, 0, atol=1e-8) true ``` """ -function isapprox(x::Number, y::Number; atol::Real=0, rtol::Real=rtoldefault(x,y,atol), nans::Bool=false) - x == y || (isfinite(x) && isfinite(y) && abs(x-y) <= max(atol, rtol*max(abs(x), abs(y)))) || (nans && isnan(x) && isnan(y)) +function isapprox(x::Number, y::Number; + atol::Real=0, rtol::Real=rtoldefault(x,y,atol), + nans::Bool=false, norm::Function=abs) + x == y || (isfinite(x) && isfinite(y) && norm(x-y) <= max(atol, rtol*max(norm(x), norm(y)))) || (nans && isnan(x) && isnan(y)) end """ diff --git a/test/math.jl b/test/math.jl index 79deaac247a7e..d98da02958941 100644 --- a/test/math.jl +++ b/test/math.jl @@ -670,10 +670,16 @@ end @test exp10(Float16(1.0)) === Float16(exp10(1.0)) end -# #22742: updated isapprox semantics -@test !isapprox(1.0, 1.0+1e-12, atol=1e-14) -@test isapprox(1.0, 1.0+0.5*sqrt(eps(1.0))) -@test !isapprox(1.0, 1.0+1.5*sqrt(eps(1.0)), atol=sqrt(eps(1.0))) +@testset "isapprox" begin + # #22742: updated isapprox semantics + @test !isapprox(1.0, 1.0+1e-12, atol=1e-14) + @test isapprox(1.0, 1.0+0.5*sqrt(eps(1.0))) + @test !isapprox(1.0, 1.0+1.5*sqrt(eps(1.0)), atol=sqrt(eps(1.0))) + + # #13132: Use of `norm` kwarg for scalar arguments + @test isapprox(1, 1+1.0e-12, norm=abs) + @test !isapprox(1, 1+1.0e-12, norm=x->1) +end # test AbstractFloat fallback pr22716 struct Float22716{T<:AbstractFloat} <: AbstractFloat