Calculating square roots using perfect squares

139 Views Asked by At

I recently discovered a way to quickly calculate perfect squares (that are close to a prior-known perfect square), then extrapolated from that a method to mentally calculate the square root of numbers, quickly. Unfortunately, the square root process produces an answer that is minutely off, and since I cannot find any mention of the method I use, haven't been able to find any way to fix the drift. (As a note: I'll refer to my process for calculating the perfect squares as "Proximity", and for square roots "Interpolation".)

I'll begin with the background describing Proximity. If a number $n$ and its square ($n^2$) are known (for example, $4^2 = 16$), then the value of $(n + 1)^2$ can be easily calculated by $n^2 + n + (n+1)$, or the known square value added to its originating number plus the next number (as demonstrated $16 + 4 + 5 = 25 = 5^2$). It can also be used to calculate the previous perfect square - $16 - 4 - 3 = 9 = 3^2$.

As I first thought of it, Proximity would be useful to calculate a perfect square close to a known perfect square. $20^2 = 400$ is easy, but if I didn't remember the result of $22^2$, instead of doing the math normally, I'd know $400 + 20 + 42 + 22 = 484$ ($42$ is $21 + 21$, the first from traversing $20$ to $21$ and the second from traversing $21$ to $22$. Using Proximity, I'd only need to remember fewer perfect squares - I could calculate $29^2$ was $900 - 30 - 29 = 841$. The difference from one perfect square ($n^2$) to the next ($(n + 1)^2)$) is always $n + (n + 1)$.

This brings us on to Interpolation. While thinking about this, I wanted a quick method for calculating the square root of a number. Bracketing it was easy - $\sqrt{18}$ would be between $4$ and $5$. But I then realized I could use its position between the perfect squares to help. As $18$ is $2$ away from $16$, and the difference between the perfect squares was $9$, $\sqrt{18}$ could quickly be calculated to $4 \frac{2}{9}$.

Unfortunately, there is a problem with the Interpolation method. While $4 \frac{2}{9} = 4.222222...$, $\sqrt{18} = 4.242640...$. All told, the difference between the results for $\sqrt{18}$ is $\approx 0.02041846489706256$.

I'll include a small Python program at the end to display all the differences, but it can be summarized as such:

  1. The true square root is always larger than the Interpolation calculated root, except on perfect squares, where they match.
  2. The largest difference for an integer is at $\sqrt{2}$, with a difference of approximately $0.08088$.
  3. The differences diminish as the distance between perfect squares increases (the larger the number, the more accurate the calculation).
  4. The difference between the true and calculated root is greater the further the calculating number is from a perfect square. The numbers equidistant from perfect squares will have the greatest difference from true, while those next to perfect squares will be closest.
  5. Differences from true value will not match each other over the midpoint described in rule 4. The accuracy increases the closer the number approaches the next perfect square. For example, Interpolation's value for $\sqrt{17}$ (one off from $16 = 4^2$) will have a greater distance from true than Interpolation's value for $\sqrt{24}$ (one off from $25 = 5^2$).
  6. Above $36$ ($6^2$), no difference is greater than $0.02$. Beyond $144$ ($12^2$), no difference is greater than $0.01$.

As it currently stands, Interpolation is a good method for ballpark numbers. I was wondering if there was a way to make it more accurate. Square root progressions between numbers are not linear, but there may be some equation that could easily be mentally applied to make it more accurate, or perhaps even fix the difference entirely.

The following Python program displays the differences between the true root and Interpolation root. For ease, it can be copied and run here.

import math
for i in range(1, 1000):
    actual = math.sqrt(i)
    calc_int = int(actual)
    calc_numerator = i - math.pow(calc_int, 2)
    calc_denominator = math.pow(calc_int + 1, 2) - math.pow(calc_int, 2)
    print(f"{i}: {(actual % 1) - (calc_numerator / calc_denominator)}")