error in generating prime numbers in python - python

I want to print all the prime numbers from 1 to 10 but nothing gets printed when i run the program
c=0
nums = []
k=0
for a in range(1,11):
for b in range(1,11):
if a%b==0:
c = c+1
if c==2:
nums.append(a)
k = k+1
for d in nums:
print nums[d]

I can't figure out why you are using k
and your c should reset in "a" loop and out of "b" loop
code like this:
nums = []
for a in range(1, 11):
c = 0
for b in range(1, 11):
if a % b == 0:
c = c + 1
if c == 2:
nums.append(a)
print nums

You should reset c to zero before the beginning of each inner loop:
nums = []
for a in range(1,11):
c = 0
for b in range(1,11):
if a%b==0:
c = c+1
if c==2:
nums.append(a)
for d in nums:
print d
Additionally, you should use print d, since the for-loop already gives every element in nums.
Using a list comprehension is generally faster and considered more pythonic than using a for-loop.
There are many different ways of calculating prime numbers. Here are some of them.
Here is your original algorithm, with some improvements;
def prime_list(num):
"""Returns a list of all prime numbers up to and including num.
:num: highest number to test
:returns: a list of primes up to num
"""
if num < 3:
raise ValueError('this function only accepts arguments > 2')
candidates = range(3, num+1, 2)
L = [c for c in candidates if all(c % p != 0 for p in range(3, c, 2))]
return [2] + L
For primes >2, they must be odd numbers. So candidates should contain only odd numbers.
For an odd number c to be prime, one must ensure that c modulo all previous odd numbers (p) must be non-zero.
Lastly, 2 is also prime.
A further improvement is to restrict p up to sqrt(c):
import math
def prime_list2(num):
if num < 3:
raise ValueError('this function only accepts arguments > 2')
candidates = range(3, num+1, 2)
L = [c for c in candidates if all(c % p != 0 for p in
range(3, int(math.sqrt(c))+1, 2))]
return [2] + L
Another implementation:
def prime_list3(num):
num += 1
candidates = range(3, num, 2)
results = [2]
while len(candidates):
t = candidates[0]
results.append(t)
candidates = [i for i in candidates if not i in range(t, num, t)]
return results
This starts off with a list of candidates that contains all odd numbers. Then is calculates a new list of candidates by removing the first number of the previous list and all all multiples of it.
Let's look at the speed of the algorithms.
For small numbers, the original prime_list is the fastest;
In [8]: %timeit prime_list(10)
100000 loops, best of 3: 8.68 µs per loop
In [9]: %timeit prime_list2(10)
100000 loops, best of 3: 10.9 µs per loop
In [10]: %timeit prime_list3(10)
100000 loops, best of 3: 8.96 µs per loop
For larger numbers, prime_list2 comes out the winner:
In [5]: %timeit prime_list(1000)
100 loops, best of 3: 8.28 ms per loop
In [6]: %timeit prime_list2(1000)
100 loops, best of 3: 2.46 ms per loop
In [7]: %timeit prime_list3(1000)
10 loops, best of 3: 23.5 ms per loop
In [11]: %timeit prime_list(10000)
1 loops, best of 3: 646 ms per loop
In [12]: %timeit prime_list2(10000)
10 loops, best of 3: 25.4 ms per loop
In [13]: %timeit prime_list3(10000)
1 loops, best of 3: 2.13 s per loop

I added two print statements to your code - first, under if a%b==0:, I added print a,b; and I print the final value of c after that loop. I get this output:
1 1
1
2 1
2 2
3
3 1
3 3
5
4 1
4 2
4 4
8
5 1
5 5
10
6 1
6 2
6 3
6 6
14
7 1
7 7
16
8 1
8 2
8 4
8 8
20
9 1
9 3
9 9
23
10 1
10 2
10 5
10 10
27
This tells you why you get nothing printed: after the b loop in a == 1, c is 1; after the same loop in the next iteration of the outer loop, c is now 3. So c==2 is never True when that test is made, so nums stays empty.
This also gives you a big hint as to what you need to do to fix it. c keeps increasing, but it should start counting afresh for each iteration of the outer loop - so, move your c=0 to be inside the outer for loop. You also need to change your final print loop to print d instead of print nums[d], or you will get another error. With those changes, your code looks like this:
nums = []
k=0
for a in range(1,11):
c=0
for b in range(1,11):
if a%b==0:
c = c+1
if c == 2:
nums.append(a)
k = k+1
for d in nums:
print d
and it prints
2
3
5
7
as expected.

