🔬60. Examining the Real role of Perl 6, part 3

As promised yesterday, let us take a look at the two methods of the Real role: polymod and base.


I already devoted a post to the Int.polymod method, but the method also exists in the Real role. Let us see if it is different.

method polymod(Real:D: +@mods) {
    my $more = self;
    my $lazy = @mods.is-lazy;
    fail X::OutOfRange.new(
        :what('invocant to polymod'), :got($more), :range<0..Inf>
    ) if $more < 0; 
    gather { 
        for @mods -> $mod {
            last if $lazy and not $more;
                using => 'polymod', numerator => $more
            ) unless $mod;
            take my $rem = $more % $mod;
            $more -= $rem;
            $more /= $mod;
        take $more if ($lazy and $more) or not $lazy;

It looks familiar. Comparing to the method of Int, the separation of lazy and non-lazy lists is incorporated in the main loop. In the rest, it is again the mod operation (in the form of %) and a division (and some additional subtraction).

Try the method on the same 120 (but as a Numeric value):

> say 120.polymod(10,10)
(0 2 1)

> say 120e0.polymod(10,10)
(0 2 1)

The first method is a call of Int.polymod, while the second one is Real.polymod. The results are the same.

A final note on the method. Just notice that it also works with non-integer values:

> 120.34.polymod(3.3, 4.4)
(1.54 0.8 8)

Indeed, 1.54 + 0.8 * 3.3 + 8 * 3.3 * 4.4 = 120.34.


The base method converts a number to its representation in a different system, e. g., hexadecimal, octal, or in a system with 5 or 35 digits. Extrapolating hexadecimal system, you may guess that if there are 36 digits, then the digits are 0 to 9 and A to Z.

A few examples with the numbers with a floating point (actually, Rat numbers here):

> 120.34.base(10)
> 120.34.base(36)
> 120.34.base(3)
> 120.34.base(5)

The fractional part is converted separately. The second argument of the method limits the number of digits in it. Compare:

> 120.34.base(5)
> 120.34.base(5, 2)

I will skip the details of the method internals and will only show the most interesting parts.

The signature of the method in the src/core/Real.pm file is the following:

 method base(Int:D $base, $digits? is copy)

The documentation interprets that quite differently (although correct semantically):

method base(Real:D: Int:D $base where 2..36, $digits? --> Str:D)

The possible digits are listed explicitly (not in ranges):

my @conversion := <0 1 2 3 4 5 6 7 8 9
                   A B C D E F G H I J
                   K L M N O P Q R S T
                   U V W X Y Z>;

Finally, the last gathering of the separate digits into a resulting string is done like that, using a call to the Int.base method:

my Str $r = $int_part.base($base);
$r ~= '.' ~ @conversion[@frac_digits].join if @frac_digits;
# if $int_part is 0, $int_part.base doesn't see the sign of self
$int_part == 0 && self < 0 ?? '-' ~ $r !! $r;

The method also does some heuristics to determine the number of digits after the floating point:

my $prec = $digits // 1e8.log($base.Num).Int;
. . .
for ^$prec {
    last unless $digits // $frac;
    $frac = $frac * $base;
    push @frac_digits, $frac.Int;
    $frac = $frac - $frac.Int;

Compare now the method with the same method from the Int class:

multi method base(Int:D: Int:D $base) {
    2 <= $base <= 36
        ?? nqp::p6box_s(nqp::base_I(self,nqp::unbox_i($base)))
        !! Failure.new(X::OutOfRange.new(
            what => "base argument to base", :got($base), :range<2..36>))

In this case, all the hard work is delegated to the base_I function of NQP.

And that’s more or less all that I wanted to cover from the Real role internals.

One thought on “🔬60. Examining the Real role of Perl 6, part 3”

Leave a Reply


WordPress.com Logo


Google photo


Twitter picture


Facebook photo


Connecting to %s