Some more Strings

In [4]:
#Strings are 'immutable' meaning 
s = 'hello'
s[0] = 'y' #gives an error
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-f45c478b8328> in <module>()
      1 #Strings are 'immutable' meaning
      2 s = 'hello'
----> 3 s[0] = 'y' #gives an error

TypeError: 'str' object does not support item assignment
In [3]:
#but can be changed like below 
s = 'y' + s[1:]
s
Out[3]:
'yello'

Different ways of approching a problems (algorithms)

  • Approximation (guess and check)
    • You assume a number and check with small increments

Guess and Check

In [27]:
#example for guess and check
x = 1678
epsilon = 0.01
step = 0.1
guess = 0.0
num_steps = 0

while guess <= x:
    num_steps += 1
    if abs(guess**2 -x) < epsilon:
        break
    else:
        guess += step
        

if abs(guess**2 - x) >= epsilon:
    print('failed')
else:
    print('succeeded: ' + str(guess))
print("Number of steps taken is "+str(num_steps))
failed
Number of steps taken is 16781
  • Bisection search
    • eleminate half of the range based on the input
In [26]:
#example for bisection search 
x = 1678
high = x
low = 0
ans = 0
num_steps = 0

while ans <= x:
    num_steps += 1
    ans = (high+low)/2
    if abs(ans**2 -x) < epsilon:
        break
    elif (ans**2 -x) > 0:
        high = ans
    else:
        low = ans

if abs(ans**2 - x) >= epsilon:
    print('failed')
else:
    print('succeeded: ' + str(ans))

print("Number of steps taken is "+str(num_steps))
succeeded: 40.963396310806274
Number of steps taken is 23

Bisection search reduces the number of steps by a lot. For example to find a square root of 1678 guess and check method takes 16781 steps while bisection takes 23.

Newton-raphson

  • If g is an approximation to the root, then

$$ g-p(g)/p'(g)$$

is a better approximation where p' is derivative of p

for square root $$ F(x)= x^2 - 24 $$ solutions to this equation is the square root of 24.

$$ F'(x)= 2*x $$

there fore we have, when for 24 $$x=g$$ $$ g - (g^2-24)/(2*g)$$

In [120]:
x = 1678
epsilon = 0.01
guess = x/2
num_steps = 0
while abs(guess**2 -x) >= epsilon:
    num_steps += 1
    guess = guess - ((guess**2 - x)/(2*guess))

if abs(guess**2 - x) >= epsilon:
    print('failed')
else:
    print('succeeded: ' + str(guess))

print("Number of steps taken is "+str(num_steps))
    
succeeded: 40.96339829764579
Number of steps taken is 8

To compute square root of 1678 number of steps taken by

1) Guess and check- 16781

2) Bisection Search- 23

3) Newton-Raphson- 8


Floats and Fractions

Note: decimal numbers are convertred to integers by multiplying '2^p' then the integer is converted to binary and then the binary number is divided by same '2^p' (binary divison).

In [37]:
# converting fraction into binary 
x = float(input('Enter a decimal number between 0 and 1: '))

p = 0
while ((2**p)*x)%1 != 0:
    p += 1

num = int(x*(2**p))

result = ''
if num == 0:
    result = '0'
while num > 0:
    result = str(num%2) + result
    num = num//2

for i in range(p - len(result)):
    result = '0' + result

result = result[0:-p] + '.' + result[-p:]
print('The binary representation of the decimal ' + str(x) + ' is ' + str(result))
Enter a decimal number between 0 and 1: 0.6
The binary representation of the decimal 0.6 is .10011001100110011001100110011001100110011001100110011

Functions

Decomposition : Break a problem into different self contained pieces.

Abstraction : Trying to understand the behaviour without nessasrily knowing how it works.

Reuseable piece of code is called Function.

In [18]:
def f(x, y):
    '''
    This is how comments inside a functions are written
    
    '''
    print(x,"Inside fucntion X")
    return x + y - 2 #values of x and y are only valid inside the function - local variable

x=5 #globel variable 

print(f(2,3),"Function return value") #calling the function 

print(x,"Outside Function X")
2 Inside fucntion X
3 Function return value
5 Outside Function X

Recursive Functions

Function is called in itself in loop to perform certain tasks

In [ ]:
# multiplication a*b
def mult(a,b):
    if b==1: #last condition
        return a
    else:
        return a + mutl(a,b-1) #same function is called for reduced variable 
mult(10,5)
In [28]:
#finding factorial of a number 
def fact(n):
    if n == 1 or n == 0: # last condition
        return 1
    else:
        return n*fact(n-1) #same function is called for reduced variable 
fact(5)
Out[28]:
120

Modules or functions can be called and used from other files

This can be done by using 'import'

Suppose module circle.py has two function area and circumference it can be use as below

import circle

print(circle.area(3))

and

print(circle.circumference(3))

Different way of importing

from circle import * # will import all the modules

Files

  • every operating system has its own way of handling files; Python provides an operating-system independent means to access files, using a file handle
  • nameHandle= open(‘kids’, ‘w’)
  • creates a file named kids and returns file handle which we can name and thus reference. The windicates that the file is to opened for writing into.
In [33]:
nameHandle= open('kids', 'w') #creats and opens file named kids with write option
for i in range(2):
    name = input('Enter name: ')
    nameHandle.write(name + "  ")
nameHandle.close()
Enter name: A
Enter name: B
In [36]:
nameHandle= open('kids', 'r') #opens file in read access and prints the information
for line in nameHandle:
    print(line)
nameHandle.close()
A  B  

Some use of built in functions

In [11]:
A = 'ABC'
A.index("B")
Out[11]:
1
In [12]:
str2 = 'Number one - the larch'
str2.find('n')
Out[12]:
8
In [15]:
len("abc")
Out[15]:
3

Reference

  • edX course offered by MIT
  • 6.00.1x Introduction to Computer Science and Programming Using Python