Произвольная точность арифметики с Ruby - PullRequest
5 голосов
/ 19 мая 2010

Как, черт возьми, это делает Руби? Знает ли Йорг или кто-то еще, что происходит за кулисами?

К сожалению, я не очень хорошо знаю C, поэтому bignum.c мало мне поможет. Мне было просто любопытно, что кто-то может объяснить (простым английским языком) теорию, лежащую в основе любого чудодейственного алгоритма, который он использует.

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

3680634882592232678947008400605218658383382320373532046559596214370256093004722315301038736145051752186913452575898963911303931894479697716458323821923660765366311320017761759779321786587036607784657658118308278769820141240229486719756781317249580644279499028104989732710307877167814674195241800407343989969529308325089341169459661201767351208231519597795368522900903774525022369908394534167906404561164711397515467500486021892910286409705747626001859502261382445301874892116158640211353120779120188446307803074622052528077377576720943206923731010325174595184975240151201651667241898167663972478241753948020282281600271006239988736674357990730546189068554604883514266113106340234890442918605103523019124266084888074623121265902068304137826645542604112663788666266537557636277965690829317856456008162368911681417749932674881717021721910727310692168816682946256794926961489769998687156714408742064272120567173730996397111689011974404165902265241927828428964154146116881873912320483277389658202659 3409310817205487518824659176087713165789563358657661185727701178249794352294501124843043920129701511946873071236400763937391081195343030947683245323012399675023571078708664107031028872538959513893678471527415042649541619666983267998025343680786418716005458904566402715881795854937449051239905544881914848704936367461166460989003008854959199246636005004256627034833091179548764704594930128661465865007129969565224526608067298992179934250929163533082787426478958730697447232771870430635244592599615561915378391323721271601041029499987756974528735342290344338756274645252286042041668901973291379807377328153357091020520776715712817418487335705083075277790004194325673849906782148842105387086902273869881605981057922100256088299988476325216174756689383517855896114234930446650640237355631870717571086698303531312206832110245782411201496938722547625934287286636355038384072001083290669536055355664754529584996627998083056124296001365452951499511358490905081301519892828320218919461550140343555306014771313 9766323195743324848047347575473228198492343231496580885057330510949058490527738662697480293583612233134502078182014347192522391449087738579081585795613547198599661273567662441490401862839817822686573112998663038868314974259766039340894024308383451039874674061160538242392803580758232755749310843694194787991556647907091849600704712003371103926967137408125713631396699343733288014254084819379380555174777020843568689927348949484201042595271932630685747613835385434424807024615161848223715989797178155169951121052285149157137697718850449708843330475301440373094611119631361702936342263219382793996895988331701890693689862459020775599439506870005130750427949747071390095256759203426671803377068109744629909769176319526837824364926844730545524646494321826241925107158040561607706364484910978348669388142016838792902926158979355432483611517588605967745393958061959024834251565197963477521095821435651996730128376734574843289089682710350244222290017891280419782767803785277960834729869249991658417000499998 999

Ответы [ 5 ]

17 голосов
/ 19 мая 2010

Простой: он делает это так же, как вы , начиная с первого класса. За исключением того, что он не вычисляет в базе 10, он вычисляет в базе 4 миллиарда (и изменяется).

Подумайте об этом: с нашей системой счисления мы можем представлять только числа от 0 до 9. Итак, как мы можем вычислить 6+7 без переполнения? Легко: мы делаем фактически переполнены! Мы не можем представить результат 6+7 как число от 0 до 9, но мы можем переполниться на следующее место и представить его как два числа между 0 и 9: 3 раза; 10 0 + 1 раз; 10 1 . Если вы хотите добавить два числа, вы добавляете их по цифрам справа и переполняете («перенос») слева. Если вы хотите умножить два числа, вам нужно умножить каждую цифру одного числа индивидуально на другое число, а затем сложить промежуточные результаты.

Арифметика BigNum (именно так обычно называют этот вид арифметики, когда числа больше, чем собственные машинные числа) работает в основном так же. За исключением того, что база не 10, и не 2, & ndash; это размер целого числа нативной машины. Таким образом, на 32-битной машине это будет основание 2 32 или 4 & times; 294 & thinsp; 967 & thinsp; 296.

В частности, в Ruby Integer на самом деле является абстрактным классом, который никогда не бывает вдохновленным. Вместо этого у него есть два подкласса, Fixnum и Bignum, и числа автоматически перемещаются между ними, в зависимости от их размера. В MRI и YARV Fixnum может содержать 31 или 63-битное целое число со знаком (один бит используется для тегирования) в зависимости от собственного размера слова машины. В JRuby Fixnum может хранить целое 64-битное целое число со знаком, даже на 32-битной машине.

Самая простая операция - сложение двух чисел. И если вы посмотрите на реализацию +, а точнее bigadd_core в YARV's bignum.c , то это не слишком , чтобы следовать. Я тоже не могу читать C, но вы можете ясно увидеть, как он зацикливается на отдельных цифрах.

2 голосов
/ 19 мая 2010

Вы можете прочитать источник для bignum.c ...

На очень высоком уровне, не вдаваясь в какие-либо подробности реализации, bignum s рассчитываются "вручную", как вы это делали в начальной школе. Конечно, есть, конечно, много оптимизаций, которые можно применить, но в этом суть.

2 голосов
/ 19 мая 2010

Я не знаю деталей реализации, поэтому расскажу, как будет работать базовая реализация Big Number.

По сути, вместо того, чтобы полагаться на "целые числа" ЦП, он создаст свой собственный, используя несколько целых чисел ЦП. Чтобы сохранить произвольную точность, допустим, у вас есть 2 бита. Таким образом, текущее целое число равно 11. Вы хотите добавить одно. В нормальных целых числах ЦП это будет равно 00

Но, для большого числа, вместо переворачивания и сохранения «фиксированной» целочисленной ширины, он выделил бы другой бит и смоделировал сложение так, чтобы число стало правильным 100.

Попробуйте посмотреть, как двоичная математика может быть сделана на бумаге. Это очень просто и тривиально для преобразования в алгоритм.

1 голос
/ 21 января 2011

Beaconaut APICalc 2 , выпущенный 18 января 2011 года, который представляет собой целочисленный калькулятор произвольной точности для арифметики Бигнума, криптографического анализа и исследования теории чисел ......

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

0 голосов
/ 19 мая 2010

Используется класс Bignum

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

Rdoc доступен конечно

...