A question came up on StackOverflow today regarding testing whether integers were perfect squares. The person asking the question said his first idea was to take the (floating point) square root, round the result to the nearest integer, square that, and see whether he got the original number back. But he thought maybe there was a faster way that avoided floating point arithmetic.
My suggestion was to first look at the number in hexidecimal (base 16) and see whether the number could be ruled out as a square before proceeding. Squares in base 16 end in 0, 1, 4, or 9. (You can see this by brute force: square every number from 0 to 15 and take the remainder dividing by 16.) You can find the end of the number in hex by a fast bit operation, then rule out 12 out of every 16 numbers. Then do the square root and square procedure on the 4 out of 16 numbers that slip through the hexidecimal filter. Here’s C++ code for the algorithm.
int PerfectSquare(int n)
{
int h = n & 0xF; // last hexidecimal "digit"
if (h > 9)
return 0; // return immediately in 6 cases out of 16.
// Take advantage of Boolean short-circuit evaluation
if ( h != 2 && h != 3 && h != 5 && h != 6 && h != 7 && h != 8 )
{
// take square root if you must
int t = (int) floor( sqrt((double) n) + 0.5 );
return t*t == n;
}
return 0;
}
This algorithm ran about twice as fast as always taking the square root. The analogous C# code also ran about twice as fast as the more direct method.
What about looking at other bases? We want to use bases that are powers of 2 so we can get the last “digit” quickly. Half the numbers in base 4 are potential squares. Three out of eight numbers in base 8 are potential squares. Four out of 16 are potential squares in base 16. So taking smaller powers of 2 is probably not faster. Seven out of 32 numbers are potential squares base 32, a slightly lower ratio than base 16, but at the cost of more comparisons. I haven’t benchmarked using bases other than 16, but I doubt they are faster. If any are faster, I imagine the difference is small.
Here are a couple number theory problem that comes out of the problem above. First, how many numbers have square roots mod 2n, i.e. for how many values y does x2 ≡ y (mod 2n) have a solution? Call that number g(n). For example, g(3) = 3, g(4) = 4, g(5) = 7, g(6) = 12. Is there a simple formula for g(n)? Second, what is the minimum value of g(n)/2n?
Update: See Michael Lugo’s solution to the number theory questions in the comments below or more discussion here.
Update: According to the StackOverflow discussion, the base 64 technique was a little faster than the base 16 technique, at least when implemented in C#. The relative speeds of variations on the algorithm depend on what language you’re using.

{ 1 trackback }
{ 3 comments… read them below or add one }
Michael Lugo 11.18.08 at 07:34
The encyclopedia of integer sequences gives the simple formula g(n) = [(2^n + 10)/6], where [x] is the greatest integer less than or equal to x. (g(6) is in fact 12; the possible residues are 0, 1, 4, 9, 16, 17, 25, 33, 36, 41, 49, 57.) So {g(n)/2^n} is a sequence which decreases towards a limit of 1/6, although it never gets there.
Daniel Lemire 11.18.08 at 20:19
Useless but… oh!… so beautiful. Thank you.
Řrřola 02.20.10 at 11:55
I think you’d speed up the code considerably if you used the table-in-a-constant trick:
if ((1<<0 | 1<<1 | 1<<4 | 1<> (n & 0xF) & 1) do_the_sqrt;or, if you have 64-bit integers,
if (0x2001002010213ULL >> (n & 0x3F) & 1) do_the_sqrt;