@@ -1128,6 +1128,14 @@ The following recipes have a more mathematical flavor:
11281128 if n > 1:
11291129 yield n
11301130
1131+ def totient(n):
1132+ "Count of natural numbers up to n that are coprime to n."
1133+ # https://mathworld.wolfram.com/TotientFunction.html
1134+ # totient(12) --> 4 because len([1, 5, 7, 11]) == 4
1135+ for p in unique_justseen(factor(n)):
1136+ n = n // p * (p - 1)
1137+ return n
1138+
11311139 def nth_combination(iterable, r, index):
11321140 "Equivalent to list(combinations(iterable, r))[index]"
11331141 pool = tuple(iterable)
@@ -1429,6 +1437,25 @@ The following recipes have a more mathematical flavor:
14291437 >>> all (list (factor(n)) == sorted (factor(n)) for n in range (2_000 ))
14301438 True
14311439
1440+ >>> totient(0 ) # https://www.wolframalpha.com/input?i=totient+0
1441+ 0
1442+ >>> first_totients = [1 , 1 , 2 , 2 , 4 , 2 , 6 , 4 , 6 , 4 , 10 , 4 , 12 , 6 , 8 , 8 , 16 , 6 ,
1443+ ... 18 , 8 , 12 , 10 , 22 , 8 , 20 , 12 , 18 , 12 , 28 , 8 , 30 , 16 , 20 , 16 , 24 , 12 , 36 , 18 ,
1444+ ... 24 , 16 , 40 , 12 , 42 , 20 , 24 , 22 , 46 , 16 , 42 , 20 , 32 , 24 , 52 , 18 , 40 , 24 , 36 ,
1445+ ... 28 , 58 , 16 , 60 , 30 , 36 , 32 , 48 , 20 , 66 , 32 , 44 ] # https://oeis.org/A000010
1446+ ...
1447+ >>> list (map (totient, range (1 , 70 ))) == first_totients
1448+ True
1449+ >>> reference_totient = lambda n : sum (math.gcd(t, n) == 1 for t in range (1 , n+ 1 ))
1450+ >>> all (totient(n) == reference_totient(n) for n in range (1000 ))
1451+ True
1452+ >>> totient(128_884_753_939 ) == 128_884_753_938 # large prime
1453+ True
1454+ >>> totient(999953 * 999983 ) == 999952 * 999982 # large semiprime
1455+ True
1456+ >>> totient(6 ** 20 ) == 1 * 2 ** 19 * 2 * 3 ** 19 # repeated primes
1457+ True
1458+
14321459 >>> list (flatten([(' a' , ' b' ), (), (' c' , ' d' , ' e' ), (' f' ,), (' g' , ' h' , ' i' )]))
14331460 ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
14341461
0 commit comments