5
\$\begingroup\$

I typed this up quickly as an intuitive solution for determining if a given number is a perfect square.

How could I improve this? I already know that it doesn't handle the case where the number is 1. I'm wondering if I could generalize the calculation so it rounds up. What can I look into to develop a mindset for tackling these sorts of problems?

int number = 1000000;
int half = (number + 2 - 1)/2;
int square = 0;
boolean isSquare = false;

for( int i = half; i > 0 ; i-- ){

    square = i*i;

    if( square > number )
        continue;

    if( square == number ){
        System.out.println( "This number is a perfect square" );
        isSquare = true;
        break;
    } 

}

if( !isSquare ){
    System.out.println( "This number is not a perfect square" );
}
\$\endgroup\$
2

4 Answers 4

7
\$\begingroup\$

You could make use of the fact that n² = the sum of the first n odd numbers (for integral n ≥ 0), rather than having to compute i * i every time through the loop.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Interesting number set property. Didn't know about that one. Thanks. \$\endgroup\$
    – James P.
    Commented Jul 29, 2013 at 4:17
  • \$\begingroup\$ Is two additions cheaper than a multiplication? \$\endgroup\$ Commented Jul 29, 2013 at 16:47
  • 1
    \$\begingroup\$ Did the experiment, was twice as fast... \$\endgroup\$
    – thriqon
    Commented Aug 9, 2013 at 0:24
  • \$\begingroup\$ The property derives from (n+1)² - n² = 2n + 1, the next greater odd number. \$\endgroup\$
    – Joop Eggen
    Commented Oct 16, 2015 at 12:26
4
\$\begingroup\$

You can narrow down your search range. If a number requires n bits to represent, its square root is between 1 << ((n-1) / 2) and 1 << ((n+1) / 2). You can determine number of bits with something like:

int numBits(long l) {
  for (int i = 62; i >= 0; i--) {
    if (l & (1 << i)) return i + 1;
  }
  return 0;
}
\$\endgroup\$
1
  • \$\begingroup\$ I had an error in the shift statements, which I've now fixed. \$\endgroup\$
    – ruds
    Commented Jul 29, 2013 at 6:29
2
\$\begingroup\$

There are significant improvements that can be made by choosing a more optimal algorithm.

Better algorithms for finding the root of x² - n = 0 are :

  • Halving intervals to search for the root. This is called the bisection method.

  • Even faster would be Newton's method : follow the tangent line on your current approximated root, to find a closer approximation.

Note the pseudo code on the linked wiki pages.

Both are defined to use reals, but can easily be adapted to accept only integer results : once improvements stop or are less than the distance to the nearest integer, you either have found an exact integer result, or the root isn't an integer.

\$\endgroup\$
1
\$\begingroup\$

What you need is to use integer square root algorithm and verify that the root's square value is the original number (e.g. x == isqrt(x)^2).

You can find integer square root algorithm code here: http://medialab.freaknet.org/martin/src/sqrt/

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.