The Math::BigRat Trap

rat tail

With the latest stable release of perl, v5.24.0, you could easily get trapped into using a problematic combination of math modules. Here is how, and what you should do to avoid trouble.

The Scenario

Perl has been supporting arbitrary precision integer, floating point, and rational number math with core modules for a long time. Math::BigInt and Math::BigFloat have been in the core since perl 5. Math::BigRat was first released with perl v5.8.0 in 2002. Currently these modules undergo heavy refactoring and also partial redesign, as can be seen in the changes files of the Math-BigInt and Math-BigRat distributions. Now here is the catch.

Math-BigInt-1.999718 of April 22, 2016, introduced changes to a couple of functions that were not particularly well documented before, but used by Math::BigRat, among others. Consequently, Math-BigRat-0.260803, also of April 22, 2016, was fixed to no longer depend on the old behaviour. These releases did not make it into the perl v5.24.0 release that came three weeks later, though.

The Path of Deception

Now as most of us know, these math modules can be made quite a bit faster by installing interfaces to heavy-duty math engines such as GMP or Pari. Modules providing the glue to these backends, such as Math::BigInt::GMP, are not in the perl core. You'll install them from CPAN. Not surprisingly they also have seen releases addressing the latest semantic changes.

The Tragedy

So you have perl v5.24.0 and want fast big rats rational arithmetic. A brand new Math-BigInt-GMP from CPAN will pull you a brand new Math-BigInt from CPAN, too, as the GMP glue depends on a later Math::BigInt version than you have. Your old version of Math::BigRat, however, will not be touched. And it will give you wrong results. Rational arithmetic simply will no longer work correctly on your platform.

The Escape Route

To fix this, you need to upgrade Math::BigRat from CPAN as well. Manually. This will not happen automatically as a consequence of your installing Math-BigInt-GMP.

The Morale

As a user, when you install something, your installer will likely take care of dependencies, but you in turn should look out for reverse dependencies. can help you there somewhat. A tool running all the test suites of your installed modules after every change would be nicer, but I haven't come by one yet. If you upgrade everything you have once in a while you will at least run some tests, and you will eventually escape from situations like the big rat trap, while occasionally some prematurely released stuff may bite you.

As a module maintainer, if you don't like a particular functionality, you could make your users' lives easier by adding and advertising new methods rather than just replacing existing ones. If you feel really strong about getting rid of something you can stage a deprecation cycle. Research, discuss, announce, make the change configurable, allow some time to pass, swap defaults, wait some more, remove if you must.

I admit I didn't always act like that myself. If my modules had been in the core for more than two decades, I probably would.


Could this not simply be fixed by making Math::BigInt::GMP depend on the newer version of Math::BigRat?

That would make the problem go away. But it would do so by foisting Math::BigRat on everyone who installs Math::BigInt::GMP, whether they need BigRat or not.

I haven't seen this blog post before now. As the maintainer of these modules, it would have been nice to know about the issues you mention.

The distributions are a maintenance nightmare. I assume the original author did the best he could, but the quasi object oriented design is fundamentally broken. The problems caused by the broken design were "fixed" by creating shortcuts which made the modules into a mess of spaghetti code.

In addition, it has been difficult to understand how the modules are supposed to behave. In many cases, the documentation (POD) says one thing, the comments in the code says something else, and the actual behaviour matches neither of them.

The distributions Math-BigInt (which includes Math::BigInt and Math::BigFloat), Math-BigRat (which include Math::BigRat), and bignum (which includes bigint, bignum, and bigrat) are so tightly coupled together that I think the only solution is to put them together in one distribution so that all of them are updated together.

Leave a comment

About martin

user-pic Blogging about Mathematics, Programming Languages, Open-Source, Privacy, Security, Board Games, Bicycles, Classical Music, and more.