Python prime number code running slow - python

I am trying to solve the problem mentioned here: https://www.spoj.pl/problems/PRIME1/
I am also giving the description below.
Peter wants to generate some prime numbers for his cryptosystem. Help him! Your task is to generate all prime numbers between two given numbers!
Input
The input begins with the number t of test cases in a single line (t<=10). In each of the next t lines there are two numbers m and n (1 <= m <= n <= 1000000000, n-m<=100000) separated by a space.
Output
For every test case print all prime numbers p such that m <= p <= n, one number per line, test cases separated by an empty line.`
My code is as below. I am thinking remove method on list is very slow.
import sys
import math
num = int(sys.stdin.readline());
indices = []
maxrange = 2
while(num > 0):
a,b = sys.stdin.readline().split(" ");
a = int(a)
b = int(b)
if(a < 2):
a = 2
indices.append((a,b))
if(b > maxrange):
maxrange= b
num = num - 1
val = int(math.sqrt(maxrange)+1)
val2 = int(math.sqrt(val)+1)
checks = range(2,val2)
for i in range(2,val2):
for j in checks:
if(i!= j and j%i == 0):
checks.remove(j)
primes = range(2,val)
for i in checks:
for j in primes:
if(i != j and j%i == 0):
primes.remove(j)
primes2 = range(2,maxrange)
for i in primes:
for j in primes2:
if(j != i and j%i == 0):
primes2.remove(j)
for (a,b) in indices:
for p in primes2:
if(a<= p and b >= p):
print p
if(p > b):
break
print
I think python list remove is very slow. My code is correct but I am getting timelimit exceeded. can someone help me improve this code.

A primality testing function will perform best. There's pseudocode on the Miller-Rabin wikipedia page

Instead of removing the element that is not a prime, why not replace it with some sentinel value, perhaps -1 or None? Then when printing, just print the values that aren't sentinels.
Use a list of length (n-m), and then the index for number i is x[m+i].

remove() isn't slow in the grand scheme of things, it's just that the code calls it a LOT.
As dappawit suggests, rather than modifying the list, change the value in the list so you know that it isn't a valid number to use.
I also see that when you generate the set of prime numbers, you use range(2,maxrange) which is okay, but not efficient if the lower bound is much greater than 2. You'll be wasting computing time on generating primes that aren't even relevant to the problem space. If nothing else, keep track of minrange as well as maxrange.
A bug with your original code is that you use range(2,maxrange). That means maxrange is not in the list of numbers considered. Try 3 5 as input for a and b to see the bug.
range(2,maxrange+1) fixes the problem.
Another bug in the code is that you modify the original sequence:
From Python docs - for-statement
It is not safe to modify the sequence being iterated over in the loop (this can only happen for mutable sequence types, such as lists). If you need to modify the list you are iterating over (for example, to duplicate selected items) you must iterate over a copy. The slice notation makes this particularly convenient:
My python skills are rudimentary, but this seems to work:
Old:
primes2 = range(2,maxrange)
for i in primes:
for j in primes2:
if(j != i and j%i == 0):
primes2.remove(j)
for (a,b) in indices:
for p in primes2:
if(a<= p and b >= p):
New:
primes2 = array.array('L', range(minrange,maxrange+1))
for i in primes:
for j in primes2:
if(j != i and j%i == 0):
primes2[j-minrange] = 0
for (a,b) in indices:
for p in primes2:
if (p != 0):
if(a<= p and b >= p):
You could also skip generating the set of prime numbers and just test the numbers directly, which would work if the sets of numbers you have to generate prime numbers are not overlapping (no work duplication).
enter link description here

Here's a deterministic variant of the Miller–Rabin primality test for small odd integers in Python:
from math import log
def isprime(n):
assert 1 < n < 4759123141 and n % 2 != 0, n
# (n-1) == 2**s * d
s = 0
d = n-1
while d & 1 == 0:
s += 1
d >>= 1
assert d % 2 != 0 and (n-1) == d*2**s
for a in [2, 7, 61]:
if not 2 <= a <= min(n-1, int(2*log(n)**2)):
break
if (pow(a, d, n) != 1 and
all(pow(a, d*2**r, n) != (n-1) for r in xrange(s))):
return False
return True
The code intent is to be an executable pseudo-code.

Related

Lambda function for calculating sum of primes

While writing a python program for calculating the sum of primes between 2 to n (both inclusive), I am getting the error "The generator is not callable"
Can anyone help with the error or suggest what am I missing here?
n = int(input())
sum = 0
sum = sum(list(filter((lambda n: n%y != 0 for y in range(2, n)), range(2, n+1))))
print(sum)
1. first error: "TypeError: 'generator' object is not callable"
this error raise because you pass to filter build-in method a generator, you "cover" the lambda method with parentheses:
filter((lambda n: n%y != 0 for y in range(2,n)), range(2,n+1))
Solution: "uncover" the parentheses
filter(lambda n: n%y != 0 for y in range(2,n), range(2,n+1))
2. second error: "SyntaxError: Generator expression must to be
parenthesized":
lambda n: n%y != 0 for y in range(2,n)
the error is clear: n%y != 0 for y in range(2,n) is a generator and needs to be be parenthesized,
here you want to test if the number is a prime so you want to check if all the values from your generator are True
Solution: use the build-in method all
lambda n: all(n%y != 0 for y in range(2,n))
3. last error: "TypeError: 'int' object is not callable"
sum=0
this is happening because you are using sum build-in method name for your variable sum, so the sum is not anymore the built-in method but an integer
Solution: another name for your variable:
n_prime_sum = 0
here is your code with the fixes:
n = int(input())
n_prime_sum = 0
n_prime_sum = sum(list(filter(lambda n: all(n%y != 0 for y in range(2,n)), range(2,n+1))))
n_prime_sum
# n = 10
output:
17
also, you can define a function that generates all the prime btw 2 and n (both inclusive) then apply the sum build-in method on this function:
# original code by David Eppstein, UC Irvine, 28 Feb 2002
# with comments by Eli Bendersky, https://stackoverflow.com/a/568618
def gen_primes(n):
"""Much more efficient prime generation, the Sieve of Eratosthenes"""
D = {}
q = 2 # The running integer that's checked for primeness
while q <= n:
if q not in D:
# q is a new prime.
# Yield it and mark its first multiple that isn't
# already marked in previous iterations
#
yield q
D[q * q] = [q]
else:
# q is composite. D[q] is the list of primes that
# divide it. Since we've reached q, we no longer
# need it in the map, but we'll mark the next
# multiples of its witnesses to prepare for larger
# numbers
for p in D[q]:
D.setdefault(p + q, []).append(p)
del D[q]
q += 1
n = int(input())
n_prime_sum = sum(gen_primes(n))
print(n_prime_sum)
# n = 10
output:
17
most of the code for the function gen_prime comes from here
Well, in my imagination this approach being optimal would
only divide with (already) known primes (and not every number)
up to the square root of the given number
import math
primes=[2]
def isprime(n): # NB! this is fragile,
s=int(math.sqrt(n)) # relies on `primes` being
for p in primes: # already fully grown
if n%p==0: # up to the sqrt(n)
return False
if p>s:
return True
maxn=19
for i in range(3,maxn+1):
if isprime(i):
primes.append(i)
print(primes)
print(sum(primes))
Then comes the uglification make it lambda part
isprime=lambda n:all(n%p!=0 for p in primes)
works, but it misses the sqrt magic, then
isprime=lambda n:all(n%p!=0 for p in (p for p in primes if p<=int(math.sqrt(n))))
which calculates int(math.sqrt(n)) for all known primes, but that could be a one-time parameter instead, either for a filter() or for an innner lambda (this latter one is shown here):
isprime=lambda n:all(n%p!=0 for p in (lambda s:(p for p in primes if p<=s))(int(math.sqrt(n))))
I still do not like the fact that it compares all primes to s, stopping in the middle may be more efficient, getting a slice with index(next(...)) can do that:
isprime=lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))])
just it remains ugly that next() and index() traverse a part of the list twice.
Then comes the outer loop, I would use reduce() for that from functools, as the accumulator of the reduction could be the actual list of primes, and then it would not be a separate variable.
Step 0 would be making it in a minimalist way, still with the variable primes lying around, but using the terrible trick with tuples, (do,some,things,result)[3] will do the things, and evaluate to the result:
primes=[2]
isprime=lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))])
maxn=19
ps=functools.reduce(lambda primes,n:(primes.append(n) if isprime(n) else None,primes)[1],range(3,maxn+1),primes)
print(ps)
print(primes)
print(sum(primes)) # ps and primes are the same list actually
and then finalize the monster:
import math
import functools
plist=lambda maxn:functools.reduce(lambda primes,n:(primes.append(n) if (lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))]))(n) else None,primes)[1],range(3,maxn+1),[2])
primes=plist(19)
print(primes)
print(sum(primes))
Test: https://ideone.com/0y7dN9
Output:
[2, 3, 5, 7, 11, 13, 17, 19]
77
The takeaway message would be: lambdas can be useful, but actually you do not always have to use them.
A slightly cleaner version:
n = int(input())
nums = range(2, n + 1)
for i in range(2, n + 1):
nums = list(filter(lambda x: x == i or x % i, nums))
print(sum(nums))
You can also write it like this with list comprehension:
from math import sqrt, floor
sum(( p
for p in range(2, n+1)
if all( p%q != 0 for q in range(2, floor(sqrt(p))+1) ) ))
You don't need to check all the numbers, just the ones until the square root of the own number.
Example: You can find out that 10 = 2 * 5 is non a prime by checking 10 % 2 == 0 or 10 % 5 == 0. With the square root limit, you'd only check until 3, but that's fine since you'd already have seen the 2, and defined 10 as not prime.
If this application is for you to explore, you might want to check the sieve of Eratosthenes algorithm to find the prime numbers, which is considered one of the most efficient ways to find small primes.
However, if you just need to find the primes and sum them, you can always use a library like gmpy2. Check this answer to know more.
Your solution is almost correct. But you need to use all inside the lambda function, because you want all the n%y != 0 statements to be true:
sum(list(filter((lambda n: all(n%y != 0 for y in range(2,n))), range(2,n+1))))
As pointed out in the comments, you could improve the efficiency of your code by checking only the divisors which are not greater than the square root of the number:
import math
sum(list(filter((lambda n: all(n%y != 0 for y in range(2,int(math.sqrt(n))+1))), range(2,n+1))))
Explanation
n%y != 0 for y in range(2,n) is a generator, not a boolean value!
all(n%y != 0 for y in range(2,n)) is a boolean value corresponding to n%2 != 0 and n%3 != 0 and ... and n%(n-1) != 0
After reading all the answers and trying/testing myself, I have redesigned the answer, which you can modify as per your need:
# get the user input
n = int(input())
from functools import reduce
# create a list with all the primes within the input number range
n_prime = range(2, n + 1)
for i in range(2, n + 1):
n_prime = list(filter(lambda x: x == i or x % i, n_prime))
# print the list of primes obtained from above
print(n_prime)
# let's add all these numbers in the above list and print the summed value
sum_n_prime = reduce(lambda x, y : x + y, n_prime)
print(sum_n_prime)

Advanced Hailstone - Nested loop / combination

Generating a hailstone sequence that follows the pattern below:
if x is even -> x/2
if x is odd -> [a]x+[b]
where a and b are integer values {0,...,10}, allowing for 121 possible combinations of a and b. I need to list whether the sequence converges for all 1000 x values
I am using python to solve the problem, I'm a beginner at coding with python but am a quick learner and need guidance on how to resolve
`for n in range(1,1001):
for i in a:
for j in b:
while j != 1 & i != 1:
print ("a:", i, "b:", j)
if j % 2 == 0:
j = j / 2
length = length + 1
else:
n = (n * j) + i
if n == 1:
print (n)
'
the above works in that it runs but it doesn't do what I want. It just keeps looping integer one and wont move past it
I see following problems in your code:
range usage, range does not accept list as argument, you should use for i in a: when a is list, rework all your fors accordingly.
broken while syntax: you have too many :s in your while, should be one : (at end)
possibly broken indentation: note that if is not aligned with corresponding else, keep in mind that in Python language indentation is crucial
j = j / b will produce error - you can't divide int by list
you never define n, thus n = (n * a) + 1 and all other lines with n, will produce errors
Keep in mind that my list of problems might be incomplete
'a = [0,1,2,3,4,5,6,7,8,9,10]
b = [0,1,2,3,4,5,6,7,8,9,10]
for n in range(1,1001):
for i in a:
for j in b:
while j != 1 & i != 1:
print ("a:", i, "b:", j)
if j % 2 == 0:
j = j / 2
length = length + 1
else:
n = (n * j) + i
if n == 1:
print (n)'
updates...I want to still be able to understand when it converges and it won't move to the next value

