Home > Enterprise >  Incorrect Output from loop function (For and While)
Incorrect Output from loop function (For and While)

Time:09-27

For my class assignment I am working on code that uses loops utilizing Heron's method to find an estimate of the square root while also displaying the iteration and relative change.

I have the following code:

# Problem 1.

def square_root_for(a, x0, max_iter = 10, tol=1e-14):  
    
    """ (number, integer, number) -> float

    Return an estimate of the square root of a number using the Heron's method.
        
    >>> square_root_for(5, 5)
    Iteration | Estimate         | Relative Change
    -------------------------------------------------
    1         | 3.00000000000000 | 0.4000000000000000
    2         | 2.33333333333333 | 0.2222222222222222
    3         | 2.23809523809524 | 0.0408163265306123
    4         | 2.23606889564336 | 0.0009053870529653
    5         | 2.23606797749998 | 0.0000004106060359
    6         | 2.23606797749979 | 0.0000000000000842
    7         | 2.23606797749979 | 0.0000000000000000
    2.23606797749979
    """
    
    x = [x0]
    x.append(a/x0)
  
    print('Iteration | Estimate         | Relative Change')
    print('-------------------------------------------------')
         
    
    for i in range(1,max_iter):
       
        change = (abs(x[i] - x[i-1]) / x[i-1])
        if change > tol:
            x.append(1/2 * (x[i]   (a / x[i])))
        else:
            break
        print('{}         | {:.14f} | {:.16f}'.format(i, x[i], change))
    return(x[i])

        
        
    
           
# Don't change or delete the 5 lines of code below.
a = 5
max_iter = 100
tol = 1e-15
x_final = square_root_for(a, a, max_iter, tol)
print('Final estimate using square_root_for is {0}'.format(x_final))

# Problem 2.

def square_root_while(a, x0, tol=1e-14):
    """ (number, number, number) -> float

    Return an estimate of the square root of a number using the Heron's method.
        
    >>> square_root_while(5, 5)
    Iteration | Estimate         | Relative Change
    -------------------------------------------------
    1         | 3.00000000000000 | 0.4000000000000000
    2         | 2.33333333333333 | 0.2222222222222222
    3         | 2.23809523809524 | 0.0408163265306123
    4         | 2.23606889564336 | 0.0009053870529653
    5         | 2.23606797749998 | 0.0000004106060359
    6         | 2.23606797749979 | 0.0000000000000842
    7         | 2.23606797749979 | 0.0000000000000000
    2.23606797749979
    """
    
    x = [x0]
    x.append(a/x0)
  
    print('Iteration | Estimate         | Relative Change')
    print('-------------------------------------------------')
    
    i = 1
    while i < max_iter   1:
        change = (abs(x[i] - x[i-1]) / x[i-1])
        if change > tol:
            x.append(1/2 * (x[i]   (a / x[i])))

        else:
            break
        print('{}         | {:.14f} | {:.16f}'.format(i, x[i], change))
        i  = 1
        
    return x[i]

        

# Don't change or delete the 4 lines of code below.
a = 5
tol = 1e-15
x_final = square_root_while(a, a, tol)
print('Final estimate using square_root_while is {0}'.format(x_final))

The problem is that my output is incorrect. The correct output (As seen in the docstrings) would be:

Iteration | Estimate         | Relative Change
    -------------------------------------------------
    1         | 3.00000000000000 | 0.4000000000000000
    2         | 2.33333333333333 | 0.2222222222222222
    3         | 2.23809523809524 | 0.0408163265306123
    4         | 2.23606889564336 | 0.0009053870529653
    5         | 2.23606797749998 | 0.0000004106060359
    6         | 2.23606797749979 | 0.0000000000000842
    7         | 2.23606797749979 | 0.0000000000000000
    2.23606797749979

My output is:

Iteration | Estimate         | Relative Change
    -------------------------------------------------
    1         | 1.00000000000000 | 0.8000000000000000
    2         | 3.00000000000000 | 2.0000000000000000
    3         | 2.33333333333333 | 0.2222222222222222
    4         | 2.23809523809524 | 0.0408163265306123
    5         | 2.23606889564336 | 0.0009053870529653
    6         | 2.23606797749998 | 0.0000004106060359
    7         | 2.23606797749979 | 0.0000000000000842
    2.23606797749979

The problem is in the first two lines of outputs, but I can't figure out what I did wrong. Maybe it is something with the math? A student asked my teacher a similar problem and she said "When you do your first append, it's a little different from the other appends re. the math." I'm not sure if that helps. Any tips would be appreciated I am very stuck.

CodePudding user response:

You need to make the following changes to your code:

  • the second line in your function should be x.append(0.5*(x0 a/x0)). You need the average of x and a/x (as in every other iteration).
  • the print statement should be executed before the if/else block to print the last line where your relative change falls below the tolerance.

Try:

def square_root_for(a, x0, max_iter = 10, tol=1e-14):  
    x = [x0]
    x.append(0.5*(x0   a/x0))
  
    print('Iteration | Estimate         | Relative Change')
    print('-------------------------------------------------')
    
    for i in range(1, max_iter):
        change = (abs(x[i] - x[i-1]) / x[i-1])
        print('{}         | {:.14f} | {:.16f}'.format(i, x[i], change))
        if change > tol:
            x.append(1/2 * (x[i]   (a / x[i])))
        else:
            break
    return(x[i])

>>> square_root_for(5, 5, 100, 1e-15)
Iteration | Estimate         | Relative Change
-------------------------------------------------
1         | 3.00000000000000 | 0.4000000000000000
2         | 2.33333333333333 | 0.2222222222222222
3         | 2.23809523809524 | 0.0408163265306123
4         | 2.23606889564336 | 0.0009053870529653
5         | 2.23606797749998 | 0.0000004106060359
6         | 2.23606797749979 | 0.0000000000000842
7         | 2.23606797749979 | 0.0000000000000000
Final estimate using square_root_for is 2.23606797749979

CodePudding user response:

In general, if you find yourself guess at what order lines of code should go in, you should try rewriting the code - by now, you should understand what each line means, look at the below:

def square_root_for(a, first_guess, max_iter=10, tol=1e-14):
    print('Iteration | Estimate         | Relative Change')
    print('-------------------------------------------------')

    # put a and the first guess in a list
    guesses = [a, first_guess]
    # loop for a maximum of max_iter times
    for i in range(1, max_iter):
        # add a new guess to the end of the list
        guesses.append(1 / 2 * (guesses[i]   (a / guesses[i])))
        # compute the relative change between the last guess [-1] and the one before [-2]
        change = abs(guesses[-1] - guesses[-2]) / guesses[-2]
        print('{}         | {:.14f} | {:.16f}'.format(i, guesses[-1], change))
        # stop if the change is at or below tol
        if change <= tol:
            break
    # return the last guess in the list as the result
    return guesses[-1]

This returns the same correct result, but note how every line that does something is actually easier to understand, because it more literally describes itself. You almost don't need the comments.

  • Related