Skip to content

Commit 660701d

Browse files
committed
fix(maths): add the leftover prime factor in sum_of_divisors
sum_of_divisors only multiplied in the prime factors it found while trial-dividing, so any prime factor above the trial-division bound was dropped: 94 of the first 119 inputs returned the wrong answer (sum_of_divisors(3) -> 1 instead of 4, sum_of_divisors(12) -> 7 instead of 28). number_of_divisors in the same file already handles this case with `if n > 1: div *= 2`. Also compute with // instead of /: the function accumulated a float and truncated with int(s), so sum_of_divisors(2**62) returned 9223372036854775808 instead of 9223372036854775807 and large inputs were off by orders of magnitude (3**40 was wrong by ~10^4). math.isqrt replaces int(math.sqrt(n)) for the same reason. Verified against an independent factorization of sigma(n) for n = 1..50000: 0 mismatches.
1 parent 6e03a48 commit 660701d

1 file changed

Lines changed: 18 additions & 6 deletions

File tree

‎maths/basic_maths.py‎

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ def sum_of_divisors(n: int) -> int:
6767
"""Calculate Sum of Divisors.
6868
>>> sum_of_divisors(100)
6969
217
70+
>>> sum_of_divisors(12)
71+
28
72+
>>> sum_of_divisors(7)
73+
8
74+
>>> sum_of_divisors(2**40)
75+
2199023255551
76+
>>> sum_of_divisors(2**62)
77+
9223372036854775807
7078
>>> sum_of_divisors(0)
7179
Traceback (most recent call last):
7280
...
@@ -82,17 +90,21 @@ def sum_of_divisors(n: int) -> int:
8290
temp = 1
8391
while n % 2 == 0:
8492
temp += 1
85-
n = int(n / 2)
93+
n //= 2
8694
if temp > 1:
87-
s *= (2**temp - 1) / (2 - 1)
88-
for i in range(3, int(math.sqrt(n)) + 1, 2):
95+
s *= (2**temp - 1) // (2 - 1)
96+
for i in range(3, math.isqrt(n) + 1, 2):
8997
temp = 1
9098
while n % i == 0:
9199
temp += 1
92-
n = int(n / i)
100+
n //= i
93101
if temp > 1:
94-
s *= (i**temp - 1) / (i - 1)
95-
return int(s)
102+
s *= (i**temp - 1) // (i - 1)
103+
# Whatever is left is a single prime factor above the trial-division
104+
# bound, so it contributes 1 + n to the sum.
105+
if n > 1:
106+
s *= n + 1
107+
return s
96108

97109

98110
def euler_phi(n: int) -> int:

0 commit comments

Comments
 (0)