这段代码如何打印这么大的数字?我在Ubuntu 14.04(gcc 4.8.2)上尝试过它。 它在任何编译器的MS Windows上都不起作用(即使是MinGW,也称为“gcc for Windows”)。为什么呢?
#include <stdio.h>
#include <math.h>
int main()
{
printf("%.0f\n",pow(2,500));
}
Ubuntu输出:
3273390607896141870013189696827599152216642046043064789483291368096133796404
674554883270092325904157150886684127560071009217256545885393053328527589376
Windows输出:
3273390607896141900000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
(仅为清晰起见而添加换行符。)
答案 0 :(得分:7)
如OP提示并由@ user300234评论,2^500
是一个501位数字,但这不是问题。
pow(2,500)
返回double
,约3.27e150
,通常为binary64。此类型支持大约15-17个十进制数字的精度。因此对于 near 3.27e150
附近的数字,打印更多17个有效数字通常并不重要。它远小于DBL_MAX
,可能约为1.798e308
。
这里的诀窍是pow(2,500)
完全可以表示为浮点double
(binary64)。这可能会让人觉得double
具有数百位精度 - 但事实并非如此。
两种不同的编辑处理double
以不同的方式转换为文本,一旦打印了17个左右的数字 - 这是C规范允许的。正确数字的最小数量为DBL_DECIMAL_DIG
- 在两个系统上可能为17。
考虑打印 next 更大double
。虽然下一个双打可以打印150个左右的数字,但通常这些额外的数字通过DBL_DECIMAL_DIG
只是许多应用程序的噪音。
// 2 ^ 500
327339060789614 187001318969682759915221664...
// next
327339060789614 259685191399243448970154045...
答案 1 :(得分:4)
MinGW也使用的Microsoft Visual C运行时库(msvcrt.dll
)仅支持最多17位数的精度,因为这足以唯一地标识(IEEE 754)double
但好消息:使用VS2015 CTP4编译的代码产生与Ubuntu示例相同的输出。如果您正在使用MinGW-w64,则可以在将__USE_MINGW_ANSI_STDIO
或1
编译器选项包含在同一输出之前将<stdio.h>
定义为-D
。
答案 2 :(得分:0)
这不是一个新的答案,但与其他人已经说过的内容略有不同:
区别在于pow()
函数:区别在于printf()
函数。 Ubuntu printf()正在打印pow(2,500)
的确切十进制值。 Windows printf()正在打印一个正确到17位十进制数的近似值。
在某种意义上,这两种实现都是正确的;但我会说Windows printf()更多正确。这就是原因:
如果您关心的精度超过17位,则不应使用double
。
通常,大多数双重计算的结果仅在前17位中正确。 (pow(2, n)
是一个非常特殊的情况,答案对于范围内的任何 n 都是完全正确的。)通过打印非常大的双精度的精确十进制值,Ubuntu库愚弄你;假设你有
double a = ...;
double b = ...;
double c = a*b;
printf("%f", c);
您不想知道c
的确切价值,因为对于大多数a
和b
,c
不等于到a*b
:它只是a * b的近似 - 一个近似值,精确到大约17位有效数字。
如果你需要超过17位数的精度,那么你应该使用像GMP这样的扩展精度数学库(https://gmplib.org/)