As mentioned in my original comment and all the answers, the square root of 2 is irrational. The square root of every integer that's not a perfect square is irrational for that matter, so 2 isn't special in that regard. What matters is that x**2 == 2
will never be true for any x
of finite precision (since finite precision is another way of saying a number is rational).
The other answers suggest searching until you reach some fixed, pre-determined accuracy. That works well, especially if you know the binary order of magnitude of the answer ahead of time, since then you can set the accuracy of the result to be in the last digit.
I'd like to suggest a more natural approach. You can check if your center value exactly equals one of the bounds. That would mean that half the difference between the bounds represents less than one digit of precision in your current guess. Your phrasing of the center is already correct: i = low + (high - low) / 2
can be compared to low
and high
using ==
, while i = (low + high) / 2
may not. This is because the precision of high - low
is greater than or equal to the precision of either bound, while low + high
is likely to lose some digits.
So here is what I would recommend:
num = 2
low = 1
high = num
guess = low + (high - low) / 2
count = 0
while guess != low and guess != high:
sqr = guess * guess
if sqr == num:
break
elif(sqr < num):
low = guess
else:
high = guess
guess = low + (high - low) / 2
count += 1
else:
if abs(low * low - num) < abs(high * high - num):
guess = low
else:
guess = high
print(count, ':', sqr)
print(num ** (.5), '~=', guess)
I've added count
for verification. The result is obtained in 52 iterations, accurate within 1 digit of precision:
52 : 2.0000000000000004
1.4142135623730951 ~= 1.4142135623730951
The final check against the bounds (the else
clause of the while
) ensures that you get the closest one to the desired result, regardless of which one you hit first.
The convergence is sane: a 64-bit floating point number in IEEE-754 format has 53 bits in the mantissa, so it makes sense that you would have to halve your search space exactly that many times to get your result (the first time is outside the loop).
Here's the snippet I used for testing: https://ideone.com/FU9r82