Create a divisors list and indetify primary numbers - python

I tackled a beginners' exercise:
"asks the user for a number and then prints out a list of all the divisors of that number."
NB - I reviewed similar questions in this forum but decided to post the following as they didn't address
my needs.
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 the 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)
Thanks for your consideration.

Related

Is there a way to remove elements of a range without creating an array/list of included/excluded values in a for loop? (Python)

I am using Python 3.9 and I have created a very simple program to identify whether or not a number is prime when given in integer input.
My code itself works, but it can be very slow even given large numbers
(50 million+). I am using a for loop to check if any numbers between 1
and the input(x) are evenly divisible by the input(x). I want to exclude all
even numbers and multiples of 5 from the range since no primes are even or end in 5.
Is there a way to explicitly remove all evens and multiples of 5 without creating an array of excluded/included values like I did?
Here is a snippet code and time of the program for reference:
#program with filtering out evens and multiples of 5
print("Is your number prime?? Well... let's check!")
#'x' can actually be any input but I am using 60000049 as a constant value for the sake of timing.
x=60000049
factorlist=[]
#Included_values is an array in which all elements are divided into 'x' after it excluded all evens and multiples of 5.
included_values=[]
for i in range (1,x+1):
if i%2!=0 or i%5!=0:
included_values.append(i)
for i in range(1,len(included_values)):
if x%included_values[i]==0:
factorlist.append(i)
if len(factorlist)>2:
print("Oh no! It appears like the number you have entered is not prime. Try again!")
print('The factors to your number are:',factorlist)
if len(factorlist)<=2:
print('Yay! You have chosen a prime number!!')
Yay! You have chosen a prime number!!
~17.96522307395935
The first version of my program is much slower than the one that does not exclude any values:
#My program without filtering out evens or multiples of 5.
#'x' can actually be any number but I am using 60000049 for the sake of timing.
print("Is your number prime?? Well... let's check!")
x=60000049
factorlist=[]
for i in range (1,x+1):
if x%i==0:
factorlist.append(i)
if len(factorlist)>2:
print("Oh no! It appears like the number you have entered is not prime. Try again!")
print('The factors to your number are:',factorlist)
if len(factorlist)==2:
print('Yay! You have chosen a prime number!!')
Yay! You have chosen a prime number!!
~6.147368431091309
As you can see, my second program is much faster because it does not cycle through the range to get an array of excluded values first.
If there is a way to exclude even values and multiples of 5 first without cycling through the entire range (1,x+1), it would make my program much faster. If this is possible, let me know!
To answer your question, you could of course have an if inside the for to skip values. Well you already do, but using a list. I mean you could just have condition there.
Otherwise, a list comprehension is a more efficient way to create a new list than calling append in a loop like you do:
included_values = [i for i in range(1, x+1)
if i%2 !=0 or i%5 != 0]
I did that change in https://replit.com/#ToniAlatalo/DapperSeagreenMacro#main.py
Also the other for I think you could convert from:
for i in range(1,len(included_values)):
to:
for value in included_values:
Which might be a tiny bit faster but probably not much different.
If you want to exclude multiples of 2 or 5 only, you can try using list comprehension included_values = [k for k in range(1,x+1) if k%2!=0 and k%5!=0]
If you want your program to be "more efficient", I suggest checking to the square root of x only. included_values = [k for k in range(1, math.ceil(math.sqrt(x)))]
But, your code is not that efficient.
x = int(input("Is your number prime?? Well... let's check! Type your number here:" ))
from math import sqrt, ceil
if x ==2:
print('Your number is a prime')
elif x < 2:
print("Your number isn't prime")
else:
print('Your number is not prime' if any([k for k in range(2,ceil(sqrt(x))) if x%k==0]) else 'Your number is a prime')
Breakdown of code:
x = int(input("Is your number prime?? Well... let's check! Type your number here:" )) This will get your "x", but if x is predetermined, you can skip this.
from math import sqrt,ceil This will import sqrt and ceil from the math library
if x ==2:
print('Your number is a prime')
elif x < 2:
print("Your number isn't prime")
Check if number is smaller than 3, if it's 2, print the number is prime, else print that it's not prime
print('Your number is not prime' if any([k for k in range(1,ceil(sqrt(x))) if x%k==0]) else 'Your number is a prime') Check if any([k for k in range(2,ceil(sqrt(x))) if x%k==0]) is true, if it's true, number isn't a prime, but if it's false, number is a prime(Since x isn't divisible by any number in range of 2 to square root of x).
Granted, this is not perfect but will be fast enough for normal uses.
The i%2!=0 or i%5!=0 condition will only exclude multiples of 10 from your included_values list. Also, your next loop adds an index (instead of a factor) to the factorlist so it doesn't print the right factors even for the ones it does find (try it with x=15) it will also find that 10 is prime.
All this being said, if you want to list all the factors of the number (when it is not prime), you can't really skip any divisors.
To make it go faster, what you could do is check for factors up to the square root of x and add each divisor along with the resulting quotient for every match you find.
x = 60000049
factors = []
for f in range(1,int(x**0.5)+1):
if x%f == 0:
factors.extend({x//f,f})
print(factors) # [60000049, 1]
By skipping multiples of 2 and 5, appart from skipping factors and producing a wrong result, you'd only reduce the number of tests by 60% but stopping at the square root will eliminate 99.98% of them (for x=60000049).

Have some doubts in this python program (PRIME or NOT)

So, I wrote a code to find if a number is PRIME or NOT...
I wrote it in 2 different ways, they are almost same but I just had a doubt. So here it is:
1st code:
num = int(input("Enter the number: "))
lim = num//2 + 1
for i in range(2,lim):
if num % i == 0:
print("Prime!")
break
else:
print("Not Prime!")
2nd Code:
num = int(input("Enter the number: "))
for i in range(2,num):
if num % i == 0:
print("Prime!")
break
else:
print("Not Prime!")
The 1st code takes the input(num) and according to the input sets a limit(which is the half number + 1)
and then checks if the num is divisible by all the numbers in range (2 to lim)
The second one is same but instead of setting a limit it just checks all numbers lower than the input, which means it has to do a little more work...
Now both of these are almost same, the only difference is I saved a line in 2nd one and output efficiency is also better!
Which code would you want me to prefer/
also if this code has any problems, pointing them out would be helpful!
Thanks :)
Explanation
The most important piece of iteration, namely determining whether a number is prime or not, is to keep track of it. Without this process and in the OP's program, a variable is not used to handle this, meaning that he checks whether a number is or isn't prime every single time and concludes at that point. He also uses an else statement which is syntactically incorrect.
To prevent this, we can use a variable to keep track of this. Let's call it isprime. We need to assume that a number will always be a prime unless otherwise said. This can be achieved by setting isprime to default be True, and setting it to be False when we conclude that it is not a prime, because is has a divisor. Finally, we can check this variable at the end and determine whether that number is a prime or not, because it would be set to False if not, or left as True if it is.
Another observation made is that the limit for determining primes can be reduced down to sqrt(n). This is because we do not need to find every factor if it exists, just its lowest corresponding factor. Let's look at an example:
Factors of 24: 2, 3, 4, 6, 8, 12
We can stop checking for the factors right here:
2, 3, 4 | 6, 8, 12, 24
This is because if a number has a factor (such as greater than the square root), it will have a corresponding factor less than the square root. As a result, we can set our limit to be sqrt(n), just for peace of mind + a time complexity of O(sqrt(n)) v. O(n).
As an extra note, sqrt is not inbuilt into Python. You will have to import it from the math library using:
from math import sqrt
Final Code
# Setup
num = int(input("Enter the number: "))
lim = sqrt(num)
isprime = True
# Loop & check
for i in range(2,lim):
if num % i == 0:
isprime = False
break
# Results
if isprime:
print("Prime!")
else:
print("Not prime!")
The logic of the solution is wrong. You gave to switch the "Prime" and "Not Prime" tags. Like follows;
num = int(input("Enter the number: "))
lim = num//2 + 1
for i in range(2,lim):
if num % i == 0:
print("Not Prime!")
break
else:
print("Prime!")
The solution 1 is more efficient because you do not need to do extra
computation to check num//2 + 1. So it is preferable.

Codechef practice problem - Chef and demonetisation

THE QUESTION IS:
In a country called Chef Land, there was a lot of monetary fraud, so Chefu, the head of the country, decided to choose new denominations of the local currency ― all even-valued coins up to an integer N should exist. After a few days, a citizen complained that there was no way to create an odd value, so Chefu decided that he should also introduce coins with value 1. Formally, you are given an integer N; for v=1 and each even positive integer v≤N, coins with value v exist.
You are also given an integer S. To handle transactions quickly, find the minimum number of coins needed to pay a price S.
Input
The first line of the input contains a single integer T denoting the number of test cases. The description of T test cases follows.
The first and only line of each test case contains two space-separated integers S and N.
Output
For each test case, print a single line containing one integer ― the minimum number of coins.
Constraints
1≤T≤10,000
1≤S≤109
2≤N≤109
N is even
Subtasks
Subtask #1 (100 points): original constraints
Example Input
4
2 2
1 14
30 10
31 4
Example Output
1
1
3
9
MY SOLUTION IS
n=int(input())
res=[]
for i in range(1,n+1):
S,N = [int(x) for x in input().split()]
rem=S%N
if rem == 0:
res.append(int(S/N))
else:
if rem==1:
res.append(int(S/N+1))
else:
if rem/2 == 0:
res.append(int(S/N+1))
else:
res.append(int(S/N+2))
for j in res:
print(j)
Its showing my answer is wrong. Can anyone help me ?
Actually, I was not considering the case of getting 1 as a remainder i.e. in case of numbers like 31,41,51 etc. Which was causing me trouble. Well, after considering the above condition and some little manipulation it finally worked. Hope you understand it. And thank you for your responses.
n=int(input())
res=[]
for i in range(n):
S,N = [int(x) for x in input().split()]
rem=S%N
if S==1:
res.append(int(1))
elif(rem == 0):
res.append(int(S/N))
else:
if(rem%2==0 or rem==1):
res.append(int(S/N+1))
else:
res.append(int(S/N+2))
for j in res:
print(j)

How to fix error in python code, which will not run over large numbers?

I have written a recursive Python program which I have attached below, which prints out the palindromic primes in an interval. I cannot use loops.
palindromic_primes.py:
import sys
sys.setrecursionlimit(30000)
# this function places all the numbers between the start and end points into
# a list and determines whether they are prime numbers by seeing if they have
# a remainder of 0 when divided, else numbers that dont have remainder of zero
# are stored.
def check_prime(num_list, number):
if num_list == []:
print(number)
else:
num = num_list[0]
if number % num == 0:
pass
else:
num_list.pop(0)
check_prime(num_list, number)
# this checks whether the numbers in the interval are palindromes by comparing
# the first 'letter' to the last 'letter' for each number and seeing whether
# they match.
def check_palindrome(nums):
nums1 = nums[::-1]
if nums1 == nums:
new_list = list(range(2, int(nums)))
check_prime(new_list, int(nums))
# this takes both functions and only stores the numbers that match in both
# functions.
def check_done(lists):
# takes numbers not stored (so the numbers that are palindromes and primes)
if lists != []:
check_palindrome(str(lists[0]))
lists.pop(0)
check_done(lists)
start_int = int(sys.argv[1])
ending_int = int(sys.argv[2])
palindromic_primes = print("The palindromic primes are:")
# the list will analyse all numbers from the start point till the end point
list1 = list(range(start_int, ending_int+1))
check_done(list1)
I have an error that I am not sure how to fix as the code works fine until I enter an input such as starting point 10000 and ending point 20000, as it gives me a segmentation fault.
when entered to wing IDE, this is what given back [evaluate palindromeprimes.py] Enter the starting point N: 10000 Enter the ending point M: 20000 The palindromic primes are:aborted (disconnected). when I enter it into my school marking system I get this: Your program produced: Enter the starting point N: Enter the ending point M: Segmentation fault Input supplied to your program: 10000 20000 Differences in the files are as follows: 1,29c1,3
Apparently, i need to make my code more efficient, but I'm not sure how to go about this. I saw told to think of the properties of prime numbers and factors, such as the fact that prime numbers are all odd. Factors occur in pairs, so if the number has no factors before some 'midpoint' then it wont have any after that 'midpoint' either
If your problem is one of computational efficiency then it's not necessarily a Python question
These facts should help to reduce the recursion depth:
There are many more palindromic numbers than primes - therefore check
your number is a prime BEFORE you check it's a palindrome
To check a number is not a prime you only need to check that the
modulus is zero when you divide by number up to (and including) the square root of the candidate
You only need to check that the number modulus is zero when you
divide by prime numbers (if it's divisible by 9, 15, 21 ..., it is divisible by 3)

Incorrect max and min in Python code

When I try to run this code, I get incorrect maximums and minimums. Could anyone tell me how I can fix it? I am not allowed to use 'max' and 'min'.
UPDATE: I have updated the code and it still doesn't work properly.
UPDATE 2: The code works now! Thank you so much guys!
minimum=float('inf')
maximum=None
count=0
total=0
number=input ("Please enter the amount of numbers you wish to categorize: ")
while True:
num = input("Enter a number: ")
count+=1
total+=num
if num is None or num < minimum:
minimum = num
if num is None or num > maximum:
maximum = num
if count == number:
break
print "The average of your numbers is ", round ((total / count),2),"."
print 'The largest number is:', maximum,"."
print 'The smallest number is:', minimum,"."
Your initial values and conditions for minimum and maximum are incorrect.
minimum = None
maximum = None
...
if minimum is None or num < minimum:
minimum = num
if maximum is None or num > maximum:
maximum = num
...
You could also fix this by checking if count equals 1 instead of identity to None.
In addition to what Ignacio said, you're breaking out of your loop too early. You want to process the last number you enter before breaking, so move the if count == number: break block after the min/max setting blocks.
Note that you can set a number to infinity or negative infinity by
maximum=float('-inf')
minimum=float('inf')
print minimum, maximum
This might be useful for your homework ;)
Ignacio's answer would be preferable if you want to consider the case that the user enters 0 for number (since None would be a more seasonable maximum of no numbers than -inf).
Edit:
Remark to mVChr's correct finding:
Instead of using a while True loop with a break why not writing
while count < number:
or even use a for loop:
for count in xrange(number):
As this is homework you're supposed to learn. Here are some ideas how to solve the problem:
One error is that you're initializing maximum and minimum to 0 on program startup. if you only type in positiv numbers minimum will stay at 0 but won't be the real minimum. To solve this case you should look into lists or initialize both variables to some values that uniquely identifies an invalid initial value that won't leak into your calculation (I suggest None). On the first iteration set both minimum and maximum to the first entered value.
After modfifications: You are comparing strings since raw_input returns strings, not numbers. You have to convert those strings into integer values using int, for example int(raw_input( ... )). Additionally you had a badly indented break of which I fixed the indent.
Other idea: Since you're not allowed to use min and max you might just use
tmp=sorted([int(raw_input('Number: ')) for x in xrange(number)])
minimum, maximum = tmp[0], tmp[-1]
but I guess this defeats your assignment :)
The solution that requires the least treatment of special values, would be to initialize both variables to +/- infinity.
minimum=float("-inf")
maximum=float("inf")

Categories

Resources