Written by Doug Issichopoulos dougissi.com in Nov. 2022

In [1]:
import matplotlib.pyplot as plt
In [2]:
def plot_guess(x, guess, smallest_guess_too_big, largest_guess_too_small):
    height = .5
    line_height = height / 2
    xmin = 0
    xmax = x
    fig = plt.figure(figsize=(10, height))
    ax = fig.add_subplot(111)
    ax.set_ylim(0, height)

    # draw horizontal line
    plt.hlines(line_height, xmin, xmax)
    
    # draw vertical lines
    def plot_vline(x_val, color=None):
        plt.vlines(x_val, 0, height, colors=color)
    plot_vline(xmin)
    plot_vline(xmax)
    plot_vline(smallest_guess_too_big, "red")
    plot_vline(largest_guess_too_small, "red")
    

    # draw a point on the line
    plt.plot(guess, line_height, 'ro', ms = 4, mfc = 'r')

    # add bookend and guess
    plt.text(xmin - 0.1, height/8*3, xmin, horizontalalignment='right')
    plt.text(xmax + 0.1, height/8*3, xmax, horizontalalignment='left')

    plt.axis('off')
    plt.show()
    

def nth_root(x: float, n: int):
    """Calculate the nth root of x"""
    
    if x < 0:
        raise NotImplemented("not implemented for negative values")
    if n < 0:
        raise NotImplemented("not implemented for negative root values")
        
    if x == 0 or x == 1:
        return x
    
    guess = x / 2
    prev_guess = None
    
    if x > 1:
        smallest_guess_too_big = x
        largest_guess_too_small = 0
    else:  # x < 1
        smallest_guess_too_big = 1
        largest_guess_too_small = x
    
    guess_nth_power = guess ** n 
    
    while (guess_nth_power != x and guess != prev_guess):
        plot_guess(x, guess, smallest_guess_too_big, largest_guess_too_small)
        text = f"guess: {guess}^{n} = {guess_nth_power}"
        if guess_nth_power > x:
            smallest_guess_too_big = guess
            prev_guess = guess
            new_guess = (largest_guess_too_small + guess) / 2
            text = f"{text} > {x}"
        else:
            largest_guess_too_small = guess
            prev_guess = guess
            new_guess = (guess + smallest_guess_too_big) / 2
            text = f"{text} < {x}"
            
        print(text)
        guess_nth_power = new_guess ** n
        guess = new_guess
        
    plot_guess(x, guess, smallest_guess_too_big, largest_guess_too_small)
    print(f"{guess}^{n} = {guess_nth_power}, woo!")
        
    return guess
    
        
