Python sqrt() doubles runtime? - python

I've recently started learning Python. My apologies if this is really obvious.
I am following along with the 2008 MIT open course on Computer Science and am working on the problem of calculating the 1000th prime integer. Python 2.7.3, Win7 lappy (cough, cough...)
Here's the code I came up with:
num = 3
primeList = [2]
while len(primeList) < 1000:
for i in primeList:
if num % i == 0:
break
else:
primeList.append(num)
num += 1
print "The 1,000th PRIME integer is", primeList[999]
One of the assignment conditions was to only check odd numbers. Given the starting num is three, I figured it would be easy enough to simply change num+=1 to num+=2. Of note: I won't bore you with the detailed code I composed, but while writing this I was using a very verbose mode of printing out the results of each check, whether or not it was prime, which number was being checked, which integer divided into it if it wasn't prime & such (again, sorry - newB!)
At this point I became curious to test if this was actually taking less time to compute - seemed like if half the numbers are being checked for primacy, it should take half the time, no?
I imported the time module to check how long this was taking. Computing to the 1000th was pretty quick either way so I increased the number of primes I was searching for to the 10,000th and didn't see any significant difference. between num+=1 & num+=2
import time
start = time.time()
num = 3
primeList = [2]
while len(primeList) < 10000:
for i in primeList:
if num % i == 0:
break
else:
primeList.append(num)
num += 2
print "The 10,000th PRIME integer is", primeList[9999]
end = time.time()
print "That took %.3f seconds" % (end-start)
Sometimes the n+=2 even took a couple milliseconds longer. ?. I thought this was odd and was wondering if someone could help me understand why - or, more to the point: how?
Furthermore, I next imported the sqrt() function thinking this would reduce the number of integers being checked before confirming primacy, but this doubled the runtime =^O.
import time
start = time.time()
from math import sqrt
num = 3
primeList = [2]
while len(primeList) < 100000:
for i in primeList:
if i <= sqrt(num):
if num % i == 0:
break
else:
primeList.append(num)
num += 2
print "The 100,000th PRIME integer is",primeList[99999]
end = time.time()
print 'that took', end - start, "seconds, or", (end-start)/60, "minutes"
Certainly - it might be the way I've written my code! If not, I'm curious what exactly I am invoking here that is taking so long?
Thank you!

Two things.
First, you're calculating sqrt(n) on every loop iteration. This will add work, because it's something else your code now has to do on every pass through the loop.
Second, the way you're using sqrt doesn't reduce the number of numbers it checks, because you don't exit the loop even when i is bigger than sqrt(n). So it keeps doing a do-nothing loop for all the higher numbers.
Try this instead:
while len(primeList) < 100000:
rootN = sqrt(num)
for i in primeList:
if i <= rootN:
if num % i == 0:
break
else:
primeList.append(num)
break
else:
primeList.append(num)
num += 2
This finds 100,000 primes in about 3 seconds on my machine.

Related

How to remove the trailing , following a end=','

New to Python & the community. Navigating different exercises and I'm having trouble finding the solution. I need to remove the trailing, that follows when using end=','
Any wisdom or guidance is very appreciated!
low = 10000
up = 10050
for num in range(low, up + 1):
if num > 1:
for i in range(2, num):
if (num % i) == 0:
break
else:
print(num,end=',')
It looks like you're trying to print prime numbers in a given range. Arguably, mixing discovery of prime numbers and printing them is what causes the problem. With proper decomposition, this problem won't exist:
def generate_primes(low, up):
for num in range(max(low, 2), up+1):
if all(num % i for i in range(2, num)):
yield num
print(*generate_primes(low, up), sep=',')
As a positive side effect, you can now reuse prime generator in other parts of the program which don't require printing.
Also note that checking all numbers up to num is not necessary - if the number is composite one of the factors will be less or equal to sqrt(num). So, a faster prime generator would be something like:
def generate_primes(low, up):
for num in range(max(low, 2), up+1):
if all(num % i for i in range(2, int(num**0.5 + 1))):
yield num
Try this :
low = 10000
up = 10050
nums = []
for num in range(low, up + 1):
if num > 1:
for i in range(2, num):
if (num % i) == 0:
break
else:
nums.append(str(num))
a = ",".join(nums)
print(a)
Essentially, just add all the elements that will be outputted in a list and then use the join function to convert them into a string and print it.
Solution
import sys
low = 10000
up = 10050
firstValuePrinted = 0
for rootIndex, num in enumerate(range(low, up + 1)):
if num > 1:
for subIndex, i in enumerate(range(2, num)):
if (num % i) == 0:
break
else:
print("", end = "," if firstValuePrinted==1 else "")
firstValuePrinted = 1
print(num, end = "")
sys.stdout.flush()
Explanation
Since we can't determine on which number num the loop will exit we can't exactly know the end condition. But we can figure out the starting number.
So based on that logic, instead of printing the "," at the end we actually print it at the start by using a variable to maintain if we have printed any values or not in the above code that is done by firstValuePrinted.
sys.stdout.flush() is called to ensure the console prints the output right away and does not wait for the program to complete.
Note: Don't forget to import sys at the start of the file.
Benefits when compared to other answers
This type of implementation is useful if you want to output the num variable continuously so as to not have to wait for all the numbers to be calculated before writing the value.
If you put all the values into an array and then print, you actually need large memory for storing all the numbers (if low and up is large) as well as the console will wait till the for loop is completed before executing the print command.
Especially when dealing with prime numbers if the low and up variables are far apart like low=0 and up=1000000 it will take a long time for it to be processed before any output can be printed. While with the above implementation it will be printed as it is being calculated. While also ensuring no additional "," is printed at the end.

