Prime numbers in a given range using Sieve of Eratosthenes - python

I am trying to print prime numbers less than 'n'.The code is below:
def prime_numbers(n):
A=[1 for i in range(n+1)]
for i in range(2,int(sqrt(n))):
if A[i]==1:
for j in range(i*2,n,i):
A[j]=0
for i in range(n):
if A[i]:
print(i)
Output for
prime_numbers(10)
is
0
1
2
3
5
7
9
The program correctly prints for 100. What changes do I need to make?

The end point in a range() is not included. Since sqrt(10) is 3.1623, your range() loops to 2 and no further, and the multiples of 3 are not removed from your list. Your code works for 100, because it doesn't matter if you test for multiples 10 (those are already covered by 2 and 5).
The same issue applies to your other loops; if you want to include n itself as a candidate prime number you should also include it in the other ranges.
Note that you also want to ignore 0 and 1, those are not primes. You could add A[0] = A[1] = False at the top to make sure your last loop doesn't include those, or start your last loop at 2 rather than 0.
You want to add one to the floored square root to make sure it is tested for:
for i in range(2, int(sqrt(n)) + 1):
I'd use booleans rather than 0 and 1, by the way, just for clarity (there is not much of a performance or memory footprint difference here):
def prime_numbers(n):
sieve = [True] * (n + 1) # create a list n elements long
for i in range(2, int(sqrt(n)) + 1):
if sieve[i]:
for j in range(i * 2, n + 1, i):
sieve[j] = False
for i in range(2, n + 1):
if sieve[i]:
print(i)
I used [..] * (n + 1) to create a list of n items (plus 0); this produces a list with n shallow copies of the contents of the left operand. That's faster than a list comprehension, and the shared references are fine since True is a singleton in Python.
Demo:
>>> prime_numbers(31)
2
3
5
7
11
13
17
19
23
29
31
Note that 31 is included there; your code would have resulted in incorrect output as you'd have left in all the multiples of 5.

Related

find pairs of numbers where cube is equal to square

