【问题标题】:Arbitrary precision arithmetic with Ruby使用 Ruby 进行任意精度算术运算
【发布时间】:2011-02-21 11:26:17
【问题描述】:

Ruby 到底是如何做到这一点的? Jörg 或其他人是否知道幕后发生的事情?

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

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

3680634882592232678947008400605218658383382320373532046559596214370256093004722315301038736145051752186913452575898963911303931894479697716458323821923660765366311320017761759779321786587036607784657658118308278769820141240229486719756781317249580644279499028104989732710307877167814674195241800407343989969529308325089341169459661201767351208231519597795368522900903774525022369908394534167906404561164711397515467500486021892910286409705747626001859502261382445301874892116158640211353120779120188446307803074622052528077377576720943206923731010325174595184975240151201651667241898167663972478241753948020282281600271006239988736674357990730546189068554604883514266113106340234890442918605103523019124266084888074623121265902068304137826645542604112663788666266537557636277965690829317856456008162368911681417749932674881717021721910727310692168816682946256794926961489769998687156714408742064272120567173730996397111689011974404165902265241927828428964154146116881873912320483277389658202659340 9310817205487518824659176087713165789563358657661185727701178249794352294501124843043920129701511946873071236400763937391081195343030947683245323012399675023571078708664107031028872538959513893678471527415042649541619666983267998025343680786418716005458904566402715881795854937449051239905544881914848704936367461166460989003008854959199246636005004256627034833091179548764704594930128661465865007129969565224526608067298992179934250929163533082787426478958730697447232771870430635244592599615561915378391323721271601041029499987756974528735342290344338756274645252286042041668901973291379807377328153357091020520776715712817418487335705083075277790004194325673849906782148842105387086902273869881605981057922100256088299988476325216174756689383517855896114234930446650640237355631870717571086698303531312206832110245782411201496938722547625934287286636355038384072001083290669536055355664754529584996627998083056124296001365452951499511358490905081301519892828320218919461550140343555306014771313976 6323195743324848047347575473228198492343231496580885057330510949058490527738662697480293583612233134502078182014347192522391449087738579081585795613547198599661273567662441490401862839817822686573112998663038868314974259766039340894024308383451039874674061160538242392803580758232755749310843694194787991556647907091849600704712003371103926967137408125713631396699343733288014254084819379380555174777020843568689927348949484201042595271932630685747613835385434424807024615161848223715989797178155169951121052285149157137697718850449708843330475301440373094611119631361702936342263219382793996895988331701890693689862459020775599439506870005130750427949747071390095256759203426671803377068109744629909769176319526837824364926844730545524646494321826241925107158040561607706364484910978348669388142016838792902926158979355432483611517588605967745393958061959024834251565197963477521095821435651996730128376734574843289089682710350244222290017891280419782767803785277960834729869249991658417000499998999

【问题讨论】:

    标签: ruby math bignum arbitrary-precision


    【解决方案1】:

    简单:从一年级开始,它就和做的一样。除了它不以 10 为底进行计算外,它以 40 亿为底进行计算(并且会发生变化)。

    想一想:在我们的数字系统中,我们只能表示从09 的数字。那么,我们如何计算6+7 而不会溢出呢?简单:我们确实实际上溢出了!我们不能将6+7 的结果表示为09 之间的数字,但我们可以 溢出到下一个位置并将其表示为两个 之间的数字09:3×100 + 1×101。如果要添加两个数字,则从右侧按数字添加它们并溢出(“进位”)到左侧。如果你想将两个数字相乘,你必须将一个数字的每个数字分别与另一个数字相乘,然后将中间结果相加。

    BigNum 算术(这就是这种数字大于本机机器数的算术通常被称为)的工作方式基本相同。除了基数不是 10,也不是 2,它是本机机器整数的大小。因此,在 32 位机器上,它将是基数 232 或 4 294 967 296。

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

    最简单的操作是将两个数字相加。如果您查看 YARV 的 bignum.c 中的 + 或者更确切地说是 bigadd_core 的实现,那么跟随它并不是不好。我也看不懂 C,但你可以清楚地看到它是如何在单个数字上循环的。

    【讨论】:

    • 你解释事物的方式真是太好了。感谢您的所有帮助:)
    【解决方案2】:

    你可以阅读bignum.c的源代码...

    在非常高的级别上,无需任何实施细节,bignums 就像您在小学时所做的那样是“手动”计算的。现在,肯定有许多可以应用的优化,但这就是它的要点。

    【讨论】:

    • 不幸的是,我不太了解 C。我只是有点好奇,有人可以(用简单的英语)解释它使用的任何奇迹算法背后的理论。
    • @macek:那个“奇迹算法”和你在一年级学的一样。好吧,可以做各种疯狂的优化,但本质上是一样的。想一想:you 可以将 23*45 相乘,即使我们的数字系统仅通过使用 multiple 数字就可以从 0 变为 9。在计算机上也可以这样做,除了从04294967296 的数字系统。
    【解决方案3】:

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

    基本上,它不会依赖 CPU“整数”,而是使用多个 CPU 整数创建自己的。为了存储任意精度,假设您有 2 位。所以当前整数是 11。你想加一。在正常的 CPU 整数中,这将翻转到 00

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

    尝试查找如何在纸上完成二进制数学。它非常简单,转换为算法也很简单。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        它使用 Bignum 类

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

        Rdoc 当然可用

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-11-16
          • 2013-02-09
          • 2015-10-29
          • 1970-01-01
          相关资源
          最近更新 更多