立方体根代码中的错误

时间:2014-11-26 04:13:44

标签: 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;
}

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

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

2 个答案:

答案 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