Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Comments on Where did my proper divisor sum program went wrong?

Parent

Where did my proper divisor sum program went wrong?

+5
−1

Here in Python, I created a program for this challenge and I'm having trouble debugging it. I already fixed most errors I have on my program but here's what I have left:

x=y=z=[];i=0.0;a=int(input());b=0
for c in range(1,a+1):
	for d in range(1,a):
		i+=1
		if a/c==i and c!=a:b+=c
	if b<a:x.append(c)
	elif b>a:y.append(c)
	else:z.append(c)
	i=b=0
print("[",end='')
for j in x:
	print(j,end='')
	if j!=len(x):print(" ",end='')
print("], [",end='')
for j in y:
	print(j,end='')
	if j!=len(y):print(" ",end='')
print("], [",end='')
for j in z:
	print(j,end='')
	if j!=len(z):print(" ",end='')
print("]",end='')

Here's the unshortened code with comments:

x=y=z=[] # Initialize up 3 empty lists
i=0.0 # initialize a float to make sure the numbers would be checked if it's a proper divisor
a=int(input()) # input an integer
b=0 # initialize the value for the proper divisor sum
for c in range(1,a+1): # start a for loop that checks which list should the number in the range of 1 and the input
	for d in range(1,a): # start a for loop to get the proper divisor sum of each number in the range of 1 and the input
		i+=1 # increment 1 for rechecking		
		if a/c==i and c!=a: # check if the number is a proper divisor
			b+=c # if it is, then add it to the sum
	if b<a:
		x.append(c) # add to the list if the number is deficient
	elif b>a:
		y.append(c) # add to the list if the number is abundant
	else:
		z.append(c) # add to the list if the number is perfect
	i=b=0 # reset the numbers for rechecking
print("[", end = '') # start the output by adding a bracket without a newline
for j in x: # print all deficient numbers as a list
	print(j, end = '') # print the number according to the for loop without a newline
	if j != len(x):
		print(" ", end = '') # print a space to separate numbers without a newline except for the last number in the list
print("], [", end = '') # End the list, proceed to the next one
for j in y: # print all abundant numbers as a list
	print(j, end = '') # print the number according to the for loop without a newline
	if j != len(y):
		print(" ", end = '') # print a space to separate numbers without a newline except for the last number in the list
print("], [", end = '') # End the list, proceed to the next one
for j in z: # print all perfect numbers as a list
	print(j, end = '') # print the number according to the for loop without a newline
	if j != len(z):
		print(" ", end = '') # print a space to separate numbers without a newline except for the last number in the list
print("]", end = '') # end it with a bracket

Basically, I'm trying to make a number checker so I can get the inputted number's proper divisor sum, which in my understanding is the sum of divisors that results in a quotient that can be formatted as n.00000..., but the resulting output leaves me with all the numbers from 1 to the input. See it for yourself! (SIFY)

I've been trying to figure out where the problem lies and I suspect it has to do with the first for loop, but I don't know where exactly to fix. Where did I mess up or how do I fix this?

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.
Why should this post be closed?

1 comment thread

General comments (5 comments)
Post
+10
−0

When you do x=y=z=[], you're making x, y and z point to the same list. Example:

x=y=z=[]
# add element to x
x.append(1)
# add element to y
y.append(2)
# but x, y and z all point to the same list
print(z) # [1, 2]

So the first thing to fix is this, set a different list to each:

x = []
y = []
z = []

And now, when you add elements to one, it doesn't change the others.


Now the algorithm: in the first loop, c is the number you want to check. So in the second loop, the upper bound should be related to c, not to a.

Actually, to be honest, this code is too confusing to me and I gave up trying to understand what you did. So I'll just suggest another algorithm. And it seems that you were trying to code-golf, but for the sake of clarity, I'll use better names for the variables and not focus on the make-the-smallest-possible-code aspect.

First of all, you don't need to test number 1. One might think I'm "cheating", but 1 has no proper divisors, so the sum of their proper divisors is zero, hence it can already start at the deficients list.

And all numbers are divisible by 1, so the sum of divisors can be initialized with 1, and I can start checking the divisors from number 2.

To check if a number is divisible by another, just use the % operator, which gives you the remainder. Ex: when 100 is divided by 2, the remainder is zero (100 % 2 == 0), but by 3, the remainder is 1 (100 % 3 == 1). Hence, 2 is a divisor of 100, but 3 isn't. Tl;dr: just check if the result of % is zero.

Another important detail is: when you find a divisor, you potencially found another one. Let's say the number is 100. If I find divisor 2, I also found another divisor, which is the result of 100 divided by 2 (aka 50). The only exception is divisor 10, because 100 / 10 is also 10.

