Week 2 notebook

From last week:

The if statement:

In [2]:
a = 101

if a%2 == 0:
    print('even')
else:
    print('odd')
odd

The for loop

In [3]:
for n in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
    print(n**3)
1
8
27
64
125
216
343
512
729
1000
In [4]:
cubes = []
for n in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
    cubes.append(n**3)
In [5]:
print(cubes)
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

Note: for loops work with strings too:

In [6]:
for letter in 'Buffalo':
    print(letter + '!')
B!
u!
f!
f!
a!
l!
o!

Our goal: checking if a number is a prime or not

In [7]:
n = 10

for d in [2, 3, 4, 5, 6, 7, 8, 9]:
    if n%d == 0:
        print('{} is not a prime number'.format(n))
10 is not a prime number
10 is not a prime number

The range() function:

range(n) produces all integers from 0 to n-1:

In [8]:
for x in range(5):
    print(x)
0
1
2
3
4

range(m, n) generates integers from m to n-1:

In [9]:
for x in range(2, 5):
    print(x)
2
3
4

range(m, n, k) increments integers by k at each step:

In [14]:
for x in range(1, 11, 3):
    if x == 4:
        pass
    else:
        print(x)
1
7
10
In [24]:
n = 12345

for d in range(2,n):
    if n%d == 0:
        print('{} is not a prime number'.format(n))
12345 is not a prime number
12345 is not a prime number
12345 is not a prime number
12345 is not a prime number
12345 is not a prime number
12345 is not a prime number

Note: range() does not produce a list, but an iterable object:

In [18]:
s = range(5)
print(s)
range(0, 5)

range(n) can be turned into a list using the list():

In [21]:
s = list(range(5))
In [22]:
print(s)
[0, 1, 2, 3, 4]

Fine-tuning loops: break and continue:

break can be used to immediately terminate a loop:

In [27]:
for letter in "Mississippi":
    print(letter)
    if letter == 's':
        print('letter "s" found!')
        break
M
i
s
letter "s" found!

continue can be used to immediately go to the next iteration of the loop:

In [28]:
for letter in 'Mississippi':
    if letter == 's':
        continue
    print(letter)
M
i
i
i
p
p
i
In [43]:
n = 10175765

for d in range(2,n):
    if n%d == 0:
        print('{} is not a prime number'.format(n))
        break
    elif d == n-1:
        print('it is a prime')
10175765 is not a prime number
In [41]:
n = 101

prime = True
for d in range(2,n):
    if n%d == 0:
        print('{} is not a prime number'.format(n))
        prime = False
        break
if prime:
    print('it is a prime')
it is a prime

Defining functions

In [45]:
def multiply(a, b):
    c = a*b
    print('{}*{} = {}'.format(a, b, c))
In [46]:
multiply(2,3)
2*3 = 6
In [47]:
multiply(3, 'hello')
3*hello = hellohellohello
In [49]:
def isprime(n):
    for d in range(2,n):
        if n%d == 0:
            print('{} is not a prime number'.format(n))
            break
        elif d == n-1:
            print('it is a prime')
In [51]:
isprime(2**19-1)
it is a prime

Return value of a function

In [52]:
def multiply2(a, b):
    c = a*b
    return c
In [54]:
x = multiply2(3,2)
In [55]:
print(x)
6
In [56]:
y = multiply2(12,123)
In [57]:
print(y)
1476

Note: A function will exit immediately after it encounters the return statement:

In [58]:
def f(a):
    print('before return')
    return 2*a
    print('after return')
In [60]:
x = f(100)
before return
In [61]:
print(x)
200
In [11]:
def isprime(n):
    for d in range(2,n):
        if n%d == 0:
            return False
            break
        elif d == n-1:
            return True
In [13]:
print(isprime(2))
None
In [14]:
def isprime(n):
    for d in range(2,n):
        if n%d == 0:
            return False
            break
        elif d == n-1:
            return True
    return True
In [15]:
isprime(2)
Out[15]:
True
In [16]:
isprime(1)
Out[16]:
True
In [5]:
def isprime(n):
    if n < 2:
        return False
    for d in range(2,n):
        if n%d == 0:
            return False
            break
        elif d == n-1:
            return True
    return True
In [18]:
for n in range(20):
    print(n, isprime(n))
0 False
1 False
2 True
3 True
4 False
5 True
6 False
7 True
8 False
9 False
10 False
11 True
12 False
13 True
14 False
15 False
16 False
17 True
18 False
19 True
In [19]:
def myprimes(n):
    primes = []
    for d in range(2, n+1):
        if isprime(d):
            primes.append(d)
    return primes
