Skip to content

Commit

Permalink
allow factoring non-positive numbers (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
rfourquet authored and ararslan committed Jun 29, 2016
1 parent 62545e7 commit c1e6328
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 6 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ Dict{Int64,Int64} with 2 entries:
5 => 2
> ```
> For convenience, a negative number `n` is factored as `-1*(-n)` (i.e. `-1` is considered
to be a factor), and `0` is factored as `0^1`:
> ```julia
julia> factor(-9) # == -1*3^2
Dict{Int64,Int64} with 2 entries:
-1 => 1
3 => 2
> ```
> ```julia
julia> factor(0)
Dict{Int64,Int64} with 1 entries:
0 => 1
> ```
> ```
factor(ContainerType, n) -> ContainerType
> Return the factorization of `n` stored in a `ContainerType`, which must be a
Expand Down
51 changes: 46 additions & 5 deletions src/Primes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,19 @@ if VERSION >= v"0.5.0-dev+4340"
else
export isprime, primes, primesmask, factor
end
using Base: BitSigned
using Base.Checked.checked_neg
else
typealias BitSigned Union{Int128,Int16,Int32,Int64,Int8}
function checked_neg(x::Integer)
y = -x
(y<0) == (x<0) && throw(OverflowError())
y
end
end



# Primes generating functions
# https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
# https://en.wikipedia.org/wiki/Wheel_factorization
Expand Down Expand Up @@ -219,7 +230,7 @@ isprime(n::Int128) = n < 2 ? false :
# http://maths-people.anu.edu.au/~brent/pub/pub051.html
#
"""
factor(n) -> Dict
factor(n::Integer) -> Dict
Compute the prime factorization of an integer `n`. Returns a dictionary. The
keys of the dictionary correspond to the factors, and hence are of the same type as `n`.
Expand All @@ -232,11 +243,41 @@ Dict{Int64,Int64} with 2 entries:
2 => 2
5 => 2
```
For convenience, a negative number `n` is factored as `-1*(-n)` (i.e. `-1` is considered
to be a factor), and `0` is factored as `0^1`:
```jldoctest
julia> factor(-9) # == -1*3^2
Dict{Int64,Int64} with 2 entries:
-1 => 1
3 => 2
julia> factor(0)
Dict{Int64,Int64} with 1 entries:
0 => 1
```
"""
function factor{T<:Integer,K<:Integer}(n::T, h::Associative{K,Int}=Dict{T,Int}())
0 < n || throw(ArgumentError("number to be factored must be > 0, got $n"))
n == 1 && return h
isprime(n) && (h[n] = 1; return h)
# check for special cases
if n < 0
h[-1] = 1
if isa(n, BitSigned) && n == typemin(T)
h[2] = 8*sizeof(T)-1
return h
else
return factor(checked_neg(n), h)
end
elseif n == 0
h[0] = 1
return h
elseif n == 1
return h
elseif isprime(n)
h[n] = 1
return h
end

local p::T
for p in PRIMES
if n % p == 0
Expand All @@ -254,7 +295,7 @@ function factor{T<:Integer,K<:Integer}(n::T, h::Associative{K,Int}=Dict{T,Int}()
end

"""
factor(ContainerType, n) -> ContainerType
factor(ContainerType, n::Integer) -> ContainerType
Return the factorization of `n` stored in a `ContainerType`, which must be a
subtype of `Associative` or `AbstractArray`, a `Set`, or an `IntSet`.
Expand Down
12 changes: 11 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ euler7(n) = primes(floor(Int,n*log(n*log(n))))[n]

# factor(Vector, n)
for V in (Vector, Vector{Int}, Vector{Int128})
@test_throws ArgumentError factor(V, 0)
@test factor(V, 1) == Int[]
@test factor(V, 3) == [3]
@test factor(V, 4) == [2,2]
Expand All @@ -224,3 +223,14 @@ end
@test_throws MethodError factor(Int, 10)
@test_throws MethodError factor(Any, 10)
@test_throws MethodError factor(Tuple, 10)

# factor non-positive numbers:
@test factor(0) == Dict(0=>1)
@test factor(-1) == Dict(-1=>1)
@test factor(-9) == Dict(-1=>1, 3=>2)

@test factor(typemin(Int32)) == Dict(-1=>1, 2=>31)
@test factor(typemin(Int64)) == Dict(-1=>1, 2=>63)
@test factor(typemin(Int128)) == Dict(-1=>1, 2=>127)

@test factor(1) == Dict{Int,Int}()

0 comments on commit c1e6328

Please sign in to comment.