C ++中数字的第n个根中的精度错误

时间:2014-06-08 19:31:29

标签: c++ algorithm math floating-accuracy

我从之前关于此主题的主题中了解到,使用float算法会导致精度异常。但有趣的是我观察到相同的函数表现为两种不同的方式。
使用COUT输出 4 但如果我将结果保存到变量中,则结果 3 < / b>!

#include <iostream>
#include <cmath>
using namespace std;
#define mod 1000000007
long long int fastPower(long long int a, int n){
    long long int res = 1;
    while (n) {
            if (n & 1) res = (res * a) % mod;
            n >>= 1; a = (a * a) % mod;
    }
    return res;
}
int main() {
    int j = 3;
    cout << pow(64, (double)1.0/(double)j) << endl; // Outputs 4
    int root = pow(64, (double)1.0/(double)j);
    cout << root << endl;                           // Outputs 3
    /* As said by "pts", i tried including this condition in my code but including this line in my code resulted in TimeLimitExceeded(TLE). */
    if (fastPower(root+1,j) <= 64) root++;
    cout << root << endl;                           // Outputs 4 :)
    return 0;
}

Code output on Ideone.com
现在,我们如何在编程竞赛中避免此类错误。 我不想使用'round'函数,因为我只需要root的整数值。即
63 (1/6) = 1,20 (1/2) = 4等...
我应该如何修改我的代码,以便将正确的结果存储在根变量中。

3 个答案:

答案 0 :(得分:2)

据我所知,C和C ++中没有单行答案可以使a的{​​{1}}根被舍入。

作为一种快速解决方法,您可以执行以下操作:

b

这不适用于每个值,但通过调整常量(int root(int a, int b) { return floor(pow(b, 1.0 / a) + 0.001); } ),您可能会很幸运,它可以用于测试输入。

要解决此问题,请在使用0.001时使用pow,如果它返回r,请通过乘法尝试r - 1rr + 1它返回(使用整数的快速取幂)。这大部分时间都可以使用。

如果您需要一种可以100%工作的解决方案,那么请不要使用浮点数。例如,使用指数二进制搜索。有更快的算法(如牛顿迭代),但如果你在整数上使用它们,那么你需要编写自定义逻辑,以便在它们停止收敛时找到确切的解决方案。

答案 1 :(得分:2)

pow返回双倍。当使用cout时,它是圆形的(因此,它是4)。当你将它转换为int时,它只是截断小数部分。 Pow返回类似4-eps的东西(由于精度问题)。当它被截断时,它等于3。 肮脏的黑客在编程竞赛中很有用:int root = (int)(pow(...) + 1e-7)

答案 2 :(得分:0)

您的计划有两个问题:

  1. pow(int, int)重载不再可用。要避免此问题,请将第一个参数转换为doublefloatlong double

  2. 此外,cout的命令正在上层回答您的答案(3.something into 4)并保存您的数据正在删除所有小数部分并且仅接受整数部分。