Perl 6 small stuff #4: Why Perl isn’t COBOL nor Python nor Java (or… having fun with Rats)

After a few years away from programming, I’m trying to get up to speed again by learning Perl 6. This series is meant to be sort of a progress report, showcasing not only what I’ve learnt but also all of my misunderstandings and errors.

When I checked my inbox this morning, I got the usual email from Medium recommending stories I should read. This one piqued *) my interest: Is COBOL holding you hostage with Math?

This is a fascinating read about how financial and governmental institutions, as well as airlines and countless others, are still using software written in Cobol. Marianne Bellotti, the author, explains why they’re still using it — and why Cobol in some cases still may be a better fit than for instance Java.

As the article explains, it all has to do with how floats are handled by default (i.e. binary representation of floats) versus fixed precision floats. You should read the original article to understand the finer points; but as of now it’s enough to know that due to the differences, the same calculation can yield as different results as

168.939167671  | 4.9990600687785413938424188

The former is using default floats in Python, the latter is the result when using the fixed point type Decimal from the decimal package. The latter is closer to correct than the former. And as you can see: The difference is not marginal, it’s huge; imagine what rounding errors such as these would cost the IRS or your local bank, had they been taken at face value.

Cobol’s support of fixed point floats is why these institutions are still relying on Cobol instead of newer technologies such as Java (which handles floats similarly to Python’s default).

And here is one of the real difference between Perl 6 and other languages. I saw Larry Wall say somewhere that with Perl 6 he wanted a language where Math works. And that the secret to that is the Rat (rational) data type. Rats represents numbers internally as fractions, so most of the precision related errors won’t show up here.

What’s even better: You don’t have to think about it.

Below is a Perl 6 implementation of the Python code. Compare the Perl 6 version with the Python code in Is COBOL holding you hostage with Math? (no really, now you should read it before reading further. Most of what follows will make less sense if you haven’t).

#!/usr/bin/env perl6
sub rec($y, $z) {
return 108 - ((815-1500/$z)/$y);
}
sub default-behavior(Int $N, $default) {
my @x = (4, 4.25);
for (2..$N+1) -> $i {
my $n = rec(@x[$i-1], @x[$i-2]);
$n = $n.Num if !$default;
@x.append($n);
}
return @x;
}
my @y = default-behavior(20, True);
my @n = default-behavior(20, False);
for @y.kv -> $i, $p {
my ($a, $b) = $p.Rat.nude;
say $i.fmt("%02d") ~ " | " ~ @y[$i].fmt("%3.10f") ~
" | "~ @n[$i].fmt("%3.10f") ~ " | $a/$b";
}

Consider the output below and compare it to the Python output. The output of the Perl 6 code is a little different: The first column is self explanatory, the second shows Perl6’s default behavior, the third shows the float representation — the errors of which I have to explicitly coerce — and the fourth shows the internal fraction representation of the number in column two.

00 | 4.0000000000 | 4.0000000000 | 4/1
01 | 4.2500000000 | 4.2500000000 | 17/4
02 | 4.4705882353 | 4.4705882353 | 76/17
03 | 4.6447368421 | 4.6447368421 | 353/76
04 | 4.7705382436 | 4.7705382436 | 1684/353
05 | 4.8557007126 | 4.8557007126 | 8177/1684
06 | 4.9108474991 | 4.9108474991 | 40156/8177
07 | 4.9455374041 | 4.9455374035 | 198593/40156
08 | 4.9669625818 | 4.9669625693 | 986404/198593
09 | 4.9800457014 | 4.9800454510 | 4912337/986404
10 | 4.9879794485 | 4.9879744208 | 24502636/4912337
11 | 4.9927702881 | 4.9926694965 | 122336033/24502636
12 | 4.9956558915 | 4.9936371620 | 611148724/122336033
13 | 4.9973912684 | 4.9569659720 | 3054149297/611148724
14 | 4.9984339439 | 4.1829179009 | 15265963516/3054149297
15 | 4.9990600720 | -14.4971549507 | 76315468673/15265963516
16 | 4.9994359371 | 139.4819461498 | 381534296644/76315468673
17 | 4.9996615241 | 101.4151436597 | 1907542343057/381534296644
18 | 4.9997969007 | 100.0697650170 | 9537324294796/1907542343057
19 | 4.9998781355 | 100.0034856744 | 47685459212513/9537324294796
20 | 4.9999268795 | 100.0001742733 | 238423809278164/47685459212513

This is a long text just to make a very simple point: The Math and rounding errors shown in Is COBOL holding you hostage with Math? is not a problem with Perl6, as the Rat data type makes sure that they won’t happen.

What’s even better: Doing the right thing is Perl6’s default. I actually have to explicitly ask for trouble — by converting the Rat to a Num, as shown here:

$n = $n.Num if !$default; 

In short, Perl6 gently holds your hand and just assumes that you want the correct behavior instead of forcing you to work around the wrong behavior.

Now — I don’t think financial institutions will drop Cobol for Perl6 just because of this. But at least other languages should be inspired by this, and perhaps implement similar stuff in future versions. Just as perlre eventually found its way into numerous other languages.

A side note: I have to say that I have had a hard time identifying a Perl6 killer feature — twenty years ago Perl5 had sophisticated regexp handling as its killer feature. But I have to say perhaps some of this can be? Statistics and ML/AI math is all the rage these days. What they depend on is correct math.

What’d happen if we’d expand correct math and implemented ML/AI as a first class citizen of Perl6, simplify it significantly compared to existing solutions – hide the nitty gritty – -nd make Perl6 the AI tool for beginners? Then we’re talking killer feature!

In the mean time: Have fun with Rats. They’re just like their rodent counterparts — they’re everywhere and are awesome when you get to understand them.

PS! I guess I’ve made lots of errors again, and even misunderstood a few things. Feel free to hit me with comments and corrections again. I love learning more – and unlearn my misconceptions.

*) Thanks to Dave Cross for pointing out that in english something piques my interest, not peaks. It’s fascinating how english is full of similar sounding words that’s spelled differently — and sometimes even surprisingly different.