|
1 | 1 | # This file includes code that was formerly a part of Julia. License is MIT: http://julialang.org/license |
2 | | - |
3 | 2 | module Primes |
4 | 3 |
|
5 | | -using Base.Iterators: repeated |
| 4 | +using Base.Iterators: repeated, rest |
6 | 5 |
|
7 | 6 | import Base: iterate, eltype, IteratorSize, IteratorEltype |
8 | 7 | using Base: BitSigned |
9 | 8 | using Base.Checked: checked_neg |
10 | 9 | using IntegerMathUtils |
11 | 10 |
|
12 | | -export isprime, primes, primesmask, factor, eachfactor, ismersenneprime, isrieselprime, |
| 11 | +export isprime, primes, primesmask, factor, eachfactor, divisors, ismersenneprime, isrieselprime, |
13 | 12 | nextprime, nextprimes, prevprime, prevprimes, prime, prodfactors, radical, totient |
14 | 13 |
|
15 | 14 | include("factorization.jl") |
@@ -592,7 +591,7 @@ given by `f`. This method may be preferable to [`totient(::Integer)`](@ref) |
592 | 591 | when the factorization can be reused for other purposes. |
593 | 592 | """ |
594 | 593 | function totient(f::Factorization{T}) where T <: Integer |
595 | | - if !isempty(f) && first(first(f)) == 0 |
| 594 | + if iszero(sign(f)) |
596 | 595 | throw(ArgumentError("ϕ(0) is not defined")) |
597 | 596 | end |
598 | 597 | result = one(T) |
@@ -908,4 +907,90 @@ julia> prevprimes(10, 10) |
908 | 907 | prevprimes(start::T, n::Integer) where {T<:Integer} = |
909 | 908 | collect(T, Iterators.take(prevprimes(start), n)) |
910 | 909 |
|
| 910 | +""" |
| 911 | + divisors(n::Integer) -> Vector |
| 912 | +
|
| 913 | +Return a vector with the positive divisors of `n`. |
| 914 | +
|
| 915 | +For a nonzero integer `n` with prime factorization `n = p₁^k₁ ⋯ pₘ^kₘ`, `divisors(n)` |
| 916 | +returns a vector of length (k₁ + 1)⋯(kₘ + 1) containing the divisors of `n` in |
| 917 | +lexicographic (rather than numerical) order. |
| 918 | +
|
| 919 | +`divisors(-n)` is equivalent to `divisors(n)`. |
| 920 | +
|
| 921 | +For convenience, `divisors(0)` returns `[]`. |
| 922 | +
|
| 923 | +# Example |
| 924 | +
|
| 925 | +```jldoctest |
| 926 | +julia> divisors(60) |
| 927 | +12-element Vector{Int64}: |
| 928 | + 1 # 1 |
| 929 | + 2 # 2 |
| 930 | + 4 # 2 * 2 |
| 931 | + 3 # 3 |
| 932 | + 6 # 3 * 2 |
| 933 | + 12 # 3 * 2 * 2 |
| 934 | + 5 # 5 |
| 935 | + 10 # 5 * 2 |
| 936 | + 20 # 5 * 2 * 2 |
| 937 | + 15 # 5 * 3 |
| 938 | + 30 # 5 * 3 * 2 |
| 939 | + 60 # 5 * 3 * 2 * 2 |
| 940 | +
|
| 941 | +julia> divisors(-10) |
| 942 | +4-element Vector{Int64}: |
| 943 | + 1 |
| 944 | + 2 |
| 945 | + 5 |
| 946 | + 10 |
| 947 | +
|
| 948 | +julia> divisors(0) |
| 949 | +Int64[] |
| 950 | +``` |
| 951 | +""" |
| 952 | +function divisors(n::T) where {T<:Integer} |
| 953 | + n = abs(n) |
| 954 | + if iszero(n) |
| 955 | + return T[] |
| 956 | + elseif isone(n) |
| 957 | + return [n] |
| 958 | + else |
| 959 | + return divisors(factor(n)) |
| 960 | + end |
| 961 | +end |
| 962 | + |
| 963 | +""" |
| 964 | + divisors(f::Factorization) -> Vector |
| 965 | +
|
| 966 | +Return a vector with the positive divisors of the number whose factorization is `f`. |
| 967 | +Divisors are sorted lexicographically, rather than numerically. |
| 968 | +""" |
| 969 | +function divisors(f::Factorization{T}) where {T<:Integer} |
| 970 | + sgn = sign(f) |
| 971 | + if iszero(sgn) # n == 0 |
| 972 | + return T[] |
| 973 | + elseif isempty(f) || length(f) == 1 && sgn < 0 # n == 1 or n == -1 |
| 974 | + return [one(T)] |
| 975 | + end |
| 976 | + |
| 977 | + i = m = 1 |
| 978 | + fs = rest(f, 1 + (sgn < 0)) |
| 979 | + divs = Vector{T}(undef, prod(x -> x.second + 1, fs)) |
| 980 | + divs[i] = one(T) |
| 981 | + |
| 982 | + for (p, k) in fs |
| 983 | + i = 1 |
| 984 | + for _ in 1:k |
| 985 | + for j in i:(i+m-1) |
| 986 | + divs[j+m] = divs[j] * p |
| 987 | + end |
| 988 | + i += m |
| 989 | + end |
| 990 | + m += i - 1 |
| 991 | + end |
| 992 | + |
| 993 | + return divs |
| 994 | +end |
| 995 | + |
911 | 996 | end # module |
0 commit comments