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