5 Best Ways to Check if a Number is a Perfect Number in Python

Rate this post

πŸ’‘ Problem Formulation: We aim to determine if a given integer is a perfect number. In number theory, a perfect number is a positive integer that is equal to the sum of its proper divisors, excluding the number itself. For instance, 28 is a perfect number because its divisors (1, 2, 4, 7, 14) sum up to 28.

Method 1: Using a Loop

This method involves iterating through all possible divisors of the input number and accumulating their sum. If the sum of divisors matches the original number, it is perfect.

Here’s an example:

def is_perfect_number(num):
    sum_of_divisors = 0
    for i in range(1, num):
        if num % i == 0:
            sum_of_divisors += i
    return sum_of_divisors == num

print(is_perfect_number(28))

Output: True

This function is_perfect_number iterates from 1 up to the number (exclusive) and checks if each integer is a divisor. If it is, it adds that number to sum_of_divisors. After completion, it checks if the sum of these divisors equals to the original number to determine if it’s perfect.

Method 2: Using List Comprehension

Python’s list comprehension feature can be used for a cleaner approach to gather all divisors and calculate their sum in a single line of code.

Here’s an example:

def is_perfect_number(num):
    return sum([i for i in range(1, num) if num % i == 0]) == num

print(is_perfect_number(28))

Output: True

In this simplified approach, list comprehension is used to create a list of all divisors of num, which is then passed to the sum function. The result is compared directly to the initial number to check for perfection.

Method 3: Utilizing the sqrt Function

We can improve efficiency by iterating only up to the square root of the number because a divisor larger than the square root would have a corresponding divisor smaller than the square root.

Here’s an example:

import math

def is_perfect_number(num):
    sum_of_divisors = 1
    for i in range(2, int(math.sqrt(num)) + 1):
        if num % i == 0:
            sum_of_divisors += i + num // i
    return sum_of_divisors == num

print(is_perfect_number(28))

Output: True

In this code snippet, we start the sum at 1, since 1 is a divisor of every number. By iterating up to the square root, we avoid unnecessary checks and, when a divisor is found, we add both the divisor and its corresponding pair to the sum. Eventually, we compare this sum to the input number.

Method 4: Using a Generator Expression

A generator expression allows us to evaluate the sum without creating an intermediate list, thus being more memory efficient.

Here’s an example:

def is_perfect_number(num):
    return sum(i for i in range(1, num) if num % i == 0) == num

print(is_perfect_number(28))

Output: True

Here, we have replaced the list comprehension with a generator expression. This means we sum up the divisors lazily, which can be useful for memory optimization especially with larger numbers.

Bonus One-Liner Method 5: Using sum with Generator Expression

For the enthusiasts of one-liners, we present this concise expression that does it all at once.

Here’s an example:

print(sum(i for i in range(1, 28) if 28 % i == 0) == 28)

Output: True

This one-liner checks the perfection of the number 28 directly within the print statement using a generator expression. It is neat but sacrifices readability for brevity.

Summary/Discussion

  • Method 1: Loop. Straightforward implementation. Not the most efficient for large numbers due to iteration over all integers less than the number.
  • Method 2: List Comprehension. More Pythonic and concise. Still, it’s not efficient for large numbers due to the same iteration issue.
  • Method 3: Utilizing sqrt. It’s more efficient as it reduces the iterations required. However, it involves slightly more complex logic.
  • Method 4: Generator Expression. Memory efficiency as it avoids creating an intermediate list. Suitable for large numbers but may not provide a significant speed advantage.
  • Method 5: One-Liner using Generator Expression. Extremely concise. Best used for quick checks or small scripts. Might be hard to read and understand for beginners.