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
You could use a range for your return boolean, although it may lead to unprecise outputs depending on how stringent your requirements are:
double threshold = 0.01;
return (squareRootN*squareRootN > n-threshold) && (squareRootN*squareRootN < n+threshold);
long long
is an integer type. So, your +0.5 is lost in truncation.
You might use std::sqrt as a guess and test with multiplication:
#include <cmath>
#include <limits>
#include <iostream>
bool isPerfectSquare(long long n){
double guess = sqrt(n);
long long r = std::floor(guess);
if(r*r == n) return true;
else {
r = std::ceil(guess);
return r*r == n;
}
}
int main() {
const long long Limit = std::pow(10, std::numeric_limits<long long>::digits10 / 2);
std::cout << " Limit: " << Limit << '\n';
for (long long i = 0; i < Limit; ++i) {
if( ! isPerfectSquare(i*i)) {
std::cout << "Failure: " << i << '\n';
return 0;
}
}
std::cout << "Success\n";
}
You could use the result of the floating point square root as a hint only. Convert it to an integer. Check if the square is equal. If it is higher or lower, decrement or increment it, then recheck for the square, and continue until you have bound the parameter with: c1*c1 <= n <= (c1+1)*(c1+1)
The code is fine!
I have taken the time to write a small test. As the input range is limited, we can simply validate the function for every input.
Not that I did have to add an explicit cast to double for the sqrt function for it to compile. (using MS VC++ 10)
#include <math.h>
#include <iostream>
#include <set>
bool isPerfectSquare(long long n){
long long squareRootN=(long long)(sqrt((double)n)+0.5);
return squareRootN*squareRootN == n;
}
int main()
{
// for the input range,
// generate a set with numbers that are known to be perfect squares.
// all the rest are not.
std::set<long long> perfectSquares;
for(long long i = 1ll; i <= 100000ll; ++i) {
perfectSquares.insert(i*i);
}
std::cout << "Created lookup." << std::endl;
// now test the function for all the numbers in the input range
int progress = -1;
for(long long i = 1ll; i <= 10000000000ll; ++i) {
bool expected = (perfectSquares.count(i) == 1);
bool actual = isPerfectSquare(i);
if(expected != actual) {
std::cout << "Failed for " << i << std::endl;
}
int newprogress = i / 100000000ll;
if(newprogress != progress) {
progress = newprogress;
std::cout << "Progress " << progress << "%" << std::endl;
}
}
std::cout << "Test finished." << std::endl;
}
Results? Pass for all values! The problem must be in the code that uses the function. Maybe add input range validation to the function.
You use round
.
bool isPerfectSquare(long long n){
long long squareRootN=(long long)round((sqrt(n)));
if(squareRootN*squareRootN == n) {
return true;
}
else {
return false;
}
round
rounds the number to the nearest rounding. The function will be true only if n is a perfect square.