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

## polymod

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; Failure.new(X::Numeric::DivideByZero.new: 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.

## base

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 > 120.34.base(36) 3C.C8N1FU > 120.34.base(3) 11110.100012 > 120.34.base(5) 440.132223

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

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

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”