I think there is a precision problem with the following code:
bool isPerfectSquare(long long n){
long long squareRootN=(long long)(sqrt(n)+0.5);
return
Sqrt(4) could return 1.9999
No, 4 and 2 are exactly representable as binary floating point numbers. No precision problems there.
The problem is that long long
has 64 bits of precision, but double
has only 52, so all solutions that rely on calling sqrt(double)
will start failing when you hit that limit. Here is a simple test program:
#include <iostream>
#include <math.h>
#include <stdlib.h>
bool isPerfectSquare(long long n)
{
double root = sqrt(n);
return floor(root) == root;
}
void check(long long x)
{
if (!isPerfectSquare(x))
std::cerr << x << " should be perfect\n", exit(1);
if (isPerfectSquare(x-1))
std::cerr << x-1 << " should NOT be perfect\n", exit(1);
if (isPerfectSquare(x+1))
std::cerr << x+1 << " should NOT be perfect\n", exit(1);
}
int main()
{
for (long long i = 2; i < 3037000499; ++i)
check(i * i);
std::cout << "all tests passed\n";
}
And here is the output on my computer:
4503599627370497 should NOT be perfect
Note that log(4503599627370497)/log(2) = 52
. In case you don't care about numbers that large, you can use the simple solution that merely checks whether sqrt
returns an integral result.
mmmm don't use float/double for your true/false outcome (you'll end up having approximation problems) Much better the integer apporach:
boolean is_square(long long n)
{
long long a=n;
while (a*a>n)
{
a=div(a+div(n,a),2);
}
return a*a==n;
}
div() is the integer division without remainder (you can use GCD() in some ways)
I know, I know... care must be taken for overflow issues