Skip to content

Commit

Permalink
hypot behaves like L2-norm, adjust the docstring to reflect this
Browse files Browse the repository at this point in the history
  • Loading branch information
giordano committed May 7, 2019
1 parent 040a3e5 commit a835c4a
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 7 deletions.
16 changes: 14 additions & 2 deletions base/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ sqrt(x::Real) = sqrt(float(x))
"""
hypot(x, y)
Compute the hypotenuse ``\\sqrt{x^2+y^2}`` avoiding overflow and underflow.
Compute the hypotenuse ``\\sqrt{|x|^2+|y|^2}`` avoiding overflow and underflow.
# Examples
```jldoctest; filter = r"Stacktrace:(\\n \\[[0-9]+\\].*)*"
Expand All @@ -535,6 +535,9 @@ ERROR: DomainError with -2.914184810805068e18:
sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
Stacktrace:
[...]
julia> hypot(3, 4im)
5.0
```
"""
hypot(x::Number, y::Number) = hypot(promote(x, y)...)
Expand Down Expand Up @@ -566,7 +569,16 @@ end
"""
hypot(x...)
Compute the hypotenuse ``\\sqrt{\\sum x_i^2}`` avoiding overflow and underflow.
Compute the hypotenuse ``\\sqrt{\\sum |x_i|^2}`` avoiding overflow and underflow.
# Examples
```jldoctest
julia> hypot(-5.7)
5.7
julia> hypot(3, 4im, 12.0)
13.0
```
"""
hypot(x::Number...) = sqrt(sum(abs2(y) for y in x))

Expand Down
70 changes: 65 additions & 5 deletions test/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -983,8 +983,68 @@ end

isdefined(Main, :Furlongs) || @eval Main include("testhelpers/Furlongs.jl")
using .Main.Furlongs
@test hypot(Furlong(0), Furlong(0)) == Furlong(0.0)
@test hypot(Furlong(3), Furlong(4)) == Furlong(5.0)
@test hypot(Furlong(NaN), Furlong(Inf)) == Furlong(Inf)
@test hypot(Furlong(Inf), Furlong(NaN)) == Furlong(Inf)
@test hypot(Furlong(Inf), Furlong(Inf)) == Furlong(Inf)
@test (@inferred hypot(Furlong(0), Furlong(0))) == Furlong(0.0)
@test (@inferred hypot(Furlong(3), Furlong(4))) == Furlong(5.0)
@test (@inferred hypot(Furlong(NaN), Furlong(Inf))) == Furlong(Inf)
@test (@inferred hypot(Furlong(Inf), Furlong(NaN))) == Furlong(Inf)
@test (@inferred hypot(Furlong(0), Furlong(0), Furlong(0))) == Furlong(0.0)
@test (@inferred hypot(Furlong(Inf), Furlong(Inf))) == Furlong(Inf)
@test (@inferred hypot(Furlong(1), Furlong(1), Furlong(1))) == Furlong(sqrt(3))
@test_broken (@inferred hypot(Furlong(Inf), Furlong(NaN), Furlong(0))) == Furlong(Inf)
@test (@inferred hypot(Furlong(Inf), Furlong(Inf), Furlong(Inf))) == Furlong(Inf)
@test isnan(hypot(Furlong(NaN), Furlong(0), Furlong(1)))

@testset "hypot" begin
@test_broken (@inferred hypot(floatmax())) == floatmax()
@test (@inferred hypot(floatmax(), floatmax())) == Inf
@test (@inferred hypot(floatmin(), floatmin())) == 2floatmin()
@test_broken (@inferred hypot(floatmin(), floatmin(), floatmin())) == 3floatmin()
@test_broken (@inferred hypot(1e-162)) 1e-162
@test_broken (@inferred hypot(2e-162, 1e-162, 1e-162)) hypot(2,1,1)*1e-162
@test_broken (@inferred hypot(1e162)) 1e162
@test hypot(-2) === 2.0
@test hypot(-2, 0) === 2.0
let i = typemax(Int)
@test (@inferred hypot(i, i)) i * 2
@test_broken (@inferred hypot(i, i, i)) i * 3
@test_broken (@inferred hypot(i, i, i, i)) 2.0i
@test_broken (@inferred hypot(i//1, 1//i, 1//i)) i
end
let i = typemin(Int)
@test_broken (@inferred hypot(i, i)) -√2i
@test_broken (@inferred hypot(i, i, i)) -√3i
@test_broken (@inferred hypot(i, i, i, i)) -2.0i
end
@testset "$T" for T in (Float32, Float64)
@test (@inferred hypot(T(Inf), T(NaN))) == T(Inf) # IEEE754 says so
@test_broken (@inferred hypot(T(Inf), T(3//2), T(NaN))) == T(Inf)
@test (@inferred hypot(T(1e10), T(1e10), T(1e10), T(1e10))) 2e10
@test isnan_type(T, hypot(T(3), T(3//4), T(NaN)))
@test hypot(T(1), T(0)) === T(1)
@test hypot(T(1), T(0), T(0)) === T(1)
@test (@inferred hypot(T(Inf), T(Inf), T(Inf))) == T(Inf)
for s in (zero(T), floatmin(T)*1e3, floatmax(T)*1e-3, T(Inf))
@test hypot(1s, 2s) s * hypot(1,2) rtol=8eps(T)
# @test hypot(1s, 2s, 3s) ≈ s * hypot(1,2,3) rtol=8eps(T)
end
end
@testset "$T" for T in (Float16, Float32, Float64, BigFloat)
let x = 1.1sqrt(floatmin(T))
@test (@inferred hypot(x,x/4)) x * sqrt(17/BigFloat(16))
# @test (@inferred hypot(x,x/4,x/4)) ≈ x * sqrt(9/BigFloat(8))
end
let x = 2sqrt(nextfloat(zero(T)))
@test (@inferred hypot(x,x/4)) x * sqrt(17/BigFloat(16))
@test_broken (@inferred hypot(x,x/4,x/4)) x * sqrt(9/BigFloat(8))
end
let x = sqrt(nextfloat(zero(T))/eps(T))/8, f = sqrt(4eps(T))
@test hypot(x,x*f) x * hypot(one(f),f) rtol=eps(T)
@test_broken hypot(x,x*f,x*f) x * hypot(one(f),f,f) rtol=eps(T)
end
end
@testset "complex arguments issue#31941" begin
@test hypot(im) === 1.0
@test hypot(1, im) sqrt(2)
@test hypot(1, im, -im) sqrt(3)
end
end

0 comments on commit a835c4a

Please sign in to comment.