Skip to content

Commit b3b0a91

Browse files
authored
Add aliquot_sum.py new function and dotests
1 parent c3d4b9e commit b3b0a91

1 file changed

Lines changed: 121 additions & 39 deletions

File tree

maths/aliquot_sum.py

Lines changed: 121 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,130 @@
1-
def aliquot_sum(input_num: int) -> int:
1+
def aliquot_sum(
2+
input_num: int, return_factors: bool = False
3+
) -> int | tuple[int, list[int]]:
24
"""
3-
Finds the aliquot sum of an input integer, where the
4-
aliquot sum of a number n is defined as the sum of all
5-
natural numbers less than n that divide n evenly. For
6-
example, the aliquot sum of 15 is 1 + 3 + 5 = 9. This is
7-
a simple O(n) implementation.
8-
@param input_num: a positive integer whose aliquot sum is to be found
9-
@return: the aliquot sum of input_num, if input_num is positive.
10-
Otherwise, raise a ValueError
11-
Wikipedia Explanation: https://en.wikipedia.org/wiki/Aliquot_sum
12-
13-
>>> aliquot_sum(15)
14-
9
15-
>>> aliquot_sum(6)
16-
6
17-
>>> aliquot_sum(-1)
18-
Traceback (most recent call last):
19-
...
20-
ValueError: Input must be positive
21-
>>> aliquot_sum(0)
22-
Traceback (most recent call last):
23-
...
24-
ValueError: Input must be positive
25-
>>> aliquot_sum(1.6)
26-
Traceback (most recent call last):
27-
...
28-
ValueError: Input must be an integer
29-
>>> aliquot_sum(12)
30-
16
31-
>>> aliquot_sum(1)
32-
0
33-
>>> aliquot_sum(19)
34-
1
5+
Calculates the aliquot sum of a positive integer. The aliquot sum is defined as
6+
the sum of all proper divisors of a number (all divisors except the number itself).
7+
8+
This implementation uses an optimized O(sqrt(n)) algorithm for efficiency.
9+
10+
Args:
11+
input_num: Positive integer to calculate aliquot sum for
12+
return_factors: If True, returns tuple (aliquot_sum, sorted_factor_list)
13+
14+
Returns:
15+
Aliquot sum if return_factors=False
16+
Tuple (aliquot_sum, sorted_factor_list) if return_factors=True
17+
18+
Raises:
19+
TypeError: If input is not an integer
20+
ValueError: If input is not positive
21+
22+
Examples:
23+
>>> aliquot_sum(15)
24+
9
25+
>>> aliquot_sum(15, True)
26+
(9, [1, 3, 5])
27+
>>> aliquot_sum(1)
28+
0
3529
"""
30+
# Validate input type - must be integer
3631
if not isinstance(input_num, int):
37-
raise ValueError("Input must be an integer")
32+
raise TypeError("Input must be an integer")
33+
34+
# Validate input value - must be positive
3835
if input_num <= 0:
39-
raise ValueError("Input must be positive")
40-
return sum(
41-
divisor for divisor in range(1, input_num // 2 + 1) if input_num % divisor == 0
42-
)
36+
raise ValueError("Input must be positive integer")
37+
38+
# Special case: 1 has no proper divisors
39+
if input_num == 1:
40+
# Return empty factor list if requested
41+
return (0, []) if return_factors else 0
42+
43+
# Initialize factors list with 1 (always a divisor)
44+
factors = [1]
45+
total = 1 # Start sum with 1
46+
47+
# Calculate square root as optimization boundary
48+
sqrt_num = int(input_num**0.5)
49+
50+
# Iterate potential divisors from 2 to square root
51+
for divisor in range(2, sqrt_num + 1):
52+
# Check if divisor is a factor
53+
if input_num % divisor == 0:
54+
# Add divisor to factors list
55+
factors.append(divisor)
56+
total += divisor
57+
58+
# Calculate complement (pair factor)
59+
complement = input_num // divisor
60+
61+
# Avoid duplicate for perfect squares
62+
if complement != divisor:
63+
factors.append(complement)
64+
total += complement
65+
66+
# Sort factors for consistent output
67+
factors.sort()
68+
69+
# Return based on return_factors flag
70+
return (total, factors) if return_factors else total
71+
72+
73+
def classify_number(n: int) -> str:
74+
"""
75+
Classifies a number based on its aliquot sum:
76+
- Perfect: aliquot sum = number
77+
- Abundant: aliquot sum > number
78+
- Deficient: aliquot sum < number
79+
80+
Args:
81+
n: Positive integer to classify
82+
83+
Returns:
84+
Classification string ("Perfect", "Abundant", or "Deficient")
85+
86+
Raises:
87+
ValueError: If input is not positive
88+
89+
Examples:
90+
>>> classify_number(6)
91+
'Perfect'
92+
>>> classify_number(12)
93+
'Abundant'
94+
>>> classify_number(19)
95+
'Deficient'
96+
"""
97+
# Validate input
98+
if n <= 0:
99+
raise ValueError("Input must be positive integer")
100+
101+
# Special case: 1 is always deficient
102+
if n == 1:
103+
return "Deficient"
104+
105+
# Calculate aliquot sum
106+
s = aliquot_sum(n)
107+
108+
# Determine classification
109+
if s == n:
110+
return "Perfect"
111+
return "Abundant" if s > n else "Deficient"
43112

44113

45114
if __name__ == "__main__":
46115
import doctest
47-
116+
117+
# Run embedded doctests for verification
48118
doctest.testmod()
119+
120+
# Additional demonstration examples
121+
print("Aliquot sum of 28:", aliquot_sum(28)) # Perfect number
122+
print("Factors of 28:", aliquot_sum(28, True)[1])
123+
print("Classification of 28:", classify_number(28))
124+
125+
# Large number performance test
126+
try:
127+
print("\nCalculating aliquot sum for 10^9...")
128+
print("Result:", aliquot_sum(10**9)) # 1497558336
129+
except Exception as e:
130+
print(f"Error occurred: {e}")

0 commit comments

Comments
 (0)