How can I speed this python code up?

I have made some code that calculates prime numbers (Nothing special I know) and as expected it slows down the bigger the number, I know it is impossible to make it the same speed no matter the number but I am sure I could improve it's speed, I just don't know how...
import time
number = 1000000001
count = 0
start = time.time()
while number > 1000000000 and number < 10000000000000:
for i in range(1, round(number/2 + 1)):
if (number / i).is_integer():
count += 1
if count > 1:
break
if count < 2:
print(str(number) + ' prime')
number = number + 1
count = 0
end = time.time()
print(end - start)
Several things:
you do not have to check from 1, but 3, 5 and all odd numbers;
you do not have to check until n/2, but you can stop at sqrt(n);
do not use division, since then you work with floating points, but use % to check modulo;
you only have to check odd numbers (or two); and
you can omit the greater than check in the while loop, since the number only increments.
So an improved version would be:
import time
from math import sqrt # import square root
start = time.time()
for number in range(1000000001,10000000000000,2): # use for, hops of 2
for i in range(3, int(sqrt(number))+1,2): # check 3, 5,... up to sqrt(n)
if number % i == 0: # use modulo checks instead of floating point
break
else: # use a for-else structure for faster ending
print(str(number) + ' prime')
count = 0
end = time.time()
print(end - start)
Nevertheless, Python is not designed to get the most out of a CPU. If you really want to code a superoptimized algorithm, you will have to pick a faster (and less convenient) programming language.

Enumeration to find Nth prime with Python