In [20]:
print(myprimes(20))
[2, 3, 5, 7, 11, 13, 17, 19]
In [21]:
print(myprimes(23))
[2, 3, 5, 7, 11, 13, 17, 19, 23]
In [1]:
def isprime2(n):
    if n < 2:
        return False
    for d in range(2, round(n**0.5) +1):
        if n%d == 0:
            return False
            break
        elif d == n-1:
            return True
    return True
In [29]:
isprime(2**19 -1)
Out[29]:
True
In [30]:
isprime2(2**19 -1)
Out[30]:
True

Code timing

In [3]:
from time import time
In [32]:
help(time)
Help on built-in function time in module time:

time(...)
    time() -> floating point number
    
    Return the current time in seconds since the Epoch.
    Fractions of a second may be present if the system clock provides them.

In [33]:
time()
Out[33]:
1504790973.562887
In [34]:
time()
Out[34]:
1504790987.002996
In [35]:
st = time()
isprime(2**19 -1)
et = time()
print(et-st)
0.0682058334350586
In [36]:
st = time()
isprime2(2**19 -1)
et = time()
print(et-st)
0.000164031982421875
In [7]:
st = time()
isprime(2**31 -1)
et = time()
print(et-st)
389.0052547454834
In [41]:
st = time()
print(isprime2(2**31 -1))
et = time()
print(et-st)
True
0.009147882461547852
In [42]:
def myprimes2(n):
    primes = []
    for d in range(2, n+1):
        if isprime2(d):
            primes.append(d)
    return primes

Project: false primes

In [45]:
m = 23
n = 14
p = 3

m%p == n%p
Out[45]:
True

Def: A number $p$ is prime-like if $$a^p \equiv a \ (mod \ p) $$ for all $0< a < p$.

Note: Every prime number is prime-like.

Def: A number $p$ is a false prime if it is prime-like but not a prime.

The smallest false prime is 561.

In [46]:
isprime(561)
Out[46]:
False

Part 1. Find at least 20 false primes.

Note Note: you can compute (a**p)%k more efficiently using the pow(a, p, k):

In [48]:
(100**50)%7
Out[48]:
4
In [49]:
pow(100, 50, 7)
Out[49]:
4
In [8]:
st = time()
(10**3000000)%111
print(time() - st)
1.1840121746063232
In [9]:
st = time()
pow(10, 3000000, 111)
print(time() - st)
5.698204040527344e-05

Logical operators: not, and, or

"not <exp>" is True if <exp> if False and False if <exp> is True:

In [52]:
isprime(100)
Out[52]:
False
In [53]:
not isprime(100)
Out[53]:
True

"<exp1> and <exp2>" is True only if both expressions are True:

In [54]:
isprime(2) and isprime(5)
Out[54]:
True
In [55]:
isprime(2) and isprime(10)
Out[55]:
False
In [56]:
isprime(4) and isprime(10)
Out[56]:
False

"<exp1> or <exp2>" is True it at least one expression is True:

In [57]:
isprime(2) or isprime(5)
Out[57]:
True
In [58]:
isprime(2) or isprime(10)
Out[58]:
True
In [59]:
isprime(4) or isprime(10)
Out[59]:
False
In [60]:
for i in range(100):
    if isprime(i) and i%10 == 1:
        print(i)
11
31
41
61
71
In [61]:
for i in range(100):
    if isprime(i) and (i%10 == 1 or i%10 == 9):
        print(i)
11
19
29
31
41
59
61
71
79
89

Project part 2:

For each false prime find its primary decompositon and analyze it.

For this write a primary(n) function that gives the primary decompositon of a number n.

The while loop

Syntax:

while <boolean expression>:
    <code to be executed>

The loop will repeat as long as the boolean expression is true:

In [62]:
from time import sleep
In [63]:
n = 10

while n > 0:
    print(n)
    sleep(1)
    n -= 1
10
9
8
7
6
5
4
3
2
1

This can be done with a for loop too:

In [64]:
for s in range(10,0, -1):
    print(s)
    sleep(1)
10
9
8
7
6
5
4
3
2
1

Collatz conjecture

In [11]:
n = 31

while n != 1:
    if n%2 == 0:
        n = int(n/2)
    else:
        n = 3*n + 1
    print(n)
94
47
142
71
214
107
322
161
484
242
121
364
182
91
274
137
412
206
103
310
155
466
233
700
350
175
526
263
790
395
1186
593
1780
890
445
1336
668
334
167
502
251
754
377
1132
566
283
850
425
1276
638
319
958
479
1438
719
2158
1079
3238
1619
4858
2429
7288
3644
1822
911
2734
1367
4102
2051
6154
3077
9232
4616
2308
1154
577
1732
866
433
1300
650
325
976
488
244
122
61
184
92
46
23
70
35
106
53
160
80
40
20
10
5
16
8
4
2
1