Your c is not reset to zero inside the loop (the first loop). So set c=0 after line: for a in range(1,11):
I dont know what your k is for. Is it usefull for anything?
Printing the prime numbers dont do nums[d], print d. You are looping on the items not on the indices.

Your code has multiple issues - Every prime number is divisible by 1 so your checks will fail, you are printing nums[d] which is wrong, k is doing nothing, variable nomenclature is too obfuscated, you have unnecessary runs in for loop - you don't need to iterate for all values of b in range, it is sufficient to iterate over existing prime numbers and so on.
Here is how I would write it
primes = [2]
upper_limit = 1000 #find all primes < 1000
for candidate in range(2, upper_limit):
can_be_prime = True
for prime in primes:
if candidate % prime == 0:
can_be_prime = False
break
if can_be_prime:
primes.append(candidate)
print primes

This solution is a little neater:
nums = []
for a in range(2, 101):
for b in range(2, a):
if a % b == 0:
break
else:
nums.append(a)
print nums
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]
Still, there is no point trying b > sqrt(a).

Try this:
nums = []
k=0
for a in range(2,11):
c=0
for b in range(1,11):
if a%b==0:
c = c+1
if c==2:
nums.append(a)
k = k+1
for d in nums:
print d
You will get
2
3
5
7
Note the code could be more efficient.

Related

Get the closest higher value from a sequence

I have a sequence like: 4, 8, 16, 32, 64, 128, 256, 512
now I have a number
a = 5
then
b = 8
means b is the closest higher digit according to a from the sequence.
Now a = x then b = ?
I offer two solutions. The first is probably the most obvious and intuitive. The second is more advanced but more efficient.
Simple and intuitive
Here is a simple intuitive approach. The following function returns the closest number greater than or equal to the argument num in the sequence 4, 8, 16, 32, 64, .... The function first assigns n to 4. Then, so long as n is strictly less than the argument num, n is assigned the next value in the sequence and the comparison is made again. Once n is greater than or equal to num, we return n.
def seq_1(num):
"""Returns the closest number greater than or equal to num in the
sequence 4, 8, 16, 32, 64, ...
"""
n = 4
while (n < num):
n *= 2
return n
More efficient, but more advanced
A less intuitive approach but more efficient is obtained by first recognizing that the sequence is defined by
a_0 = 4;
a_n = 2 * a_(n-1) for n in {1, 2, 3, ...}.
Notice how a_(n-1) = 2 * a_(n-2). Substituting this into a_n = 2 * a_(n-1), we obtain a_n = (2 ** 2) * a_(n-2). More generally, through repeated substitutions, we obtain a_n = (2 ** n) * a_(0) or a_n = (2 ** n) * 4 or
a_n = (2 ** (n + 2)) for n in {0, 1, 2, 3, ...}
So the first element a_0 is 2 ** 2 = 4, the second element a_1 is 2 ** 3 = 8, the third is 2 ** 4 = 16 and so on.
This suggests the solution:
def seq_2(num):
"""Returns the closest number greater than or equal to num in the
sequence 4, 8, 16, 32, 64, ...
"""
if num < 4:
return 4
return 1 << (num - 1).bit_length()
if num is less than 4 we return 4.
1 << (num - 1).bit_length() evaluates to the closest power of 2 greater than or equal to num.
This requires the following knowledge:
2 is 10 in binary, 2 ** 2 is 100 in binary, 2 ** 3 is 1000 in binary, ..., 2 ** n in binary is 1 followed by n zeros.
bit_length() is a method defined for Python ints that "[r]eturn[s] the number of bits necessary to represent an integer in binary" (docs).
i << j shifts i left by j bits. For example
In [1]: bin(1)
Out[1]: '0b1' # 2 to the power of 0.
In [2]: bin(1 << 5)
Out[2]: '0b100000' # 2 to the power of 5.
Timings
# seq_1(420_000)
657 ns ± 0.55 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
# seq_2(420_000)
116 ns ± 0.416 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
Providing that your sequence is in ascending sorted order then:
seq = [4,8,16,32,64,128,256,512]
def get_next_highest(seq, a):
b = None
for i in range(len(seq)-1, -1, -1):
if seq[i] <= a:
break
b = seq[i]
return b
print(get_next_highest(seq, 5))
If you have a sorted sequence you can use bisect from Pythons standard library.
import bisect
data = [4, 8, 16, 32, 64, 128, 256, 512]
a = 5
index = bisect.bisect(data, a)
b = data[index]
You will have to add a boundary check if you expect a to have a value larger than the last element of the list.
This code demonstrates how it works with random values.
import bisect
import random
def get_next_highest(data, value):
try:
return data[bisect.bisect(data, value)]
except IndexError:
return None
def main():
data = sorted([random.randint(1, 100) for _ in range(10)])
a = 50
b = get_next_highest(data, a)
print(data, a, b)
if __name__ == '__main__':
main()

