这里发生了什么:
#include <stdio.h>
#include <math.h>
int main(void) {
printf("17^12 = %lf\n", pow(17, 12));
printf("17^13 = %lf\n", pow(17, 13));
printf("17^14 = %lf\n", pow(17, 14));
}
我得到了这个输出:
17^12 = 582622237229761.000000
17^13 = 9904578032905936.000000
17^14 = 168377826559400928.000000
13和14与wolfram alpa cf:
不匹配12: 582622237229761.000000
582622237229761
13: 9904578032905936.000000
9904578032905937
14: 168377826559400928.000000
168377826559400929
此外,一些奇怪的部分并没有错 - 只有一个是错的!
如果这是我达到pow()
可以为我做的限制,那么有没有可以计算出来的替代方案?我需要一个可以计算x^y
的函数,其中x^y
总是小于ULLONG_MAX。
答案 0 :(得分:65)
pow
适用于double
个数字。这些表示形式s * 2 ^ e的数字,其中s是53位整数。因此double
可以将所有整数存储在2 ^ 53以下,但只有某些整数高于2 ^ 53。特别是,它只能表示偶数&gt; 2 ^ 53,因为对于e> 0值始终是2的倍数。
17 ^ 13需要54位来准确表示,因此e设置为1,因此计算出的值变为偶数。正确的值是奇数,因此它不会令人惊讶。同样,17 ^ 14需要58位来表示。这也是一个巧合的巧合(只要你没有应用太多的数论),它恰好是从 32的多个开始,这是粒度其中double
个数量的四舍五入。
对于精确整数取幂,您应该一直使用整数。编写自己的double
- 免费取幂程序。如果y
可能很大,则通过平方使用取幂,但我认为它总是小于64,这使得这个问题没有实际意义。
答案 1 :(得分:14)
您获得的数字太大,无法准确地用double
表示。双精度浮点数基本上包含53个有效二进制数字,可以表示最大2^53
或9,007,199,254,740,992的所有整数。
对于更高的数字,最后的数字会被截断,计算结果将四舍五入到可以表示为double
的下一个数字。对于仅略高于限制的17^13
,这是最接近的偶数。对于大于2^54
的数字,这是可被4整除的最接近的数字,依此类推。
答案 2 :(得分:14)
如果您的输入参数是非负整数,那么您可以实现自己的pow
。
<强>递归:强>
unsigned long long pow(unsigned long long x,unsigned int y)
{
if (y == 0)
return 1;
if (y == 1)
return x;
return pow(x,y/2)*pow(x,y-y/2);
}
<强>迭代:强>
unsigned long long pow(unsigned long long x,unsigned int y)
{
unsigned long long res = 1;
while (y--)
res *= x;
return res;
}
<强>高效:强>
unsigned long long pow(unsigned long long x,unsigned int y)
{
unsigned long long res = 1;
while (y > 0)
{
if (y & 1)
res *= x;
y >>= 1;
x *= x;
}
return res;
}
答案 3 :(得分:2)
对其他好答案的一个小补充:在x86架构下,通常有x87 80-bit extended format,大多数C编译器都通过long double
类型支持。{{3}}。此格式允许使用最大2^64
的整数运算,无间隙。
pow()
中的<math.h>
类似于long double
个数字powl()
。还应注意,long double
值的格式说明符不是double
值的格式说明符 - %Lf
。所以使用long double
类型的正确程序如下所示:
#include <stdio.h>
#include <math.h>
int main(void) {
printf("17^12 = %Lf\n", powl(17, 12));
printf("17^13 = %Lf\n", powl(17, 13));
printf("17^14 = %Lf\n", powl(17, 14));
}
斯蒂芬·佳能在评论中指出,不能保证这个程序应该给出确切的结果。