Reputation: 1
I would like to know, how I can add up all possible divisors of a number in python without the given number itself. For example, all possible divisors of the number 36 are 1, 2, 3, 4, 6, 9, 12 and 18. When you add them up, you should get a total of 55. I would like to know how to get these divisors with a while loop.
I have tried the following code:
def sum_divisors(n):
sum = 0
divisor = 2
while n % divisor == 0:
if n == 0:
return 0
print(n / divisor)
divisor += 1
print(sum_divisors(36))
When I excecute this code I only get the number 18, 12, and 9. After these numbers I get "None". I think my problem is, when I execute this code the divisor will add 1 as long as the condition ist "True". But when the programm have to divide 36 / 5 the remainder is 1 and the code will no longer be excecuted because the condition is "False". So I tried to fix this problem with the following code:
def sum_divisors(n):
sum = 0
divisor = 2
while n % divisor == 0:
if n == 0:
return 0
if n % divisor == 1:
divisor += 2
print(n / divisor)
divisor += 1
print(sum_divisors(36))
But this code din't work either. Do you have some tips how I can fix this problem. I only want to have tips and not suggested solutions. I am aware that I still need to find a code on how to add everything up. But I will surely be able to solve this problem. ;)
Upvotes: 0
Views: 1178
Reputation: 42139
You could adapt a prime factorisation algorithm to build a set of divisors (exclude the number itself from the result if needed):
def getDivs(N):
factors = {1}
maxP = int(N**0.5) # largest possible prime factor
p,inc = 2,1 # candidate divisors (primes)
while p <= maxP: # up to √(remaining N)
while N%p==0:
factors.update([f*p for f in factors]) # expand divisors
N //= p # reduce N
maxP = int(N**0.5) # new max prime
p,inc = p+inc,2 # next divisor
if N>1:
factors.update([f*N for f in factors]) # ultimate prime
return factors - {max(factors)} # exclude number itself
output:
getDivs(36)
{1, 2, 3, 4, 6, 9, 12, 18}
sum(getDivs(36))
55
getDivs(1001001001)
{1, 7, 762377, 11, 13, 77000077, 143, 91000091, 1313, 1415843,
9901, 69307, 1000001, 707, 7000007, 128713, 11000011, 77,
13000013, 143000143, 1111, 91, 7777, 101, 9191, 1001, 14443,
101101, 108911, 9910901, 900991}
sum(getDivs(1001001001))
356444375
If you don't need to list the divisors themselves and are only looking for their sum, you can get it in O(√N) time in a comprehension:
def divSum(N):
return sum(sum({d,N//d}) for d in range(2,int(N**0.5)+1) if N%d == 0) + 1
divSum(36) # 55
divSum(1001001001) # 356444375
Upvotes: 0
Reputation: 26961
I highly suggest using the generator approach. We generate all possible divisors and then sum them. It will allow you to get the individual divisors as well:
import math
from typing import Iterator
def iter_divisors(n: int, /) -> Iterator[int]:
"""Iterate over the divisors of a given integer."""
if n == 0:
yield 0
return
sqrt = math.sqrt(n)
# math.ceil explanation:
# If sqrt is a whole number, we check everything until sqrt.
# Else, we check everything until the closest integer from below.
for i in range(1, math.ceil(sqrt)):
if n % i == 0:
yield i
yield n // i
# If the sqrt is whole, yield it only once (6 instead of 6,6 in 36)
if sqrt.is_integer():
yield int(sqrt)
Then you can sum it:
>>> print(sum(iter_divisors(36)))
91
Keep in mind it includes both 1 and n. You can subtract them if needed:
>>> print(sum(iter_divisors(36)) - 36)
55
Upvotes: 1
Reputation: 169
One possibility is to first get a list separately (in that case I called this method ' divisor_nums'). It contains all possible numbers that can be divided by, for example, '36'.
# // Get all possible numbers that can be devided
def divisor_nums(num: int) -> list:
return [x for x in range(num) for y in range(num) if x * y == num]
# ... 2, 3, 4, 6, 9, 12, 18 (with 36)
In the second section I iterate all numbers from the above list with a counter. In the comparison, list[i] == list[i] = 0
. Well, maybe not the best option, but possibly one of many.
def sum_divisors(num):
sum = 0
i = -1
lst = divisor_nums(num)
while lst[i] % lst[i] == 0:
sum += lst[i]
i += 1
if i >= len(lst)-1:
break
return sum
print(divisor_nums(36))
print(sum_divisors(36))
PS: The divisor_nums()
function is only optional. You can also include this list directly in the sum_divisors
function
Upvotes: 0
Reputation: 634
This will work for your case.
def sum_divisors(n):
sum = 0
divisor = 1
while divisor<n:
if n%divisor == 0:
sum+= divisor
divisor += 1
return sum
print(sum_divisors(36))
Upvotes: 0
Reputation: 1757
def sum_divisors(num):
Sum=0
n=1
while n<=(num//2):
if num%n==0:
Sum += n
n += 1
return Sum
print(sum_divisors(36))
55
Upvotes: 0
Reputation: 27315
How about a for loop:
def sum_divisors(n):
ds = 1
for i in range(2, (n//2)+1):
if n % i == 0:
ds += i
return ds
print(sum_divisors(36))
Output:
55
Upvotes: 0