Skip to content

Commit 2a156f1

Browse files
committed
disallow complex numbers
1 parent dc26b09 commit 2a156f1

File tree

2 files changed

+12
-66
lines changed

2 files changed

+12
-66
lines changed

base/range.jl

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,8 +1536,8 @@ See also [`range`](@ref) for linearly spaced points.
15361536
!!! compat "Julia 1.11"
15371537
This function requires at least Julia 1.11.
15381538
"""
1539-
logrange(start::Number, stop::Number, length::Integer) = LogRange(start, stop, Int(length))
1540-
logrange(start::Number, stop::Number; length::Integer) = LogRange(start, stop, Int(length))
1539+
logrange(start::Real, stop::Real, length::Integer) = LogRange(start, stop, Int(length))
1540+
logrange(start::Real, stop::Real; length::Integer) = logrange(start, stop, length)
15411541

15421542

15431543
"""
@@ -1594,58 +1594,15 @@ julia> 2 .^ (0:3:9) |> println
15941594
[1, 8, 64, 512]
15951595
```
15961596
1597-
For complex `T`, all points lie on the same branch of [`log`](@ref) as is used by `log(start)`
1598-
and `log(stop)`. That is, all branch cuts are on the negative real axis.
1599-
1600-
Other branches can be used by adjusting the arguments. For instance `start * logrange(1, stop/start, length)`
1601-
places the cut where `stop/start` is negative real, i.e. where [`angle`](@ref)`(stop/start) ≈ pi`.
1602-
1603-
```jldoctest
1604-
julia> Base.LogRange{ComplexF32}(1, -1+0im, 5) |> collect
1605-
5-element Vector{ComplexF32}:
1606-
1.0f0 + 0.0f0im
1607-
0.70710677f0 + 0.70710677f0im
1608-
6.123234f-17 + 1.0f0im
1609-
-0.70710677f0 + 0.70710677f0im
1610-
-1.0f0 + 0.0f0im
1611-
1612-
julia> ans ≈ cis.(LinRange{Float32}(0, pi, 5))
1613-
true
1614-
1615-
julia> lo = -1+0.01f0im; hi = -1-0.01f0im;
1616-
1617-
julia> angle(lo), angle(hi) # either side of branch cut
1618-
(3.131593f0, -3.131593f0)
1619-
1620-
julia> logrange(lo, hi, 5) |> collect # goes near to +1
1621-
5-element Vector{ComplexF32}:
1622-
-1.0f0 + 0.01f0im
1623-
0.0050000623f0 + 1.0000376f0im
1624-
1.00005f0 + 0.0f0im
1625-
0.0050000623f0 - 1.0000376f0im
1626-
-1.0f0 - 0.01f0im
1627-
1628-
julia> lo .* logrange(1, hi/lo, 5) # stays near -1
1629-
5-element Vector{ComplexF32}:
1630-
-1.0f0 + 0.01f0im
1631-
-1.0000374f0 + 0.0050000628f0im
1632-
-1.00005f0 + 0.0f0im
1633-
-1.0000376f0 - 0.0050000623f0im
1634-
-1.0f0 - 0.009999999f0im
1635-
1636-
julia> angle(hi/lo) # far from branch cut
1637-
0.01999933f0
1638-
```
1639-
16401597
!!! compat "Julia 1.11"
16411598
This type requires at least Julia 1.11.
16421599
"""
1643-
struct LogRange{T<:Number,X} <: AbstractArray{T,1}
1600+
struct LogRange{T<:Real,X} <: AbstractArray{T,1}
16441601
start::T
16451602
stop::T
16461603
len::Int
16471604
extra::Tuple{X,X}
1648-
function LogRange{T}(start::T, stop::T, length::Int) where {T<:Number}
1605+
function LogRange{T}(start::T, stop::T, length::Int) where {T<:Real}
16491606
# LogRange(0, 1, 100) could be == [0,0,0,0,...,1], that's the limit start -> 0,
16501607
# but seems more likely to give silent surprises than returning NaN.
16511608
a = iszero(start) ? T(NaN) : T(start)
@@ -1657,11 +1614,11 @@ struct LogRange{T<:Number,X} <: AbstractArray{T,1}
16571614
elseif len == 1 && start != stop
16581615
throw(ArgumentError(LazyString(
16591616
"LogRange(", start, ", ", stop, ", ", len, "): endpoints differ, while length is 1")))
1660-
elseif T <: Real && ((start<0) || (stop<0))
1617+
elseif start < 0 || stop < 0
16611618
throw(DomainError((start, stop),
1662-
"LogRange will only return complex results if called with a complex argument"))
1619+
"LogRange(start, stop, length) does not accept negative numbers"))
16631620
end
1664-
if T <: Integer || T <: Complex{<:Integer}
1621+
if T <: Integer
16651622
# LogRange{Int}(1, 512, 4) produces InexactError: Int64(7.999999999999998)
16661623
throw(ArgumentError("LogRange{T} does not support integer types"))
16671624
end
@@ -1670,10 +1627,10 @@ struct LogRange{T<:Number,X} <: AbstractArray{T,1}
16701627
end
16711628
end
16721629

1673-
function LogRange{T}(start::Number, stop::Number, len::Integer) where {T}
1630+
function LogRange{T}(start::Real, stop::Real, len::Integer) where {T}
16741631
LogRange{T}(convert(T, start), convert(T, stop), convert(Int, len))
16751632
end
1676-
function LogRange(start::Number, stop::Number, len::Integer)
1633+
function LogRange(start::Real, stop::Real, len::Integer)
16771634
T = float(promote_type(typeof(start), typeof(stop)))
16781635
LogRange{T}(convert(T, start), convert(T, stop), convert(Int, len))
16791636
end
@@ -1684,7 +1641,7 @@ length(r::LogRange) = r.len
16841641
first(r::LogRange) = r.start
16851642
last(r::LogRange) = r.stop
16861643

1687-
function _logrange_extra(a::Number, b::Number, len::Int)
1644+
function _logrange_extra(a::Real, b::Real, len::Int)
16881645
loga = log(1.0 * a) # widen to at least Float64
16891646
logb = log(1.0 * b)
16901647
(loga/(len-1), logb/(len-1))
@@ -1708,7 +1665,7 @@ function getindex(r::LogRange{T}, i::Int) where {T}
17081665
# accurate, nor does it handle NaN/Inf as desired, hence the cases above.
17091666
logx = (r.len-i) * r.extra[1] + (i-1) * r.extra[2]
17101667
x = _exp_allowing_twice64(logx)
1711-
return T <: Real ? copysign(T(x), r.start) : T(x)
1668+
return T(x)
17121669
end
17131670

17141671
function show(io::IO, r::LogRange{T}) where {T}

test/ranges.jl

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2611,16 +2611,6 @@ end
26112611
@test logrange(1000, 1, 4) [1000, 100, 10, 1]
26122612
@test logrange(1, 10^9, 19)[1:2:end] 10 .^ (0:9)
26132613

2614-
# negative & complex
2615-
@test logrange(1, -1+0.0im, 3) [1, im, -1] # branch cut first arg
2616-
@test logrange(1, -1-0.0im, 3) [1, -im, -1]
2617-
@test logrange(-1+1e-10im, 1, 3) [-1, im, 1] # branch cut second arg
2618-
@test logrange(-1-1e-10im, 1, 3) [-1, -im, 1]
2619-
@test logrange(im + 1e-10, -im + 1e-10, 3) [im, 1, -im] # no branch cut here
2620-
@test logrange(im - 1e-10, -im - 1e-10, 3) [im, 1, -im]
2621-
@test logrange(1+im, -1-im, 5) [1+im, sqrt(2), 1-im, -sqrt(2)*im, -1-im]
2622-
@test logrange(-1+im, -1-im, 3) [-1+im, sqrt(2), -1-im]
2623-
26242614
# endpoints
26252615
@test logrange(0.1f0, 100, 33)[1] === 0.1f0
26262616
@test logrange(0.789, 123_456, 135_790)[[begin, end]] == [0.789, 123_456]
@@ -2660,8 +2650,6 @@ end
26602650
@test eltype(logrange(1, 10, Int32(3))) == Float64
26612651
@test eltype(logrange(1, 10f0, 3)) == Float32
26622652
@test eltype(logrange(1f0, 10, 3)) == Float32
2663-
@test eltype(logrange(1f0, 10+im, 3)) == ComplexF32
2664-
@test eltype(logrange(1f0, 10.0+im, 3)) == ComplexF64
26652653
@test eltype(logrange(1, big(10), 3)) == BigFloat
26662654
@test logrange(big"0.3", big(pi), 50)[1] == big"0.3"
26672655
@test logrange(big"0.3", big(pi), 50)[end] == big(pi)
@@ -2676,6 +2664,7 @@ end
26762664
@test_throws ArgumentError logrange(1, 10, 1) # endpoints must not differ
26772665
@test_throws DomainError logrange(1, -1, 3) # needs complex numbers
26782666
@test_throws DomainError logrange(-1, -2, 3) # not supported, for now
2667+
@test_throws MethodError logrange(1, 2+3im, length=4) # not supported, for now
26792668
@test_throws ArgumentError logrange(1, 10, 2)[true] # bad index
26802669
@test_throws BoundsError logrange(1, 10, 2)[3]
26812670
@test_throws ArgumentError Base.LogRange{Int}(1,4,5) # no integer ranges

0 commit comments

Comments
 (0)