Efficient permutations of array elements with no repetitions in python [duplicate]

So I received a challenge that states the following:
"Design a program that takes as input a 9 digit number where no digit appears twice and produces as output an arrangement of the same 9 digits corresponding to the next highest number. If no such number exists, the algorithm should indicate this. So for example, if the input is 781623954 the output would be 781624359."
So I came up with this idea to flip the indexes, so check the last index with the one right before to see which is bigger and compare then flip if necessary but for some reason my code isn't working. I only did the work for checking the last two digits not all the digits, so if you can help me out and check it for me and if you have any better ideas on how to tackle this problem, please share.
input = raw_input("Enter 9 Digits: ")
x = 9
while x>0:
x-=1
if input[8] > input[7]:
temp = input[8]
input[8] == input[7]
input[7] == temp
print input
break
Here's a more efficient approach, using the algorithm of the 14th century Indian mathematician Narayana Pandita, which can be found in the Wikipedia article on Permutation. This ancient algorithm is still one of the fastest known ways to generate permutations in order, and it is quite robust, in that it properly handles permutations that contain repeated elements.
The code below includes a simple test() function that generates all permutations of an ordered numeric string.
#! /usr/bin/env python
''' Find the next permutation in lexicographic order after a given permutation
This algorithm, due to Narayana Pandita, is from
https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
1. Find the largest index j such that a[j] < a[j + 1]. If no such index exists,
the permutation is the last permutation.
2. Find the largest index k greater than j such that a[j] < a[k].
3. Swap the value of a[j] with that of a[k].
4. Reverse the sequence from a[j + 1] up to and including the final element a[n].
Implemented in Python by PM 2Ring 2015.07.28
'''
import sys
def next_perm(a):
''' Advance permutation a to the next one in lexicographic order '''
n = len(a) - 1
#1. Find the largest index j such that a[j] < a[j + 1]
for j in range(n-1, -1, -1):
if a[j] < a[j + 1]:
break
else:
#This must be the last permutation
return False
#2. Find the largest index k greater than j such that a[j] < a[k]
v = a[j]
for k in range(n, j, -1):
if v < a[k]:
break
#3. Swap the value of a[j] with that of a[k].
a[j], a[k] = a[k], a[j]
#4. Reverse the tail of the sequence
a[j+1:] = a[j+1:][::-1]
return True
def test(n):
''' Print all permutations of an ordered numeric string (1-based) '''
a = [str(i) for i in range(1, n+1)]
i = 0
while True:
print('%2d: %s' % (i, ''.join(a)))
i += 1
if not next_perm(a):
break
def main():
s = sys.argv[1] if len(sys.argv) > 1 else '781623954'
a = list(s)
next_perm(a)
print('%s -> %s' % (s, ''.join(a)))
if __name__ == '__main__':
#test(4)
main()
I am not convinced that your approach of flipping digits is guaranteed to find the next highest number (at least not without further checks)
Here a simple solution:
Simply increment the input number and check if the conditions are met or if no number can be found.
set() can be used to get the set of unique digits in the number.
input_num = '781623954'
next_num = int(input_num) + 1
input_digits = set(input_num)
found = False
while not found:
next_num += 1
next_digits = set(str(next_num))
found = len(next_digits) == 9 and input_digits == next_digits
if next_num > 987654321:
break
if found:
print(next_num)
else:
print("No number was found.")
input[8] == input[7]
input[7] == temp
you probably meant:
input[8] = input[7]
input[7] = temp
didn't you?
Which, as stated in the comments, wouldn't work directly on the string, as it is immutable in Python. So, as a first step, you could make a list of characters from that string:
input = list(input)
and as a last step, get a string back from the modified list:
input = ''.join(input)
BTW, you might want to benefit from Python tuple unpacking which allows you to swap two variables without having to introduce a third one:
input[7], input[8] = input[8], input[7]

