Skip to content

Commit 0f851df

Browse files
committed
add nextprimes/prevprimes iterators (fix #55)
1 parent 4deaf52 commit 0f851df

File tree

2 files changed

+153
-2
lines changed

2 files changed

+153
-2
lines changed

src/Primes.jl

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ module Primes
44

55
using Base.Iterators: repeated
66

7+
import Base: start, next, done, eltype, iteratorsize, iteratoreltype
78
using Base: BitSigned
89
using Base.Checked: checked_neg
910

1011
export isprime, primes, primesmask, factor, ismersenneprime, isrieselprime,
11-
nextprime, prevprime, prime, prodfactors, radical, totient
12+
nextprime, nextprimes, prevprime, prevprimes, prime, prodfactors, radical, totient
1213

1314
include("factorization.jl")
1415

@@ -528,6 +529,11 @@ function totient(n::Integer)
528529
totient(factor(abs(n)))
529530
end
530531

532+
# add: checked add (when makes sense), result of same type as first argument
533+
534+
add(n::BigInt, x::Int) = n+x
535+
add(n::Integer, x::Int) = Base.checked_add(n, oftype(n, x))
536+
531537
# add_! : "may" mutate the Integer argument (only for BigInt currently)
532538

533539
# modify a BigInt in-place
@@ -541,7 +547,7 @@ function add_!(n::BigInt, x::Int)
541547
end
542548

543549
# checked addition, without mutation
544-
add_!(n::Integer, x::Int) = Base.checked_add(n, oftype(n, x))
550+
add_!(n::Integer, x::Int) = add(n, x)
545551

546552
"""
547553
nextprime(n::Integer, i::Integer=1; interval::Integer=1)
@@ -664,4 +670,114 @@ julia> prime(3)
664670
prime(::Type{T}, i::Integer) where {T<:Integer} = i < 0 ? throw(DomainError(i)) : nextprime(T(2), i)
665671
prime(i::Integer) = prime(Int, i)
666672

673+
674+
struct NextPrimes{T<:Integer}
675+
start::T
676+
end
677+
678+
Base.start(np::NextPrimes) = np.start < 2 ? np.start : add(np.start, -1)
679+
Base.next(np::NextPrimes, state) = (p = nextprime(add(state, 1)); (p, p))
680+
Base.done(np::NextPrimes, state) = false
681+
682+
Base.iteratorsize(::Type{<:NextPrimes}) = Base.IsInfinite()
683+
Base.iteratoreltype(::Type{<:NextPrimes}) = Base.HasEltype() # default
684+
685+
Base.eltype(::Type{NextPrimes{T}}) where {T} = T
686+
687+
"""
688+
nextprimes(start::Integer)
689+
690+
Returns an iterator over all primes greater than or equal to `start`,
691+
in ascending order.
692+
"""
693+
nextprimes(start::Integer) = NextPrimes(start)
694+
695+
"""
696+
nextprimes(T::Type=Int)
697+
698+
Returns an iterator over all primes, with type `T`.
699+
Equivalent to `nextprimes(T(1))`.
700+
"""
701+
nextprimes(::Type{T}) where {T<:Integer} = nextprimes(one(T))
702+
nextprimes() = nextprimes(Int)
703+
704+
"""
705+
nextprimes(start::Integer, n::Integer)
706+
707+
Returns an array of the first `n` primes greater than or equal to `start`.
708+
709+
# Example
710+
711+
```
712+
julia> nextprimes(10, 3)
713+
3-element Array{Int64,1}:
714+
11
715+
13
716+
17
717+
```
718+
"""
719+
nextprimes(start::T, n::Integer) where {T<:Integer} =
720+
iterate(x->nextprime(add(x, 1)), nextprime(start), n)
721+
722+
struct PrevPrimes{T<:Integer}
723+
start::T
724+
end
725+
726+
start(np::PrevPrimes) = np.start+one(np.start) # allow wrap-around
727+
next(np::PrevPrimes, state) = (p = prevprime(state-one(state)); (p, p))
728+
done(np::PrevPrimes, state) = state == 2
729+
730+
iteratorsize(::Type{<:PrevPrimes}) = Base.SizeUnknown()
731+
iteratoreltype(::Type{<:PrevPrimes}) = Base.HasEltype() # default
732+
733+
eltype(::Type{PrevPrimes{T}}) where {T} = T
734+
735+
"""
736+
prevprimes(start::Integer)
737+
738+
Returns an iterator over all primes less than or equal to `start`,
739+
in descending order.
740+
741+
# Example
742+
743+
```
744+
julia> collect(prevprimes(10))
745+
4-element Array{Int64,1}:
746+
7
747+
5
748+
3
749+
2
750+
```
751+
"""
752+
prevprimes(start::Integer) = PrevPrimes(max(one(start), start))
753+
754+
"""
755+
prevprimes(start::Integer, n::Integer)
756+
757+
Returns an array of the first `n` primes less than or equal to `start`,
758+
in descending order.
759+
760+
# Example
761+
762+
```
763+
julia> prevprimes(10, 3)
764+
3-element Array{Int64,1}:
765+
7
766+
5
767+
3
768+
```
769+
"""
770+
prevprimes(start::T, n::Integer) where {T<:Integer} =
771+
iterate(x->prevprime(add(x, -1)), prevprime(start), n)
772+
773+
function iterate(f, x::T, n::Integer) where T
774+
v = Vector{T}(n)
775+
n != 0 && (@inbounds v[1] = x)
776+
@inbounds for i = 2:n
777+
x = f(x)
778+
v[i] = x
779+
end
780+
v
781+
end
782+
667783
end # module

test/runtests.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,38 @@ for T in (Int, UInt, BigInt)
390390
@test prodfactors(factor(Set, T(123456))) == 3858
391391
@test prod(factor(T(123456))) == 123456
392392
end
393+
394+
@testset "nextprimes(::$T)" for T = (Int32, Int64, BigInt)
395+
for (i, p) in enumerate(nextprimes(T))
396+
@test nextprime(0, i) == p
397+
i > 20 && break
398+
end
399+
@test nextprimes() == nextprimes(Int)
400+
for (i, p) in enumerate(nextprimes(T(5)))
401+
@test nextprime(T(5), i) == p
402+
i > 20 && break
403+
end
404+
@test nextprimes(T(5), 10) == [nextprime(T(5), i) for i=1:10]
405+
@test nextprimes(1, 1)[1] == nextprimes(2, 1)[1] == 2
406+
@test nextprimes(3, 1)[1] == 3
407+
@test nextprimes(4, 1)[1] == nextprimes(5, 1)[1] == 5
408+
end
409+
410+
411+
@testset "prevprimes(::$T)" for T = (Int32, Int64, BigInt)
412+
for (i, p) in enumerate(prevprimes(T(500)))
413+
@test prevprime(T(500), i) == p
414+
i > 20 && break
415+
end
416+
@test prevprimes(T(500), 10) == [prevprime(T(500), i) for i=1:10]
417+
@test prevprimes(6, 1)[1] == prevprimes(5, 1)[1] == 5
418+
@test prevprimes(4, 1)[1] == prevprimes(3, 1)[1] == 3
419+
@test prevprimes(2, 1)[1] == 2
420+
@test_throws ArgumentError prevprimes(2, 2)
421+
let p8 = collect(prevprimes(typemax(Int8)))
422+
@test length(p8) == 31
423+
@test p8[end] == 2
424+
@test p8[1] == 127
425+
end
426+
427+
end

0 commit comments

Comments
 (0)