diff --git a/base/math.jl b/base/math.jl index 6ed69188371dd..4626a684d5f0e 100644 --- a/base/math.jl +++ b/base/math.jl @@ -95,11 +95,10 @@ julia> clamp.([11, 8, 5], 10, 6) # an example where lo > hi 10 ``` """ -clamp(x::X, lo::L, hi::H) where {X,L,H} = - ifelse(x > hi, convert(promote_type(X,L,H), hi), - ifelse(x < lo, - convert(promote_type(X,L,H), lo), - convert(promote_type(X,L,H), x))) +function clamp(x::X, lo::L, hi::H) where {X,L,H} + T = promote_type(X, L, H) + return (x > hi) ? convert(T, hi) : (x < lo) ? convert(T, lo) : convert(T, x) +end """ clamp(x, T)::T @@ -120,7 +119,14 @@ julia> trunc(Int, 4pi^2) 39 ``` """ -clamp(x, ::Type{T}) where {T<:Integer} = clamp(x, typemin(T), typemax(T)) % T +function clamp(x, ::Type{T}) where {T<:Integer} + # delegating to clamp(x, typemin(T), typemax(T)) would promote types + # this way, we avoid unnecessary conversions + # think of, e.g., clamp(big(2) ^ 200, Int16) + lo = typemin(T) + hi = typemax(T) + return (x > hi) ? hi : (x < lo) ? lo : convert(T, x) +end """ diff --git a/test/math.jl b/test/math.jl index f3c6dc5bb103f..c88905018fb3a 100644 --- a/test/math.jl +++ b/test/math.jl @@ -47,6 +47,17 @@ has_fma = Dict( clamp!(x, 1, 3) @test x == [1.0, 1.0, 2.0, 3.0, 3.0] end + + @test clamp(typemax(UInt64), Int64) === typemax(Int64) + @test clamp(typemin(Int), UInt64) === typemin(UInt64) + @test clamp(Int16(-1), UInt16) === UInt16(0) + @test clamp(-1, 2, UInt(0)) === UInt(2) + @test clamp(typemax(UInt16), Int16) === Int16(32767) + + # clamp should not allocate a BigInt for typemax(Int16) + x = big(2) ^ 100 + @test (@allocated clamp(x, Int16)) == 0 + end @testset "constants" begin