我正在使用标准库方法 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。为什么会这样?
有人可以提出更好的算法吗?
如果您在 上打印更多数字x
,您将看到问题所在(我随机选择了 30):
double x ;
x = pow(64, 1.0/3);
printf("x=%.30lf\n",x);
输出:
x=3.99999999...999600000000
所以很明显,如果你把它x
转换成 aint
它就会变成3
.
没有“完美”的解决方案。如果您只处理整数,您可以创建自己的根函数,但如果您希望能够使用浮点数,则需要处理由于浮点表示而导致的准确性问题。
可能有一些 C 库可以帮助您解决此类问题。
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
正如@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;
}