8 字节如何容纳 302 个十进制数字?(欧拉挑战16)

How can 8 bytes hold 302 decimal digits? (Euler challenge 16)

本文关键字:挑战 十进制数字 字节 何容纳      更新时间:2023-10-16

c++ pow(2,1000) 对于双精度来说是正常的,但它正在工作。 为什么?

所以我已经学习了几个星期C++,但数据类型仍然让我感到困惑。

首先是一件小事:0xbadc0de另一个线程中发布的代码对我不起作用。首先pow(2,1000)给了我this more than once instance of overloaded function "pow" matches the argument list.

我通过更改pow(2,1000)修复了它 -> pow(2.0,1000)看起来很好,我运行它并得到这个:

https://i.stack.imgur.com/bbRat.png

而不是

10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376

它缺少很多值,可能是什么原因造成的?

但现在才是真正的问题。我想知道 302 位长的数字如何适合双精度(8 字节)?0xFFFFFFFFFFFFFFFF = 18446744073709551616那么这个数字怎么会比这大呢?

我认为这与浮点数编码的东西有关。另外,如果不0xFFFFFFFFFFFFFFFF,可以存储在 8 个字节中的最大数字是多少?

八个字节包含 64 位信息,因此您可以使用这些位存储2^64 ~ 10^20唯一项目。这些项目可以很容易地解释为从 02^64 - 1 的整数。因此,您不能在 302 个字节中存储 8 个十进制数字;010^303 - 1之间的大多数数字都不能这样表示。

浮点数可以保存302个十进制数字的近似值;这是因为它们分别存储尾数和指数。此表示中的数字存储一定数量的有效数字(如果我没记错的话,双精度为 15-16)和一个指数(可以进入数百个内存服务)。但是,如果十进制的长度为 X 字节,那么它只能区分2^(8X)不同的值......不太可能精确地表示具有 302 个十进制数字的整数。

要表示这些数字,您必须使用更多位:实际上大约 1000 或 125 字节。

它被称为"浮点"是有原因的。数据类型包含一个标准意义上的数字,以及一个表示小数点所属位置的指数。这就是为什么pow(2.0, 1000)有效,这就是为什么你会看到很多零。浮点数(或双精度数,只是一个较大的浮点数)包含固定数量的精度。所有剩余的数字最终为零。尝试pow(2.0, -1000),您将反过来看到相同的情况。

浮点数(32 位)中的十进制精度位数约为 7,双精度(64 位)约为 16 位十进制数字。

现在大多数系统都使用IEEE浮点数,我只是链接到一个非常好的描述。此外,关于特定标准IEEE 754-1985的文章详细描述了各种大小浮点数的位布局。

> 2.0 ^ 1000 在数学上将有一个十进制(非浮点)输出。 IEEE 浮点数,在您的情况下,双精度数(因为 pow 函数接收双精度并输出双精度)具有分配给尾数的 64 位表示中的 52 位。 如果你算一下,2^52 = 4,503,599,627,370,496。 因为浮点数可以表示正数和负数,所以整数表示实际上将是 ~ 2^51 = 2,251,799,813,685,248。 请注意,有 16 位数字。 您看到的输出中有 16 个质量(非零)数字。

本质上,pow 函数将执行幂运算,但是一旦幂超过 ~2^51,它将开始失去精度。 最终,它将保持前 ~16 个十进制数字的精度,但所有其他数字的权利将无法保证。

因此,这是一个浮点精度/舍入问题。

如果您严格处于无符号整数土地中,则数字将在 (2^64 - 1) = 18,446,744,073,709,551,616 之后溢出。 溢出的意思是,您永远不会真正看到该数字高于所提供的数字,事实上我相信此操作的答案将是 0。 一旦答案超过 2^64,结果寄存器将为零,任何乘法后词将为 0 * 2,这将始终导致 0。 我必须尝试一下。

确切的答案(如您所显示的)可以使用使用多精度库的标准计算机获得。 它们的作用是通过连接多个较小的数据类型来模拟较大的位计算机,并使用算法进行动态转换和打印。 Mathematica 是实现任意精度数学计算库的数学引擎的一个例子。

点类型可以覆盖比相同大小的整数类型大得多的范围,但精度较低。

它们表示一个数字,如下所示:

  • 符号s表示正或负;
  • m,一个介于 1 和 2 之间的值,给出一定数量的精度;
  • 指示数字比例的指数e

该值本身计算为 m * pow(2,e) ,如果设置了符号位,则取其反。

标准double有一个 53 位尾数,可提供大约 16 位十进制数字的精度。

因此,如果您需要表示精度超过 (例如) 64 位的整数,则 64 位整数和 64 位浮点类型都不起作用。您将需要一个大整数类型,其中包含尽可能多的位来表示您正在使用的值,或者(取决于您正在解决的问题)一些其他表示形式,例如质因数分解。标准C++中没有这样的类型,因此您需要自己制作。

如果要计算某些字节可以容纳的数字范围,则应为(2^(64位 - 1位))到(2^(64位 - 1位) - 1)。

因为变量最左边的数字用于表示符号(+和-)。所以数字负边的范围应该是:(2^(64位 - 1位))数字正边的范围应该是:(2^(64位 - 1位) - 1)由于 0,正范围为 -1(以避免每边计数 0 的声誉)。

例如,如果我们计算 64 位,则范围应该是 ==>大约 [-9.223372e+18] 到 [9.223372e+18]