In [3]:
nth_root(8, 2)
guess: 4.0^2 = 16.0 > 8
guess: 2.0^2 = 4.0 < 8
guess: 3.0^2 = 9.0 > 8
guess: 2.5^2 = 6.25 < 8
guess: 2.75^2 = 7.5625 < 8
guess: 2.875^2 = 8.265625 > 8
guess: 2.8125^2 = 7.91015625 < 8
guess: 2.84375^2 = 8.0869140625 > 8
guess: 2.828125^2 = 7.998291015625 < 8
guess: 2.8359375^2 = 8.04254150390625 > 8
guess: 2.83203125^2 = 8.020401000976562 > 8
guess: 2.830078125^2 = 8.009342193603516 > 8
guess: 2.8291015625^2 = 8.003815650939941 > 8
guess: 2.82861328125^2 = 8.001053094863892 > 8
guess: 2.828369140625^2 = 7.999671995639801 < 8
guess: 2.8284912109375^2 = 8.000362530350685 > 8
guess: 2.82843017578125^2 = 8.000017259269953 > 8
guess: 2.828399658203125^2 = 7.999844626523554 < 8
guess: 2.8284149169921875^2 = 7.999930942663923 < 8
guess: 2.8284225463867188^2 = 7.99997410090873 < 8
guess: 2.8284263610839844^2 = 7.99999568007479 < 8
guess: 2.828428268432617^2 = 8.000006469668733 > 8
guess: 2.828427314758301^2 = 8.000001074870852 > 8
guess: 2.8284268379211426^2 = 7.999998377472593 < 8
guess: 2.8284270763397217^2 = 7.999999726171666 < 8
guess: 2.8284271955490112^2 = 8.000000400521245 > 8
guess: 2.8284271359443665^2 = 8.000000063346452 > 8
guess: 2.828427106142044^2 = 7.999999894759058 < 8
guess: 2.8284271210432053^2 = 7.999999979052754 < 8
guess: 2.828427128493786^2 = 8.000000021199604 > 8
guess: 2.8284271247684956^2 = 8.000000000126178 > 8
guess: 2.8284271229058504^2 = 7.999999989589466 < 8
guess: 2.828427123837173^2 = 7.999999994857823 < 8
guess: 2.8284271243028343^2 = 7.999999997492001 < 8
guess: 2.828427124535665^2 = 7.9999999988090895 < 8
guess: 2.8284271246520802^2 = 7.999999999467634 < 8
guess: 2.828427124710288^2 = 7.9999999997969065 < 8
guess: 2.8284271247393917^2 = 7.999999999961543 < 8
guess: 2.8284271247539436^2 = 8.00000000004386 > 8
guess: 2.8284271247466677^2 = 8.000000000002702 > 8
guess: 2.8284271247430297^2 = 7.999999999982122 < 8
guess: 2.8284271247448487^2 = 7.999999999992412 < 8
guess: 2.828427124745758^2 = 7.999999999997557 < 8
guess: 2.828427124746213^2 = 8.00000000000013 > 8
guess: 2.8284271247459856^2 = 7.999999999998843 < 8
guess: 2.8284271247460993^2 = 7.999999999999486 < 8
guess: 2.828427124746156^2 = 7.999999999999807 < 8
guess: 2.8284271247461845^2 = 7.999999999999968 < 8
guess: 2.8284271247461987^2 = 8.000000000000048 > 8
guess: 2.8284271247461916^2 = 8.000000000000009 > 8
guess: 2.828427124746188^2 = 7.9999999999999885 < 8
guess: 2.82842712474619^2 = 7.999999999999998 < 8
guess: 2.8284271247461907^2 = 8.000000000000004 > 8
guess: 2.8284271247461903^2 = 8.000000000000002 > 8
guess: 2.82842712474619^2 = 7.999999999999998 < 8
2.82842712474619^2 = 7.999999999999998, woo!
Out[3]:
2.82842712474619
In [4]:
nth_root(16, 2)
guess: 8.0^2 = 64.0 > 16
4.0^2 = 16.0, woo!
Out[4]:
4.0
In [5]:
nth_root(625, 4)
guess: 312.5^4 = 9536743164.0625 > 625
guess: 156.25^4 = 596046447.7539062 > 625
guess: 78.125^4 = 37252902.98461914 > 625
guess: 39.0625^4 = 2328306.4365386963 > 625
guess: 19.53125^4 = 145519.15228366852 > 625
guess: 9.765625^4 = 9094.947017729282 > 625
guess: 4.8828125^4 = 568.4341886080801 < 625
guess: 7.32421875^4 = 2877.6980798284058 > 625
guess: 6.103515625^4 = 1387.7787807814457 > 625
guess: 5.4931640625^4 = 910.5216580707065 > 625
guess: 5.18798828125^4 = 724.4291971852945 > 625
guess: 5.035400390625^4 = 642.889062298091 > 625
guess: 4.9591064453125^4 = 604.8027001632518 < 625
guess: 4.99725341796875^4 = 623.6278401269716 < 625
guess: 5.016326904296875^4 = 633.2035244346242 > 625
guess: 5.0067901611328125^4 = 628.402002773146 > 625
guess: 5.002021789550781^4 = 626.0115080856422 > 625
guess: 4.999637603759766^4 = 624.8188215785862 < 625
guess: 5.000829696655273^4 = 625.4149515985414 > 625
guess: 5.0002336502075195^4 = 625.1168332928778 > 625
guess: 4.999935626983643^4 = 624.9678141133987 < 625
guess: 5.000084638595581^4 = 625.0423203723565 > 625
guess: 5.000010132789612^4 = 625.005066410207 > 625
guess: 4.999972879886627^4 = 624.9864400536383 < 625
guess: 4.9999915063381195^4 = 624.995753179881 < 625
guess: 5.000000819563866^4 = 625.0004097820336 > 625
guess: 4.999996162950993^4 = 624.9980814777048 < 625
guess: 4.999998491257429^4 = 624.999245629056 < 625
guess: 4.999999655410647^4 = 624.9998277053415 < 625
guess: 5.0000002374872565^4 = 625.0001187436367 > 625
guess: 4.999999946448952^4 = 624.9999732244764 < 625
guess: 5.000000091968104^4 = 625.0000459840534 > 625
guess: 5.000000019208528^4 = 625.000009604264 > 625
guess: 4.99999998282874^4 = 624.99999141437 < 625
guess: 5.000000001018634^4 = 625.000000509317 > 625
guess: 4.999999991923687^4 = 624.9999959618435 < 625
guess: 4.999999996471161^4 = 624.9999982355803 < 625
guess: 4.999999998744897^4 = 624.9999993724487 < 625
guess: 4.999999999881766^4 = 624.9999999408828 < 625
guess: 5.0000000004502^4 = 625.0000002250999 > 625
guess: 5.000000000165983^4 = 625.0000000829914 > 625
guess: 5.000000000023874^4 = 625.0000000119371 > 625
guess: 4.99999999995282^4 = 624.99999997641 < 625
guess: 4.999999999988347^4 = 624.9999999941735 < 625
guess: 5.000000000006111^4 = 625.0000000030553 > 625
guess: 4.999999999997229^4 = 624.9999999986145 < 625
guess: 5.00000000000167^4 = 625.0000000008349 > 625
guess: 4.999999999999449^4 = 624.9999999997247 < 625
guess: 5.0000000000005596^4 = 625.0000000002798 > 625
guess: 5.000000000000004^4 = 625.0000000000023 > 625
guess: 4.999999999999726^4 = 624.9999999998632 < 625
guess: 4.999999999999865^4 = 624.9999999999325 < 625
guess: 4.999999999999934^4 = 624.9999999999671 < 625
guess: 4.99999999999997^4 = 624.9999999999849 < 625
guess: 4.999999999999988^4 = 624.9999999999937 < 625
guess: 4.9999999999999964^4 = 624.9999999999982 < 625
5.0^4 = 625.0, woo!
Out[5]:
5.0
In [6]:
nth_root(0.5, 2)
guess: 0.25^2 = 0.0625 < 0.5
guess: 0.625^2 = 0.390625 < 0.5
guess: 0.8125^2 = 0.66015625 > 0.5
guess: 0.71875^2 = 0.5166015625 > 0.5
guess: 0.671875^2 = 0.451416015625 < 0.5
guess: 0.6953125^2 = 0.48345947265625 < 0.5
guess: 0.70703125^2 = 0.4998931884765625 < 0.5
guess: 0.712890625^2 = 0.5082130432128906 > 0.5
guess: 0.7099609375^2 = 0.5040445327758789 > 0.5
guess: 0.70849609375^2 = 0.5019667148590088 > 0.5
guess: 0.707763671875^2 = 0.5009294152259827 > 0.5
guess: 0.7073974609375^2 = 0.5004111677408218 > 0.5
guess: 0.70721435546875^2 = 0.5001521445810795 > 0.5
guess: 0.707122802734375^2 = 0.5000226581469178 > 0.5
guess: 0.7070770263671875^2 = 0.49995792121626437 < 0.5
guess: 0.7070999145507812^2 = 0.49999028915772215 < 0.5
guess: 0.7071113586425781^2 = 0.5000064735213527 > 0.5
guess: 0.7071056365966797^2 = 0.49999838130679564 < 0.5
guess: 0.7071084976196289^2 = 0.5000024274058887 > 0.5
guess: 0.7071070671081543^2 = 0.5000004043542958 > 0.5
guess: 0.707106351852417^2 = 0.49999939283003414 < 0.5
guess: 0.7071067094802856^2 = 0.4999998985920371 < 0.5
guess: 0.70710688829422^2 = 0.5000001514731345 > 0.5
guess: 0.7071067988872528^2 = 0.5000000250325778 > 0.5
guess: 0.7071067541837692^2 = 0.49999996181230544 < 0.5
guess: 0.707106776535511^2 = 0.4999999934224411 < 0.5
guess: 0.7071067877113819^2 = 0.5000000092275093 > 0.5
guess: 0.7071067821234465^2 = 0.5000000013249752 > 0.5
guess: 0.7071067793294787^2 = 0.49999999737370815 < 0.5
guess: 0.7071067807264626^2 = 0.49999999934934164 < 0.5
guess: 0.7071067814249545^2 = 0.5000000003371584 > 0.5
guess: 0.7071067810757086^2 = 0.49999999984325005 < 0.5
guess: 0.7071067812503316^2 = 0.5000000000902043 > 0.5
guess: 0.7071067811630201^2 = 0.4999999999667271 < 0.5
guess: 0.7071067812066758^2 = 0.5000000000284657 > 0.5
guess: 0.7071067811848479^2 = 0.4999999999975964 < 0.5
guess: 0.7071067811957619^2 = 0.500000000013031 > 0.5
guess: 0.7071067811903049^2 = 0.5000000000053137 > 0.5
guess: 0.7071067811875764^2 = 0.5000000000014551 > 0.5
guess: 0.7071067811862122^2 = 0.49999999999952577 < 0.5
guess: 0.7071067811868943^2 = 0.5000000000004904 > 0.5
guess: 0.7071067811865532^2 = 0.5000000000000081 > 0.5
guess: 0.7071067811863827^2 = 0.4999999999997669 < 0.5
guess: 0.707106781186468^2 = 0.4999999999998875 < 0.5
guess: 0.7071067811865106^2 = 0.49999999999994776 < 0.5
guess: 0.7071067811865319^2 = 0.4999999999999779 < 0.5
guess: 0.7071067811865426^2 = 0.499999999999993 < 0.5
guess: 0.7071067811865479^2 = 0.5000000000000006 > 0.5
guess: 0.7071067811865452^2 = 0.4999999999999968 < 0.5
guess: 0.7071067811865466^2 = 0.49999999999999867 < 0.5
guess: 0.7071067811865472^2 = 0.4999999999999996 < 0.5
guess: 0.7071067811865476^2 = 0.5000000000000001 > 0.5
guess: 0.7071067811865475^2 = 0.4999999999999999 < 0.5
0.7071067811865475^2 = 0.4999999999999999, woo!
Out[6]:
0.7071067811865475