【问题标题】:c++ pow(2,1000) is normaly to big for double, but it's working. why?c++ pow(2,1000) 通常对于 double 来说很大,但它正在工作。为什么?
【发布时间】:2011-11-14 09:00:41
【问题描述】:

代码:

#iclude <math.h>

int main(){
double somenumber = pow(2, 1000);
printf("%lf\n", somenumber);
return 0;
}

我得到了这个巨大的数字: 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376 P>

这显然对双倍来说太大了。它是如何工作的?

【问题讨论】:

  • 我很高兴您能看一眼一个数字并判断它是否太大而无法放入双人床。我不能。
  • 如果我在一个知道列宽的终端上查看它,我可以除了边界情况... :-)
  • 浮点表示.点的位置浮动(c.f.定点)对于双精度点可以浮动多达2^-1022到2^1023。但是,提示就在名称中。
  • @Peter Lawrey:2^-1074 是下限,而不是 2^-1022。 2^-1074 和 2^-1022 之间的数字可以用 IEEE 754 格式表示,但作为非规范化数字。
  • “这显然对 double 来说太大了” - 不,不是(尤其不是明显 ;))

标签: c++ c numbers


【解决方案1】:

这显然对双倍来说太大了。它是如何工作的?

21000 在可以用双精度表示的数字范围内。所以这个数字对于双倍来说显然不算大。

我怀疑您所说的“太大”是指打印的位数远大于可以存储在 double 中的 16 位左右的数字。要求计算机打印超过 16 个十进制数字并没有错。错在假设那些额外的数字有任何意义。

在这种特殊情况下,打印的数字完全正确。那是因为计算机特别对待pow(2,some_int)。 2 的幂可以精确地表示为双精度数。用于计算精确整数值的十进制表示的算法将给出完全正确的十进制表示。

除此之外,一切都结束了。更改您的程序,使其打印 3646 例如:

#include <math.h>
#include <stdio.h>

int main(){
  double somenumber = pow(3, 646);
  printf("%lf\n", somenumber);
  return 0;
}

它仍然会打印一个很大的长数字,但只有前 16 位左右的数字是正确的。

【讨论】:

  • 好的,我想我差不多明白了。最后一个问题:那个巨大的数字,它是否像 2 的幂一样存储在 somenumber 变量中,并且是 printf 的实现计算该数字的十进制表示?对吗?
  • @user938183 是的,你是对的。数字只是计算机中的数字。但是 printf 把它们变成了可以打印在屏幕上的字符串
  • @user938183:是的,printf 计算十进制表示——至少在大多数计算机上是这样。 IEEE 浮点标准还允许使用十进制而不是二进制指数。大多数计算机使用二进制格式。许多计算器使用十进制指数。
  • 是的,计算十进制表示是printf 的一部分,而不是double 变量值的固有属性。 printf 显示的值只需要在第一个 DECIMAL_DIG 位置正确,即使 2^1000 具有 double 的精确表示。一个好的实现会打印出确切的值,但这样做并不简单,而且在计算时间和空间上相当昂贵。
  • 注意 - C 标准并不要求这个数字可以精确表示。但大多数系统使用以 2 为底的浮点数。
【解决方案2】:

它是 2 的幂,浮点数本质上存储为 2 的(倍数)幂。

同样,在十进制系统中,精确表示 101000 只需要很小的空间,这应该不会让您感到惊讶,但是对于其他值的大幂次,这种简洁的表示法是不可能的,样3 1000 SUP> = 1322070819480806636890455259752144365965422032752148167664920368226828597346704899540778313850608061963909777696872582355950954582100618911865342725257953674027620225198320803878014774228964841274390400117588618041128947815623094438061566173054086674490506178125480344405547054397038895817465368254916136220830268563778582290228416398307887896918556404084898937609373242171846359938695516765018940588109060426089671438864102814350385648747165832010614366132173102768902855220001。

【讨论】:

    【解决方案3】:

    double 通常有 11 位的 exp(-1022~1023 标准化),52 位的事实和 1 位的符号。因此,它根本不会太大。 更多解释见IEEE 754 on Wikipedia

    【讨论】:

    • @ltsik 标准化浮点数保存为 1.xxxx * 2 ^ yyyyy。其中 xxx 称为事实部分,yyyy 称为 exp 部分。这并不是大多数情况下的数字(当数字将以二进制表示无限重复时,就像十进制的 1/3。或者它不会无限重复但根本不适合 xxxx 的分配位)。跨度>
    • @Itsik:换句话说,浮点数是计算机进行科学记数法的方式。 2^1000 不需要 1000 位来表示它。 double 通过存储底数 (2) 和指数 (1000) 来存储 2^1000。显然,存储一个 2 和一个 1000 所花费的时间远少于 1000 位。
    • @Itsik:但是,如果您希望能够表示 0 到 (2^1000)-1 之间的每个整数,则确实需要 1000 位。这与浮点类型相反; double 可以表示的值范围不连续。例如,您不能将1/3 完全存储在double 中。
    • @user938183 3^1000 超过 1.111111111(52 个二进制数)*2^1023
    • @user939183:可以用双精度表示的 3 的最大整数幂是 3646。大多数计算机用于双精度的 IEEE 754 格式只能表示大约 4.94066e-324 和 1.79769e+308 之间的值。就您的计算机而言,任何绝对值小于最小值的东西都是零,任何大于最大值的东西都是无穷大。
    猜你喜欢
    • 2021-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多