Combinations of Combinations

There are nearly 14 million combinations from a selection of 6 numbers from a range of 1-49. From the 14 million, I've cut the combinations down to 8.9 million by selecting only those where the sum of the 6 number combination must equate to between 120 and 180.
Example: 5, 10, 20, 27, 29, 40 = 131
Of the remaining 8.9 million combinations, I'm trying to remove all combinations that contain less than 2 and more than 4 odd numbers.
Basically, I want Python to show me how many combinations of those 8.9 million combinations have between 2-4 odd numbers in their combinations. All combinations of only 1 or less odd numbers and 5 or more odd numbers would be excluded from the results.
Example: 5, 10, 20, 27, 32, 40 = 2 odd numbers (it would be included in the amount of combinations).
Thank you!
import functools
_MIN_SUM = 120
_MAX_SUM = 180
_MIN_NUM = 1
_MAX_NUM = 49
_NUM_CHOICES = 6
#functools.lru_cache(maxsize=None)
def f(n, l, s):
assert(all(isinstance(v, int) and v >= 0 for v in (n, l, s)))
return 0 if s > _MAX_SUM else (
int(s >= _MIN_SUM) if n == 0 else (
sum(f(n-1, i+1, s+i) for i in range(l, _MAX_NUM+1))
)
)
result = f(_NUM_CHOICES, _MIN_NUM, 0)
print('Number of choices = {}'.format(result))
You can use the combinations() function from itertools and just brutally count the combinations that are eligible:
from itertools import combinations
eligible = 0
for combo in combinations(range(1,50),6):
total = sum(combo)
if total < 120 or total > 180:
continue
odds = sum(n&1 for n in combo)
if odds < 2 or odds > 4:
continue
eligible += 1
print(eligible) # 7221936
It only takes a few seconds (10-12)
You can do almost exactly the same as you are currently doing. Just add a parameter that counts how many odd numbers there are and increase it when you add an odd. Then you can adjust your tests accordingly:
import functools
_MIN_SUM = 120
_MAX_SUM = 180
_MIN_NUM = 1
_MAX_NUM = 49
_NUM_CHOICES = 6
_MIN_ODDS = 2
_MAX_ODDS = 4
#functools.lru_cache(maxsize=None)
def f(n, l, s = 0, odds = 0):
if s > _MAX_SUM or odds > _MAX_ODDS:
return 0
if n == 0 :
return int(s >= _MIN_SUM and odds >= _MIN_ODDS)
return sum(f(n-1, i+1, s+i, odds + i % 2) for i in range(l, _MAX_NUM+1))
result = f(_NUM_CHOICES, _MIN_NUM)
print('Number of choices = {}'.format(result))
Because it's memoized and prunes branches, this runs quickly:
150 ns ± 13 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
Running it with the more managable:
_MIN_SUM = 1
_MAX_SUM = 8
_MIN_NUM = 1
_MAX_NUM = 8
_NUM_CHOICES = 2
_MIN_ODDS = 2
_MAX_ODDS = 4
returns 4 which corresponds to the set:
(1, 3),
(1, 5),
(1, 7),
(3, 5)

