How do I determine whether a given integer is between two other integers (e.g. greater than/equal to 10000 and less than/equal to 30000)?
What I've attempted so far is not working:
if number >= 10000 and number >= 30000:
print ("you have to pay 5% taxes")
if 10000 <= number <= 30000:
pass
For details, see the docs.
>>> r = range(1, 4)
>>> 1 in r
True
>>> 2 in r
True
>>> 3 in r
True
>>> 4 in r
False
>>> 5 in r
False
>>> 0 in r
False
Your operator is incorrect. It should be if number >= 10000 and number <= 30000:. Additionally, Python has a shorthand for this sort of thing, if 10000 <= number <= 30000:.
Your code snippet,
if number >= 10000 and number >= 30000:
print ("you have to pay 5% taxes")
actually checks if number is larger than both 10000 and 30000.
Assuming you want to check that the number is in the range 10000 - 30000, you could use the Python interval comparison:
if 10000 <= number <= 30000:
print ("you have to pay 5% taxes")
This Python feature is further described in the Python documentation.
There are two ways to compare three integers and check whether b is between a and c:
if a < b < c:
pass
and
if a < b and b < c:
pass
The first one looks like more readable, but the second one runs faster.
Let's compare using dis.dis:
>>> dis.dis('a < b and b < c')
1 0 LOAD_NAME 0 (a)
2 LOAD_NAME 1 (b)
4 COMPARE_OP 0 (<)
6 JUMP_IF_FALSE_OR_POP 14
8 LOAD_NAME 1 (b)
10 LOAD_NAME 2 (c)
12 COMPARE_OP 0 (<)
>> 14 RETURN_VALUE
>>> dis.dis('a < b < c')
1 0 LOAD_NAME 0 (a)
2 LOAD_NAME 1 (b)
4 DUP_TOP
6 ROT_THREE
8 COMPARE_OP 0 (<)
10 JUMP_IF_FALSE_OR_POP 18
12 LOAD_NAME 2 (c)
14 COMPARE_OP 0 (<)
16 RETURN_VALUE
>> 18 ROT_TWO
20 POP_TOP
22 RETURN_VALUE
>>>
and using timeit:
~$ python3 -m timeit "1 < 2 and 2 < 3"
10000000 loops, best of 3: 0.0366 usec per loop
~$ python3 -m timeit "1 < 2 < 3"
10000000 loops, best of 3: 0.0396 usec per loop
also, you may use range, as suggested before, however it is much more slower.
if number >= 10000 and number <= 30000:
print ("you have to pay 5% taxes")
Define the range between the numbers:
r = range(1,10)
Then use it:
if num in r:
print("All right!")
The trouble with comparisons is that they can be difficult to debug when you put a >= where there should be a <=
# v---------- should be <
if number >= 10000 and number >= 30000:
print ("you have to pay 5% taxes")
Python lets you just write what you mean in words
if number in xrange(10000, 30001): # ok you have to remember 30000 + 1 here :)
In Python3, you need to use range instead of xrange.
edit: People seem to be more concerned with microbench marks and how cool chaining operations. My answer is about defensive (less attack surface for bugs) programming.
As a result of a claim in the comments, I've added the micro benchmark here for Python3.5.2
$ python3.5 -m timeit "5 in range(10000, 30000)"
1000000 loops, best of 3: 0.266 usec per loop
$ python3.5 -m timeit "10000 <= 5 < 30000"
10000000 loops, best of 3: 0.0327 usec per loop
If you are worried about performance, you could compute the range once
$ python3.5 -m timeit -s "R=range(10000, 30000)" "5 in R"
10000000 loops, best of 3: 0.0551 usec per loop
Below are few possible ways, ordered from best to worse performance (i.e first one will perform best)
# Old school check
if 10000 >= b and b <=30000:
print ("you have to pay 5% taxes")
# Python range check
if 10000 <= number <= 30000:
print ("you have to pay 5% taxes")
# As suggested by others but only works for integers and is slow
if number in range(10000,30001):
print ("you have to pay 5% taxes")
While 10 <= number <= 20 works in Python, I find this notation using range() more readable:
if number in range(10, 21):
print("number is between 10 (inclusive) and 21 (exclusive)")
else:
print("outside of range!")
Keep in mind that the 2nd, upper bound parameter is not included in the range set as can be verified with:
>>> list(range(10, 21))
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
However prefer the range() approach only if it's not running on some performance critical path. A single call is still fast enough for most requirements, but if run 10,000,000 times, we clearly notice nearly 3 times slower performance compared to a <= x < b:
> { time python3 -c "for i in range(10000000): x = 50 in range(1, 100)"; } 2>&1 | sed -n 's/^.*cpu \(.*\) total$/\1/p'
1.848
> { time python3 -c "for i in range(10000000): x = 1 <= 50 < 100"; } 2>&1 | sed -n 's/^.*cpu \(.*\) total$/\1/p'
0.630
Suppose there are 3 non-negative integers: a, b, and c. Mathematically speaking, if we want to determine if c is between a and b, inclusively, one can use this formula:
(c - a) * (b - c) >= 0
or in Python:
> print((c - a) * (b - c) >= 0)
True
You want the output to print the given statement if and only if the number falls between 10,000 and 30,000.
Code should be;
if number >= 10000 and number <= 30000:
print("you have to pay 5% taxes")
You used >=30000, so if number is 45000 it will go into the loop, but we need it to be more than 10000 but less than 30000. Changing it to <=30000 will do it!
I'm adding a solution that nobody mentioned yet, using Interval class from sympy library:
from sympy import Interval
lower_value, higher_value = 10000, 30000
number = 20000
# to decide whether your interval shhould be open or closed use left_open and right_open
interval = Interval(lower_value, higher_value, left_open=False, right_open=False)
if interval.contains(number):
print("you have to pay 5% taxes")
Try this simple function; it checks if A is between B and C (B and C may not be in the right order):
def isBetween(A, B, C):
Mi = min(B, C)
Ma = max(B, C)
return Mi <= A <= Ma
so isBetween(2, 10, -1) is the same as isBetween(2, -1, 10).
The condition should be,
if number == 10000 and number <= 30000:
print("5% tax payable")
reason for using number == 10000 is that if number's value is 50000 and if we use number >= 10000 the condition will pass, which is not what you want.
Related
I always thought comparisons were the fastest operation a computer could execute. I remember hearing it on a presentation from D. Knuth where he'd write loops in descending order "because comparison against 0 is fast". I also read that multiplications should be slower than additions here.
I'm surprised to see that, in both Python 2 and 3, testing under both Linux and Mac, comparisons seem to be much slower than arithmetic operations.
Could anyone explain why?
%timeit 2 > 0
10000000 loops, best of 3: 41.5 ns per loop
%timeit 2 * 2
10000000 loops, best of 3: 27 ns per loop
%timeit 2 * 0
10000000 loops, best of 3: 27.7 ns per loop
%timeit True != False
10000000 loops, best of 3: 75 ns per loop
%timeit True and False
10000000 loops, best of 3: 58.8 ns per loop
And under python 3:
$ ipython3
Python 3.5.2 | packaged by conda-forge | (default, Sep 8 2016, 14:36:38)
Type "copyright", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: %timeit 2 + 2
10000000 loops, best of 3: 22.9 ns per loop
In [2]: %timeit 2 * 2
10000000 loops, best of 3: 23.7 ns per loop
In [3]: %timeit 2 > 2
10000000 loops, best of 3: 45.5 ns per loop
In [4]: %timeit True and False
10000000 loops, best of 3: 62.8 ns per loop
In [5]: %timeit True != False
10000000 loops, best of 3: 92.9 ns per loop
This is happening due to Constant Folding in the Peep Hole optimizer within Python compiler.
Using the dis module, if we break each of the statements to look inside how they are being translated at machine level, you will observe that all operators like inequality, equality etc are first loaded into memory and then evaluated. However, all expressions like multiplication, addition etc are calculated and loaded as a constant into memory.
Overall, this leads to a lesser number of execution steps, making the steps faster:
>>> import dis
>>> def m1(): True != False
>>> dis.dis(m1)
1 0 LOAD_GLOBAL 0 (True)
3 LOAD_GLOBAL 1 (False)
6 COMPARE_OP 3 (!=)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def m2(): 2 *2
>>> dis.dis(m2)
1 0 LOAD_CONST 2 (4)
3 POP_TOP
4 LOAD_CONST 0 (None)
7 RETURN_VALUE
>>> def m3(): 2*5
>>> dis.dis(m3)
1 0 LOAD_CONST 3 (10)
3 POP_TOP
4 LOAD_CONST 0 (None)
7 RETURN_VALUE
>>> def m4(): 2 > 0
>>> dis.dis(m4)
1 0 LOAD_CONST 1 (2)
3 LOAD_CONST 2 (0)
6 COMPARE_OP 4 (>)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def m5(): True and False
>>> dis.dis(m5)
1 0 LOAD_GLOBAL 0 (True)
3 JUMP_IF_FALSE_OR_POP 9
6 LOAD_GLOBAL 1 (False)
>> 9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
As others have explained, this is because Python's peephole optimiser optimises arithmetic operations but not comparisons.
Having written my own peephole optimiser for a Basic compiler, I can assure you that optimising constant comparisons is just as easy as optimising constant arithmetic operations. So there is no technical reason why Python should do the latter but not the former.
However, each such optimisation has to be separately programmed, and comes with two costs: the time to program it, and the extra optimising code taking up space in the Python executable. So you find yourself having to do some triage: which of these optimisations is common enough to make it worth the costs?
It seems that the Python implementers, reasonably enough, decided to optimise the arithmetic operations first. Perhaps they will get round to comparisons in a future release.
A quick disassambling reveals that the comparison involves more operations. According to this answer, there is some precalculation done by the "peephole optimiser" (wiki) for multiplication, addition, etc., but not for the comparison operators:
>>> import dis
>>> def a():
... return 2*3
...
>>> dis.dis(a)
2 0 LOAD_CONST 3 (6)
3 RETURN_VALUE
>>> def b():
... return 2 < 3
...
>>> dis.dis(b)
2 0 LOAD_CONST 1 (2)
3 LOAD_CONST 2 (3)
6 COMPARE_OP 0 (<)
9 RETURN_VALUE
Like others have commented - it is due to the peep hole optimizer which pre-computes the results of 2*3 (6). As the dis shows
0 LOAD_CONST 3 (6)
But try this - it will disable the optimizer from pre-computing the results
>>> def a(a, b):
... return a*b
...
>>> dis.dis(a)
2 0 LOAD_FAST 0 (a)
3 LOAD_FAST 1 (b)
6 BINARY_MULTIPLY
7 RETURN_VALUE
>>> def c(a,b):
... return a<b
...
>>> dis.dis(c)
2 0 LOAD_FAST 0 (a)
3 LOAD_FAST 1 (b)
6 COMPARE_OP 0 (<)
9 RETURN_VALUE
>>>
If you time these functions the compare will be faster.
For python case the above answers are correct. For machine code things a bit more complicated. I assume we are talking about integer operations here, with floats and complex objects none of the below will apply. Also, we assume that the values you are comparing are already loaded into registers. If they are not fetching them from wherever they are could take 100 of times longer than the actual operations
Modern CPUs have several ways to compare two numbers. Very popular ones are doing XOR a,b if you just want to see if two values are equal or CMP a,b if you want to know the relationship between the values ( less, greater, equal, etc ). CMP operation is just a subtraction with the result thrown away because we are only interested in post-op flags.
Both of these operations are of depth 1, so they could be executed in a single CPU cycle. This is as fast as you can go. Multiplication is a form of repeated additions so the depth of the operation is usually equal to the size of your register. There are some optimizations that could be made to reduce the depth, but generally multiplication is one of the slower operations that CPU can perform.
However, multiplying by 0,1 or any power of 2 could be reduced to shift operation. Which is also depth one operation. So it takes the same time as comparing two numbers. Think about decimal system, you can multiply any number by 10, 100, 1000 by appending zeros at the end of the number. Any optimizing compiler will recognize this type of multiplication and use the most efficient operation for it. Modern CPUs are also pretty advanced, so they can perform same optimization in the hardware by counting how many bits are set in any of the operands. And if it's just one bit the operation will be reduced to the shift.
So in your case multiplying by 2 is as fast as comparing two numbers. As people above pointed out any optimizing compiler will see that you are multiplying two constants, so it will replace just replace the function with returning a constant.
Wow, The answer by #mu 無 blew my mind! However, it is important not to generalize when deriving your conclusions... You are checking the times for CONSTANTS not variables. For variables, multiplication seems to be slower than comparison.
Here is the more interesting case, in which the numbers to be compared are stored in actual variables...
import timeit
def go():
number=1000000000
print
print 'a>b, internal:',timeit.timeit(setup="a=1;b=1", stmt="a>b", number=number)
print 'a*b, internal:',timeit.timeit(setup="a=1;b=1", stmt="a*b", number=number)
print 'a>b, shell :',
%%timeit -n 1000000000 "a=1;b=1" "a>b"
print 'a*b, shell :',
%%timeit -n 1000000000 "a=1;b=1" "a*b"
go()
The result gives:
a>b, internal: 51.9467676445
a*b, internal: 63.870462403
a>b, shell :1000000000 loops, best of 3: 19.8 ns per loop
a>b, shell :1000000000 loops, best of 3: 19.9 ns per loop
And order is restored in the universe ;)
For completeness, lets see some more cases... What about if we have one variable and one constant?
import timeit
def go():
print 'a>2, shell :',
%%timeit -n 10000000 "a=42" "a>2"
print 'a*2, shell :',
%%timeit -n 10000000 "a=42" "a*2"
go()
a>2, shell :10000000 loops, best of 3: 18.3 ns per loop
a*2, shell :10000000 loops, best of 3: 19.3 ns per loop
what happens with bools?
import timeit
def go():
print
number=1000000000
print 'a==b : ', timeit.timeit(setup="a=True;b=False",stmt="a==b",number=number)
print 'a and b : ', timeit.timeit(setup="a=True;b=False",stmt="a and b",number=number)
print 'boolean ==, shell :',
%%timeit -n 1000000000 "a=True;b=False" "a == b"
print 'boolean and, shell :',
%%timeit -n 1000000000 "a=False;b=False" "a and b"
go()
a==b : 70.8013108982
a and b : 38.0614485665
boolean ==, shell :1000000000 loops, best of 3: 17.7 ns per loop
boolean and, shell :1000000000 loops, best of 3: 16.4 ns per loop
:D Now this is interesting, it seems boolean and is faster than ==. However all this would be ok as the Donald Knuth would not loose his sleep, the best way to compare would be to use and...
In practice, we should check numpy, which may be even more significant...
import timeit
def go():
number=1000000 # change if you are in a hurry/ want to be more certain....
print '==== int ===='
print 'a>b : ', timeit.timeit(setup="a=1;b=2",stmt="a>b",number=number*100)
print 'a*b : ', timeit.timeit(setup="a=1;b=2",stmt="a*b",number=number*100)
setup = "import numpy as np;a=np.arange(0,100);b=np.arange(100,0,-1);"
print 'np: a>b : ', timeit.timeit(setup=setup,stmt="a>b",number=number)
print 'np: a*b : ', timeit.timeit(setup=setup,stmt="a*b",number=number)
print '==== float ===='
print 'float a>b : ', timeit.timeit(setup="a=1.1;b=2.3",stmt="a>b",number=number*100)
print 'float a*b : ', timeit.timeit(setup="a=1.1;b=2.3",stmt="a*b",number=number*100)
setup = "import numpy as np;a=np.arange(0,100,dtype=float);b=np.arange(100,0,-1,dtype=float);"
print 'np float a>b : ', timeit.timeit(setup=setup,stmt="a>b",number=number)
print 'np float a*b : ', timeit.timeit(setup=setup,stmt="a*b",number=number)
print '==== bool ===='
print 'a==b : ', timeit.timeit(setup="a=True;b=False",stmt="a==b",number=number*1000)
print 'a and b : ', timeit.timeit(setup="a=True;b=False",stmt="a and b",number=number*1000)
setup = "import numpy as np;a=np.arange(0,100)>50;b=np.arange(100,0,-1)>50;"
print 'np a == b : ', timeit.timeit(setup=setup,stmt="a == b",number=number)
print 'np a and b : ', timeit.timeit(setup=setup,stmt="np.logical_and(a,b)",number=number)
print 'np a == True : ', timeit.timeit(setup=setup,stmt="a == True",number=number)
print 'np a and True : ', timeit.timeit(setup=setup,stmt="np.logical_and(a,True)",number=number)
go()
==== int ====
a>b : 4.5121130192
a*b : 5.62955748632
np: a>b : 0.763992986986
np: a*b : 0.723006032235
==== float ====
float a>b : 6.39567713272
float a*b : 5.62149055215
np float a>b : 0.697037433398
np float a*b : 0.847941712765
==== bool ====
a==b : 6.91458288689
a and b : 3.6289697892
np a == b : 0.789666454087
np a and b : 0.724517620007
np a == True : 1.55066706189
np a and True : 1.44293071804
Again, same behavior...
So I guess, one can benefit by using instead for == in general,
at least in Python 2 (Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Feb 16 2016, 09:58:36) [MSC v.1500 64 bit (AMD64)]), where I tried all these...
How do I determine whether a given integer is between two other integers (e.g. greater than/equal to 10000 and less than/equal to 30000)?
What I've attempted so far is not working:
if number >= 10000 and number >= 30000:
print ("you have to pay 5% taxes")
if 10000 <= number <= 30000:
pass
For details, see the docs.
>>> r = range(1, 4)
>>> 1 in r
True
>>> 2 in r
True
>>> 3 in r
True
>>> 4 in r
False
>>> 5 in r
False
>>> 0 in r
False
Your operator is incorrect. It should be if number >= 10000 and number <= 30000:. Additionally, Python has a shorthand for this sort of thing, if 10000 <= number <= 30000:.
Your code snippet,
if number >= 10000 and number >= 30000:
print ("you have to pay 5% taxes")
actually checks if number is larger than both 10000 and 30000.
Assuming you want to check that the number is in the range 10000 - 30000, you could use the Python interval comparison:
if 10000 <= number <= 30000:
print ("you have to pay 5% taxes")
This Python feature is further described in the Python documentation.
There are two ways to compare three integers and check whether b is between a and c:
if a < b < c:
pass
and
if a < b and b < c:
pass
The first one looks like more readable, but the second one runs faster.
Let's compare using dis.dis:
>>> dis.dis('a < b and b < c')
1 0 LOAD_NAME 0 (a)
2 LOAD_NAME 1 (b)
4 COMPARE_OP 0 (<)
6 JUMP_IF_FALSE_OR_POP 14
8 LOAD_NAME 1 (b)
10 LOAD_NAME 2 (c)
12 COMPARE_OP 0 (<)
>> 14 RETURN_VALUE
>>> dis.dis('a < b < c')
1 0 LOAD_NAME 0 (a)
2 LOAD_NAME 1 (b)
4 DUP_TOP
6 ROT_THREE
8 COMPARE_OP 0 (<)
10 JUMP_IF_FALSE_OR_POP 18
12 LOAD_NAME 2 (c)
14 COMPARE_OP 0 (<)
16 RETURN_VALUE
>> 18 ROT_TWO
20 POP_TOP
22 RETURN_VALUE
>>>
and using timeit:
~$ python3 -m timeit "1 < 2 and 2 < 3"
10000000 loops, best of 3: 0.0366 usec per loop
~$ python3 -m timeit "1 < 2 < 3"
10000000 loops, best of 3: 0.0396 usec per loop
also, you may use range, as suggested before, however it is much more slower.
if number >= 10000 and number <= 30000:
print ("you have to pay 5% taxes")
Define the range between the numbers:
r = range(1,10)
Then use it:
if num in r:
print("All right!")
The trouble with comparisons is that they can be difficult to debug when you put a >= where there should be a <=
# v---------- should be <
if number >= 10000 and number >= 30000:
print ("you have to pay 5% taxes")
Python lets you just write what you mean in words
if number in xrange(10000, 30001): # ok you have to remember 30000 + 1 here :)
In Python3, you need to use range instead of xrange.
edit: People seem to be more concerned with microbench marks and how cool chaining operations. My answer is about defensive (less attack surface for bugs) programming.
As a result of a claim in the comments, I've added the micro benchmark here for Python3.5.2
$ python3.5 -m timeit "5 in range(10000, 30000)"
1000000 loops, best of 3: 0.266 usec per loop
$ python3.5 -m timeit "10000 <= 5 < 30000"
10000000 loops, best of 3: 0.0327 usec per loop
If you are worried about performance, you could compute the range once
$ python3.5 -m timeit -s "R=range(10000, 30000)" "5 in R"
10000000 loops, best of 3: 0.0551 usec per loop
Below are few possible ways, ordered from best to worse performance (i.e first one will perform best)
# Old school check
if 10000 >= b and b <=30000:
print ("you have to pay 5% taxes")
# Python range check
if 10000 <= number <= 30000:
print ("you have to pay 5% taxes")
# As suggested by others but only works for integers and is slow
if number in range(10000,30001):
print ("you have to pay 5% taxes")
While 10 <= number <= 20 works in Python, I find this notation using range() more readable:
if number in range(10, 21):
print("number is between 10 (inclusive) and 21 (exclusive)")
else:
print("outside of range!")
Keep in mind that the 2nd, upper bound parameter is not included in the range set as can be verified with:
>>> list(range(10, 21))
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
However prefer the range() approach only if it's not running on some performance critical path. A single call is still fast enough for most requirements, but if run 10,000,000 times, we clearly notice nearly 3 times slower performance compared to a <= x < b:
> { time python3 -c "for i in range(10000000): x = 50 in range(1, 100)"; } 2>&1 | sed -n 's/^.*cpu \(.*\) total$/\1/p'
1.848
> { time python3 -c "for i in range(10000000): x = 1 <= 50 < 100"; } 2>&1 | sed -n 's/^.*cpu \(.*\) total$/\1/p'
0.630
Suppose there are 3 non-negative integers: a, b, and c. Mathematically speaking, if we want to determine if c is between a and b, inclusively, one can use this formula:
(c - a) * (b - c) >= 0
or in Python:
> print((c - a) * (b - c) >= 0)
True
You want the output to print the given statement if and only if the number falls between 10,000 and 30,000.
Code should be;
if number >= 10000 and number <= 30000:
print("you have to pay 5% taxes")
You used >=30000, so if number is 45000 it will go into the loop, but we need it to be more than 10000 but less than 30000. Changing it to <=30000 will do it!
I'm adding a solution that nobody mentioned yet, using Interval class from sympy library:
from sympy import Interval
lower_value, higher_value = 10000, 30000
number = 20000
# to decide whether your interval shhould be open or closed use left_open and right_open
interval = Interval(lower_value, higher_value, left_open=False, right_open=False)
if interval.contains(number):
print("you have to pay 5% taxes")
Try this simple function; it checks if A is between B and C (B and C may not be in the right order):
def isBetween(A, B, C):
Mi = min(B, C)
Ma = max(B, C)
return Mi <= A <= Ma
so isBetween(2, 10, -1) is the same as isBetween(2, -1, 10).
The condition should be,
if number == 10000 and number <= 30000:
print("5% tax payable")
reason for using number == 10000 is that if number's value is 50000 and if we use number >= 10000 the condition will pass, which is not what you want.
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)
Here is a Python function for generating my own specific type for UUID (It's a long story for why I can't use uuid.uuid1()):
def uuid():
sec = hex(int(time()))[2:]
usec = hex(datetime.now().microsecond)[2:]
rand = hex(choice(range(256)))[2:]
return upper(sec + usec + rand)
# 534AD79CDF1D27
Now, let's let that run for a long period of time, and see if we find any duplicates:
UUIDs Duplicates
100000 2
200000 8
300000 8
400000 8
500000 8
600000 9
700000 9
800000 9
900000 9
1000000 10
1100000 14
1200000 14
1300000 14
1400000 17
1500000 17
1600000 18
1700000 21
1800000 24
1900000 24
2000000 27
Yep! Nearly 30 duplicates in fact... Now, here's a new function without the random byte at the end:
def uuid():
sec = hex(int(time()))[2:]
usec = hex(datetime.now().microsecond)[2:]
return upper(sec + usec)
#534ADA2AC4A41
Let's see how many duplicates we get now:
UUIDs Duplicates
100000 0
200000 0
300000 0
400000 0
500000 0
600000 0
700000 0
800000 0
900000 0
1000000 0
1100000 0
1200000 0
1300000 0
1400000 0
1500000 0
1600000 0
1700000 0
1800000 0
1900000 0
2000000 0
Well, would you look at that? Not a single duplicate! Also, if you're curious how I'm determining the number of duplicates, here is the code for that:
len([x for x, y in Counter(ids).items() if y > 1])
Now, on to the actual question: How does adding a randomly generated byte increase the number of duplicates?
The problem is that you are using hex() without zero-padding. hex(int(time())) is basically always 8 nybbles long because it increments quite slowly, so that first part is constant length. Nybble here refers to a single hex digit.
But, hex(datetime.now().microsecond) is not a constant length. It will vary between 1 nybble (up to 9 us) up to 5 nybbles (for 999999 us). Without the "random byte", this isn't a problem because you can get the microsecond value uniquely by truncating off the seconds.
However, your "random byte" is also produced without any padding! So, you can end up generating a 1 nybble random byte, or a 2 nybble random byte. So, you will end up potentially creating more conflicts because you can generate the same uuid with e.g. a 3-nybble usec and a 2-nybble rand, as with a 4-nybble usec and a 1-nybble rand. So, for example, these two are collisions:
usec = 0xabc
rand = 0xde
and
usec = 0xabcd
rand = 0xe
To fix this, pad all of your strings. This is really easy to do with format:
usec = format(datetime.now().microsecond, '05x') # hexify `microsecond` with 5 fixed hex digits
usec will be between 1 and 5 characters and rand will be between 1 and 2 characters, so it's not too surprising that concatenating the two (within the same second) will produce collisions.
For example, usec = '12' and rand = '3' yields the same string as usec = '1' and rand = '23' (i.e. '123').
You could avoid this by left-padding them so that usec is always exactly 5 characters and rand is always exactly 2 characters.
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.