立方体根代码中的错误

gsd*_*sdf 0 c++ debugging

我正在编写一个程序来检查给定的数字是否有一个整数的立方根.这是我的代码: -

#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;
}
Run Code Online (Sandbox Code Playgroud)

这里c存储具有整数立方根的数字的数量.我的代码的问题是它总是给出两个作为答案,而答案应该大于两个,因为有许多数字,如8,64,27 ....

我想知道为什么我得到两个结果,我无法捕捉到这个错误!!

M.M*_*M.M 5

发生了什么是舍入误差.由于1/3在IEEE754中不能完全表示,因此得到的近似值略小于三分之一.

然后,当你计算,例如,pow(216, 1./3.)结果是5.9999999999999991118.因此,当你这样做时m - (int)m,你得到0.9999999999999991118的不等于零,所以你的测试失败了.

你的代码发现的唯一两种情况是两个最小的立方体(2和3),这个误差很小,它仍然比较等于零.

要查看计算结果的完整精度,您可以发送<< setprecision(20)cout.(你可能需要#include <iomanip>这个).

要解决这个问题,您需要做两件事:

  • 更换m - (int)mm - round(m)或类似
  • 检查数字是否非常接近0,而不是确切地说0.

有关第二部分的讨论,请参阅此问题.对于小案例,这适用于我:

abs(m - round(m)) < 0.000001
Run Code Online (Sandbox Code Playgroud)

但是,对于较大的数字,您可能需要考虑这个epsilon值的大小.这种方法实际上可能无法正常工作,因为可能从来没有一个小到足以排除误报但足以捕获所有真实案例的epsilon.

另一个改进是使用标准cbrt功能而不是这个pow.