Ok, so I admittedly am kind of a noob, and I've been going through a course on udemy for programming. The problem is asking to write a function that finds all the prime numbers up to the number given. So I started writing the following code to extract the numbers that are not even, as well as the numbers not evenly divisible by 3 just to start:
def count_primes(num):
num_list5 = []
for i in range(num + 1):
print(i)
if i % 2 != 0 or i % 3 != 0:
num_list5.append(i)
return num_list5
When I call the function with a number of 100 like:
count_primes(100)
In the output, I get the num_list5 showing all the numbers in the range except for 6 and multiples of 6:
[1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13, 14 ...]
Its like the if statement is doing an AND operation here... because 6 would be divisible by 2 AND 3. Is this a bug or something? Or am I not understanding and/or operations correctly?
What's weird is that it was working at one point and after making a change and reverting it, it started doing this...
I'm using VSCode and Jupyter notebooks and tried both Python 3.8.5 64-bit and 3.9.4 64-bit on Ubuntu 20.04
i % 2 != 0 or i % 3 != 0 is equal to not (i % 2 == 0 and i % 3 == 0) (De Morgan's laws)
It should be i % 2 != 0 and i % 3 != 0
If you are looking to generate all primes less than num, you should loop over all numbers j less than i and check if i%j is zero rather than just 2 and 3.
def count_primes(num):
num_list5 = []
for i in range(2, num + 1): # start at 2 because 1 and zero are not primes
print(i)
for j in range(2, i):
if i%j == 0:
break
else:
num_list5.append(i)
return num_list5
if __name__ == "__main__":
n = 100
print(count_primes(n))
Note that using Sieve of Eratosthenes method, this can be done more efficiently:
import math
def count_primes_sieve(num):
num_list5 = [False, False] + [True]*(num - 1)
for i in range(2, math.ceil(math.sqrt(num)) + 1):
if num_list5[i]:
j = i * i
while j < len(num_list5):
num_list5[j] = False
j += i
return [i for i, p in enumerate(num_list5) if p]
if __name__ == "__main__":
n = 100
print(count_primes_sieve(n))
We know some facts about prime numbers which you can use in your program. Negative numbers, 0 and 1 are not prime. 2 is the only even prime. A prime number only has itself and 1 as factors. From multiplication we know that if a x b = c then one of a, b is <= sqrt(c). That last fact helps us cut down the number of trial divisors we have to test. We can test for a prime by looking for a number that divides the target but is not the target itself or 1. If we find such a number then the target is not prime.
Here is some pseudocode to help:
function isPrime(num)
// 1, 0, negatives not prime.
if (num < 2)
return false
end if
// 2 is the only even prime.
if (num MOD 2 = 0)
return (num = 2)
end if
// Try odd factors up to square root.
limit <- 1 + sqrt(num)
for (test <- 3; test < limit; test <- test + 2)
if (num MOD test = 0)
// Not prime, we have found a factor.
return false
end if
end for
// If we get this far then num is prime.
return true
end function
After figuring out the propositional math and de Morgan's Law as someone pointed out, I was able to come up with a pretty simple solution using or and mod operators and only goes through a the sequence once:
def count_primes(num):
num_list5 = []
for i in range(2, num + 1):
if i == 2 or i == 3 or i == 5 or i == 7:
num_list5.append(i)
if not (i % 2 == 0 or i % 3 == 0 or i % 5 == 0 or i % 7 == 0):
num_list5.append(i)
return num_list5
print(count_primes(100))
Related
I need to create a program that takes user input n and the finds the first n numbers that aren't divisible by any other prime numbers except 2, 3, and 5. This is what I've got so far:
def is_divisible(i):
for k in range(7, i):
if is_prime(k) == 1 and i % k == 0:
return 1
else:
return 0
def is_prime(k):
for j in range(2, k):
if k % j == 0:
return 0
else:
return 1
while True:
while True:
while True:
try:
n = input("How many numbers do you want to find: ")
n = n.replace(" ", "")
n = int(n)
break
except:
print("Input only natural numbers")
continue
if n == 0:
print("Input only natural numbers")
continue
else:
break
count = 0
i = 0
while count < n:
if i % 2 == 0 and i % 3 == 0 and i % 5 == 0 and is_divisible(i) == 0:
print(i)
count += 1
i += 1
else:
i += 1
repeat = input("To repeat press (1), to end press anything else: ")
if str(repeat) == "1":
continue
else:
print("Bye!")
break
If asked to find 10 numbers the program outputs:
30
60
90
120
150
180
240
270
300
330
The program didn't print 210 (which is divisible by 7) so the algorithm seems, at least, partly correct, but 330 is printed (which is divisible by 11) and I can't figure out why. If I manually change i to 330 and k to 11, the is_prime function correctly finds that 11 is a prime number, but the is_divisible function still returns 0. I can't figure out what's wrong. Any help will be greatly appreciated!
Thanks!
First, you need to fix your is_prime like #Barmar mentions above
Note, this can be optimized in multiple ways, the simplest of which is to only check for j in range(2, int(math.sqrt(k))+1) because a number k won't have any prime factors greater than sqrt(k). Also, we can memorize all the prime numbers found so far, so that if the same number is checked multiple times, subsequent checks are much faster. You can use better algorithms to check if a number is prime, but this should suffice for our purposes.
import math
# A set to remember prime numbers
primes = set()
def is_prime(k):
if k == 1: return False # 1 is not prime
if k in primes: return True # Check remembered prime numbers
# Check all numbers in the closed interval [2, sqrt(k)]
for j in range(2, int(math.sqrt(k))+1):
if k % j == 0:
return False
# Prime number, so remember it
primes.add(k)
return True
The first n numbers that aren't divisible by any prime numbers other than 2, 3, and 5
Since your number needs to be divisible by 2, 3, and 5, you don't need to look at all numbers as you do currently. Just look at multiples of 2 * 3 * 5, i.e. multiples of 30, since those are the only numbers that are going to be multiples of 2, 3, and 5.
So now your problem becomes: "Print 30 * i, where i is not a multiple of a prime number other than 2, 3, and 5. i.e., you need to get the prime factors of i, and check that this set contains only 2, 3, and 5.
There are a number of ways to get the prime factors of a number. Here's a simple one:
def prime_factors(k):
# If k is prime, it is its only prime factor
if is_prime(k):
return {k}
factors = set()
# If divisible by 2, add 2 as a prime factor
if k % 2 == 0:
factors.add(2)
# Check all odd numbers in the closed interval [3, k//2]
for i in range(3, k//2+1, 2):
if k % i == 0 and is_prime(i):
factors.add(i)
return factors
Now that we've defined our helper functions, we just need to call them:
n = 10
i = 1
count = 0
while count < n:
factors = prime_factors(i)
# If we remove {2, 3, 5} from factors, do we get an empty set?
if not factors.difference({2, 3, 5}):
print(2 * 3 * 5 * i)
count += 1
i += 1
Which prints:
30
60
90
120
150
180
240
270
300
360
If you are indeed looking for regular numbers as #Mark and #Kelly suggest in their comments, then you simply skip the multiplication by 2 * 3 * 5:
n = 10
i = 1
count = 0
while count < n:
factors = prime_factors(i)
# If we remove {2, 3, 5} from factors, do we get an empty set?
if not factors.difference({2, 3, 5}):
print(i)
count += 1
i += 1
gives:
1
2
3
4
5
6
8
9
10
12
Here's a bit of code that looks for values that have other factors besides 2,3,5. If there are other factors in there, they must be other prime values because we remove the prime factors 2,3,5 from the number.
primes = [ 2, 3, 5]
count = 10
answers = []
value = 2
while len(answers) < count:
test_value = value
for prime in primes:
while test_value % prime == 0:
test_value //= prime
if test_value == 1:
answers.append(value)
value += 1
print(answers)
Ok, the performance discussion from #Kelly Bundy bothered me - so I added a different approach - but it's got problems.
import sys
primes = [ 2, 3, 5]
count = int(sys.argv[1])
base = round( count ** (1./3.) )
powers = [0] * len(primes)
answers = []
while True:
value = 1
for n in range(len(primes)):
value *= primes[n] ** powers[n]
answers.append(value)
for n in range(len(powers)):
powers[n] += 1
if powers[n] != base:
break
powers[n] = 0
else:
break
for x in sorted(answers):
print(x)
Basically, all of the numbers we want to find are of the form: 2**x * 3**y * 5**z . And so, if we just vary x,y,and z, we can compute all of the qualifying numbers.
The the problem boils down to, which values of x,y, and z are valid. To be honest, I haven't figured that out. All I do is come up with count combinations of x,y,z where I just count values (using some base counting system). For instance, if I need to come up with 1,000 combinations, I just produce all of the combinations of x,y,z where the values are between 0 and 9. And so i get the values (000 - 999). And this produces the values: 2**0 * 3**0 * 5**0 all the way up to 2**9 * 3**9 * 5**9. Now, I'm definitely missing some values. The 1,000 numbers I come up with are NOT the first 1,000 numbers.
Your is_divisible method basically only checks 7 and then returns either 1 or 0.
You want to check all the numbers in the range.
def is_divisible(i):
for k in range(7, i):
if is_prime(k) == 1 and i % k == 0:
return 1
return 0
Your is_prime method suffers from this issue as well:
def is_prime(k):
for j in range(2, k):
if k % j == 0:
return 0
return 1
Fixing these issues, however, is going make this algorithm EXTREMELY slow so you will need to consider some strategies that will make it faster.
Caching the numbers that you have already checked for primeness would be a start.
Here's my code for printing the sum of prime divisors of each number between 18 to 25. But it is only printing 5.
For example:
18 has prime factors 2, 3 hence sum = 5,
19 is prime, hence sum of factors = 0,
20 has prime factors 2 and 5, hence sum = 7,
21 has prime factors 3 and 7, hence sum = 10,
22 has prime factors 2 and 11, hence sum = 13,
23 is prime. hence sum = 0,
24 has prime factors 2 and 3, hence sum = 5,
25 has prime factor 5, hence sum = 5
Therefore, it should print [5,0,7,10,13,0,5,5]
I believe I should use break statement but i tried it didn't work. As I am beginner in python, any kind of help much appreciated.
def isPrime(n):
i = 2
while i * i <= n:
# n has a factor, hence not a prime
if (n % i == 0):
return False
i += 1
# we reach here if n has no factors
# and hence n is a prime number
return True
def summ(l, r):
summ = 0
arrayofdivisors = []
arrayofsum = []
# iterate from lower to upper
for i in range(l, r + 1) :
# if i is prime, it has no factors
if (isPrime(i)) :
continue
for j in range(2, i):
# check if j is a prime factor of i
if (i % j == 0 and isPrime(j)) :
arrayofdivisors.append(j)
if(len(arrayofdivisors)>1):
ans = sum(arrayofdivisors)
arrayofsum.append(ans)
return arrayofsum
# Driver code
if __name__ == "__main__":
l = 18
r = 25
print(summ(l, r))
Try this
def isPrime(n) :
if (n <= 1) :
return False
if (n <= 3) :
return True
if (n % 2 == 0 or n % 3 == 0) :
return False
i = 5
while(i * i <= n) :
if (n % i == 0 or n % (i + 2) == 0) :
return False
i = i + 6
return True
def Sum(N):
SumOfPrimeDivisors = [0] * (N + 1)
for i in range(2, N + 1) :
if (SumOfPrimeDivisors[i] == 0) :
for j in range(i, N + 1, i) :
SumOfPrimeDivisors[j] += i
return SumOfPrimeDivisors[N]
arr=[]
for i in range(18,26):
if isPrime(i):
arr.append(0)
else:
arr.append(Sum(i))
print(arr)
It's almost impossible to tell because of the way you've formatted things, but the problem here is that your "return" statement is indented one position too far. Thus, you return at the end of the first loop, before it has a chance to check anything else. Un-indent the return arrayofsum and it should work.
Then, you are initializing arrayofdivisors outside the main loop, so it just kept getting larger and larger. Then, you weren't adding 0 to the list for prime numbers, as your spec required.
Note that if statements in Python do not need parentheses, like they do in C.
def isPrime(n):
i = 2
while i * i <= n:
# n has a factor, hence not a prime
if n % i == 0:
print(n,'not prime')
return False
i += 1
# we reach here if n has no factors
# and hence n is a prime number
print(n,"prime")
return True
def summ(l, r):
# iterate from lower to upper
arrayofsum = []
for i in range(l, r + 1) :
arrayofdivisors = []
# if i is prime, it has no factors
if isPrime(i):
arrayofsum.append(0)
continue
for j in range(2, i):
# check if j is a prime factor of i
if i % j == 0 and isPrime(j):
arrayofdivisors.append(j)
arrayofsum.append( sum(arrayofdivisors) )
return arrayofsum
# Driver code
if __name__ == "__main__":
l = 18
r = 25
print(summ(l, r))
I am struggling to determine how to get an answer for the following problem.
What I am attempting to do is take x in a list of numbers (eg 1 to 2,000,000) and divide by a certain range of numbers, y, for example 1 to 20 and return my x value only if it is divisible by all the numbers in the second list.
I have tried the following but when I check the list I am trying to append to it returns a blank
divisibles = []
def isdivisible(x):
for i in range(1,21):
if x%i!=0:
return False
return True
for x in range(1,2000001):
if isdivisible(x):
divisibles.append(x)
Please could someone help me.
I am generally struggling with testing for an all case in general.
Thanks.
I believe this might be because no number from 1 to 2000000 is divisible by all numbers from 1 to 20.
Try calculating the LCM for those numbers first.
Your code is fine, but the result is indeed an empty list. There are several primes in range(1, 21):
2, 3, 5, 7, 11, 13, 17, 19
So, the number that will pass your check must be divisible by all of them, so it'll be at least the product of these primes:
>>> 2*3*5*7*11*13*17*19
9,699,690
You're checking up to 2 million, which isn't nearly enough.
Think that it is not possible to find a number in this range that satisfies this function because there are prime numbers such as 1,2,3,5,7 that can only be divided between them and 1. So maybe this function works, but no number fits this divisible range.
First: to check if a number is divisible by all numbers from 1 to 20 you don't need to test all dividers, it is enough to test their Least Common Multiple, which in this case is 232792560. Second: this number is greater than 2000000, so there aren't any numbers in 1 to 2000000 range satisfying your condition.
Optimized solution:
primes = []
temporary_dividor_check = []
max_nominator_divisible = []
max_div = 1
min_denominator = 1
max_denominator = 21
min_nominator = 1
max_nominator = 20000000
counter = 1
nominators = list(range(min_nominator,max_nominator+1))
denominators = range(min_denominator,max_denominator+1)
def generate_prime_numbers(start,end):
global primes
for val in range(start, end + 1):
if val > 1:
for n in range(2, val//2 + 2):
if (val % n) == 0:
break
else:
if n == val//2 + 1:
primes.append(val)
generate_prime_numbers(min_denominator,max_denominator+1)
for prime in primes:
max_div = max_div*prime
while counter * max_div < max_nominator:
max_nominator_divisible.append(counter*max_div)
counter += 1
for divisible1 in max_nominator_divisible:
if divisible1 % max_div == 0:
for denominator in denominators:
divisible = divisible % denominator
if divisible == 0:
temporary_dividor_check.append(denominator)
if temporary_dividor_check == list(denominators):
print("{} is divisible by all denominators".format(divisible1))
temporary_dividor_check = []
The simplest but super CPU-hungry (wasteful)
nominators = range(1,20000000)
denominators = range(1,21)
temporary_dividor_check = []
for nominator in nominators:
for denominator in denominators:
divisible = nominator%denominator
if divisible == 0:
temporary_dividor_check.append(denominator)
if temporary_dividor_check == list(denominators):
print("{} is divisible by all denominators".format(nominator))
temporary_dividor_check = []
Again im stuck on a problem..
I wanted to create a function that puts out all prim factors of a given number.
It was pretty much finished but it wouldnt put out correct factors for numbers which have the same prim factor more than once, for example: 20 - 5, 2, 2
So i added a while loop which checked if the product of all factors equals the number i put in.
Thanks for any help :)
prime_numbers = []
def prime_gen(upper_limit):
for i in range(2, upper_limit):
for j in range(2, i):
if i % j == 0:
break
else:
prime_numbers.append(i)
return prime_numbers
def list_product(list):
sum = 1
for i in list:
sum *= i
return sum
prime_factors = []
def prime_factor(number):
while list_product(prime_factors) != number: #without the while it checked every factor only once
for i in reversed(prime_gen(number)):
while number % i != 0:
break
else:
if i != 1:
number /= i
prime_factors.append(i)
continue
else:
break
prime_factor(20)
print (prime_factors)
Just use a for loop, getting you list of primes from prime_gen:
def prime_gen(upper_limit):
prime_numbers = [2]
for i in range(3, upper_limit,2):
for j in range(2, i):
if i % j == 0:
break
else:
prime_numbers.append(i)
return prime_numbers
def prime_factors(n):
p_f = []
for prime in prime_gen(n):
# while n is divisible keep adding the prime
while n % prime == 0:
p_f.append(prime)
# update n by dividing by the prime
n //= prime
if n > 1:
p_f.append(n)
return p_f
print(prime_factors(40))
[2, 2, 2, 5] # -> 2*2*2*5
If you take 40 as an example:
(40, 2) # first prime 2, 40 is divisible by 2
(20, 2) # 40 //= 2 == 20, 20 is divisible by 2
(10, 2) # 20 //= 2 == 10, 10 is divisible by 2
(5, 5) # 10 //=2 == 5, 5 is not evenly divisible by 2 or 3 so we get 5
If you want a fast way to generate the primes, you can use a sieve:
from math import sqrt
def sieve_of_eratosthenes(n):
primes = range(3, n + 1, 2) # primes above 2 must be odd so start at three and increase by 2
for base in xrange(len(primes)):
if primes[base] is None:
continue
if primes[base] >= sqrt(n): # stop at sqrt of n
break
for i in xrange(base + (base + 1) * primes[base], len(primes), primes[base]):
primes[i] = None
primes.insert(0,2)
sieve=filter(None, primes)
return sieve
The error you are getting (TypeError: 'float' object cannot be interpreted as an integer) is ultimately caused by this statement:
number /= i
In Python 3, the result of /= is always a float. To perform integer division (so that number remains an integer), use:
number //= i
After fixing this, you'll find that you have a logic error that causes an infinite loop.
I'm trying to find the largest prime factor of the number x, Python gives me the error that the range is too large. I've tried using x range but I get an OverflowError: Python int too large to convert to C long
x = 600851475143
maxPrime = 0
for i in range(x):
isItPrime = True
if (x%i == 0):
for prime in range(2,i-1):
if (i%prime == 0):
isItPrime = False
if (isItPrime == True):
if (i > maxPrime):
maxPrime = i;
print maxPrime
In old (2.x) versions of Python, xrange can only handle Python 2.x ints, which are bound by the native long integer size of your platform. Additionally, range allocates a list with all numbers beforehand on Python 2.x, and is therefore unsuitable for large arguments.
You can either switch to 3.x (recommended), or a platform where long int (in C) is 64 bit long, or use the following drop-in:
import itertools
range = lambda stop: iter(itertools.count().next, stop)
Equivalently, in a plain form:
def range(stop):
i = 0
while i < stop:
yield i
i += 1
This is what I would do:
def prime_factors(x):
factors = []
while x % 2 == 0:
factors.append(2)
x /= 2
i = 3
while i * i <= x:
while x % i == 0:
x /= i
factors.append(i)
i += 2
if x > 1:
factors.append(x)
return factors
>>> prime_factors(600851475143)
[71, 839, 1471, 6857]
It's pretty fast and I think it's right. It's pretty simple to take the max of the factors found.
2017-11-08
Returning to this 5 years later, I would use yield and yield from plus faster counting over the prime range:
def prime_factors(x):
def diver(x, i):
j = 0
while x % i == 0:
x //= i
j += 1
return x, [i] * j
for i in [2, 3]:
x, vals = diver(x, i)
yield from vals
i = 5
d = {5: 2, 1: 4}
while i * i <= x:
x, vals = diver(x, i)
yield from vals
i += d[i % 6]
if x > 1:
yield x
list(prime_factors(600851475143))
The dict {5: 2, 1: 4} uses the fact that you don't have to look at all odd numbers. Above 3, all numbers x % 6 == 3 are multiples of 3, so you need to look at only x % 6 == 1 and x % 6 == 5, and you can hop between these by alternately adding 2 and 4, starting from 5.
The accepted answer suggests a drop-in replacement for xrange, but only covers one case. Here is a more general drop-in replacement.
def custom_range(start=0,stop=None,step=1):
'''xrange in python 2.7 fails on numbers larger than C longs.
we write a custom version'''
if stop is None:
#handle single argument case. ugly...
stop = start
start = 0
i = start
while i < stop:
yield i
i += step
xrange=custom_range
I would definitely stick with xrange since creating a list between 0 and what looks like a number rivaled by infinity would be taxing for memory. xrange will generate only the numbers when asked. For the number too large problem, you might want to try a "long". This can be achieved by writing a L on the end of the number. I made my own version to test it out. I put in a small sleep as to not destroy my computer into virtually a while(1) loop. I was also impatient to see the program come to a complete end, so I put in print statements
from time import sleep
x = 600851475143L
maxPrime = 0
for i in xrange(1,x):
isItPrime = True
if (x%i) == 0:
for prime in xrange(2,i-1):
if (i%prime) == 0:
isItPrime = False
break
if isItPrime:
maxPrime = i
print "Found a prime: "+str(i)
sleep(0.0000001)
print maxPrime
Hope this helps!
EDIT:
I also did a few more edits to yield this version. It is fairly efficient and I checked quite a few numbers this program provides (it seems to check out so far):
from time import sleep
x = 600851475143L
primes = []
for i in xrange(2,x):
isItPrime = True
for prime in primes:
if (i%prime) == 0:
isItPrime = False
break
if isItPrime:
primes.append(i)
print "Found a prime: "+str(i)
sleep(0.0000001)
print primes[-1]
Very uneficient code, that's not the best way of getting dividers, I've done it with a for and range, but I can't execute it because of the long variables, so I decided to implement it with a for using a while, and increment a counter by myself.
For 32 bit int like 13195:
# The prime factors of 13195 are 5, 7, 13 and 29.
# What is the largest prime factor of the number 600851475143 ?
i = 13195
for j in xrange(2, i, 1):
if i%j == 0:
i = i/j
print j
Good way for longer numbers:
# The prime factors of 13195 are 5, 7, 13 and 29.
# What is the largest prime factor of the number 600851475143 ?
i = 600851475143
j = 2
while i >= j:
if i%j == 0:
i = i/j
print j
j = j+1
The last prime is the last printed value.
Another implementation for python 2 range():
import itertools
import operator
def range(*args):
"""Replace range() builtin with an iterator version."""
if len(args) == 0:
raise TypeError('range() expected 1 arguments, got 0')
start, stop, step = 0, args[0], 1
if len(args) == 2: start, stop = args
if len(args) == 3: start, stop, step = args
if step == 0:
raise ValueError('range() arg 3 must not be zero')
iters = itertools.count(start, step)
pred = operator.__ge__ if step > 0 else operator.__le__
for n in iters:
if pred(n, stop): break
yield n