Search code examples
algorithmsearchiterationbisection

bisection search square root implementation


When trying to find a close approximate of the square root of a number bisection algorithms seems to perform extremely well.

In fact bisection search gives a result in just a second for the square root of 10^45

start_time = time.time()
x = 10**45
epsilon = 0.01
numGuesses = 0
low = 0.0
high = max(1.0, x)
ans = (high + low)/2.0

while abs(ans**2 - x) >= epsilon:
    print('low =', low, 'high =', high, 'ans =', ans)
    numGuesses += 1
    if ans**2 < x:
        low = ans
    else:
        high = ans    
    ans = (high + low)/2.0
print('numGuesses =', numGuesses)
print(ans, 'is close to square root of', x)

elapsed_time = time.time() - start_time
print(elapsed_time)

But when it comes to finding 10**46 it calculates for so long I eventually terminate it...

start_time = time.time()
x = 10**46
epsilon = 0.01
numGuesses = 0
low = 0.0
high = max(1.0, x)
ans = (high + low)/2.0

while abs(ans**2 - x) >= epsilon:
    print('low =', low, 'high =', high, 'ans =', ans)
    numGuesses += 1
    if ans**2 < x:
        low = ans
    else:
        high = ans    
    ans = (high + low)/2.0
print('numGuesses =', numGuesses)
print(ans, 'is close to square root of', x)

elapsed_time = time.time() - start_time
print(elapsed_time)

Is there any explanation? Can anyone run it?


Solution

  • @Lecagy is correct. The problem is that there are a finite number of floating point numbers. Therefore when you average two that are next to each other, the average is one of the two.

    You just need to add a condition to check for this.

    import time
    start_time = time.time()
    x = 10**46
    epsilon = 0.01
    numGuesses = 0
    low = 0.0
    high = max(1.0, x)
    ans = (high + low)/2.0
    
    while abs(ans**2 - x) >= epsilon and ans != low and ans != high:
        print('low =', low, 'high =', high, 'ans =', ans)
        numGuesses += 1
        if ans**2 < x:
            low = ans
        else:
            high = ans
        ans = (high + low)/2.0
    print('numGuesses =', numGuesses)
    print(ans, 'is close to square root of', x)
    
    elapsed_time = time.time() - start_time
    print(elapsed_time)
    

    And now it runs instantly but is not guaranteed to be within epsilon.