So, for each divisor found (the remainder is zero), I check if the other divisor is the same number (if not, I found another divisor). Using this method, I can iterate only until the square root of the number (ex: if the number is 100, I can make the loop until 10). That's because if some number N has divisors, it can be written as a product of two integers (let's say a * b), which means that if a and b were both greater than the square root of N, then their product would be greater than N, so at least one of them must be smaller than the square root. Therefore, if we loop until the square root, we find one divisor, and by dividing the number by this divisor, we find the other one.

The code will be like this:

from math import sqrt

x = int(input())

deficient = [ 1 ] # "cheating"
perfect = []
abundant = []
for n in range(2, x + 1): # no need to check 1
    # calculate sum of proper divisors of n
    div_sum = 1 # 1 is always a divisor
    for div_candidate in range(2, int(sqrt(n)) + 1):
        if n % div_candidate == 0: # divisor found
            div_sum += div_candidate
            # get the other divisor
            other_divisor = n // div_candidate
            if other_divisor != div_candidate: # avoid the square root, if n is a perfect square
                div_sum += other_divisor

    # add n to the proper list
    if div_sum > n:
        abundant.append(n)
    elif div_sum < n:
        deficient.append(n)
    else:
        perfect.append(n)

print([ abundant, perfect, deficient ])

Note that, in Python, when you print a list, it's already displayed delimited by [ ] and the elements separated by commas. So there's no need to make all those loops. Even if you need different separators, you could use join instead:

# just an example
numbers = [1, 2, 3]
# using join to print the numbers separated by some string
print('<{}>'.format('; '.join(map(str, numbers)))) # <1; 2; 3>
# in Python >= 3.6, use f-strings
print(f'<{"; ".join(map(str, numbers))}>') # <1; 2; 3>

Anyway, that's beside the point. If you print the lists directly, the output will be like [ element1, element2, etc ]. In the end, I put all the 3 lists inside another list, to make the ouput match the format specified by the challenge. Example, for x equals to 15, the output is:

[[12], [6], [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15]]

Well, if you think that starting the deficients list with 1 is "cheating", then let's see another approach (still ignoring the code-golf aspect). You could create a generator function that yields the proper divisors, just to keep things more organized, IMO:

from math import sqrt

# generator function that yields all the proper divisors of n
def proper_divisors(n):
    if n <= 1: # for n <= 1, there are no proper divisors
        return
    yield 1 # 1 is always a divisor
    for div_candidate in range(2, int(sqrt(n)) + 1):
        if n % div_candidate == 0: # divisor found
            yield div_candidate
            # get the other divisor
            other_divisor = n // div_candidate
            if other_divisor != div_candidate:
                yield other_divisor

And then we can use this function with the built-in sum, to get the sum of those divisors:

x = int(input())
deficient = []
perfect = []
abundant = []

for n in range(1, x + 1):
    # calculate sum of proper divisors of n
    div_sum = sum(proper_divisors(n))

    # add n to the proper list
    if div_sum > n:
        abundant.append(n)
    elif div_sum < n:
        deficient.append(n)
    else:
        perfect.append(n)

print([ abundant, perfect, deficient ])

Of course you could also do it without the function, adding the if n <= 1 to the first code. But I don't really mind "cheating" and initializing the deficients list with 1.


If you want to code-golf, I'm not the best one to give you some advice (I can only suggest the more obvious thing). I think code golf is a curious thing, but I personally don't enjoy programming like that, because it starts getting too complicated, IMO. One example is this trick to have just one list of lists:

result = [ [], [], [] ]
for n in range(1, x + 1):
    # calculate sum of divisors of n
    div_sum = sum(proper_divisors(n))

    # add n to the proper list
    result[(n > div_sum) - (n < div_sum) + 1].append(n)

print(result)

It uses the suggested implementation of the cmp built-in, which no longer exists in Python. It basically returns -1 if n is less than div_sum, zero if they're equal and 1 if n is greater. Then I add 1 to this result, in order to get the respective index on the result list (which has 3 other lists in it: the abundant, perfect and deficient lists).

That's a way to make the code shorter, but certainly not clearer. Anyway, at least now you have a code that works and can code-golf it...

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.

1 comment thread

General comments (3 comments)
General comments
General Sebast1an‭ wrote over 3 years ago

the best answer so far. it's sad that I can't accept it but thanks.

elgonzo‭ wrote over 3 years ago · edited over 3 years ago

Great answer! Although, if i am picky (and a bit of an ar*ehole) i think you took the challenge away from Derrick, now he needs to find himself another one :-) I also think a mention of "rubber duck debugging" would apply to the situation Derrick found himself in. Still, not trying to take away anything from your answer - well explained and structured -- so here goes my upvote...

hkotsubo‭ wrote over 3 years ago

@elgonzo There's still the challenge of code-golfing the code (make it as small as possible). But as I said, I'm not the best one to suggest anything about that, so it's "left as an exercise to the reader (aka Derrick)" :-)