So, last spring I did a series of posts on making a Pi spigot. Unfortunately, the project foundered a bit, as it turned out that only Rakudo had the subsignatures needed to make the code pretty, but only Niecza had the big integers needed to make the code work.
Fast forward to today. Now both Rakudo and Niecza can handle the best version of the code with no problem!
Let me emphasize that again. A year ago, neither implementation had those two features. Eight months ago, each had one. Today both have both. What’s more, Rakudo seems to have made some pretty impressive speed improvements.
I think the awkward situation with Rakudo Star has helped obscure the fantastic good news in Perl 6. Right now we have two distinct Perl 6 implementations, each of which is markedly better than anything available a year ago. While there are still some rough edges, both implementations are making visible progress every single day.
Okay, enough cheerleading. Time to finish the Pi story. It turned out there was one last complication. I had never actually tried to use the code to generate an infinite stream of Pi. I always stopped at 40 digits. Confident that the algorithm must work, I tweaked the output to just continue generating digits until you stopped the program with control-C. And I ran it using Niecza, and it printed
3.14159265358979323846264338327950288419716 9399375105820974944592307816406286208998628 0348253421170679821480865
And then it just sat there, calculating. After a few minutes I stopped it and tried it in Rakudo, and got the exact same result.
Well, after adding a few debugging say
s here and there, I found the problem. The extr
sub was returning NaN
. It turns out that both compilers have issues with dividing huge numbers. Here’s the division operation that was causing the problem:
826855066209083067690330954944954674053 707782399091459328155002954168455127712 564546723209828068849110223672691692080 858850302237001093531862737473606364113 314687502675869281622802970765988449203 963736097729699655628829895255493809983 868753943269929165690008254816168624365 041070395716948346309925280258763697273 816643106559428329680316113883598846477 019844021876290510680558354153412094804 165563855909020631086890050609449881578 622437959410200560054513816596644762131 226627968813825552929967132893776980417 525678140579476414867767644626389410380 794467097761379794479928269796859019439 705966555011741254554959832606241504043 482378842096776403191455346497512084739 323724281071973237937801014210278895804 940475966938880398182275335278425442994 287812050560074302564177393567873480740 249095636709741437469651121924884638352 523975466249955052660310789169884060356 70777782797813415527343750 / 7640045443 915776552858245682965495041201868477244 923723289802372673948570989301189643881 881673616027696317656701576457227272117 067947294675092324411286583110995372015 785893970194452345100095389207557064515 618905243737091067059065039684867000766 465399984513882758095027633673968549038 659642193965599458094646356792444696562 299054844575814305259223023977803302735 242307789179027935107449661143998428584 590618630170775872761731454567203230484 311106708425828778192240791257477924515 937573923664112071637127786446287936043 637833776529791999568414593746973068229 015816020732598109749879566833692821582 816119454436978125677364775318707235283 939392855143663977524974469973442065855 128922452382372338686111634084367257050 255499210918328304009454606504169283500 652033488755998721320134300149134205253 095344802815192912405314659633341062491 389270940370884860337596933277382049709 5584869384765625
Turns out the bottom number is bigger than can be presented by a Num
, so the division operation ends up becoming N / Inf
, which is NaN
. This is a bit obscured in Rakudo because the division operation actually returns a Rat
(which should be illegal according to the spec!), but then .floor
is called on the result, which tries to convert to Num
before doing the floor operation.
This opens several questions, like: Should Perl 6’s Int / Int
operator be modified to try to cope with this sort of case?
But for the Pi problem, the good news is this: every time the extr
sub is called, its result is fed to .floor
. That means we simply needed to replace /
with div
and get rid of the .floor
s.
And with that, the code easily produces 2,000+ digits of Pi using either Rakudo or Niecza!
Leave a comment