22== Perfect Number ==
33In number theory, a perfect number is a positive integer that is equal to the sum of
44its positive divisors, excluding the number itself.
5+
56For example: 6 ==> divisors[1, 2, 3, 6]
67 Excluding 6, the sum(divisors) is 1 + 2 + 3 = 6
78 So, 6 is a Perfect Number
89
9- Other examples of Perfect Numbers: 28, 486 , ...
10+ The first few perfect numbers are: 6, 28, 496, 8128, 33550336 , ...
1011
1112https://en.wikipedia.org/wiki/Perfect_number
13+ https://oeis.org/A000396
1214"""
1315
1416
@@ -17,70 +19,286 @@ def perfect(number: int) -> bool:
1719 Check if a number is a perfect number.
1820
1921 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)
2129
2230 Args:
23- number: The number to be checked.
31+ number: The positive integer to be checked.
2432
2533 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+
3039 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
67126 """
68127 if not isinstance (number , int ):
69128 raise ValueError ("number must be an integer" )
129+
70130 if number <= 0 :
71131 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 ]
73255
74256
75257if __name__ == "__main__" :
76258 from doctest import testmod
77259
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