|
1 | | -from __future__ import annotations # Enable modern type hints |
| 1 | +from __future__ import annotations |
2 | 2 |
|
| 3 | +import doctest |
| 4 | +from typing import overload, Tuple |
| 5 | + |
| 6 | +@overload |
| 7 | +def aliquot_sum(input_num: int) -> int: ... |
| 8 | +@overload |
| 9 | +def aliquot_sum(input_num: int, return_factors: bool) -> Tuple[int, list[int]]: ... |
3 | 10 |
|
4 | 11 | def aliquot_sum( |
5 | 12 | input_num: int, return_factors: bool = False |
6 | | -) -> int | tuple[int, list[int]]: |
| 13 | +) -> int | Tuple[int, list[int]]: |
7 | 14 | """ |
8 | | - Calculates the aliquot sum of a positive integer. The aliquot sum is defined as |
9 | | - the sum of all proper divisors of a number (all divisors except the number itself). |
10 | | -
|
11 | | - This implementation uses an optimized O(sqrt(n)) algorithm for efficiency. |
12 | | -
|
| 15 | + Calculates the aliquot sum of a positive integer. |
| 16 | + The aliquot sum is the sum of all proper divisors of a number. |
| 17 | + |
13 | 18 | Args: |
14 | | - input_num: Positive integer to calculate aliquot sum for |
15 | | - return_factors: If True, returns tuple (aliquot_sum, sorted_factor_list) |
16 | | -
|
| 19 | + input_num: Positive integer |
| 20 | + return_factors: If True, returns (sum, sorted_factor_list) |
| 21 | + |
17 | 22 | Returns: |
18 | | - Aliquot sum if return_factors=False |
19 | | - Tuple (aliquot_sum, sorted_factor_list) if return_factors=True |
20 | | -
|
| 23 | + Aliquot sum or (sum, factors) if return_factors=True |
| 24 | + |
21 | 25 | Raises: |
22 | | - TypeError: If input is not an integer |
23 | | - ValueError: If input is not positive |
24 | | -
|
| 26 | + TypeError: If input not integer |
| 27 | + ValueError: If input not positive |
| 28 | + |
25 | 29 | Examples: |
26 | 30 | >>> aliquot_sum(15) |
27 | 31 | 9 |
28 | 32 | >>> aliquot_sum(15, True) |
29 | 33 | (9, [1, 3, 5]) |
30 | | - >>> aliquot_sum(1) |
31 | | - 0 |
32 | 34 | """ |
33 | | - # Validate input type - must be integer |
| 35 | + # Validate input |
34 | 36 | if not isinstance(input_num, int): |
35 | 37 | raise TypeError("Input must be an integer") |
36 | | - |
37 | | - # Validate input value - must be positive |
38 | 38 | if input_num <= 0: |
39 | 39 | raise ValueError("Input must be positive integer") |
40 | | - |
| 40 | + |
41 | 41 | # Special case: 1 has no proper divisors |
42 | 42 | if input_num == 1: |
43 | | - # Return empty factor list if requested |
44 | 43 | return (0, []) if return_factors else 0 |
45 | | - |
46 | | - # Initialize factors list with 1 (always a divisor) |
| 44 | + |
| 45 | + # Initialize factors and total |
47 | 46 | factors = [1] |
48 | | - total = 1 # Start sum with 1 |
49 | | - |
50 | | - # Calculate square root as optimization boundary |
| 47 | + total = 1 |
51 | 48 | sqrt_num = int(input_num**0.5) |
52 | | - |
53 | | - # Iterate potential divisors from 2 to square root |
| 49 | + |
| 50 | + # Find factors efficiently |
54 | 51 | for divisor in range(2, sqrt_num + 1): |
55 | | - # Check if divisor is a factor |
56 | 52 | if input_num % divisor == 0: |
57 | | - # Add divisor to factors list |
58 | 53 | factors.append(divisor) |
59 | 54 | total += divisor |
60 | | - |
61 | | - # Calculate complement (pair factor) |
62 | 55 | complement = input_num // divisor |
63 | | - |
64 | | - # Avoid duplicate for perfect squares |
65 | 56 | if complement != divisor: |
66 | 57 | factors.append(complement) |
67 | 58 | total += complement |
68 | | - |
69 | | - # Sort factors for consistent output |
| 59 | + |
70 | 60 | factors.sort() |
71 | | - |
72 | | - # Return based on return_factors flag |
73 | 61 | return (total, factors) if return_factors else total |
74 | 62 |
|
75 | | - |
76 | 63 | def classify_number(n: int) -> str: |
77 | 64 | """ |
78 | | - Classifies a number based on its aliquot sum: |
79 | | - - Perfect: aliquot sum = number |
80 | | - - Abundant: aliquot sum > number |
81 | | - - Deficient: aliquot sum < number |
82 | | -
|
83 | | - Args: |
84 | | - n: Positive integer to classify |
85 | | -
|
86 | | - Returns: |
87 | | - Classification string ("Perfect", "Abundant", or "Deficient") |
88 | | -
|
89 | | - Raises: |
90 | | - ValueError: If input is not positive |
91 | | -
|
| 65 | + Classifies number based on aliquot sum: |
| 66 | + - Perfect: sum = number |
| 67 | + - Abundant: sum > number |
| 68 | + - Deficient: sum < number |
| 69 | + |
92 | 70 | Examples: |
93 | 71 | >>> classify_number(6) |
94 | 72 | 'Perfect' |
95 | 73 | >>> classify_number(12) |
96 | 74 | 'Abundant' |
97 | | - >>> classify_number(19) |
98 | | - 'Deficient' |
99 | 75 | """ |
100 | | - # Validate input |
101 | 76 | if n <= 0: |
102 | 77 | raise ValueError("Input must be positive integer") |
103 | | - |
104 | | - # Special case: 1 is always deficient |
105 | 78 | if n == 1: |
106 | 79 | return "Deficient" |
107 | | - |
108 | | - # Explicitly request integer-only aliquot sum |
109 | | - s = aliquot_sum(n, return_factors=False) |
110 | | - |
111 | | - # Determine classification |
| 80 | + |
| 81 | + s = aliquot_sum(n) # Always returns int |
112 | 82 | if s == n: |
113 | 83 | return "Perfect" |
114 | | - elif s > n: |
115 | | - return "Abundant" |
116 | | - else: |
117 | | - return "Deficient" |
118 | | - |
| 84 | + return "Abundant" if s > n else "Deficient" |
119 | 85 |
|
120 | 86 | if __name__ == "__main__": |
121 | | - import doctest |
122 | | - |
123 | | - # Run embedded doctests for verification |
124 | 87 | doctest.testmod() |
125 | | - |
126 | | - # Additional demonstration examples |
127 | | - print("Aliquot sum of 28:", aliquot_sum(28)) # Perfect number |
128 | | - |
129 | | - # Get factors for 28 with type-safe access |
130 | | - factor_result = aliquot_sum(28, return_factors=True) |
131 | | - # Since we requested factors, we know it's a tuple |
132 | | - print("Factors of 28:", factor_result[1]) |
133 | | - |
| 88 | + |
| 89 | + print("Aliquot sum of 28:", aliquot_sum(28)) |
| 90 | + |
| 91 | + # Handle tuple return explicitly |
| 92 | + result = aliquot_sum(28, True) |
| 93 | + if isinstance(result, tuple): |
| 94 | + print("Factors of 28:", result[1]) |
| 95 | + |
134 | 96 | print("Classification of 28:", classify_number(28)) |
135 | | - |
136 | | - # Large number performance test with targeted exception handling |
| 97 | + |
| 98 | + # Large number test |
137 | 99 | try: |
138 | | - print("\nCalculating aliquot sum for 10^9...") |
139 | | - print("Result:", aliquot_sum(10**9)) # 1497558336 |
| 100 | + print("Aliquot sum for 10^9:", aliquot_sum(10**9)) |
140 | 101 | except (TypeError, ValueError) as e: |
141 | | - # Handle input-related errors |
142 | | - print(f"Input error: {e}") |
143 | | - except MemoryError: |
144 | | - # Handle potential memory issues with large numbers |
145 | | - print("Memory error: Number too large") |
146 | | - except OverflowError: |
147 | | - # Handle numeric overflow |
148 | | - print("Overflow error: Calculation too large") |
| 102 | + print(f"Error: {e}") |
0 commit comments