@@ -1128,6 +1128,14 @@ The following recipes have a more mathematical flavor:
1128
1128
if n > 1:
1129
1129
yield n
1130
1130
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
+
1131
1139
def nth_combination(iterable, r, index):
1132
1140
"Equivalent to list(combinations(iterable, r))[index]"
1133
1141
pool = tuple(iterable)
@@ -1429,6 +1437,25 @@ The following recipes have a more mathematical flavor:
1429
1437
>>> all (list (factor(n)) == sorted (factor(n)) for n in range (2_000 ))
1430
1438
True
1431
1439
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
+
1432
1459
>>> list (flatten([(' a' , ' b' ), (), (' c' , ' d' , ' e' ), (' f' ,), (' g' , ' h' , ' i' )]))
1433
1460
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
1434
1461
0 commit comments