How to select the first occurrence of a repeated item in sequence in a list using traditional python or using pandas/numpy/sciy

Let's say there is a list 'series' which has some repeated elements at several index values. Is there a way to find the first occurrence of a repeated sequence of a number.
series = [2,3,7,10,11,16,16,9,11,12,14,16,16,16,5,7,9,17,17,4,8,18,18]
Return should be similar to [5,11,17,21] which are the index values of first occurrence for repeated sequences of [16,16] , [16,16,16] , [17,17] and [18,18]
Here's one for performance using array-slicing, similar to #piRSquared's second solution but without any appending/concatenation -
a = np.array(series)
out = np.flatnonzero((a[2:] == a[1:-1]) & (a[1:-1] != a[:-2]))+1
Sample run -
In [28]: a = np.array(series)
In [29]: np.flatnonzero((a[2:] == a[1:-1]) & (a[1:-1] != a[:-2]))+1
Out[29]: array([ 5, 11, 17, 21])
Runtime test (for working solutions)
Approaches -
def piRSquared1(series):
d = np.flatnonzero(np.diff(series) == 0)
w = np.append(True, np.diff(d) > 1)
return d[w].tolist()
def piRSquared2(series):
s = np.array(series)
return np.flatnonzero(
np.append(s[:-1] == s[1:], True) &
np.append(True, s[1:] != s[:-1])
).tolist()
def Zach(series):
s = pd.Series(series)
i = [g.index[0] for _, g in s.groupby((s != s.shift()).cumsum()) if len(g) > 1]
return i
def jezrael(series):
s = pd.Series(series)
s1 = s.shift(1).ne(s).cumsum()
m = ~s1.duplicated() & s1.duplicated(keep=False)
s2 = m.index[m].tolist()
return s2
def divakar(series):
a = np.array(series)
x = a[1:-1]
return (np.flatnonzero((a[2:] == x) & (x != a[:-2]))+1).tolist()
For the setup, we are simply tiling the sample input a number of times.
Timings -
Case #1 : Large set
In [34]: series0 = [2,3,7,10,11,16,16,9,11,12,14,16,16,16,5,7,9,17,17,4,8,18,18]
In [35]: series = np.tile(series0,10000).tolist()
In [36]: %timeit piRSquared1(series)
...: %timeit piRSquared2(series)
...: %timeit Zach(series)
...: %timeit jezrael(series)
...: %timeit divakar(series)
...:
100 loops, best of 3: 8.06 ms per loop
100 loops, best of 3: 7.79 ms per loop
1 loop, best of 3: 3.88 s per loop
10 loops, best of 3: 24.3 ms per loop
100 loops, best of 3: 7.97 ms per loop
Case #2 : Much larger set (on top 2 solutions)
In [40]: series = np.tile(series0,1000000).tolist()
In [41]: %timeit piRSquared2(series)
1 loop, best of 3: 823 ms per loop
In [42]: %timeit divakar(series)
1 loop, best of 3: 823 ms per loop
Now, those two solutions differ only in the way appending is avoided in the latter one. Let's take a closer look at them and run on a smaller dataset -
In [43]: series = np.tile(series0,100).tolist()
In [44]: %timeit piRSquared2(series)
10000 loops, best of 3: 89.4 µs per loop
In [45]: %timeit divakar(series)
10000 loops, best of 3: 82.8 µs per loop
Thus, it reveals that the concatenation/append avoiding in the latter solution helps a lot when dealing with smaller datasets, but at much larger datasets, they become comparable.
Marginal improvement on larger dataset is possible with one concatenation there. Thus, the last step could be re-written as :
np.flatnonzero(np.concatenate(([False],(a[2:] == a[1:-1]) & (a[1:-1] != a[:-2]))))
You could use shift
In [3815]: s = pd.Series(series)
In [3816]: cond = (s == s.shift(-1))
In [3817]: cond.index[cond]
Out[3817]: Int64Index([5, 11, 12, 17, 21], dtype='int64')
Or, diff
In [3828]: cond = s.diff(-1).eq(0)
In [3829]: cond.index[cond]
Out[3829]: Int64Index([5, 11, 12, 17, 21], dtype='int64')
For list output use tolist
In [3833]: cond.index[cond].tolist()
Out[3833]: [5, 11, 12, 17, 21]
Details
In [3823]: s.head(10)
Out[3823]:
0 2
1 3
2 7
3 10
4 11
5 16
6 16
7 9
8 11
9 12
dtype: int64
In [3824]: cond.head(10)
Out[3824]:
0 False
1 False
2 False
3 False
4 False
5 True
6 False
7 False
8 False
9 False
dtype: bool
First create unique groups by shift with cumsum and then get mask for first duplicates and filter by boolean indexing:
s = pd.Series([2,3,7,10,11,16,16,9,11,12,14,16,16,16,5,7,9,17,17,4,8,18,18])
s1 = s.shift(1).ne(s).cumsum()
m = ~s1.duplicated() & s1.duplicated(keep=False)
s2 = m.index[m].tolist()
print (s2)
[5, 11, 17, 21]
print (s1)
0 1
1 2
2 3
3 4
4 5
5 6
6 6
7 7
8 8
9 9
10 10
11 11
12 11
13 11
14 12
15 13
16 14
17 15
18 15
19 16
20 17
21 18
22 18
dtype: int32
print (m)
dtype: int32
0 False
1 False
2 False
3 False
4 False
5 True
6 False
7 False
8 False
9 False
10 False
11 True
12 False
13 False
14 False
15 False
16 False
17 True
18 False
19 False
20 False
21 True
22 False
dtype: bool
np.diff & np.flatnonzero
This answer uses np.diff and tests for when that difference is zero. At those points, we know we have duplication. We use np.flatnonzero to give us the positions of where those differences are zero. However, we only want the first position of consecutive differences. So we use np.diff again to filter out only the first of the series of duplicates. This time we use the results as a boolean mask.
d = np.flatnonzero(np.diff(series) == 0)
w = np.append(True, np.diff(d) > 1)
d[w]
array([ 5, 11, 17, 21])
np.flatnonzero
This is a superior answer in my opinion. We build a boolean array evaluating when a value is equal to the next but not equal to the previous. We leverage np.flatnonzero to tell us the positions of the True values.
I also find the symmetry of the answer appealing.
s = np.array(series)
np.flatnonzero(
np.append(s[:-1] == s[1:], True) &
np.append(True, s[1:] != s[:-1])
)
array([ 5, 11, 17, 21])
Since we appear to be competing on speed, and it's not likely anyone will beat Divakar / piRsquared without cheating around the pandas/numpy/scipy requirement, here's my numba solution:
from numba import jit
import numpy as np
#jit
def rpt_idx(s):
out = []
j = True
for i in range(len(s)):
if s[i] == s[i+1]:
if j:
out.append(i)
j = False
else:
j = True
return out
rpt_idx(series)
Out: array([ 5, 11, 17, 21])
Probably totally overkill to pull out jit for such a trivial case, but it does give a big speedup
%timeit rpt_idx(series)
The slowest run took 10.50 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 1.99 µs per loop
%timeit divakar(series)
The slowest run took 7.73 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 12.5 µs per loop
series_ = np.tile(series,10000).tolist()
%timeit divakar(series_)
100 loops, best of 3: 20.1 ms per loop
%timeit rpt_idx(series_)
100 loops, best of 3: 5.84 ms per loop
You can imitate Python's itertools.groupby simply enough, and group adjacent duplicates together.
>>> import pandas
>>> s = pandas.Series([2, 3, 7, 10, 11, 16, 16, 9, 11, 12, 14, 16, 16, 16, 5, 7, 9, 17, 17, 4, 8, 18, 18])
>>> for _, group in s.groupby((s != s.shift()).cumsum()):
... if len(group) > 1:
... print(group.index[0])
5
11
17
21
Or as a list:
>>> [g.index[0] for _, g in s.groupby((s != s.shift()).cumsum()) if len(g) > 1]
[5, 11, 17, 21]

