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/);
One thought on “Raku string vs integer practices”