# 🔬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.

## 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.