2
\$\begingroup\$

I tackled a beginners' exercise: "asks the user for a number and then prints out a list of all the divisors of that number."

The workflow I established is: input an integer number, say x; add a variable which value is x/2, say y; declare a divisors list.

If x is greater than 4 iterate between 2 and y+1; if the remainder is zero append it the the divisors list.

If divisors list is empty or if the input number is smaller than 4 return: this is a primary number.
else, return divisors list.

I ended up with the following solution. It does the job, but isn't good enough, as it has the following issues:

What is the python's input number limit? Currently, I have no limit which is wrong as it beyond the computational capacities of any computer.

I suspect my else statement isn't tidy enough. It can be shorter... but how?

If the number is lower than 4, the script returns twice the message "the number you entered is a primary number". I could fix it with an ad-hoc solution - but it should be solved through an algorithm not in a manual manner (...at least if I try to learn coding).

I ended up iterating in range of 2 and y+2 rather y+1 as I thought. I solved it manually but I don't understand why it isn't y+1.

num = int(input("Please select a number between: "))
y = num/2
if not y==0:
    y=int(y-0.5)

list_range = list(range(2,y+2))

divisors_list = []
if num < 4:
    print("The number you entered is a primary number")
else:
    for i in list_range:
        if num%i ==0:
            divisors_list.append(i)

if not divisors_list:
    print("The number you entered is a primary number")
else:
    print(divisors_list)
\$\endgroup\$
5
  • \$\begingroup\$ If your code isn't working properly, you should post this in Stack Overflow. \$\endgroup\$
    – M-Chen-3
    Commented Mar 3, 2021 at 0:58
  • \$\begingroup\$ @M-Chen-3 Thanks. My code works, I wish to make it better - I cannot tell if it relevant here. I actually posted on overflow before, comments advised me post it here... Can you please advise how/where I can better grasp the scope of each forum? \$\endgroup\$
    – donbonbon
    Commented Mar 3, 2021 at 1:42
  • \$\begingroup\$ @donbonbon I think you're alright. The code does correctly report divisors. \$\endgroup\$
    – FMc
    Commented Mar 3, 2021 at 1:44
  • \$\begingroup\$ You should make your question a bit clearer - from the phrasing it's hard to tell if you have a problem with your code or not. \$\endgroup\$
    – M-Chen-3
    Commented Mar 3, 2021 at 1:57
  • \$\begingroup\$ The english phrase is "prime number", not "primary number" \$\endgroup\$ Commented Sep 1, 2021 at 11:21

1 Answer 1

2
\$\begingroup\$

This program has 4 parts: (1) get raw user input; (2) validate the input and convert it to its proper data type (int in this case), halting program if invalid; (3) compute the divisors; and (4) report them to the user. However, your current code has those things jumbled up. While collecting raw input you try to convert it to int (which could fail) and then you turn to preparing some variables needed to compute the divisors and then you do a little bit of validation. Here's your code with virtually no changes other than reordering the existing lines so we can see the conceptual boundaries better. It's very easy to get confused when writing code, especially if the language is new to you; a disciplined, orderly approach to keeping different things clearly separated will help you reduce the confusion.

import sys

# Get user input.
num = input("Please select a number between: ")

# Convert and validate. Stop if invalid.
num = int(num)
if num < 4:
    print("The number you entered is a primary number")
    sys.exit()

# Compute divisors.
y = num/2
if not y==0:
    y=int(y-0.5)
list_range = list(range(2,y+2))
divisors_list = []
for i in list_range:
    if num%i ==0:
        divisors_list.append(i)

# Report.
if not divisors_list:
    print("The number you entered is a primary number")
else:
    print(divisors_list)

Regarding Python's number limit, don't worry about it. The only applicable limit for a program like this is your patience. Just decide and validate.

Perhaps there are different ways of defining a divisor, but my understanding is that every integer N above 1 has at least two divisors -- namely [1, N]. If you were to embrace that idea, your code would simplify because there would be no need for special handling for prime numbers. The code below starts looking for divisors at 1; switch it to 2 to stay with your current approach.

When computing divisors, each time you find one, you usually get a second for free. For example, if the input is 24, when you find 4 you also know that 6 is one too. Also, there's no need to check for divisors beyond the number's square root.

Regarding your question about the list_range needing y + 1 or y + 2, I suspect that's because Python ranges have a non-inclusive endpoint: for example, range(1, 4) is analogous to a list of [1, 2, 3]. The divisor_rng in the code below also has to use a +1.

Here's an illustration of those comments.

import sys
import math

# Some constants.
MIN = 1
MAX = 1000

# Get user input.
reply = input(f'Enter an integer in the range {MIN}-{MAX}: ')

# Convert and validate.
try:
    num = int(reply)
    if num not in range(MIN, MAX + 1):
        raise ValueError()
except ValueError:
    print(f'Invalid reply: {reply}')
    sys.exit()

# Compute divisors.
divisors = []
divisor_rng = range(1, int(math.sqrt(num)) + 1)
for d in divisor_rng:
    if num % d == 0:
        # Store divisor.
        divisors.append(d)
        # Store its mate, unless d is the square root.
        d2 = num // d
        if d2 != d:
            divisors.append(num // d)
divisors.sort()

# Prime check.
is_prime = num > 1 and divisors == [1, num]

# Report.
print(is_prime, divisors)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ thanks so much @FMc for the detailed explanations, remarks and tips! It a pleasure to learn. Your scripts answers all the needs. Your algorithm is of a higher level, which simplifies the workflow. I still go through this so I can carefully observe the details. I slightly modified the last print a Primary number statement only if True. # Report. print("The input number is a primary number" if is_prime==True else divisors). PS - I voted but as I have no credits, it doesn't count. Hope others will vote. \$\endgroup\$
    – donbonbon
    Commented Mar 3, 2021 at 11:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.