How to count continuous numbers in numpy

I have a Numpy one-dimensional array of 1 and 0. for e.g
a = np.array([0,1,1,1,0,0,0,0,0,0,0,1,0,1,1,0,0,0,1,1,0,0])
I want to count the continuous 0s and 1s in the array and output something like this
[1,3,7,1,1,2,3,2,2]
What I do atm is
np.diff(np.where(np.abs(np.diff(a)) == 1)[0])
and it outputs
array([3, 7, 1, 1, 2, 3, 2])
as you can see it is missing the first count 1.
I've tried np.split and then get the sizes of each segments but it does not seem to be optimistic.
Is there more elegant "pythonic" solution?
Here's one vectorized approach -
np.diff(np.r_[0,np.flatnonzero(np.diff(a))+1,a.size])
Sample run -
In [208]: a = np.array([0,1,1,1,0,0,0,0,0,0,0,1,0,1,1,0,0,0,1,1,0,0])
In [209]: np.diff(np.r_[0,np.flatnonzero(np.diff(a))+1,a.size])
Out[209]: array([1, 3, 7, 1, 1, 2, 3, 2, 2])
Faster one with boolean concatenation -
np.diff(np.flatnonzero(np.concatenate(([True], a[1:]!= a[:-1], [True] ))))
Runtime test
For the setup, let's create a bigger dataset with islands of 0s and 1s and for a fair benchmarking as with the given sample, let's have the island lengths vary between 1 and 7 -
In [257]: n = 100000 # thus would create 100000 pair of islands
In [258]: a = np.repeat(np.arange(n)%2, np.random.randint(1,7,(n)))
# Approach #1 proposed in this post
In [259]: %timeit np.diff(np.r_[0,np.flatnonzero(np.diff(a))+1,a.size])
100 loops, best of 3: 2.13 ms per loop
# Approach #2 proposed in this post
In [260]: %timeit np.diff(np.flatnonzero(np.concatenate(([True], a[1:]!= a[:-1], [True] ))))
1000 loops, best of 3: 1.21 ms per loop
# #Vineet Jain's soln
In [261]: %timeit [ sum(1 for i in g) for k,g in groupby(a)]
10 loops, best of 3: 61.3 ms per loop
Using groupby from itertools
from itertools import groupby
a = np.array([0,1,1,1,0,0,0,0,0,0,0,1,0,1,1,0,0,0,1,1,0,0])
grouped_a = [ sum(1 for i in g) for k,g in groupby(a)]
I found a similar method to yours, just that this code finds the first and the last count separately. The answer is detailed in the code below:
import numpy as np
a = np.array([0,1,1,1,0,0,0,0,0,0,0,1,0,1,1,0,0,0,1,1,0,0])
print(f'a: {a}')
diff_a = np.diff(a)
print(f'diff_a: {diff_a}')
non_zero_pos_arr = np.where(diff_a != 0)[0]
print(f'Array of positions where non zero elements are present in diff_a array: {non_zero_pos_arr}')
diff_non_zero_pos_arr = np.diff(non_zero_pos_arr)
print(f'Result Array except for first and last element: {diff_non_zero_pos_arr}')
ans_first_ele = non_zero_pos_arr[0] + 1
ans_last_ele = len(diff_a) - non_zero_pos_arr[-1]
ans = np.array([], dtype=np.int8)
ans = np.append(ans, ans_first_ele)
ans = np.append(ans, diff_non_zero_pos_arr)
ans = np.append(ans, ans_last_ele)
print(f'Result Array: {ans}')
Output:
a: [0 1 1 1 0 0 0 0 0 0 0 1 0 1 1 0 0 0 1 1 0 0]
diff_a: [ 1 0 0 -1 0 0 0 0 0 0 1 -1 1 0 -1 0 0 1 0 -1 0]
Array of positions where non zero elements are present in diff_a array:
[ 0 3 10 11 12 14 17 19]
Result Array except for first and last element: [3 7 1 1 2 3 2]
Result Array: [1 3 7 1 1 2 3 2 2]

