0% found this document useful (0 votes)
92 views

Loops and Strings, GUESS-and-CHECK, Approximation, Bisection

The document discusses different numerical approximation techniques: 1) Guess-and-check involves iteratively guessing values and checking if a condition is met until a solution is found. 2) Bisection search improves on guess-and-check by narrowing the search range in half at each step. 3) Examples are provided to find the square root and cube root of a number to within a given error or epsilon using bisection search. This technique converges faster than guess-and-check by eliminating half the search space at each step.

Uploaded by

Perry Ho
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
92 views

Loops and Strings, GUESS-and-CHECK, Approximation, Bisection

The document discusses different numerical approximation techniques: 1) Guess-and-check involves iteratively guessing values and checking if a condition is met until a solution is found. 2) Bisection search improves on guess-and-check by narrowing the search range in half at each step. 3) Examples are provided to find the square root and cube root of a number to within a given error or epsilon using bisection search. This technique converges faster than guess-and-check by eliminating half the search space at each step.

Uploaded by

Perry Ho
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

LOOPS and STRINGS,

GUESS-and-CHECK,
APPROXIMATION,
BISECTION

6.00.1X LECTURE 1
- Example of guess and check for the code where you are setting up a variable outside and changing the variable inside

REVIEWING LOOPS
ans = 0
neg_flag = False
x = int(input("Enter an integer: "))
if x < 0:
neg_flag = True
while ans**2 < x:
ans = ans + 1
if ans**2 == x:
print("Square root of", x, "is", ans)
else:
print(x, "is not a perfect square”)
if neg_flag:
print("Just checking... did you mean", -x, "?”)

6.00.1X LECTURE 2
- Strings are a sequence of case sensitive letters (upper or lower case)
- You can also compare strings like you do with numbers.
- ex. you can test if two strings are equal while using the double equal sign, or can use greater than or less than using
lexicographic order to decide if two strings are greater than or less than each other

REVIEWING STRINGS
 think of as a sequence of case sensitive characters
 can compare strings with ==, >, < etc.
 len() is a function used to retrieve the length of the
string in the parentheses
 square brackets used to perform indexing into a string
to get the value at a certain index/position
s = "abc"
index: 0 1 2  indexing always starts at 0

len(s)  evaluates to 3
s[0]  evaluates to "a"
s[1]  evaluates to "b"
s[3]  trying to index out of bounds, error
6.00.1X LECTURE 3
- Slicing lets you go into string and pull out pieces of the string.

STRINGS
 can slice strings using [start:stop:step]
s = "abcdefgh"
- if -1, access
string in s[::-1]  evaluates to "hgfedbca"
reverse order
s[3:6]  evaluates to "def"
s[-1]  evaluates to "h"
 strings are “immutable” – cannot be modified
"Immutable" - i.e. it cannot be changed
s = "hello"
s[0] = 'y'  gives an error
s = 'y'+s[1:len(s)]  is allowed "hello"
Since s[0] is 'h', you cannot use s[0] = 'y' unless you change
the definition of s.
s is a new object
"yello"
You will have to redefine s.
s
6.00.1X LECTURE 4
FOR LOOPS RECAP
 for loops have a loop variable that iterates over a set of
values
for var in range(4):
<expressions>
◦ var iterates over values 0,1,2,3
◦ expressions inside loop executed with each value for var
for var in range(4,8): expressions inside the loop are going to be executed for
each value of the variable that you use
<expressions> range is a good way to iterate over numbers.

◦ var iterates over values 4,5,6,7


 range is a way to iterate over numbers, but a for loop
variable can iterate over any set of values, not just numbers!
6.00.1X LECTURE 5
- For example, you can loop over strings.

STRINGS AND LOOPS


s = "abcdefgh"
for index in range(len(s)):
if s[index] == 'i' or s[index] == 'u':
print("There is an i or u”)

for char in s: - you can write the loop in this way as well because 's' is a 'iterable'

if char == 'i' or char == 'u':


print("There is an i or u”)

6.00.1X LECTURE 6
CODE EXAMPLE
an_letters = "aefhilmnorsxAEFHILMNORSX”

word = input("I will cheer for you! Enter a word: ")


times = int(input("Enthusiasm level (1-10): "))
i = 0

while i < len(word):


- if it's a vowel, you don't it to say give me "a" A, you want to say
char = word[i] give me "an" A.
if char in an_letters:
print("Give me an " + char + "! " + char)
else:
print("Give me a " + char + "! " + char)
i += 1
print("What does that spell?”)
for i in range(times):
print(word, "!!!”)

6.00.1X LECTURE 7
6.00.1X LECTURE 8
So far, we have been doing everything with integers where there is a finite numbers to check.

What if we wanted to find the square root of any non-negative number?

APPROXIMATE SOLUTIONS
 suppose we now want to find the root of any non-
negative number?
 can’t guarantee exact answer, but just look for
something close enough
 start with exhaustive enumeration
◦ take small steps to generate guesses in order
◦ check to see if close enough

6.00.1X LECTURE 9
APPROXIMATE SOLUTIONS
 good enough solution First, need to define what is a "good enough" solution?
 start with a guess and increment by some small value
ex. Start with 1
 |guess3|- cube <= epsilon and see if it's
close.
for some small epsilon Then use 1.002,
and check that.

 decreasing increment size  slower program


 increasing epsilon  less accurate answer

6.00.1X LECTURE 10
APPROXIMATE SOLUTION
– cube root
cube = 27
epsilon = 0.01 how close do we want to be to the actual answer
guess = 0.0 the number what you are going to start with

increment = 0.0001 size which you will increase your guess as you move along
num_guesses = 0
while abs(guess**3 - cube) >= epsilon: and guess <= cube :
guess += increment
num_guesses += 1
print('num_guesses =', num_guesses)
if abs(guess**3 - cube) >= epsilon:
print('Failed on cube root of', cube)
else:
print(guess, 'is close to the cube root of', cube)

6.00.1X LECTURE 11
Some observations
 Step could be any small number
◦ If too small, takes a long time to find square root
◦ If too large, might skip over answer without getting close
enough
 In general, will take x/step times through code to find
solution
 Need a more efficient way to do this

6.00.1X LECTURE 12
6.00.1X LECTURE 13
So far, we have been using epislon to guess and check
- The issue is that with this method, it means we either have to take very small steps and take a
long time, or take larger steps, and possibly miss the solutions.
- Bisection search is a more effective way of doing this.

BISECTION SEARCH
 We know that the square root of x lies between 1 and
x, from mathematics
 Rather than exhaustively trying things starting at 1,
suppose instead we pick a number in the middle of this
range Ex. we know square root of 25 is somewhere between 1 and x. So rather than starting everything at 1 and taking
small steps, we can pick a number in between 1 and 25. Say, 12.5.

1 x
g

 If we are lucky, this answer is close enough

6.00.1X LECTURE 14
BISECTION SEARCH
 If not close enough, is guess too big or too small?
 If g**2 > x, then know g is too big; but now search

1 everything in between g and x, throw away x


new g g
 And if, for example, this new g is such that g**2 < x,
then know too small; so now search

1 throw away x
this section
new g next g g
 At each stage, reduce range of values to search by half

6.00.1X LECTURE 15
EXAMPLE OF SQUARE ROOT
x = 25
epsilon = 0.01
numGuesses = 0
low = 1.0
high = x
ans = (high + low)/2.0

while abs(ans**2 - x) >= epsilon:


print('low = ' + str(low) + ' high = ' + str(high) + ' ans = ' + str(ans))
numGuesses += 1
if ans**2 < x:
low = ans
else:
high = ans
ans = (high + low)/2.0
print('numGuesses = ' + str(numGuesses))
print(str(ans) + ' is close to square root of ' + str(x))
6.00.1X LECTURE 16
BISECTION SEARCH
– cube root
cube = 27
epsilon = 0.01 Note: this is the same code as the previous slide, but now we use
**3 rather than **2
num_guesses = 0
low = 1 Bisection is very powerful search by throwing away half.

high = cube - This only works for numbers bigger than 1


guess = (high + low)/2.0
while abs(guess**3 - cube) >= epsilon:
if guess**3 < cube :
low = guess
else:
high = guess
guess = (high + low)/2.0
num_guesses += 1
print('num_guesses =', num_guesses)
print(guess, 'is close to the cube root of', cube)
6.00.1X LECTURE 17
Bisections work with fractions. The only

BISECTION SEARCH difference is that the root doesn't lie between the
number and x itself.

CONVERGENCE It lies between 0 and that number

 search space
log2N = that means this doesn't linear time, but
◦ first guess: N/2 logarithmic time (it takes less than linear time to get
there)
◦ second guess: N/4
It is a lot quicker.
◦ gth guess: N/2g
 guess converges on the order of log2N steps
 bisection search works when value of function varies
monotonically with input
 code as shown only works for positive cubes > 1 – why?
 challenges  modify to work with negative cubes!
 modify to work with x < 1!

6.00.1X LECTURE 18
x<1
 if x < 1, search space is 0 to x but cube root is greater
than x and less than 1
 modify the code to choose the search space
depending on value of x

6.00.1X LECTURE 19
SOME OBSERVATIONS
 Bisection search radically reduces computation time –
being smart about generating guesses is important
 Should work well on problems with “ordering”
property – value of function being solved varies
monotonically with input value
◦ Here function is g**2; which grows as g grows
Monotonically - i.e. it increases as the input value increases.

For ex. g**2 will grow as g grows. g**3 will grow as g grows.

6.00.1X LECTURE 20
6.00.1X LECTURE 21
Sometimes you may get answers where you're expecting a 3.0, but the actual answer gives you 3.0000000
- To fix this, need to understand how machine actually stores the number

DEALING WITH float’s


 Floats approximate real numbers, but useful to
understand how
 Decimal number:
◦ 302 = 3*102 + 0*101 + 2*100
 Binary number
◦ 10011 = 1*24 + 0*23 + 0*22 + 1*21 + 1*20
◦ (which in decimal is 16 + 2 + 1 = 19)
 Internally, computer represents numbers in binary

6.00.1X LECTURE 22
CONVERTING DECIMAL
INTEGER TO BINARY
 Consider example of Given a decimal integer, how do we convert to Binary?

◦ x = 1*24 + 0*23 + 0*22 + 1*21 + 1*20 = 10011


 If we take remainder relative to 2 (x%2) of this number,
that gives us the last binary bit in this case, it would be the "1"
 If we then divide x by 2 (x//2), all the bits get shifted
right
◦ x//2 = 1*23 + 0*22 + 0*21 + 1*20 = 1001 if you keep doing successive divisions, can keep
track of the bits.

 Keep doing successive divisions; now remainder gets next


bit, and so on
 Let’s us convert to binary form

6.00.1X LECTURE 23
DOING THIS IN PYTHON
if num < 0:
isNeg = True
num = abs(num)
else:
isNeg = False
result = ‘‘
if num == 0:
result = ‘0’
while num > 0:
result = str(num%2) + result
num = num//2
if isNeg:
result = ‘-’ + result
6.00.1X LECTURE 24
WHAT ABOUT FRACTIONS?
 3/8 = 0.375 = 3*10-1 + 7*10-2 + 5*10-3 <-- This gives you the digits associated with each
of the placeholders

 So if we multiply by a power of 2 big enough to


convert into a whole number, can then convert to
binary, and then divide by the same power of 2
 0.375 * (2**3) = 3 (decimal)
 Convert 3 to binary (now 11)
 Divide by 2**3 (shift right) to get 0.011 (binary)
Note: you don't actually "divide" by 2**3. You take the exponent of 3 and shift the binary number.
11.0 --> 0.011 (decimal place moved 3 places to the left, OR the number 11 moved 3 places to the
right).

6.00.1X LECTURE 25
x = float(input('Enter a decimal number between 0 and 1: '))

p = 0
while ((2**p)*x)%1 != 0:
print('Remainder = ' + str((2**p)*x - int((2**p)*x)))
p += 1

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

result = '' With this code, you can now take any floating point number,
convert into something that can be represented inside of the
if num == 0: machine in binary form, and use it.
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))
6.00.1X LECTURE 26
SOME IMPLICATIONS
If there is no integer p such that x*(2**p) is a whole
number, then internal representation is always an
approximation
Suggest that testing equality of floats is not exact
◦ Use abs(x-y) < some small number, rather than x == y
Why does print(0.1) return 0.1, if not exact?
◦ Because Python designers set it up this way to
automatically round

6.00.1X LECTURE 27
6.00.1X LECTURE 28
Newton-Raphson - a general approximation algorithm to find roots of a polynomial in one variable

NEWTON-RAPHSON
 General approximation algorithm to find roots of a
polynomial in one variable
p(x) = anxn + an-1xn-1 + … + a1x + a0
 Want to find r such that p(r) = 0
 For example, to find the square root of 24, find the root of
p(x) = x2 – 24
 Newton showed that if g is an approximation to the root,
then
g – p(g)/p’(g)
is a better approximation; where p’ is derivative of p

6.00.1X LECTURE 29
NEWTON-RAPHSON
Simple case: cx2 + k
First derivative: 2cx
So if polynomial is x2 + k, then derivative is 2x
Newton-Raphson says given a guess g for root, a better
guess is
g – (g2 –k)/2g

6.00.1X LECTURE 30
NEWTON-RAPHSON
This gives us another way of generating guesses, which we can check; very efficient

This lets you find cube and square root solutions very quickly
epsilon = 0.01
y = 24.0
guess = y/2.0
numGuesses = 0

while abs(guess*guess - y) >= epsilon:


numGuesses += 1
guess = guess - (((guess**2) - y)/(2*guess))
print(‘numGuesses = ‘ + str(numGuesses))
print('Square root of ' + str(y) + ' is about ' + str(guess))

6.00.1X LECTURE 31
Iterative algorithms
 Guess and check methods build on reusing same code
◦ Use a looping construct to generate guesses, then check
and continue
 Generating guesses
◦ Exhaustive enumeration
◦ Bisection search
◦ Newton-Raphson (for root finding)

6.00.1X LECTURE 32

You might also like