0

我正在使用标准库方法 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。为什么会这样?

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

4

3 回答 3

2

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

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

输出:

x=3.99999999...999600000000 

所以很明显,如果你把它x转换成 aint它就会变成3.

没有“完美”的解决方案。如果您只处理整数,您可以创建自己的根函数,但如果您希望能够使用浮点数,则需要处理由于浮点表示而导致的准确性问题。

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

于 2014-06-08T10:56:12.290 回答
2

int覆盖向下舍入。由于浮点运算不准确,计算可能是3.999999...

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

由于您总是想向下取整,因此您可以同时使用floor(int)——但一旦浮点计算的不稳定性导致值稍小,就会遇到观察到的错误——大约为 10 -15,对于double大小计算。使用一个很小的 ​​epsilon 值来抵消它。

请注意,下面的 epsilon“软糖”值与原始数字中的有效位数有关。对于较大的数字,您需要较小的 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
于 2014-06-08T10:56:42.657 回答
0

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

虽然你总是可以这样做来逃避这个问题

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

或者您可以使用此处此处描述的Newton - Raphson方法编写自己的求幂方法

如果您对范围 ie(变量 high 和 low )有正确的猜测,您也可以使用非常快的二进制搜索

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;
}
于 2014-06-12T18:04:14.740 回答