Skip to content

Commit ef3a171

Browse files
TotalVerbararslan
authored andcommitted
Implement Euler totient function (#43)
1 parent 0a0c49b commit ef3a171

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

src/Primes.jl

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ end
1414
using Base: BitSigned
1515
using Base.Checked.checked_neg
1616

17-
export ismersenneprime, isrieselprime, nextprime, prevprime, prime, prodfactors, radical
17+
export ismersenneprime, isrieselprime, nextprime, prevprime, prime, prodfactors, radical, totient
1818

1919
include("factorization.jl")
2020

@@ -500,6 +500,37 @@ function ll_primecheck(X::Integer, s::Integer = 4)
500500
return S == 0
501501
end
502502

503+
"""
504+
totient(f::Factorization{T}) -> T
505+
506+
Compute the Euler totient function of the number whose prime factorization is
507+
given by `f`. This method may be preferable to [`totient(::Integer)`](@ref)
508+
when the factorization can be reused for other purposes.
509+
"""
510+
function totient{T <: Integer}(f::Factorization{T})
511+
if !isempty(f) && first(first(f)) == 0
512+
throw(ArgumentError("ϕ(0) is not defined"))
513+
end
514+
result = one(T)
515+
for (p, k) in f
516+
result *= p^(k-1) * (p - 1)
517+
end
518+
result
519+
end
520+
521+
"""
522+
totient(n::Integer) -> Integer
523+
524+
Compute the Euler totient function ``ϕ(n)``, which counts the number of
525+
positive integers less than or equal to ``n`` that are relatively prime to
526+
``n`` (that is, the number of positive integers `m ≤ n` with `gcd(m, n) == 1`).
527+
The totient function of `n` when `n` is negative is defined to be
528+
`totient(abs(n))`.
529+
"""
530+
function totient(n::Integer)
531+
totient(factor(abs(n)))
532+
end
533+
503534
# add_! : "may" mutate the Integer argument (only for BigInt currently)
504535

505536
# modify a BigInt in-place

test/runtests.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,37 @@ for T = (Int, UInt, BigInt)
276276
@test issorted(f.pe)
277277
end
278278

279+
# dumb implementation of Euler totient for correctness tests
280+
ϕ(n) = count(m -> gcd(n, m) == 1, 1:n)
281+
282+
@testset "totient(::$T)" for T in [Int16, Int32, Int64, BigInt]
283+
for n in 1:1000
284+
@test ϕ(T(n)) == totient(T(n)) == totient(-T(n))
285+
end
286+
@test_throws ArgumentError @inferred(totient(T(0)))
287+
end
288+
289+
# check some big values
290+
@testset "totient() correctness" begin
291+
@test totient(2^4 * 3^4 * 5^4) == 216000
292+
@test totient(big"2"^1000) == big"2"^999
293+
294+
const some_coprime_numbers = BigInt[
295+
450000000, 1099427429702334733, 200252151854851, 1416976291499, 7504637909,
296+
1368701327204614490999, 662333585807659, 340557446329, 1009091
297+
]
298+
299+
for i in some_coprime_numbers
300+
for j in some_coprime_numbers
301+
if i j
302+
@test totient(i*j) == totient(i) * totient(j)
303+
end
304+
end
305+
# can use directly with Factorization
306+
@test totient(i) == totient(factor(i))
307+
end
308+
end
309+
279310
# check copy property for big primes relied upon in nextprime/prevprime
280311
for n = rand(big(-10):big(10), 10)
281312
@test n+0 !== n

0 commit comments

Comments
 (0)