I am trying to solve this problem and despite wrapping my head around it I get stucked over and over and over.
I have a list made of one element [2] and given that and knowing that in order to get a prime number $N$ I have to check that it does not have any prime factor smaller or equal than $\sqrt{N}$, generate all prime numbers between 3 and 100
My code is the following and I will try to explain how I came up with it:
prime_numbers = [2]
for k in range(3,100): # k runs on all numbers to check them
for i in range (0,len(prime_numbers)): # i is the index of the elements in my list
if prime_numbers[i] <= sqrt(k): # first I need to check the sqrt condition
if k % prime_numbers[i] ==0: # check that element in list divides k
k+=1 # if so k++ and break the cicle
break
else:
i +=1 # otherwise go to the next elem of the list
else: #if the sqrt condition is not met I have found a prime number
value = k
prime_numbers.append(value)
When I run this code it gets into a loop with no exit, and I cannot individuate where the issue is. My best guess would be to correct the most indented else condition, but all the attempts I have done have resulted in failure. Thanks to everyone who is willing to partecipate.
This works:
prime_numbers = [2]
for prime_candidate in range(3, 100):
for known_prime in prime_numbers:
if known_prime <= sqrt(prime_candidate):
if prime_candidate % known_prime == 0:
break
else:
prime_numbers.append(prime_candidate)
Your problem mainly was, that i += 1 does not prevent prime_numbers.append to append again.
The for/else can be substituted by a separate flag to trigger all cases without a break happening earlier.
One way to get there is:
from math import sqrt
prime_numbers=[2]
for k in range(3,101):
prime=True
for i in range(2, int(sqrt(k))+2):
if k%i == 0:
prime=False
break
if prime:
prime_numbers.append(k)
print(prime_numbers)
#Output:
#[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Notes:
It's range(3,101) and not range(3,100) if assuming you want to check all numbers including 100, otherwise your last number checked will be 99.
Have a boolean variable prime; start by assuming the number is prime (prime=True)
sqrt(k) returns a float, while your range expects integers; as such - int(sqrt(k)). It's +2 to ensure your range 'to' value is never smaller than your 'from' value of 2.
if k%i == 0 (if you have a divisor) the number is not prime (prime=False) and break the for loop to move to the next k
This could be my "pythonic" by doing a list comprehension, but it may be easier for you to understand in the current format
Thanks to everyone who suggested a solution. Meanwhile I came up with one myself.
prime_numbers = [2]
for k in range(3,100):
for i in range (0,len(prime_numbers)):
if prime_numbers[i] <= sqrt(k):
if k % prime_numbers[i] ==0:
k+=1
break
else:
i +=1
else:
value = k
if(value > max(prime_numbers)):
prime_numbers.append(value)
Related
num_list = [422, 136, 524, 85, 96, 719, 85, 92, 10, 17, 312, 542, 87, 23, 86, 191, 116, 35, 173, 45, 149, 59, 84, 69, 113, 166]
count_odd = 0
list_sum = 0
i = 0
len_num_list = len(num_list)
while (count_odd < 5) and (i < len_num_list):
if num_list[i] % 2 != 0:
list_sum += num_list[i]
count_odd += 1
i += 1
print ("The numbers of odd numbers added are: {}".format(count_odd))
print ("The sum of the odd numbers added is: {}".format(list_sum))
Disclaimer: I'm a complete beginner and I find myself struggling most with while loops. For loops make sense to me.
The purpose of this code is to get the first 5 odd numbers in the list and find their sum.
I'm struggling to understand the purpose of the i variable and why they used num_list[i] % 2 != 0 (if i is set to 0 globally before the loop) to find the odd number. I'm guessing it mimics a for loop so it can iterate over the list but I'm not sure how it works. and the block of code beneath that
list_sum += num_list[i]
count_odd += 1
i += 1
is what I'm struggling with most. I don't understand what this block of code is meant to achieve and how it is working.
Your while loop continues to loop as long as the count_odd variable (number of odd numbers evaluated so far) is less than 5 and i (total number of numbers evaluated so far) is less than the length of the the list of numbers to evaluate.
Each time the code runs, if the number at the current index (i) is odd (has no remainder after being divided by 0) then the sum of the odd numbers (list_sum) is increased by the value of that number. Also the number of odd numbers evaluated (count_odd) is increase by 1 to show that another odd number is evaluated. But no matter whether or not it is an odd number, the index of the current number (i) is increased by 1 to show that the next number can be evaluated.
The code is preatty simple:
The condition on the wile mean that while he hasn't find 5 number, and while there are number in the first list, it has to work.
Than the condition:
if num_list[i] % 2 != 0:
The variabile is used to read each element of the list, while the variabile increase itself.
Then num % 2 return the
remainder of the division num/2. If it is not 0, It will be 1 for sure, so the number is odd.
The variabile increase itself because it has to read the next number in the list. If it isn't fine for you, try to learn something about list, tuples and so on
Hope will be useful
#it is the first initializing, essentially starting with 0
i = 0
len_num_list = len(num_list)
# you can reframe the while to:
# as long as you do not have 5 odd numbers AND you are not through the whole list, continue
while (count_odd < 5) and (i < len_num_list):
# num_list[i] means that you take the element with index i from the list
# since i is initialized with 0, at the first loop you take the first element (in python index starts at 0 not 1)
# SomeNumber % 2 means that if you divide the number by 2, what are the decimals.
# Only odd numbers will have decimals after division with 2, e.g. 4/2 = 2.0 but 3/2 = 1.5 so the rest would be 5
# and 5 is != 0
if num_list[i] % 2 != 0:
# number += other_number is essentially short for: number = number + other_number
# essentially you have e.g. numb = 100 and want to add 10, you can either do:
# numb = numb + 10 OR numb += 10
list_sum += num_list[i]
count_odd += 1
# since we are now through the first number of the list, which had index 0
# we now add 1 to the index and the while loop continues until the criterias stated after the "while" keyword are met.
i += 1
You can convert it to 'for' loop separating the condition checks. Indexing the num_list is unnecessary, it can be iterated over.
for n in num_list:
if n%2==0:
continue
if count_odd==5:
break
list_sum+= n
count_odd+= 1
The variable i is the variable that runs the while loop.
In the code initial i=0,and the use of (num_list[i] % 2 != 0) is to find the odd number.
Because any number divisible by 2 is a even number.Therefore in the code it is given when the number is divided by 2 it should be not equal to zero.
So it is a odd number.
Explanation of the code.
num_list[0]=422
422/2 is equal to zero.so it is not a odd number.
Then the i value is incriminating by 1
So i=i+1
i=0+1
i=1
now the value of i=1
num_list[1]=136
136/2=0 it is a even number.
Now i will again incriminating by 1
i=1+1
i=2
num_list[2]=524
524 is again even.
Then i again incriminating by 1
i=2+1
i=3
num_list[3]=85
85/2 is not zero
then list_sum=0+85
now list_sum=85
And i keeps on incriminating by 1 till 5 odd numbers is achieved.
Here is the same code with for loop
num_list = [422, 136, 524, 85, 96, 719, 85, 92, 10, 17, 312, 542, 87, 23, 86, 191, 116, 35, 173, 45, 149, 59, 84, 69, 113, 166]
countodd=0
sum=0
l=len(num_list)
for i in range(l):
if countodd<5 and num_list[i] % 2 != 0:
sum+=num_list[i]
countodd+=1
print("The numbers of odd numbers are",countodd)
print("The sum of the odd numbers is",sum)
I want to iterate through a list in python, detect prime numbers and then add them to another list.
primes = []
nprimes = []
for j in range(0, len(arr)):
num = arr[j] #my list with numbers to check
if num > 1:
for k in range(2, num):
if (num % k) == 0:
nprimes.append(num)
break
else:
primes.append(num)
else:
print(num, " can't be checked, because its smaller than 1")
I have the problem that numbers are always added which are not prime numbers. Also in general the code does not seem to work properly.
If num % k == 0 is false you can't say it's prime directly you have to wait the whole loop, so move the else with the for loop, it'll be executed of no break has been encountered which means it's prime
you may iterate directly on the values for num in arr
you can stop your loop at sqrt(num) you won't find a new divisor after that
for num in arr:
if num > 1:
for k in range(2, int(num ** 0.5) + 1):
if num % k == 0:
nprimes.append(num)
break
else:
primes.append(num)
else:
print(num, " can't be checked, because its smaller than 1")
For learning purposes, let's play with a different approach. First, I recommend you move your trial division code into its own predicate function is_prime(), that returns True or False, so it can be optimized independently of the rest of your code.
Then, I'm going to have itertools.groupby divide the list into prime and non-prime sequences that we splice onto the appropriate lists:
def is_prime(number):
if number < 2:
return False
if number % 2 == 0:
return number == 2
for divisor in range(3, int(number ** 0.5) + 1, 2):
if number % divisor == 0:
return False
return True
if __name__ == "__main__":
from random import sample
from itertools import groupby
array = sample(range(1, 100), 15)
primes = []
composites = []
for are_prime, numbers in groupby(array, is_prime):
if are_prime:
primes.extend(numbers)
else:
composites.extend(numbers)
print("Numbers:", array)
print("Primes:", primes)
print("Composites:", composites)
OUTPUT
% python3 test.py
Numbers: [91, 87, 10, 2, 11, 24, 21, 12, 46, 61, 15, 32, 57, 22, 5]
Primes: [2, 11, 61, 5]
Composites: [91, 87, 10, 24, 21, 12, 46, 15, 32, 57, 22]
%
There are lots of ways to go about this problem, many of them educational!
I wrote a code that outputs "Yes" when the input number is a perfect number, and outputs "No" when the number isn't. But when I input 6, it outputs "No". I have specified it to print "Yes" with if-else statements when the sum of divisors equal to the original input. Why is the output wrong?
n=int(input())
myList=[]
for i in range(1,n):
if n%i==0:
myList.append(n)
sum=0
for i in range(0,len(myList)):
sum=sum+myList[i]
if sum==n:
print("Yes")
else:
print("No")
Sorry for the confusion regarding my previous answer. The problem was that you were appending n instead of i in myList.append(n). Moreover, you could simply use sum to sum your list.
Your output was wrong because you were appending the number n and hence when you do sum=sum+myList[i], you were just adding n to the sum three times because instead of adding 1, 2, 3 to sum, you were adding 6, 6, 6.
n=int(input())
myList=[]
for i in range(1,n):
if n%i==0:
myList.append(i)
if sum(myList)==n:
print("Yes")
else:
print("No")
A one liner suggested by Matthias
print(('No', 'Yes')[sum(i for i in range(1, n) if not n % i) == n])
There is a cool one liner in comment section of this answer
other have already pointed out your mistake so here is how you can optimize your code a little bit.
greatest divisor of 6( =n) other than 6 is 3( = n//2) since we don't add number itself to factors_sum
while checking whether sum of factors equals to number( ie while finding perfect number),so we don't need to check whether any number greater than 3
is a factor of 6 or not.
# perfect nums example 6, 28, 496, and 8,128
n = 8128
stop = (n//2) +1 # stop is exclusive thats why extra 1
factors_sum = 0
for i in range(1,stop):
if n % i == 0:
factors_sum += i
print('Yes' if factors_sum == n else 'No') # Yes
'''
benchmark result( using timeit ran each five times)
for smaller value of n there is no significant difference but as the value of n becomes very large you can clear see the difference.
n = 33550336
1) stop = (n//2) +1
6.580396663 ( time in secs)
2) stop = n
12.635774489000001 ( time in secs)
'''
I know there are a number of ways to find the first 100 prime numbers but please help me in my approach. I find the value of count to be increasing but for some reason the while loop condition doesn't apply:
count = 0
while(count <= 20):
for i in range(2, 20):
for j in range(2, i):
if i < j:
print("The number",i,"is prime")
elif i % j == 0:
break
else:
print("The number",i,"is prime")
count = count + 1
print(count)
You could use Sieve of Eratosthenes to find the first n prime numbers:
def primes_upto(limit):
prime = [True] * limit
for n in range(2, limit):
if prime[n]:
yield n # n is a prime
for c in range(n*n, limit, n):
prime[c] = False # mark composites
To get the first 100 primes:
>>> list(primes_upto(542))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, ... ,
499, 503, 509, 521, 523, 541]
To find the first n primes, you could estimate n-th prime (to pass the upper bound as the limit) or use an infinite prime number generator and get as many numbers as you need e.g., using list(itertools.islice(gen, 100)).
This is a more simpler code. We have looped all the numbers from 0 to the number until we have printed 100 prime numbers.
n=0
i=0
while n<100:
i+=1
count=1
for j in range(2,i):
if i%j==0:
count=0
break
if count==1:
print(i,end=' ')
n+=1
If one is looking for a mix of efficiency and simple code, Numpy is worth a try. With some fancy indexing, the following code does the job of implementing the sieve of Eratosthenes.
import numpy as np
ns = np.array(range(2,N))
primes = []
last_prime=2
while last_prime:
primes.append(last_prime)
ns = ns[ns%last_prime != 0]
last_prime = ns[0] if len(ns) > 0 else None
print(primes[:100])
Then just adjust N until you do have 100 primes. A good first guess is something in the order of 100*log(100) ~ 460 (coming from the prime number theorem). This will give 88 primes. Increasing N to the value of 600, you will have enough primes.
prime_count=0
n=1
while(True):
count=0
i=2
n+=1
while(i<=n):
if(n==i):
print(n)
prime_count+=1
elif(n%i==0):
break
i+=1
if(prime_count==100):
break
I wrote a simple python module that returns the prime numbers up to a given N, using a bool flag is_prime as follows:
def generate_primes_up_to(M):
n = 2
primes = []
while n <= M:
is_prime = True
for p in primes:
if p**2 > n: break
if n % p == 0:
is_prime = False
break
if is_prime: primes.append(n)
n += 1
return primes
if __name__ == '__main__':
generate_primes_up_to(100)
which outputs:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Now, this is actually an ideal case for using the for-else construct, since the number n is prime only if no breaks occurred in the for loop. Thus, I changed the function into:
def generate_primes_up_to(M, flag='nonumpy'):
n = 2
primes = []
while n <= M:
for p in primes:
if p**2 > n: break
if n % p == 0: break
else: primes.append(n)
n += 1
return primes
but now the code outputs:
[2, 5, 27]
I don't understand why the if p**2 > n: break expression is interfering with the flow of the for-else clause. If I remove that line the code yields the right output again.
The condition causing the issue is -
if p**2 > n: break
Lets take an example - 7 , when we are checking if 7 is prime or not , we have already found out that - [2,3,5] are primes, the above condition breaks the for loop, when we check 3 as 3**2 = 9 which is greater than 7 .
Remove that condition and it works fine (Though its very slow).
In the original loop (without the for-else construct) , it worked because in that condition you just broke out of the loop, you did not change the flag is_prime .
With the for..else construct, what happens is that, the else part is only executed when we exit the loop without using break statement.
But in the case of the above condition , we use break statement and hence else part is not executed.
You can also use next:
def generate_primes_up_to(M):
n = 2
primes = []
while n <= M:
if next((False for p in primes if not n % p), True):
primes.append(n)
n += 1
return primes