Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a lazy logrange function and LogRange type #39071

Merged
merged 25 commits into from
Feb 16, 2024
Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7056ae2
add logrange
Jan 2, 2021
bb5446a
second implementation, now squashed:
Jan 3, 2021
657c378
change to AbstractVector implementation, squashed:
mcabbott Oct 21, 2021
b04c452
example chosen to show tiny errors does not, anymore
mcabbott May 31, 2022
220e438
Apply 3 suggestions
mcabbott Nov 8, 2022
ca9aec7
rm unsafe_getindex, use LazyString
mcabbott Nov 8, 2022
b0091cd
allow super-Float64 precision in powers
mcabbott Nov 8, 2022
3d75211
new implementation, using Math.exp_impl etc
mcabbott Nov 9, 2022
d96bffc
use _log_twice64_unchecked to handle subnormals
mcabbott Nov 12, 2022
29c2050
make LogRange{T} constructor work, like LinRange{T}
mcabbott Nov 13, 2022
c4edccd
lower-case logrange, as a friendlier interface?
mcabbott Nov 13, 2022
4a735e1
tidy up, rm unsafe_getindex, add _exp_allowing_twice64
mcabbott Nov 18, 2022
530a5c6
rm some doc lines
mcabbott Nov 18, 2022
bb23185
fix doc/repr tests
mcabbott Nov 18, 2022
07ae304
don't export LogRange type
mcabbott Jan 18, 2024
d5f71e9
documentation, esp complex
mcabbott Jan 18, 2024
54b3a8f
more doc tweaks
mcabbott Jan 20, 2024
57fd52a
fix tests
mcabbott Jan 21, 2024
2f7f0e9
add a note to AbstractRange requiring step
mcabbott Feb 7, 2024
dc26b09
disallow negative numbers
mcabbott Feb 9, 2024
2a156f1
disallow complex numbers
mcabbott Feb 12, 2024
ea12bdc
tidy error handling
mcabbott Feb 12, 2024
9abaf5a
add to NEWS.md
mcabbott Feb 12, 2024
4540270
throw errors for 0, Inf, NaN
mcabbott Feb 15, 2024
324553d
Merge branch 'master' into logrange
mcabbott Feb 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
make LogRange{T} constructor work, like LinRange{T}
  • Loading branch information
mcabbott committed Feb 12, 2024
commit 29c2050f5b144377a15ac6135369351d6b303e43
30 changes: 21 additions & 9 deletions base/range.jl
Original file line number Diff line number Diff line change
@@ -1533,13 +1533,12 @@ julia> LogRange(1, -1+0im, 5) ≈ cis.(LinRange(0, pi, 5)) # complex numbers
true
```
"""
struct LogRange{T,X} <: AbstractArray{T,1}
struct LogRange{T<:Number,X} <: AbstractArray{T,1}
start::T
stop::T
len::Int
mcabbott marked this conversation as resolved.
Show resolved Hide resolved
extra::Tuple{X,X}
function LogRange(start::Number, stop::Number, length::Integer)
T = float(promote_type(typeof(start), typeof(stop)))
function LogRange{T}(start::T, stop::T, length::Int) where {T<:Number}
a = iszero(start) ? T(NaN) : T(start)
b = iszero(stop) ? T(NaN) : T(stop)
len = Int(length)
@@ -1554,6 +1553,10 @@ struct LogRange{T,X} <: AbstractArray{T,1}
throw(DomainError((start, stop),
"LogRange will only return complex results if called with a complex argument"))
end
if T <: Integer || T <: Complex{<:Integer}
# LogRange{Int}(1, 512, 4) produces InexactError: Int64(7.999999999999998)
throw(ArgumentError("LogRange{T} does not support integer types"))
end
ex = if T <: Real && start + stop < 0 # start+stop allows for LogRange(-0.0, -2, 3)
_logrange_extra(-a, -b, len)
else
@@ -1563,6 +1566,14 @@ struct LogRange{T,X} <: AbstractArray{T,1}
end
end

function LogRange{T}(start::Number, stop::Number, len::Integer) where {T}
LogRange{T}(convert(T, start), convert(T, stop), convert(Int, len))
end
function LogRange(start::Number, stop::Number, len::Integer)
T = float(promote_type(typeof(start), typeof(stop)))
LogRange{T}(convert(T, start), convert(T, stop), convert(Int, len))
end

size(r::LogRange) = (r.len,)
length(r::LogRange) = r.len
mcabbott marked this conversation as resolved.
Show resolved Hide resolved

@@ -1595,8 +1606,8 @@ end
function unsafe_getindex(r::LogRange{T}, i::Int) where {T}
@inline
logx = (r.len-i) * r.extra[1] + (i-1) * r.extra[2]
x = T(exp(logx))
T <: Real ? copysign(x, r.start) : x
x = exp(logx)
T <: Real ? copysign(T(x), r.start) : T(x)
end
function unsafe_getindex(r::LogRange{T, TwicePrecision{Float64}}, i::Int) where T
@inline
@@ -1607,11 +1618,12 @@ function unsafe_getindex(r::LogRange{T, TwicePrecision{Float64}}, i::Int) where
return copysign(T(x), r.start)
end

function show(io::IO, r::LogRange) # compact
print(io, "LogRange(") # type parameters are implied by knowing r.start
show(io, first(r))
function show(io::IO, r::LogRange{T}) where {T}
print(io, "LogRange{", T, "}(")
ioc = IOContext(io, :typeinfo => T)
show(ioc, first(r))
print(io, ", ")
show(io, last(r))
show(ioc, last(r))
print(io, ", ")
show(io, length(r))
print(io, ')')
1 change: 1 addition & 0 deletions test/ranges.jl
Original file line number Diff line number Diff line change
@@ -2677,6 +2677,7 @@ end
@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

# printing
@test repr(LogRange(1,2,3)) == "LogRange(1.0, 2.0, 3)"