我认为以下代码存在精度问题:
bool isPerfectSquare(long long n){
long long squareRootN=(long long)(sqrt(n)+0.5);
return squareRootN*squareRootN == n;
}
如何解决? P.S:1< = n< = 10 ^ 10
Sqrt(4)可以返回1.9999 => 1所以我加0.5,使它变成2 圆满结束。注意:sqrt返回浮点。
这是我发现的解释,但仍然无法修复代码:
嗨,您似乎也是浮点值的受害者。如果 可能,你应该总是避免浮点比较。它得到了 最糟糕的是数字范围的增加。说,当你分配 float a = 4.0,它存储为4.000 ... 01111或3.999999 ... 9978或 类似。所以每当你输入一个平方根的情况时要小心谨慎 一个int。这些类型的错误的可能性随着范围的增加而增加 整数。
答案 0 :(得分:1)
您可以使用浮点平方根的结果作为提示。将其转换为整数。检查方块是否相等。如果它更高或更低,则递减或递增它,然后重新检查正方形,并继续直到您将参数绑定到: c1 * c1< = n< =(c1 + 1)*(c1 + 1)
答案 1 :(得分:1)
您可以使用std :: sqrt作为猜测并使用乘法进行测试:
#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";
}
答案 2 :(得分:1)
您使用round
。
bool isPerfectSquare(long long n){
long long squareRootN=(long long)round((sqrt(n)));
if(squareRootN*squareRootN == n) {
return true;
}
else {
return false;
}
round
将数字四舍五入到最近的舍入。只有当n是一个完美的正方形时,该函数才会成立。
答案 3 :(得分:0)
你可以使用一个范围作为你的返回布尔值,虽然它可能会导致不准确的输出,具体取决于你的要求有多严格:
double threshold = 0.01;
return (squareRootN*squareRootN > n-threshold) && (squareRootN*squareRootN < n+threshold);
答案 4 :(得分:0)
mmmm不使用float / double来表示你的真/假结果(你最终会遇到近似问题) 整数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()是没有余数的整数除法(你可以在某些方面使用GCD())
我知道,我知道......必须注意溢出问题
答案 5 :(得分:0)
代码很好!
我花时间写了一个小测试。 由于输入范围有限,我们可以简单地验证每个输入的函数。
并非我必须为sqrt函数添加一个显式强制转换才能进行编译。 (使用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;
}
结果?通过所有价值观! 问题必须出在使用该函数的代码中。 也许在函数中添加输入范围验证。
答案 6 :(得分:0)
Sqrt(4)可以返回1.9999
不,4和2可以完全表示为二进制浮点数。那里没有精确问题。
问题是long long
具有64位精度,但double
只有52位,因此当您达到该限制时,依赖于调用sqrt(double)
的所有解决方案都将失败。这是一个简单的测试程序:
#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";
}
这是我电脑上的输出:
4503599627370497 should NOT be perfect
请注意log(4503599627370497)/log(2) = 52
。如果你不关心那么大的数字,你可以使用简单的解决方案,只检查sqrt
是否返回一个整数结果。
答案 7 :(得分:0)
您可以简单地检查sqrt()
的地板和天花板:
bool isSquare (long long number)
{
double root = sqrt(number);
double floor = std::floor(root);
double ceil = std::ceil(root);
return (floor * floor == number) && (ceil * ceil == number);
}
答案 8 :(得分:-1)
long long
是整数类型。所以,你的+0.5在截断时会丢失。