我正在使用标准库方法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.为什么会这样?
有人可以提出更好的算法吗?
答案 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 - Raphson和here
所述的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;
}