用Ruby进行任意精度算术运算

5

究竟 Ruby 是如何做到这一点的?Jörg 或其他人知道背后发生了什么吗?

不幸的是,我不太懂 C 语言,所以 bignum.c 对我帮助不大。我只是有点好奇,是否有人能用通俗易懂的语言解释一下它使用了什么神奇的算法。

irb(main):001:0> 999**999

这是一个非常大的数字,它有309位数字。在计算机科学中,这种数字通常被称为“巨大整数”或“高精度整数”。它们通常用于需要处理非常大的数字的应用程序,例如密码学和大数据处理。

5个回答

18
简单来说,它的计算方式与你从小学开始学的一样,只不过它不是在十进制下进行运算,而是在40亿多进制下进行计算。想想看,我们的数字系统只能表示0到9这些数字,那么如果不溢出,怎样计算6+7呢?很容易,我们确实会溢出!我们无法将6+7的结果表示为0到9之间的数字,但我们可以溢出到下一个位置,并将其表示为两个0到9之间的数字:3×10^0 + 1×10^1。如果想要相加两个数字,可以从右向左逐位相加并向左溢出(“进位”)。如果想要相乘两个数字,则必须将一个数字的每个位数分别与另一个数字相乘,然后将中间结果相加。大数算术(通常称为比本机数字更大的数字)基本上也是这样工作的。除了基数不是10,也不是2,它是本机整数的大小。因此,在32位机器上,它将是2的32次方或4,294,967,296。

具体而言,在Ruby中,Integer 实际上是一个从未被实例化的抽象类。相反,它有两个子类 FixnumBignum,并且数字根据其大小自动在它们之间转换。在MRI和YARV中,Fixnum 可以容纳31或63位带符号整数(有一个位用于标记),具体取决于机器的本地字长。在JRuby中,即使在32位机器上,Fixnum 也可以容纳完整的64位带符号整数。

最简单的操作是两个数字相加。如果查看在 YARV 的 bignum.c 中的 + 或者说 bigadd_core 的实现,它也不太难懂。我也无法阅读 C 语言,但你可以清楚地看到它如何循环遍历每个单独的数字。


你有一种很好的解释事情的方式。谢谢你的帮助 :) - maček

2
您可以阅读bignum.c源代码......
在不涉及任何具体实现细节的情况下,从非常高的角度来看,bignum是像您在小学时做的那样“手动计算”的。当然,有很多优化可以应用,但这就是要点。

很不幸,我并不是很擅长C语言。我只是有点好奇,是否有人能用简单易懂的英语解释一下它所使用的神奇算法背后的理论。 - maček
@macek:那个“奇迹算法”其实就是你在一年级学过的那个。好吧,还有各种疯狂的优化方法,但本质上是一样的。想想看:可以计算23*45,即使我们的数字系统只从09,只需要使用多个数字。在计算机上也可以做到同样的事情,只不过使用的数字系统从04294967296 - Jörg W Mittag

2
我不了解具体的实现细节,因此我将介绍一个基本的大数实现方式。基本上,它不依赖于CPU“整数”,而是使用多个CPU整数创建自己的“整数”。为了存储任意精度,假设您有2位。那么当前的整数是11,您想要加1。在普通的CPU整数中,这将回滚到00。但是,对于大数,它不会回滚并保持“固定”的整数宽度,而是分配另一个位并模拟加法,使数字变为正确的100。尝试查找如何在纸上进行二进制数学运算。这很简单,并且可以轻松转换为算法。

1

0

它使用了Bignum类

irb(main):001:0> (999**999).class
=> Bignum

Rdoc 当然是可用的


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