Raku string vs integer practices

Hey there, there’s another task #066-1 offered by the Perl Weekly Challenge (why still not mentioning Raku in the name?).

Integer-divide the two given integers, $m and $n, without using multiplication, or division, or modulo.

Hey there, there’s another task #066-1 offered by the Perl Weekly Challenge (why still not mentioning Raku in the name?).

Integer-divide the two given integers, $m and $n, without using multiplication, or division, or modulo.

So, for 5 / 2 you get 2, -2 for -5 / 2, and 2 for -5 / -2. Actually, from the task definition, the floor of -5 / 2 would be -3, while the expected result is -2:

$ raku -e'say (-5/2).floor'
-3

But let’s stick to the provided examples (which makes the solution simpler but not always correct :-). The goal is to demonstrate string-vs-integer transformations.

1

Obviously, division is subtraction repeated the required number of times, so one can subtract until the initial number vanishes and count the number of loops. So, here’s the straightforward solution:

my $m = 5;
my $n = 2;

my $r = 0;
while $m >= $n {
    $m -= $n;
    $r++;
}

say $r;

It works but does not look elegant enough. The implicit operations with the counter should be done somehow indirectly.

2

What if using the sequence operator? Provide it with a pattern, and it should deduce the sequence itself. As we expect that the division gives some reminder (as in the 5 / 2 example), you cannot rely on the sequence operator to stop by itself, so we need to explain what is the condition to continue rolling:

say ($m, $m - $n ... * < $n) - 1;

Here, the ... operator gets the two first elements of the sequence $m and $m - $n. Thus, it continues to subtract $n while the current number (*) is less than $n (which means while it is big enough to be subtracted).

3

What about the sign? As we are not allowed to use proper math operations, let us use the power (here, power means strength and not **) of Raku to easily convert between numbers and string representation of an object.

print '-' if +($m ~ $n ~~ m:g/'-'/) == 1;

Woohoo, what’s going on here? First, we concatenate the numbers as strings, so -5 and 2 are transformed to -52, -5 and -2 to -5-2, and 5 and 2 to 52. Ah, yes, 5 and -2 become 5-2. Half of these cases give negative result, the rest is positive. As we do not need to print a plus, we are only interested in the cases when the number of '-' characters is odd, and that odd number can only be 1.

Match the concatenated string against the regex m:g/'-'/, and you get either 「-」 or (「-」 「-」) or (). Print the minus sign when you have only one element after regex matching.

Of course, minuses should not be considered in our sequence, so the whole program looks like this:

my $m = 5;
my $n = -2;

print '-' if +($m ~ $n ~~ m:g/'-'/) == 1;
say ($m.abs, $m.abs - $n.abs ... * < $n.abs) - 1;

Or even remove the signs in one go:

print '-' if +($m ~ $n ~~ m:g/'-'/) == 1;
($m, $n)>>.=abs;
say ($m, $m - $n ... * < $n) - 1;

4

Not enough strings? Let us use them more intensively. Convert the numbers to the strings containing as many characters as the value of the number is.

$m = 'N' x $m;
$n = 'N' x $n;

Again, a global regex match counts the number of sequences of new $n that can be placed inside the new $m.

say +($m ~~ m:g/$n/);

The reader should be trained enough to compete the solution to allow both positive and negative inputs:

my $m = -9;
my $n = -2;

$m = 'N' x $m.abs;
$n = 'N' x $n.abs;

print '-' if +($m ~ $n ~~ m:g/'-'/) == 1;
say +($m ~~ m:g/$n/);

The source code is available on GitHub.

Navigation to the Raku challenges post series

One thought on “Raku string vs integer practices”

Leave a Reply

Your email address will not be published. Required fields are marked *