Weird output on converting code from C to Python

I could successfully rum a simple program to check whether the number is prime or not in C. The code looks like this
void isPrime(int n)
{
int a=0,i;
for(i=1;i<=n;i++)
{
if(n%i==0)
a++;
}
if(a==2)
{
printf("\n%d is prime",n);
}
else
{
printf("\n%d is not prime",n);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
for(int i=2;i<=20;i++)
{
isPrime(i);
}
return 0;
}
The above code runs perfectly when I compile. I am a beginner in python and I have converted the same code into python, which looks like this.
def isPrime(n):
a=0
for x in range(1,n):
if n%x==0:
a=a+1
if a==2:
print("{} is prime".format(n))
else:
print("{} is not prime".format(n))
for n in range(2,20):
isPrime(n)
But I get a wrong output in python. The output is somewhat weird which says
2 is not prime
3 is not prime
4 is prime
5 is not prime
6 is not prime
7 is not prime
8 is not prime
9 is prime
10 is not prime
11 is not prime
12 is not prime
13 is not prime
14 is not prime
15 is not prime
16 is not prime
17 is not prime
18 is not prime
19 is not prime
I have found out that the count of 'a' is 1 less than the actual count required. For example, in case of n=8, a should be 4. But its getting counted as 3.
What could be the reason?
Why don't you add some print statements so you can see where the code fails? Adding some prints should be your first reflex when debugging.
def isPrime(n):
a=0
for x in range(1,n):
print('x,a', x,a)
if n%x==0:
print('incrementing a...')
a=a+1
print('a after loop:', a)
if a==2:
print("{} is prime".format(n))
else:
print("{} is not prime".format(n))
Output for isPrime(2):
x,a 1 0
incrementing a...
a after loop: 1
2 is not prime
Output for isPrime(7):
x,a 1 0
incrementing a...
x,a 2 1
x,a 3 1
x,a 4 1
x,a 5 1
x,a 6 1
a after loop: 1
7 is not prime
As you can see, a is never 2 because the n%n test is never executed, because with x in range(1,n), the last value for x is n-1. However, if you change your range to range(1,n+1), the test will be made:
x,a 1 0
incrementing a...
x,a 2 1
x,a 3 1
x,a 4 1
x,a 5 1
x,a 6 1
x,a 7 1
incrementing a...
a after loop: 2
7 is prime
The issue you have is that the last value produced range(start, stop) is stop-1; see the docs. Thus, isPrime should have the following for loop:
for x in range(1, n+1):
This will faithfully replicate the C code, and produce the correct output. (Note that this is also why you are only checking the numbers [2, 19] for whether they're prime, as opposed to [2, 20].)
I think the problem was with your range as mentioned above. Can I give you some short tips to make your code more "Pythonic"? :)
Instead of
if n%x==0
you would simply write
if not n%x
and instead of
a=a+1
you could use the in-place operator, e.g.,
a += 1
Here, it wouldn't make much of a difference, but if you are working with mutable objects (due to the __iadd__ method, I have more details here) you would gain a significant performance increase, e.g.,
def slow(a):
for i in range(1000):
a = a + [1,2]
def fast(a):
for i in range(1000):
a += [1,2]
a = []
b = []
%timeit -r 3 -n 1000 slow(a)
%timeit -r 3 -n 1000 fast(b)
1000 loops, best of 3: 2.94 ms per loop
1000 loops, best of 3: 181 µs per loop
Same for the binary operator instead of the format() method, however, I like the latter one better (due to its more powerful minilanguange and I would recommend it if you don't care about speed in certain computations)
%timeit -r 3 -n 1000 '{} World'.format('Hello')
%timeit -r 3 -n 1000 '%s World' %('Hello')
1000 loops, best of 3: 472 ns per loop
1000 loops, best of 3: 27.3 ns per loop
def isPrime(n):
a = 0
for x in range(1, n+1):
if not n%x:
a += 1
if a==2:
print("{} is prime".format(n))
else:
print("{} is not prime".format(n))
for n in range(2, 20):
isPrime(n)

Categories

Resources