检查一个数是否为完全平方数
Checking if a number is perfect square?
我认为以下代码存在精度问题:
bool isPerfectSquare(long long n){
long long squareRootN=(long long)(sqrt(n)+0.5);
return squareRootN*squareRootN == n;
}
如何修复? P。1 <= n <= 10^10
Sqrt(4)可以返回1.9999 => 1,所以我加了0.5,所以它变成了2四舍五入后。注:sqrt返回浮点数。
这是一个解释,我发现,但仍然不能修复代码:
嗨,看来你也是浮点值的受害者。如果可能的话,您应该始终避免浮点比较。它被最糟糕的是数字范围的增加。比如说,当你分配的时候浮点a=4.0,它被存储为4.000…01111或3.999999…9978或相似的。所以当你输入case的时候要小心一个int。这些类型的误差的可能性随着范围的增加而增加整数。
您可以使用浮点平方根的结果仅作为提示。将其转换为整数。检查平方是否相等。如果它是更高或更低,减少或增加它,然后重新检查平方,并继续,直到你绑定了参数:C1 * C1 <= (C1 +1)*(C1 +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 << "Successn";
}
您使用round
bool isPerfectSquare(long long n) {
long long squareRootN = (long long)round((sqrt(n)));
if(squareRootN * squareRootN == n) {
return true;
} else {
return false;
}
}
round
将数字四舍五入到最接近的四舍五入。
mmm不要使用float/double作为你的真/假结果(你最终会有近似问题)整数方法更好:
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())
我知道,我知道……必须注意溢出问题Sqrt(4)可以返回1.9999
No、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 perfectn", exit(1);
if (isPerfectSquare(x-1))
std::cerr << x-1 << " should NOT be perfectn", exit(1);
if (isPerfectSquare(x+1))
std::cerr << x+1 << " should NOT be perfectn", exit(1);
}
int main()
{
for (long long i = 2; i < 3037000499; ++i)
check(i * i);
std::cout << "all tests passedn";
}
下面是我电脑上的输出:
4503599627370497 should NOT be perfect
注意log(4503599627370497)/log(2) = 52
。如果您不关心这么大的数字,您可以使用简单的解决方案,仅检查sqrt
是否返回整数结果。
您可以简单地检查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);
}
您可以为您的返回布尔值使用一个范围,尽管它可能导致不精确的输出,这取决于您的要求有多严格:
double threshold = 0.01;
return (squareRootN*squareRootN > n-threshold) && (squareRootN*squareRootN < n+threshold);
代码没问题!
我花时间写了一个小测试。由于输入范围有限,我们可以简单地为每个输入验证函数。
请注意,我确实必须为sqrt
函数添加一个显式强制转换到double
以使其编译(使用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;
}
结果?传递所有值!问题一定出在使用该函数的代码中。可以在函数中添加输入范围验证。
long long
为整型。所以,你的+0.5在截断中丢失了。
- 如何找到大小'x'数组是否完全填充,在C++?
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 是否基于数组B整数打印数组A中的整数
- 检查TCHAR数组输入是否为带符号整数C++
- 将错误返回给调用方而不是立即在 C++ 中抛出错误是否是一种好的做法
- 堆栈和队列是否像C++中的数组一样传递?
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 是否假定reinterpret_cast<char*>(myTypePtr)指向数组?
- 如果分配数组引发异常,是否应该释放该数组
- 是否可以在 QAbstractItemModel 中返回正数行数和零列数?
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- 我是否不正确地集中了这些字符数组?
- 是否可以就地构造一个固定大小的数组作为函数参数?
- 在 c++ 中是否允许创建具有运行时边界的数组?
- C++ 返回指向函数内定义的静态数组的指针是否有效?
- 检查输入 std::array 指针数据是否等于某个常量数组
- 使用 SB_SETTEXT 的状态栏中显示的字符数是否有限制
- 找出(在c++中)二进制数是否是另一个二进制数的前缀
- 如何检查双精度数是否有小数部分
- 算出一个很大的数是否能被另一个数整除