在cpp中计算数字的第n个根时错误的答案

时间:2014-06-08 10:47:48

标签: c++ algorithm nth-root

我正在使用标准库方法pow()来计算正整数的第n个根。这是我程序的片段:

double x,y;
x=pow(64,(1.0/3));
int z;
printf("x=%lf\n",x);
z=(int)x;
printf("%d\n",z);

但是在找到64的立方根时.X打印为4.000000而z为3.为什么会这样?

有人可以提出更好的算法吗?

3 个答案:

答案 0 :(得分:2)

如果您在x上打印更多数字,您就会看到问题所在(我随机选择了30个):

double x ;
x = pow(64, 1.0/3);
printf("x=%.30lf\n",x);

输出:

x=3.99999999...999600000000 

所以很明显,如果你将x投射到int,它将成为3

没有一个完美的'解。如果您只处理整数,则可以创建自己的根函数,但如果您希望能够使用float,则需要处理由于浮点表示而导致的精度问题。

可能有一些C库可以帮助你解决这类问题。

答案 1 :(得分:2)

int覆盖向下舍入。自floating point operations are inaccurate起,计算结果可能是3.999999 ......

使用round(x)获得正确的结果。

由于您总是希望将向下,因此您可以同时使用floor(int) - 但是一旦浮动点不稳定,您就会遇到观察到的错误对于double大小的计算,计算导致略微更小的值 - 大约10 -15 。使用微小的epsilon值来抵消它。

请注意,下方的epsilon“fudge”值与原始数字中的有效数字相关。对于较大的数字,您需要一个较小的epsilon。

#include <stdio.h>
#include <string.h>
#include <math.h>

int main (void)
{
    double x;
    int z;

    x=pow(64,(1.0/3));
    printf("x=%lf\n",x);
    printf("x=%.30lf\n",x);

    z=(int)x;
    printf("%d\n",z);

    z=(int)(x+0.000000000000005);
    printf("%d\n",z);

    x=pow(64,(1.0/4));
    printf("x=%lf\n",x);
    printf("x=%.30lf\n",x);

    z=(int)x;
    printf("%d\n",z);

    z=(int)(x+0.0000000000000005);
    printf("%d\n",z);

    return 1;
}

结果,对于1/3和1/4的幂,

x=4.000000
x=3.999999999999999555910790149937
3
4
x=2.828427
x=2.828427124746190290949243717478
2
2

答案 2 :(得分:0)

正如@jongware所述 int override向下舍入,浮点运算可能不准确。

虽然你总能做到这一点来逃避这个问题

def invpow ( n , i):
    x = pow (n ,(1/i))
    if((int)pow((x+1) , i) <= n):
        x += 1;
    print(x)

或者您可以使用Newton - Raphsonhere

所述的here方法编写自己的取幂方法

您还可以使用二进制搜索,如果您对该范围有正确的猜测,这是非常快的 即(变量高和低)

def invpow( x, n, low, high){
    if(n==1)
        return x;
    mid=(low+high)/2;

    while(low<high){
        mid=(low+high)/2;

        raised=pw(mid,n);

        if(raised==x)
            break;

        if(raised>x)
            high=mid;
        else
            low=mid;

        if(low+1==high){
            mid=low;
            break;
            }

    }
    return mid;
}