使用Ruby进行任意精度算术

时间:2010-05-19 16:04:31

标签: ruby math bignum arbitrary-precision

Ruby如何做到这一点? Jörg或其他任何人都知道幕后发生了什么吗?

不幸的是我不太了解C,bignum.c对我没什么帮助。我有点好奇,有人可以用简单的英语解释它使用的任何奇迹算法背后的理论。

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

36806348825922326789470084006052186583833823203735320465595962143702560930047223153010387361450517521869134525758989639113039318944796977164583238219236607653663113200177617597793217865870366077846576581183082787698201412402294867197567813172495806442794990281049897327103078771678146741952418004073439899695293083250893411694596612017673512082315195977953685229009037745250223699083945341679064045611647113975154675004860218929102864097057476260018595022613824453018748921161586402113531207791201884463078030746220525280773775767209432069237310103251745951849752401512016516672418981676639724782417539480202822816002710062399887366743579907305461890685546048835142661131063402348904429186051035230191242660848880746231212659020683041378266455426041126637886662665375576​​36277965690829317856456008162368911681417749932674881717021721910727310692168816682946256794926961489769998687156714408742064272120567173730996397111689011974404165902265241927828428964154146116881873912320483277389658202659340 9310817205487518824659176087713165789563358657661185727701178249794352294501124843043920129701511946873071236400763937391081195343030947683245323012399675023571078708664107031028872538959513893678471527415042649541619666983267998025343680786418716005458904566402715881795854937449051239905544881914848704936367461166460989003008854959199246636005004256627034833091179548764704594930128661465865007129969565224526608067298992179934250929163533082787426478958730697447232771870430635244592599615561915378391323721271601041029499987756974528735342290344338756274645252286042041668901973291379807377328153357091020520776715712817418487335705083075277790004194325673849906782148842105387086902273869881605981057922100256088299988476325216174756689383517855896114234930446650640237355631870717571086698303531312206832110245782411201496938722547625934287286636355038384072001083290669536055355664754529584996627998083056124296001365452951499511358490905081301519892828320218919461550140343555306014771313976 6323195743324848047347575473228198492343231496580885057330510949058490527738662697480293583612233134502078182014347192522391449087738579081585795613547198599661273567662441490401862839817822686573112998663038868314974259766039340894024308383451039874674061160538242392803580758232755749310843694194787991556647907091849600704712003371103926967137408125713631396699343733288014254084819379380555174777020843568689927348949484201042595271932630685747613835385434424807024615161848223715989797178155169951121052285149157137697718850449708843330475301440373094611119631361702936342263219382793996895988331701890693689862459020775599439506870005130750427949747071390095256759203426671803377068109744629909769176319526837824364926844730545524646494321826241925107158040561607706364484910978348669388142016838792902926158979355432483611517588605967745393958061959024834251565197963477521095821435651996730128376734574843289089682710350244222290017891280419782767803785277960834729869249991658417000499998999

5 个答案:

答案 0 :(得分:17)

简单:从一年级开始,它就像那样做。除了它不在基数10中计算,它计算基数为40亿(并且变化)。

考虑一下:使​​用我们的号码系统,我们只能表示从09的数字。那么,我们如何计算6+7而不会溢出?容易:我们实际上溢出了!我们无法将6+7的结果表示为09之间的数字,但我们可以溢出到下一个位置并将其表示为 2 <{em>} 09之间的数字:3×10 0 + 1×10 1 。如果要添加两个数字,则从右侧以数字方式添加它们,并向左添加溢出(“进位”)。如果要将两个数相乘,则必须将一个数字的每个数字与另一个数字相乘,然后将中间结果相加。

BigNum算术(这就是通常调用数字大于本机数的算法)基本上以相同的方式工作。除了基数不是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,但是你可以清楚地看到它是如何循环的。

答案 1 :(得分:2)

您可以阅读bignum.c ...

的来源

在非常高的级别,没有进入任何实施细节,bignum是“像手工”一样计算的,就像你在小学时所做的那样。现在,肯定可以应用许多优化,但这就是它的要点。

答案 2 :(得分:2)

我不知道实现细节,所以我将介绍基本的Big Number实现如何工作。

基本上不依赖于CPU“整数”,它将使用多个CPU整数创建它自己。为了存储arbritrary精度,可以说你有2位。所以当前整数是11.你想要添加一个。在正常的CPU整数中,这将翻转到00

但是,对于大数字,它不是翻转并保持“固定”整数宽度,而是分配另一个位并模拟一个加法,以便数字变为正确的100。

尝试查看如何在纸上完成二进制数学运算。转换为算法非常简单并且很简单。

答案 3 :(得分:1)

Beaconaut APICalc 2 刚刚于2011年1月18日发布,这是一个用于bignum算术,密码分析和数论研究的任意精度整数计算器......

http://www.beaconaut.com/forums/default.aspx?g=posts&t=13

答案 4 :(得分:0)

它使用Bignum类

irb(main):001:0> (999**999).class
=> Bignum
当然可以

Rdoc