diff --git a/base/range.jl b/base/range.jl index 7eea62a43d377..bfd07de07cd99 100644 --- a/base/range.jl +++ b/base/range.jl @@ -1558,11 +1558,11 @@ same sign. All values are then negative. # Examples ```jldoctest julia> logrange(1, 4, length=5) -5-element LogRange{Float64, Base.TwicePrecision{Float64}}: +5-element Base.LogRange{Float64, Base.TwicePrecision{Float64}}: 1.0, 1.41421, 2.0, 2.82843, 4.0 julia> Base.LogRange{Float16}(-1, -4, 5) -5-element LogRange{Float16, Float64}: +5-element Base.LogRange{Float16, Float64}: -1.0, -1.414, -2.0, -2.828, -4.0 julia> logrange(1e-310, 1e-300, 11)[1:2:end] @@ -1578,11 +1578,11 @@ julia> prevfloat(1e-308, 5) == ans[2] true julia> logrange(2, Inf, 5) -5-element LogRange{Float64, Base.TwicePrecision{Float64}}: +5-element Base.LogRange{Float64, Base.TwicePrecision{Float64}}: 2.0, Inf, Inf, Inf, Inf julia> logrange(0, 4, 5) -5-element LogRange{Float64, Base.TwicePrecision{Float64}}: +5-element Base.LogRange{Float64, Base.TwicePrecision{Float64}}: NaN, NaN, NaN, NaN, 4.0 ``` @@ -1621,9 +1621,13 @@ julia> lo = -1+0.01f0im; hi = -1-0.01f0im; julia> angle(lo), angle(hi) # either side of branch cut (3.131593f0, -3.131593f0) -julia> logrange(lo, hi, 5) # goes near to +1 -5-element Base.LogRange{ComplexF32, ComplexF64}: - -1.0+0.01im, 0.00500006+1.00004im, 1.00005+0.0im, 0.00500006-1.00004im, -1.0-0.01im +julia> logrange(lo, hi, 5) |> collect # goes near to +1 +5-element Vector{ComplexF32}: + -1.0f0 + 0.01f0im + 0.0050000623f0 + 1.0000376f0im + 1.00005f0 + 0.0f0im + 0.0050000623f0 - 1.0000376f0im + -1.0f0 - 0.01f0im julia> lo .* logrange(1, hi/lo, 5) # stays near -1 5-element Vector{ComplexF32}: diff --git a/test/ranges.jl b/test/ranges.jl index 85b52fefcd52a..afeab57bcecde 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -2580,86 +2580,94 @@ end @test_throws errmsg range(CartesianIndex(1), step=CartesianIndex(1), length=3) end -@testset "LogRange" begin +@testset "logrange" begin # basic idea @test logrange(2, 16, 4) ≈ [2, 4, 8, 16] - @test LogRange(1/8, 8.0, 7) ≈ [0.125, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0] + @test logrange(1/8, 8.0, 7) ≈ [0.125, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0] @test logrange(1000, 1, 4) ≈ [1000, 100, 10, 1] - @test LogRange(1, 10^9, 19)[1:2:end] ≈ 10 .^ (0:9) + @test logrange(1, 10^9, 19)[1:2:end] ≈ 10 .^ (0:9) # negative & complex - @test LogRange(-1, -4, 3) == [-1, -2, -4] - @test LogRange(1, -1+0.0im, 3) ≈ [1, im, -1] - @test LogRange(1, -1-0.0im, 3) ≈ [1, -im, -1] + @test logrange(-1, -4, 3) == [-1, -2, -4] + @test logrange(1, -1+0.0im, 3) ≈ [1, im, -1] # branch cut first arg + @test logrange(1, -1-0.0im, 3) ≈ [1, -im, -1] + @test logrange(-1+1e-10im, 1, 3) ≈ [-1, im, 1] # branch cut second arg + @test logrange(-1-1e-10im, 1, 3) ≈ [-1, -im, 1] + @test logrange(im + 1e-10, -im + 1e-10, 3) ≈ [im, 1, -im] # no branch cut here + @test logrange(im - 1e-10, -im - 1e-10, 3) ≈ [im, 1, -im] + @test logrange(1+im, -1-im, 5) ≈ [1+im, sqrt(2), 1-im, -sqrt(2)*im, -1-im] + @test logrange(-1+im, -1-im, 3) ≈ [-1+im, sqrt(2), -1-im] # endpoints - @test LogRange(0.1f0, 100, 33)[1] === 0.1f0 - @test LogRange(0.789, 123_456, 135_790)[[begin, end]] == [0.789, 123_456] - @test LogRange(nextfloat(0f0), floatmax(Float32), typemax(Int))[end] === floatmax(Float32) - @test LogRange(nextfloat(Float16(0)), floatmax(Float16), 66_000)[end] === floatmax(Float16) - @test first(LogRange(pi, 2pi, 3000)) === LogRange(pi, 2pi, 3000)[1] === Float64(pi) - @test last(LogRange(-0.01, -0.1, 3000)) === last(LogRange(-0.01, -0.1, 3000))[end] === -0.1 + @test logrange(0.1f0, 100, 33)[1] === 0.1f0 + @test logrange(0.789, 123_456, 135_790)[[begin, end]] == [0.789, 123_456] + @test logrange(nextfloat(0f0), floatmax(Float32), typemax(Int))[end] === floatmax(Float32) + @test logrange(nextfloat(Float16(0)), floatmax(Float16), 66_000)[end] === floatmax(Float16) + @test first(logrange(pi, 2pi, 3000)) === logrange(pi, 2pi, 3000)[1] === Float64(pi) + @test last(logrange(-0.01, -0.1, 3000)) === last(logrange(-0.01, -0.1, 3000))[end] === -0.1 if Int == Int64 - @test LogRange(0.1, 1000, 2^54)[end] === 1000.0 - @test LogRange(-0.1, -1000, 2^55)[end] === -1000.0 + @test logrange(0.1, 1000, 2^54)[end] === 1000.0 + @test logrange(-0.1, -1000, 2^55)[end] === -1000.0 end # empty, only, NaN, Inf - @test first(LogRange(1, 2, 0)) === 1.0 - @test last(LogRange(1, 2, 0)) === 2.0 - @test collect(LogRange(1, 2, 0)) == Float64[] - @test isnan(first(LogRange(0, 2, 0))) - @test only(LogRange(2pi, 2pi, 1)) === LogRange(2pi, 2pi, 1)[1] === 2pi - @test isnan(LogRange(1, NaN, 3)[2]) - @test isnan(LogRange(NaN, 2, 3)[2]) - @test isnan(LogRange(1f0, NaN32, 3)[2]) - @test isnan(LogRange(NaN32, 2f0, 3)[2]) - @test isnan(LogRange(0, 2, 3)[1]) - @test isnan(LogRange(0, -2, 3)[1]) - @test isnan(LogRange(-0.0, +2.0, 3)[1]) - @test isnan(LogRange(0f0, 2f0, 3)[1]) - @test isnan(LogRange(0f0, -2f0, 3)[1]) - @test isnan(LogRange(-0f0, 2f0, 3)[1]) - @test isinf(LogRange(1, Inf, 3)[2]) - @test -Inf === LogRange(-1, -Inf, 3)[2] - @test isinf(LogRange(1f0, Inf32, 3)[2]) - @test -Inf32 === LogRange(-1f0, -Inf32, 3)[2] + @test first(logrange(1, 2, 0)) === 1.0 + @test last(logrange(1, 2, 0)) === 2.0 + @test collect(logrange(1, 2, 0)) == Float64[] + @test isnan(first(logrange(0, 2, 0))) + @test only(logrange(2pi, 2pi, 1)) === logrange(2pi, 2pi, 1)[1] === 2pi + @test isnan(logrange(1, NaN, 3)[2]) + @test isnan(logrange(NaN, 2, 3)[2]) + @test isnan(logrange(1f0, NaN32, 3)[2]) + @test isnan(logrange(NaN32, 2f0, 3)[2]) + @test isnan(logrange(0, 2, 3)[1]) + @test isnan(logrange(0, -2, 3)[1]) + @test isnan(logrange(-0.0, +2.0, 3)[1]) + @test isnan(logrange(0f0, 2f0, 3)[1]) + @test isnan(logrange(0f0, -2f0, 3)[1]) + @test isnan(logrange(-0f0, 2f0, 3)[1]) + @test isinf(logrange(1, Inf, 3)[2]) + @test -Inf === logrange(-1, -Inf, 3)[2] + @test isinf(logrange(1f0, Inf32, 3)[2]) + @test -Inf32 === logrange(-1f0, -Inf32, 3)[2] # constant - @test LogRange(1, 1, 3) == fill(1.0, 3) - @test LogRange(-1f0, -1f0, 3) == fill(-1f0, 3) - @test all(isnan, LogRange(0.0, -0.0, 3)) - @test all(isnan, LogRange(-0f0, 0f0, 3)) + @test logrange(1, 1, 3) == fill(1.0, 3) + @test logrange(-1f0, -1f0, 3) == fill(-1f0, 3) + @test all(isnan, logrange(0.0, -0.0, 3)) + @test all(isnan, logrange(-0f0, 0f0, 3)) # subnormal Float64 - x = LogRange(1e-320, 1e-300, 21) .* 1e300 - @test x ≈ LogRange(1e-20, 1, 21) rtol=1e-6 + x = logrange(1e-320, 1e-300, 21) .* 1e300 + @test x ≈ logrange(1e-20, 1, 21) rtol=1e-6 # types - @test eltype(LogRange(1, 10, 3)) == Float64 - @test eltype(LogRange(1, 10, Int32(3))) == Float64 - @test eltype(LogRange(1, 10f0, 3)) == Float32 - @test eltype(LogRange(1f0, 10, 3)) == Float32 - @test eltype(LogRange(1f0, 10+im, 3)) == ComplexF32 - @test eltype(LogRange(1f0, 10.0+im, 3)) == ComplexF64 - @test eltype(LogRange(1, big(10), 3)) == BigFloat - @test LogRange(big"0.3", big(pi), 50)[1] == big"0.3" - @test LogRange(big"0.3", big(pi), 50)[end] == big(pi) + @test eltype(logrange(1, 10, 3)) == Float64 + @test eltype(logrange(1, 10, Int32(3))) == Float64 + @test eltype(logrange(1, 10f0, 3)) == Float32 + @test eltype(logrange(1f0, 10, 3)) == Float32 + @test eltype(logrange(1f0, 10+im, 3)) == ComplexF32 + @test eltype(logrange(1f0, 10.0+im, 3)) == ComplexF64 + @test eltype(logrange(1, big(10), 3)) == BigFloat + @test logrange(big"0.3", big(pi), 50)[1] == big"0.3" + @test logrange(big"0.3", big(pi), 50)[end] == big(pi) # more constructors - @test logrange(1,2,3) === LogRange(1,2,3) == LogRange{Float64}(1,2,3) - @test logrange(1f0, 2f0, length=3) == LogRange{Float32}(1,2,3) + @test logrange(1,2,length=3) === Base.LogRange(1,2,3) == Base.LogRange{Float64}(1,2,3) + @test logrange(1f0, 2f0, length=3) == Base.LogRange{Float32}(1,2,3) # errors - @test_throws ArgumentError LogRange(1, 10, -1) - @test_throws ArgumentError LogRange(1, 10, 1) # endpoints must not differ - @test_throws DomainError LogRange(1, -1, 3) # needs complex numbers - @test_throws ArgumentError LogRange(1, 10, 2)[true] - @test_throws BoundsError LogRange(1, 10, 2)[3] - @test_throws ArgumentError LogRange{Int}(1,4,5) # no integer ranges + @test_throws UndefKeywordError logrange(1, 10) # no default length + @test_throws ArgumentError logrange(1, 10, -1) # negative length + @test_throws ArgumentError logrange(1, 10, 1) # endpoints must not differ + @test_throws DomainError logrange(1, -1, 3) # needs complex numbers + @test_throws ArgumentError logrange(1, 10, 2)[true] # bad index + @test_throws BoundsError logrange(1, 10, 2)[3] + @test_throws ArgumentError Base.LogRange{Int}(1,4,5) # no integer ranges + @test_throws MethodError Base.LogRange(1,4, length=5) # type does not take keyword # printing - @test repr(LogRange(1,2,3)) == "LogRange{Float64}(1.0, 2.0, 3)" - @test repr("text/plain", LogRange(1,2,3)) == "3-element LogRange{Float64, Base.TwicePrecision{Float64}}:\n 1.0, 1.41421, 2.0" + @test repr(Base.LogRange(1,2,3)) == "LogRange{Float64}(1.0, 2.0, 3)" + @test repr("text/plain", Base.LogRange(1,2,3)) == "3-element Base.LogRange{Float64, Base.TwicePrecision{Float64}}:\n 1.0, 1.41421, 2.0" end @testset "_log_twice64_unchecked" begin