2
2
== Perfect Number ==
3
3
In number theory, a perfect number is a positive integer that is equal to the sum of
4
4
its positive divisors, excluding the number itself.
5
+
5
6
For example: 6 ==> divisors[1, 2, 3, 6]
6
7
Excluding 6, the sum(divisors) is 1 + 2 + 3 = 6
7
8
So, 6 is a Perfect Number
8
9
9
- Other examples of Perfect Numbers: 28, 486 , ...
10
+ The first few perfect numbers are: 6, 28, 496, 8128, 33550336 , ...
10
11
11
12
https://en.wikipedia.org/wiki/Perfect_number
13
+ https://oeis.org/A000396
12
14
"""
13
15
14
16
@@ -17,70 +19,286 @@ def perfect(number: int) -> bool:
17
19
Check if a number is a perfect number.
18
20
19
21
A perfect number is a positive integer that is equal to the sum of its proper
20
- divisors (excluding itself).
22
+ divisors (positive divisors excluding the number itself).
23
+
24
+ The algorithm finds all divisors up to number//2 (since no proper divisor
25
+ can be greater than half the number) and sums them for comparison.
26
+
27
+ Time Complexity: O(sqrt(n)) with optimized divisor finding
28
+ Space Complexity: O(1)
21
29
22
30
Args:
23
- number: The number to be checked.
31
+ number: The positive integer to be checked.
24
32
25
33
Returns:
26
- True if the number is a perfect number otherwise, False.
27
- Start from 1 because dividing by 0 will raise ZeroDivisionError.
28
- A number at most can be divisible by the half of the number except the number
29
- itself. For example, 6 is at most can be divisible by 3 except by 6 itself.
34
+ True if the number is a perfect number, False otherwise.
35
+
36
+ Raises:
37
+ ValueError: If number is not an integer.
38
+
30
39
Examples:
31
- >>> perfect(27)
32
- False
33
- >>> perfect(28)
34
- True
35
- >>> perfect(29)
36
- False
37
- >>> perfect(6)
38
- True
39
- >>> perfect(12)
40
- False
41
- >>> perfect(496)
42
- True
43
- >>> perfect(8128)
44
- True
45
- >>> perfect(0)
46
- False
47
- >>> perfect(-1)
48
- False
49
- >>> perfect(33550336) # Large perfect number
50
- True
51
- >>> perfect(33550337) # Just above a large perfect number
52
- False
53
- >>> perfect(1) # Edge case: 1 is not a perfect number
54
- False
55
- >>> perfect("123") # String representation of a number
56
- Traceback (most recent call last):
57
- ...
58
- ValueError: number must be an integer
59
- >>> perfect(12.34)
60
- Traceback (most recent call last):
61
- ...
62
- ValueError: number must be an integer
63
- >>> perfect("Hello")
64
- Traceback (most recent call last):
65
- ...
66
- ValueError: number must be an integer
40
+ Basic perfect numbers:
41
+ >>> perfect(6)
42
+ True
43
+ >>> perfect(28)
44
+ True
45
+ >>> perfect(496)
46
+ True
47
+ >>> perfect(8128)
48
+ True
49
+
50
+ Large perfect number:
51
+ >>> perfect(33550336)
52
+ True
53
+
54
+ Non-perfect numbers:
55
+ >>> perfect(12)
56
+ False
57
+ >>> perfect(27)
58
+ False
59
+ >>> perfect(29)
60
+ False
61
+ >>> perfect(100)
62
+ False
63
+
64
+ Edge cases:
65
+ >>> perfect(1)
66
+ False
67
+ >>> perfect(2)
68
+ False
69
+ >>> perfect(0)
70
+ False
71
+ >>> perfect(-1)
72
+ False
73
+ >>> perfect(-6)
74
+ False
75
+
76
+ Numbers close to perfect numbers:
77
+ >>> perfect(5)
78
+ False
79
+ >>> perfect(7)
80
+ False
81
+ >>> perfect(27)
82
+ False
83
+ >>> perfect(29)
84
+ False
85
+ >>> perfect(495)
86
+ False
87
+ >>> perfect(497)
88
+ False
89
+ >>> perfect(33550335)
90
+ False
91
+ >>> perfect(33550337)
92
+ False
93
+
94
+ Type validation:
95
+ >>> perfect(12.34)
96
+ Traceback (most recent call last):
97
+ ...
98
+ ValueError: number must be an integer
99
+ >>> perfect("123")
100
+ Traceback (most recent call last):
101
+ ...
102
+ ValueError: number must be an integer
103
+ >>> perfect("Hello")
104
+ Traceback (most recent call last):
105
+ ...
106
+ ValueError: number must be an integer
107
+ >>> perfect([6])
108
+ Traceback (most recent call last):
109
+ ...
110
+ ValueError: number must be an integer
111
+ >>> perfect(None)
112
+ Traceback (most recent call last):
113
+ ...
114
+ ValueError: number must be an integer
115
+
116
+ Testing divisor sum calculation for known cases:
117
+ >>> # For 6: divisors are 1, 2, 3 -> sum = 6
118
+ >>> sum(i for i in range(1, 6//2 + 1) if 6 % i == 0) == 6
119
+ True
120
+ >>> # For 28: divisors are 1, 2, 4, 7, 14 -> sum = 28
121
+ >>> sum(i for i in range(1, 28//2 + 1) if 28 % i == 0) == 28
122
+ True
123
+ >>> # For 12: divisors are 1, 2, 3, 4, 6 -> sum = 16 ≠ 12
124
+ >>> sum(i for i in range(1, 12//2 + 1) if 12 % i == 0) == 12
125
+ False
67
126
"""
68
127
if not isinstance (number , int ):
69
128
raise ValueError ("number must be an integer" )
129
+
70
130
if number <= 0 :
71
131
return False
72
- return sum (i for i in range (1 , number // 2 + 1 ) if number % i == 0 ) == number
132
+
133
+ # Special case: 1 has no proper divisors
134
+ if number == 1 :
135
+ return False
136
+
137
+ # Find sum of all proper divisors
138
+ # We only need to check up to number//2 since no proper divisor
139
+ # can be greater than half the number
140
+ divisor_sum = sum (i for i in range (1 , number // 2 + 1 ) if number % i == 0 )
141
+
142
+ return divisor_sum == number
143
+
144
+
145
+ def perfect_optimized (number : int ) -> bool :
146
+ """
147
+ Optimized version of perfect number checker using mathematical properties.
148
+
149
+ This version uses the fact that divisors come in pairs (d, n/d) to reduce
150
+ the search space to sqrt(n).
151
+
152
+ Time Complexity: O(sqrt(n))
153
+ Space Complexity: O(1)
154
+
155
+ Args:
156
+ number: The positive integer to be checked.
157
+
158
+ Returns:
159
+ True if the number is a perfect number, False otherwise.
160
+
161
+ Examples:
162
+ >>> perfect_optimized(6)
163
+ True
164
+ >>> perfect_optimized(28)
165
+ True
166
+ >>> perfect_optimized(496)
167
+ True
168
+ >>> perfect_optimized(12)
169
+ False
170
+ >>> perfect_optimized(1)
171
+ False
172
+ >>> perfect_optimized(0)
173
+ False
174
+ >>> perfect_optimized(-1)
175
+ False
176
+ """
177
+ if not isinstance (number , int ):
178
+ raise ValueError ("number must be an integer" )
179
+
180
+ if number <= 1 :
181
+ return False
182
+
183
+ divisor_sum = 1 # 1 is always a proper divisor for n > 1
184
+
185
+ # Check divisors up to sqrt(number)
186
+ i = 2
187
+ while i * i <= number :
188
+ if number % i == 0 :
189
+ divisor_sum += i
190
+ # Add the paired divisor if it's different from i
191
+ if i != number // i :
192
+ divisor_sum += number // i
193
+ i += 1
194
+
195
+ return divisor_sum == number
196
+
197
+
198
+ def find_perfect_numbers (limit : int ) -> list [int ]:
199
+ """
200
+ Find all perfect numbers up to a given limit.
201
+
202
+ Args:
203
+ limit: The upper bound to search for perfect numbers.
204
+
205
+ Returns:
206
+ List of perfect numbers up to the limit.
207
+
208
+ Examples:
209
+ >>> find_perfect_numbers(10)
210
+ [6]
211
+ >>> find_perfect_numbers(30)
212
+ [6, 28]
213
+ >>> find_perfect_numbers(500)
214
+ [6, 28, 496]
215
+ >>> find_perfect_numbers(0)
216
+ []
217
+ >>> find_perfect_numbers(1)
218
+ []
219
+ """
220
+ if not isinstance (limit , int ) or limit < 0 :
221
+ raise ValueError ("limit must be a non-negative integer" )
222
+
223
+ return [n for n in range (1 , limit + 1 ) if perfect (n )]
224
+
225
+
226
+ def get_divisors (number : int ) -> list [int ]:
227
+ """
228
+ Get all proper divisors of a number (excluding the number itself).
229
+
230
+ Args:
231
+ number: The positive integer to find divisors for.
232
+
233
+ Returns:
234
+ List of proper divisors in ascending order.
235
+
236
+ Examples:
237
+ >>> get_divisors(6)
238
+ [1, 2, 3]
239
+ >>> get_divisors(28)
240
+ [1, 2, 4, 7, 14]
241
+ >>> get_divisors(12)
242
+ [1, 2, 3, 4, 6]
243
+ >>> get_divisors(1)
244
+ []
245
+ >>> get_divisors(7)
246
+ [1]
247
+ """
248
+ if not isinstance (number , int ) or number <= 0 :
249
+ raise ValueError ("number must be a positive integer" )
250
+
251
+ if number == 1 :
252
+ return []
253
+
254
+ return [i for i in range (1 , number // 2 + 1 ) if number % i == 0 ]
73
255
74
256
75
257
if __name__ == "__main__" :
76
258
from doctest import testmod
77
259
78
- testmod ()
79
- print ("Program to check whether a number is a Perfect number or not..." )
80
- try :
81
- number = int (input ("Enter a positive integer: " ).strip ())
82
- except ValueError :
83
- msg = "number must be an integer"
84
- raise ValueError (msg )
85
-
86
- print (f"{ number } is { '' if perfect (number ) else 'not ' } a Perfect Number." )
260
+ print ("Running doctests..." )
261
+ testmod (verbose = True )
262
+
263
+ print ("\n Perfect Number Checker" )
264
+ print ("=" * 40 )
265
+ print ("A perfect number equals the sum of its proper divisors." )
266
+ print ("Examples: 6 (1+2+3), 28 (1+2+4+7+14), 496, 8128, ..." )
267
+ print ()
268
+
269
+ while True :
270
+ try :
271
+ user_input = input ("Enter a positive integer (or 'q' to quit): " ).strip ()
272
+ if user_input .lower () == 'q' :
273
+ break
274
+
275
+ number = int (user_input )
276
+
277
+ if number <= 0 :
278
+ print ("Please enter a positive integer." )
279
+ continue
280
+
281
+ is_perfect = perfect (number )
282
+ divisors = get_divisors (number )
283
+ divisor_sum = sum (divisors )
284
+
285
+ print (f"\n Number: { number } " )
286
+ print (f"Proper divisors: { divisors } " )
287
+ print (f"Sum of divisors: { divisor_sum } " )
288
+ print (f"Is perfect: { 'Yes' if is_perfect else 'No' } " )
289
+
290
+ if is_perfect :
291
+ print (f"✓ { number } is a Perfect Number!" )
292
+ else :
293
+ print (f"✗ { number } is not a Perfect Number." )
294
+
295
+ print ("-" * 40 )
296
+
297
+ except ValueError as e :
298
+ if "invalid literal" in str (e ):
299
+ print ("Please enter a valid integer." )
300
+ else :
301
+ print (f"Error: { e } " )
302
+ except KeyboardInterrupt :
303
+ print ("\n Goodbye!" )
304
+ break
0 commit comments