8个字节怎么能存放302个十进制数字?(欧拉项目16挑战)

4

c++ pow(2,1000) is normaly to big for double, but it's working. why?

我学习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)来修复它。 看起来很好,我运行它并得到了这个:

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

而不是

10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376

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

但现在是真正的问题。我想知道302位数字如何适合double(8字节)?0xFFFFFFFFFFFFFFFF = 18446744073709551616,那么这个数字怎么可能比这还大?

我认为这与浮点数编码有关。此外,如果不是0xFFFFFFFFFFFFFFFF,最大可以存储多大的数字?


1
有302个0位小数。问题解决了,那么数字怎么可能比这个更大呢? - Lightness Races in Orbit
1
一个字节通常是8位。因此一个字节是0xFF。因此8个字节为0xFFFFFFFFFFFFFFFF或最大值为:18446744073709600000(虽然看起来我的计算器四舍五入了)。如何在64位中获得302位数字是另一个问题(压缩)?一些技巧。 - Martin York
1
这是浮点类型和整数类型之间的区别。浮点数将存储指数尾数的有限表示以及指数。指数可以告诉打印函数在尾数的小数表示后添加多少个零。基本上,它将为您提供您正在给出的pow输入的舍入输出版本,这就是为什么您看到17个有效数字然后是一大堆0的原因。 - trumpetlicks
嗯...我想我明白了浮点数部分,但是长数字仍然具有301位精度,不仅仅是0,那么你如何将301位数字适配到52位的尾数中呢? - Ollie
我指向了这个线程:https://dev59.com/sWs05IYBdhLWcg3wPPWB。我无法像他那样使它运行。我的程序截断了,然后用0填充了剩下的部分。 - Ollie
显示剩余3条评论
5个回答

8
八个字节包含64位信息,因此您可以使用这些位存储2^64 ~ 10^20个唯一项。这些项目可以轻松地解释为从0到2^64-1的整数。因此,您不能在8个字节中存储302个十进制数字;大多数介于0和10^303-1之间的数字无法这样表示。
浮点数可以保存约有302个十进制数字的近似值;这是因为它们将尾数和指数分别存储。这种表示中的数字存储一定数量的有效数字(如果我记得正确,则为双精度的15-16位)和指数(如果内存服务,则可以达到数百)。然而,如果一个十进制数X字节长,那么它只能区分2^(8X)个不同的值...足以表示具有302个十进制数字的整数。
要表示这样的数字,您必须使用更多的位:实际上约为1000位或125个字节。

可能需要1001位来表示,因为最低有效位是2^0位。 - trumpetlicks

1
它被称为“浮点数”,有其原因。该数据类型包含标准意义下的数字和指数,指数表示小数点位置。这就是为什么pow(2.0, 1000)有效,并且为什么你会看到很多零。浮点数(或双精度浮点数,只是更大的浮点数)包含固定数量的精度数字。所有剩余的数字最终都变成零。尝试pow(2.0, -1000),你将看到相反的情况。
浮点数(32位)的十进制精度位数约为7,双精度浮点数(64位)约为16位十进制数字。
现在大多数系统使用IEEE浮点数,我刚刚链接了一个非常好的描述。此外,IEEE 754-1985特定标准的文章详细描述了各种大小的浮点数的位布局。

正是我想要写的。关于计算答案:您可以使用一些标准实现的十进制算术来计算大数,例如Java中的BigInteger。 - edofic

1
浮点类型可以覆盖比相同大小的整数类型更大的范围,但精度较低。它们表示一个数字为:
- 一个符号位 s 表示正或负; - 一个尾数 m,一个值介于 1 和 2 之间,给出一定数量的精度位; - 一个指数 e 表示数字的规模。
该值本身计算为 m * pow(2,e),如果设置了符号位,则取反。
标准 double 具有 53 位尾数,可提供约 16 个十进制数字的精度。

因此,如果您需要表示超过64位精度的整数,则64位整数或64位浮点类型都无法使用。您将需要一个大整数类型,具有足够多的位来表示您正在使用的值,或者(取决于您要解决的问题)其他表示形式,例如质因数分解。在标准C++中没有这样的类型,因此您需要自己创建。


1
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是一个实现任意精度数学计算库的数学引擎的例子。

1
如果您想计算一些字节可以容纳的数字范围,应该是 (2^(64位 - 1位)) 到 (2^(64位 - 1位) - 1)。
因为变量最左边的数字用于表示符号(+和-)。 所以负数的范围应该是:(2^(64位 - 1位)) 正数的范围应该是:(2^(64位 - 1位) - 1) 正数范围中有-1是因为0(避免在每侧计数0)。
例如,如果我们正在计算64位,则范围应该约为[-9.223372e+18]到[9.223372e+18]。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接