Project Euler #3 Python

This is my solution to Project Euler Problem 3. I have written this code for Project Euler but if I put in "49" i get "49". What seems to be the problem?
n = 600851475143
i = 2
while (i * i < n):
while (n % i == 0):
n = n / i
i = i + 1
print (n)
I'm assuming you meant set n = 49.
Your outer while loop checks the condition i * i < n, which is not true for i == 7, so the outer loop breaks as soon as it hits 7. Change the < to <=.
However, your code isn't correct in the first place-- perhaps something like this is what you meant?
n = 600851475143
i = 2
factors = []
while (i <= n):
while (n % i == 0):
n = n / i
factors.append(i)
i = i + 1
print factors
You're printing n you want to print i...
Probably the fastest way to solve it by finding all the prime factors and then return the max.
Brute force solution took me less then 1 sec
I'm assuming you mean n = 49.
Your code isn't right, but the error is small -- change the < to <= and it works for Project Euler #3.
The problem of the code not working for squares such as 49 still remains though. Here is a modified piece of code that should work for squares as well.
n = 49
i = 2
while i * i <= n:
while n % i == 0:
x = n
n = n / i
i = i + 1
if n == 1:
print x
else:
print n
finding factors of N only need to check upto √N.
First basic solution:-
value of N never change
find factors upto √N & store biggest factor.
from math import sqrt
ans = -1
n = input() #or directly put
for i in range(2,int(sqrt(n))+1):
while (n%i==0):
if i > ans:
ans = i
print(ans)
Little optimized solution:-
if we change value of N, it iterate less than previous method.
only need to check % (modulus) of N with primes.
if have prime numbers list, then check/iterate with that only
unless, ignoring even numbers check numbers like 9,15,21... is prime or not, is worthless so...
excluding 2 all prime is odd.
so after check N with 2, check N with only odd numbers.
find factors upto √N & store biggest factor.
when get factor, divide N until N no have that factor
find the next factor do same process, until N become 1 (no have any factors)
from math import sqrt
ans = 2
n = input() #or directly put
while (n%2 == 0):
n /= 2
i = 3
while n > 1:
while (n%i == 0):
ans = i
n /= i
i += 2
print(ans)
find prime factors and return largest obviously
from math import sqrt
def is_prime(n):
if n ==2:return True
if n<2:return False
if n%2==0:return False
for i in range(3,int(sqrt(n))+1,2):
if n%i == 0:
return False;
return True;
n = 600851475143
i = n
while(i>1):
if is_prime(i) and is_prime(i) and n%i==0:
print(i);
break
i = i-1;
Your code is written assuming there are more than one factor, but in the case of n=49, it turns out that it has only one factor that is 7. So you can add a line checking whether it has more than one factor, or if not then it should be printed.

Range is too large Python

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

Categories