我正在编写一个程序,用于检查给定数字是否具有整数立方根 这是我的代码: -
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main(int argc, char const *argv[])
{
double m;
int c=0;
int i;
for(i=2;i<=1000000;i++)
{
m = pow(i,(1./3.));
if(m-(int)m == 0)
{
c++;
}
}
cout<<c<<endl;
}
此处c
存储具有整数多维数据集根的数字的数量。我的代码的问题是它总是给出两个作为答案,而答案应该大于两个,因为有许多数字,如8,64,27 ....
我想知道为什么我得到两个结果,我无法捕捉到错误!!
答案 0 :(得分:5)
发生了什么是舍入错误。由于1/3在IEEE754中不能完全表示,因此得到的近似值略小于三分之一。
然后,当您计算pow(216, 1./3.)
时,结果为5.9999999999999991118
。因此,当您执行m - (int)m
时,您得到的0.9999999999999991118
不等于零,因此您的测试失败。
你的代码发现的唯一两个案例是两个最小的立方体(2和3),这个误差很小,它仍然比较等于零。
要查看计算结果的完整精度,您可以将<< setprecision(20)
发送至cout
。 (您可能需要#include <iomanip>
)。
要解决此问题,您需要做两件事:
m - (int)m
替换为m - round(m)
或类似0
,而不是0
。See this question讨论第二部分。对于小案例,这适用于我:
abs(m - round(m)) < 0.000001
然而,您可能需要考虑较大数字的这个epsilon值的大小。这种方法实际上可能在一般情况下不会起作用,因为可能从来没有一个小的ε足以消除误报,但足以捕获所有真实案例。
另一项改进是使用标准cbrt
函数而不是pow
。
答案 1 :(得分:1)
您也可以这样做(虽然我只是从一开始就将数字立方体化),例如
#include <iostream>
#include <cmath>
int main(int argc, char const *argv[])
{
int c = 0;
for (int i = 2; i <= 1000000; i++)
{
int m = std::round(std::pow(i, 1. / 3));
if (std::round(std::pow(m, 3)) == i) // use std::round to be super safe
c++;
}
std::cout << c << std::endl;
}
PS:请注意我使用std::round(std::pow(m,3))
因为std::pow
可能(并且可怕)给你一个不正确的结果,即使你的基数和参数是整数,参见
std::pow with integer parameters, comparing to an integer type