I have decided it is about time that i should start learning to code. I have some knowledge of HTML and CSS but i want to be able to develop for iOS. I am aware i have a long way to go, but i aim to get there step by step.
I'm working through the MIT Python course on iTunes U and I am stuck on the homework. I understand the concept of enumeration and testing every possible outcome to find the primes, however what i have tried so far has failed me. My closest attempt is the following.
# counting confirmed primes. For loop should do remainder tests on
# all testNumbers, unless caught by the if statements that rule out
# multiples of 2,3,5,7 to speed things up. divisor increments by one
# on those numbers that do not get pulled by qualifying if statements
testNumber = 2
confirmedPrime = 0
while (confirmedPrime < 1001):
for divisor in range(1, testNumber+1):
if (testNumber/2)*2== testNumber:
testNumber += 1
elif (testNumber/3)*3 == testNumber:
testNumber += 1
elif (testNumber/5)*5 == testNumber:
testNumber += 1
elif (testNumber/7)*7 == testNumber:
testNumber += 1
elif(testNumber%divisor == 0):
testNumber += 1
confirmedPrime +=1
print testNumber
This however doesn't return the "7919" i am expecting but. It returns "7507" So somewhere there are some composites slipping through the net.
I have hunted through this site and not managed to solve it so I thought I would ask.
A few bits are off here, so let's go step by step.
You start by setting initial values, which is perfectly reasonable.
testNumber=2
confirmedPrime = 0
Then you go into a while loop, continuing until the value of the variable confirmedPrime is has reached (i.e. is equal to or bigger than) 1001. I suppose your task is to find the 1000th prime, but doing it like this you're actually finding the 1001st, because the while loop continues until confirmedPrime has the value of 1001. Change it to
while(confirmedPrime < 1000):
You immediately go into another loop, and here comes the first problem, even though it isn't what's giving you the wrong answer.
for divisor in range(1, testNumber+1)
if (testNumber/2)*2 == testNumber:
...
Doing the tests for multipliers of 2, 3, 5 and 7 inside the for loop doesn't make any sense, as you only have to to this once for each value of testNumber. So that part of the testing should be moved out of the for loop.
if (testNumber/2)*2 = testNumber: # Why not use modulo here too for consistency?
testNumber += 1
elif ...
...
else:
for divisor in range(...):
The next part is testing for other, larger divisors. You are testing divisors in the range 1 to testNumber+1. I'm not sure why you're doing this, but it's not a good idea, as your modulo test will always return zero when you come to the second last iteration, testing testNumber%testNumber. So you should change it to testNumber-1, in fact you can stop when you have reached the square root of testNumber, but I'll leave it to you to figure out why.
Now comes the biggest problem:
After the for loop is finished, you increment confirmedPrimes by 1 without actually checking if you found a prime or not. So, incrementing confirmedPrimes should only happen if none of the first tests were true and none of the "divisor tests" turned out to be true.
Rewritten using underscores instead of mixedCase (which is bad python mojo), consistent spacing etc:
import math
test_number = 7 # Already know up to 7
confirmed_primes = 4 # Already know about 2, 3, 5 and 7
while confirmed_primes < 1000:
test_number += 1
if test_number % 2 and test_number % 3 and test_number % 5 and test_number % 7:
is_prime = True
for divisor in range(11, int(math.sqrt(test_number))+1):
if test_number % divisor == 0:
is_prime = False
if is_prime:
confirmed_primes += 1
print test_number
I don't understand exactly how your algorithm is supposed to find a prime number.
A number is said to be prime if it's only divisible by 1 or himself.
Another definition is that a number is said to be prime if it's not divisible by any prime number smaller than it.
This can be the base of your algorithm, speeding up the process by a lot.
def nth_prime(n):
prime_list = []
current = 2
count = 0
while(count < n):
is_prime = True
for prime in prime_list:
if current % prime == 0:
is_prime = False
break
if is_prime:
prime_list.append(current)
count += 1
current += 1
return current - 1
print nth_prime(1000) # => 7919

Getting wrong answers for prime numbers