We are given a number N and we have to find pairs i and j where i^3=j^2
For example, let N=50 so for this we will have 3 pairs (1,1),(4,8),(9,27)
basically, we have to find pairs where the cube of one number is the same as the square of the other number in a given pair
the constraint is
1<=N<10^6
1<=i,j<N
Naive approach use 2 for loops iterate through each element and get those pairs where cube is equal to sum time complexity is O(n*2)
def get_pair(N):
for i in range(1,N):
for j in range(1,N):
if i*i*i==j*j:
print(i,j)
N=50
get_pair(N)
what will be an optimal way to solve this problem with a better time complexity?
Since you're working with integers, if there exists some number M = i^3 = j^2 for i and j between 1 and N, then that means there exists a k such that M = k^6. To find i and j, simply compare the representations of M:
(1) M = k^6 = i^3 = (k^2)^3 therefore i = k^2
(2) M = k^6 = j^2 = (k^3)^2 therefore j = k^3
Since j is always greater than or equal to i, you only need to check if 1 < k^3 < N. In other words, k should be less than the cube root of N.
k
M = k^6
i = k^2
j = k^3
2
64
4
8
3
729
9
27
4
4,096
16
64
5
15,625
25
125
6
46,656
36
216
...
...
...
...
97
8.329x10^11
9409
912,673
98
8.858x10^11
9604
941,192
99
9.415x10^11
9801
970,299
Note that 100 isn't a valid candidate for k because that would make j less than or equal to N instead of strictly less than N (if we're going with N = 10^6).
So to get the list of tuples that satisfy your problem, find the values of k such that 1 < k^3 < N and return its square and cube in a tuple.
import math
from typing import List, Tuple
N: int = 10**6
pairs: List[Tuple[int, int]] = [(k * k, k * k * k) for k in range(2, math.ceil(N**(1 / 3)))]
print(pairs)
This is a list comprehension, a shorthand for a for-loop.
I'm basically asking Python to generate a list of tuples over an index k that falls in the range defined as range(2, math.ceil(N**(1 / 3)). That range is exactly the first column of the table above.
Then, for every k in that range I make a tuple of which the first item is k^2 and the second item is k^3, just like the last two columns of the table.
Also threw in the typing library in there for good measure. Clear code is good code, even for something as small as this. Python can figure out that pairs is a list of tuples without anyone telling it, but this way I've explicitly enforced that variable to be a list of tuples to avoid any confusion when someone tries to give it a different value or isn't sure what the variable contains.
Another naive approach could be to use the "basic" values ?
def get_pair(N):
for i in range(N):
if(i**3 > MAX):
break # Limit to the max you want, and i**3 > i**2 if i > 1
print(i**2, i**3)
Time complexity seems to be O(n) (Not an expert, so correct me if i'm wrong)
This is made so that the first element cubed == second element squared:
first = a^2
second = a^3
first^3 = a^(2*3) = a^6
second^2 = a^(3*2) = a^6
You can use itertool's combinations_with_replacement function.
from itertools import combinations_with_replacement as combinations
def get_pair(N):
for i, j in combinations(range(1,N), 2):
if i*i*i==j*j:
print(i,j)
N=50
get_pair(N)
You do this with one loop (and minimal iterations) if you know that that pairs (x, y) are always y = x * i, this means you can use:
def get_pair(N):
i = 1
a = 1
while a * i < N:
b = a * i
print(a,b)
i += 1
a = i**2
N=50
get_pair(N)
This gets all 3 pairs:
1 1
4 8
9 27
In only 3 total iterations.

How to generate a list by specified rules?

How to efficiently generate a list by the specified rules?
Rules:
num 20 occurs with step 2 in the list
num 40 occurs with step 4 in the list
num 60 occurs with step 8 in the list
num 80 occurs with step 16 in the list
The end result of a list of length 15 should look like this:
[20,40,20,60,20,40,20,80,20,40,20,60,20,40,20]
The "step" rules are always a power of something. In this example is power of 2.
So, let's say we have it written as:
rules_power = 2
n1 = 20
n1_step = 2
n2 = 40
n2_step = 4
n3 = 60
n3_step = 8
n4 = 80
n4_step = 16
How do we efficiently generate such a list?
Since you mentioned step rules are always powers, there is a rule to find where each element starts (appears the first time).
[20,40,20,60,20,40,20,80,20,40,20,60,20,40,20]
0 1 3 7
As you see each new element(20, 40, 60, 80) appears first where (2 ** i - 1). Knowing this, one could easily fill the empty list using indices and steps.
length = 15
lst = [0] * length # better use comprehension
for i in xrange(2 ** 0 - 1, length, n1_step):
lst[i] = n1
for i in xrange(2 ** 1 - 1, length, n2_step):
lst[i] = n2
for i in xrange(2 ** 2 - 1, length, n3_step):
lst[i] = n3
for i in xrange(2 ** 3 - 1, length, n4_step):
lst[i] = n4
print lst
Replace the power with your other cases, and the print, xrange for python 3 usage.
If you store the values and the steps inside a list, you can do this process with two nested for loops, no matter how many rules are there.
The complexity of this is O(2n), therefore n, should be enough, however because I don't know the original problem, I cannot give more.

Improving runtime on Euler #10

So I was attacking a Euler Problem that seemed pretty simple on a small scale, but as soon as I bump it up to the number that I'm supposed to do, the code takes forever to run. This is the question:
The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.
I did it in Python. I could wait a few hours for the code to run, but I'd rather find a more efficient way to go about this. Here's my code in Python:
x = 1;
total = 0;
while x <= 2000000:
y = 1;
z = 0;
while x >= y:
if x % y == 0:
z += 1;
y += 1;
if z == 2:
total += x
x += 1;
print total;
Like mentioned in the comments, implementing the Sieve of Eratosthenes would be a far better choice. It takes up O(n) extra space, which is an array of length ~2 million, in this case. It also runs in O(n), which is astronomically faster than your implementation, which runs in O(n²).
I originally wrote this in JavaScript, so bear with my python:
max = 2000000 # we only need to check the first 2 million numbers
numbers = []
sum = 0
for i in range(2, max): # 0 and 1 are not primes
numbers.append(i) # fill our blank list
for p in range(2, max):
if numbers[p - 2] != -1: # if p (our array stays at 2, not 0) is not -1
# it is prime, so add it to our sum
sum += numbers[p - 2]
# now, we need to mark every multiple of p as composite, starting at 2p
c = 2 * p
while c < max:
# we'll mark composite numbers as -1
numbers[c - 2] = -1
# increment the count to 3p, 4p, 5p, ... np
c += p
print(sum)
The only confusing part here might be why I used numbers[p - 2]. That's because I skipped 0 and 1, meaning 2 is at index 0. In other words, everything's shifted to the side by 2 indices.
Clearly the long pole in this tent is computing the list of primes in the first place. For an artificial situation like this you could get someone else's list (say, this one), prase it and add up the numbers in seconds.
But that's unsporting, in my view. In which case, try the sieve of atkin as noted in this SO answer.

Whats the purpose of using n+1 in this eratosthenes function?

Here is a simple eratosthenes sieve for prime numbers, which removes the multiples and append them in the empty list of multiples. My question is that if I use n instead of n+1 in both for loops the answer comes out the same.
def eratosthenes(n):
multiples = []
for i in xrange(2, n+1):
if i not in multiples:
print i
for j in xrange(i*i, n+1, i):
multiples.append(j)
returns output like
eratosthenes(10)
2
3
5
7
while if I replace n+1 with n in both loops the output is still the same:
def eratosthenes(n):
multiples = []
for i in xrange(2, n):
if i not in multiples:
print i
for j in xrange(i*i, n, i):
multiples.append(j)
returns the same output as above function...
eratosthenes(10)
2
3
5
7
My question is why we use n+1 instead of n?
The Python range() and xrange() functions, like the Python slice notation, do not include the end value; xrange(2, 10) generates 8 numbers from 2 to 9, not 10. n + 1 makes sure n is part of the generated range.
Use eratosthenes(7) or eratosthenes(11) to see the difference; 10 is not a prime number and is being filtered out.

Sum of all numbers

I need to write a function that calculates the sum of all numbers n.
Row 1: 1
Row 2: 2 3
Row 3: 4 5 6
Row 4: 7 8 9 10
Row 5: 11 12 13 14 15
Row 6: 16 17 18 19 20 21
It helps to imagine the above rows as a 'number triangle.' The function should take a number, n, which denotes how many numbers as well as which row to use. Row 5's sum is 65. How would I get my function to do this computation for any n-value?
For clarity's sake, this is not homework. It was on a recent midterm and needless to say, I was stumped.
The leftmost number in column 5 is 11 = (4+3+2+1)+1 which is sum(range(5))+1. This is generally true for any n.
So:
def triangle_sum(n):
start = sum(range(n))+1
return sum(range(start,start+n))
As noted by a bunch of people, you can express sum(range(n)) analytically as n*(n-1)//2 so this could be done even slightly more elegantly by:
def triangle_sum(n):
start = n*(n-1)//2+1
return sum(range(start,start+n))
A solution that uses an equation, but its a bit of work to arrive at that equation.
def sumRow(n):
return (n**3+n)/2
The numbers 1, 3, 6, 10, etc. are called triangle numbers and have a definite progression. Simply calculate the two bounding triangle numbers, use range() to get the numbers in the appropriate row from both triangle numbers, and sum() them.
Here is a generic solution:
start=1
n=5
for i in range(n):
start += len (range(i))
answer=sum(range(start,start+n))
As a function:
def trio(n):
start=1
for i in range(n):
start += len (range(i))
answer=sum(range(start,start+n))
return answer
def sum_row(n):
final = n*(n+1)/2
start = final - n
return final*(final+1)/2 - start*(start+1)/2
or maybe
def sum_row(n):
final = n*(n+1)/2
return sum((final - i) for i in range(n))
How does it work:
The first thing that the function does is to calculate the last number in each row. For n = 5, it returns 15. Why does it work? Because each row you increment the number on the right by the number of the row; at first you have 1; then 1+2 = 3; then 3+3=6; then 6+4=10, ecc. This impy that you are simply computing 1 + 2 + 3 + .. + n, which is equal to n(n+1)/2 for a famous formula.
then you can sum the numbers from final to final - n + 1 (a simple for loop will work, or maybe fancy stuff like list comprehension)
Or sum all the numbers from 1 to final and then subtract the sum of the numbers from 1 to final - n, like I did in the formula shown; you can do better with some mathematical operations
def compute(n):
first = n * (n - 1) / 2 + 1
last = first + n - 1
return sum(xrange(first, last + 1))

Categories

Resources