I'm getting several incorrect answers in this code. For example, 9 is showing as prime. I'm guessing my problem is with using the breaks, but I can't seem to logically figure out what is wrong with this simple code someone asked me about.
for number in range(0, 1000):
for x in range(2, number):
if (number % x == 0):
break
else:
print x
break
In your script, regardless of if the number is divisble by 2 or not, it breaks the loop immediately.
I've reindented the code and this is probably closer to what you were trying to do.
In your original code, if the number is divisible by 2 (first number in the range(2,number), then you break the loop and if it is not divisible you also break the loop. So all odd numbers, like 9, looked like primes.
The else keyword after a for loop is run iff the loop exits normally. So the "is prime" part will only be printed if no divisor is found.
for number in range(0,1000):
for x in range(2,number):
if(number % x == 0):
print number,"divisible by",x
break
else:
print number, "is prime"
You can see this is anction here: http://codepad.org/XdS413LR
Also, this is a naive algorithm (not a critique of the code, exploring simple algorithms is a useful study), but you can make a little more efficient. Technically you only need to check as far as the sqare root of number, as any number larger than the square root must have a complement that is less than the square root, which should have already been encountered. So the logic in the code can be changed to:
from math import sqrt
for number in range(0,1000):
for x in range(2,int(sqrt(number/2))):
# Rest of code as above.
That said there are many ways that you can optimise the checking or discovery of prime numbers that are worth investigating if you get the chance.
I think you want something like this:
for number in xrange(100):
for i in range(2,number):
if number % i == 0:
break
else:
print number
this iterates through every number form 1-100 and checks if any number is divisible by any # besides one but you need the else: statement out side of the inner for loop so if it goes throught the inner for loop without finding a divisor its prime
Here are some alternatives. First, this checks for primes:
def check_for_prime(n):
if n == 1: return False
elif n == 2: return True
elif n%2 == 0: return False
# Elementary prime test borrowed from oeis.org/A000040.
odds = 3
while odds < n**.5+1:
if n%odds == 0: return False
odds += 2
return True
This is slightly faster, but you should have experience using yield:
def primes_plus():
yield 2
yield 3
i = 5
while True:
yield i
if i % 6 == 1:
i += 2
i += 2
Here are some alternatives.
n is the number till the range you want to find
n=100
for i in range(0,n):
num = filter(lambda y :i % y == 0,(y for y in range(2,(i/2))))
if num or i == 4:
print "%s not a prime number" %(i)
else:
print "%s is a prime number" %(i)

Calculating prime numbers

I am now doing the MIT opencourse thing, and already the second assignment, I feel it has left me out in the cold. http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00-introduction-to-computer-science-and-programming-fall-2008/assignments/pset1a.pdf
The specifics of it, are to write something that can calculate the 1000th prime number. We only know about the print, ==, =, 1=,if, else, elif, while, %, -,+,*,/, commands I think. We also don't yet know about importing libraries.
My Idea of how it would work is to take an odd number and try to divide it by, 3,4,5,6,7,8,9 and if %n !=0, then add a number to NumberofPrimes variable starting with 11 as the base of the tests, and assigning it a base value of 4 at the base of NumberofPrimes, though I don't know if that is even right, because I wouldn't know how to display the 1000th prime number.
Am I close?
The latest incarnation of it is as follows:
##calculate the 1000th prime number
potprime = 3
numberofprime = 1
cycle = if potprime%3 = 0:
break
if potpimre%4 = 0:
break
if potprime%5 = 0:
break
if potprime%6 = 0:
break
if potprime%7 = 0:
break
if potprime%8 = 0:
break
if potprime%9 = 0:
break
numberofprime + 1
potprime + 1
if potprime%2 == 0:
potprime = potprime + 1
if potprime != 0:
cycle
Where exactly am I going wrong? Walk me through it step by step. I really want to learn it, though I feel like I am just being left out in the cold here.
At this point, it would be more beneficial for me to see how a proper one could be done rather than doing this. I have been working for 3 hours and have gotten nowhere with it. If anybody has a solution, I would be more than happy to look at it and try to learn from that.
Looks like I am late
It is quite straight forward that if a number is not divisible by any prime number, then that number is itself a prime number. You can use this fact to minimize number of divisions.
For that you need to maintain a list of prime numbers. And for each number only try to divide with prime numbers already in the list. To optimize further it you can discard all prime numbers more than square root of the number to be tested. You will need to import sqrt() function for that.
For example, if you test on 1001, try to test with 3, 5, 7, 11, 13, 17, 19, 23, 29 and 31. That should be enough. Also never try to find out if an even number is prime. So basically if you test an odd number n, then after that test next number: (n + 2)
Have tested the below code. The 1000th prime number is 7919. Not a big number!!
Code may be like:
from math import sqrt
primeList = [2]
num = 3
isPrime = 1
while len(primeList) < 1000:
sqrtNum = sqrt(num)
# test by dividing with only prime numbers
for primeNumber in primeList:
# skip testing with prime numbers greater than square root of number
if num % primeNumber == 0:
isPrime = 0
break
if primeNumber > sqrtNum:
break
if isPrime == 1:
primeList.append(num)
else:
isPrime = 1
#skip even numbers
num += 2
# print 1000th prime number
print primeList[999]
The following code is gross, but since 1000 is indeed a small index, it solves your problem in a fraction of a second (and it uses only the primitives you are supposed to know so far):
primesFound = 0
number = 1
while primesFound < 1000:
number = number + 1 # start from 2
# test for primality
divisor = 2
numberIsPrime = True
while divisor*divisor <= number: # while divisor <= sqrt(number)
if number % divisor == 0:
numberIsPrime = False
break
divisor = divisor + 1
# found one?
if numberIsPrime:
primesFound = primesFound + 1
print number
You can test the solution here.
Now you should find a more efficient solution, optimize and maybe go for the 1000000-th prime...
For one thing, I'm pretty sure that in Python, if you want to have an if statement that tests whether or not A = B, you need to use the == operator, rather then the =.
For another thing, your algorithm would consider the number 143 to be prime, even though 143 = 11 * 13
You need keep track of all the prime numbers that you have already computed - add them to an array. Use that array to determine whether or not a new number that you are testing is prime.
It seems to me that you are jumping into the deep-end after deciding the kiddy-pool is too deep. The prime number project will be assignment 2 or 3 in most beginning programming classes, just after basic syntax is covered. Rather than help you with the algorithm (there are many good ones out there) I'm going to suggest that you attempt to learn syntax with the python shell before you write long programs, since debugging a line is easier than debugging an entire program. Here is what you wrote in a way that will actually run:
count = 4
n = 10 #I'm starting you at 10 because your method
#says that 2, 3, 5, and 7 are not prime
d = [2, 3, 4, 5, 6, 7, 8, 9] #a list containing the ints you were dividing by
def cycle(n): #This is how you define a function
for i in d: #i will be each value in the list d
if not n%i: #this is equal to if n%i == 0
return 0 #not prime (well, according to this anyway)
return 1 #prime
while count < 1000:
count += cycle(n) #adds the return from cycle to count
n += 1
print n - 1
The answer is still incorrect because that is not how to test for a prime. But knowing a little syntax would at least get you that wrong answer, which is better than a lot of tracebacks.
(Also, I realize lists, for loops, and functions were not in the list of things you say you know.)
Your code for this answer can be condensed merely to this:
prime_count = 1
start_number = 2
number_to_check = 2
while prime_count <= 1000:
result = number_to_check % start_number
if result > 0:
start_number +=1
elif result == 0:
if start_number == number_to_check:
print (number_to_check)
number_to_check +=1
prime_count +=1
start_number =2
else:
number_to_check +=1
start_number = 2
To answer your subsequent question, 'How do I keep track of all the prime numbers?
One way of doing this is to make a list.
primeList = [] # initializes a list
Then, each time you test a number for whether it is prime or not, add that number to primeList
You can do this by using the 'append' function.
primeList.append( potprime ) # adds each prime number to that list
Then you will see the list filling up with numbers so after the first three primes it looks like this:
>>> primeList
[11, 13, 17]
Your math is failing you. A prime number is a number that has 2 divisors: 1 and itself. You are not testing the numbers for primality.
I am very late on this but maybe my answer will be of use to someone. I am doing the same open course at MIT and this is the solution I came up with. It returns the correct 1000th prime and the correct 100,000th prime and various others in between that I have tested. I think this is a correct solution (not the most efficient I am sure but a working solution I think).
#Initialise some variables
candidate = 1
prime_counter = 1
while prime_counter < 1000:
test = 2
candidate = candidate + 2
# While there is a remainder the number is potentially prime.
while candidate%test > 0:
test = test + 1
# No remainder and test = candidate means candidate is prime.
if candidate == test:
prime_counter = prime_counter + 1
print "The 1000th prime is: " + str(candidate)
While I was at it I went on and did the second part of the assignment. The question is posed as follows:
"There is a cute result from number theory that states that for sufficiently large n the product of the primes less than n is less than or equal to e^n and that as n grows, this becomes a tight bound (that is, the ratio of the product of the primes to e^n gets close to 1 as n grows).
Computing a product of a large number of prime numbers can result in a very large number,
which can potentially cause problems with our computation. (We will be talking about how
computers deal with numbers a bit later in the term.) So we can convert the product of a set of primes into a sum of the logarithms of the primes by applying logarithms to both parts of this conjecture. In this case, the conjecture above reduces to the claim that the sum of the
logarithms of all the primes less than n is less than n, and that as n grows, the ratio of this sum to n gets close to 1."
Here is my solution. I print the result for every 1,000th prime up to the 10,000th prime.
from math import *
#Initialise some variables
candidate = 1
prime_counter = 1
sum_logs = log(2)
while prime_counter < 10000:
test = 2
candidate = candidate + 2
# While there is a remainder the number is potentially prime.
while candidate%test > 0:
test = test + 1
# No remainder and test = candidate means candidate is prime.
if candidate == test:
prime_counter = prime_counter + 1
# If the number is prime add its log to the sum of logs.
sum_logs = sum_logs + log(candidate)
if prime_counter%1000 == 0:
# For every 1000th prime print the result.
print sum_logs," ",candidate," ",sum_logs/candidate
print "The 10000th prime is: " + str(candidate)
Cheers,
Adrian
I came up with this solution in my interview, but I didn't get the job :( It has about 1/100 less iterations than the solution above:
from math import *
MAX_IDX=1000
MAX_IDX-=1
num_iter=0
l_pirme_list=[3]
candidate=l_pirme_list[0]
prime_counter=1
while prime_counter < MAX_IDX:
candidate+=2
#Cut the binary number in half. This is quite faster than sqrt()
bin_candidate=format(candidate, "2b")
max_prime_search=int(bin_candidate[:len(bin_candidate)/2+1],2)+1
# max_prime_search=sqrt(candidate)+1
candidate_is_prime=1
for prime_item in l_pirme_list:
num_iter+=1
if candidate % prime_item==0:
candidate_is_prime=0
break
elif prime_item > max_prime_search:
candidate_is_prime=1
break
if candidate_is_prime:
prime_counter+=1
l_pirme_list.append(candidate)
l_pirme_list.insert(0,2)
print "number iterations=", num_iter
print l_pirme_list[MAX_IDX]

Categories