by Arne Sommer

# Dividing Powers with Raku

 Published 27. June 2020.

This is my response to the Perl Weekly Challenge #066.

## Challenge #066.1: Divide Integers

You are given two integers `\$M` and `\$N`.

Write a script to divide the given two integers i.e. `\$M / \$N` without using multiplication, division and mod operator and return the floor of the result of the division.

Example 1
```Input: \$M = 5, \$N = 2 Output: 2 ``` Example 2
```Input: \$M = -5, \$N = 2 Output: -3 ``` Example 3
```Input: \$M = -5, \$N = -2 Output: 2 ```

Division is just subtraction in a loop. Off we go. Off we go. Off we go...:

File: divint ```#! /usr/bin/env raku unit sub MAIN (Int \$M, Int \$N where \$N != 0, :\$verbose); #  my \$count = 0; #  my \$negate = \$M.sign != \$N.sign; #  my \$M-abs = \$M.abs; #  my \$N-abs = \$N.abs; #  while \$M-abs >= \$N-abs #  { \$M-abs -= \$N-abs; #  \$count++; #  say "M: \$M-abs N: \$N-abs = \$count (negate \$negate)" if \$verbose; } if \$negate #  { \$count = -\$count; #  \$count-- if \$M-abs; #  } say \$count; #  ``` We have to take care of two things; the sign and any remainder (but only if the sign is negative).

 Divison by zero is a bad thing, so we prevent that possibility for `\$N`.

 The result.

 The result is a negative integer if one and only one of `\$M` and `\$M` is neagtive, else it is positive. We use `sign` to get the sign (`-1`, `0` or `1`).

 Are we counting down to - or up to - zero? That depends on the sign. But we can count down if we ensure that both values are positive. That is done with `abs`, that removes any negative sign. The sign of the result has been taken care of in .

 As long as the remainder is larger or equal to the divisor,

 • subtract the divisor.

 • increase the count, which is the end result.

 Should the answer be negative?

 • negate it.

 • subtract 1 (the «floor» part of the challenge description) if we have a remainder.

See docs.raku.org/routine/sign for more information about the `sign` method.

See docs.raku.org/routine/abs for more information about the `abs` method.

Running it:

```\$ raku divint 5 2 2 \$ raku divint -5 2 -3 \$ raku divint -5 -2 2 \$ raku divint 5 -2 -3 ```

With verbose mode (which would benefit from a rethink, me think...):

```\$ raku divint --verbose 5 2 : Negate the result: No : M: 3 N: 2 = 1 : M: 1 N: 2 = 2 2 \$ raku divint --verbose 25 2 : Negate the result: No :M: 23 N: 2 = 1 :M: 21 N: 2 = 2 :M: 19 N: 2 = 3 :M: 17 N: 2 = 4 :M: 15 N: 2 = 5 :M: 13 N: 2 = 6 :M: 11 N: 2 = 7 :M: 9 N: 2 = 8 :M: 7 N: 2 = 9 :M: 5 N: 2 = 10 :M: 3 N: 2 = 11 :M: 1 N: 2 = 12 12 ```

### A Perl Version

Just for fun...

Perl does not have a «sign» function, so I wrote one. I chose to do command line handling manually. Other than that, the code is pretty much the same as the raku version. Except longer...

File: divint-perl ```#! /usr/bin/env perl use feature 'say'; use feature 'signatures'; no warnings qw(experimental::signatures); my \$verbose = 0; if (@ARGV && \$ARGV eq "--verbose") { \$verbose++; shift @ARGV; } my \$M = shift(@ARGV) || die 'Specify \$M and \$N'; my \$N = shift(@ARGV) || die 'Specify \$N'; die '\$M is not an integer' unless int(\$M) == \$M; die '\$N is not an integer' unless int(\$N) == \$N; die "Unable to divide by zero" if \$N == 0; sub sign (\$value) { return 1 if \$value > 0; return 0 if \$value == 0; return -1 if \$value < 0; } my \$count = 0; my \$negate = sign(\$M) != sign(\$N); my \$M_abs = abs(\$M); my \$N_abs = abs(\$N); say ": Negate the result: ", \$negate ? 'Yes' : 'No' if \$verbose; while (\$M_abs >= \$N_abs) { \$M_abs -= \$N_abs; \$count++; say "M: \$M_abs N: \$N_abs = \$count" if \$verbose; } if (\$negate) { \$count = -\$count; \$count-- if \$M_abs; } say \$count; ```

## Challenge #066.2: Power Integers

You are given an integer `\$N`. Write a script to check if the given number can be expressed as mn where m and n are positive integers. Otherwise print 0.

Please make sure `m > 1` and `n > 1`.

BONUS: If there are more than one way to express the given number then print all possible solutions.

Example 1
For given `\$N = 9`, it should print 32 or `3^2`.

Example 2
For given `\$N = 45`, it should print `0`.

Example 3
For given` \$N = 64`, it should print all or one of `8^2` or `2^6` or `4^3`.

File: powint ```#! /usr/bin/env raku multi sub MAIN (Int \$N where \$N.is-prime, :\$one) #   { say 0; } multi sub MAIN (Int \$N where \$N > 1, :\$one) #   { my \$match = 0; #  for 2 .. \$N.sqrt -> \$base #  { for 2 .. Inf -> \$exp #  { my \$candidate = \$base ** \$exp; #  last if \$candidate > \$N; #  (say "\$base^\$exp"; \$match++; exit if \$one) if \$candidate == \$N; #  } } say 0 unless \$match; #  } ```

 Prime numbers cannot be factoralized, so we can check for that (with `is-prime`) up front. This speeds up the program in case of prime numbers, but isn' strictly necessary

 Use the «--one» command line option if you only want one result.

 The `where` clause ensures that the value is as requested by the challenge.

 Do we have a match (or more), so that we can give the «0» error message in .

 Iterate over the base number, from 2 to the square root of the original number. This will stop our loop when we have reached the largest number (for `\$base`) that we can fit (in `\$N`) by squaring it.

 The exponent, as an infinite loop.

 If the possible answer is higher than the initial value, we can abort the inner (infinite) loop.

 We have a match, print it, count it, and exit if we only wanted one result. Note the funny use of parens (the grouping operator) to stack more than one expressions into a postfix `if`. Brackets are also allowed, instead of the parens.

 No match?, say so.

See docs.raku.org/routine/is-prime for more information about `is-prime`.

See docs.raku.org/routine/** for more information about the exponentiation operator `**`.

Running it:

```\$ raku powint 9 3^2 \$ raku powint 45 0 \$ raku powint 64 2^6 4^3 8^2 \$ raku powint --one 64 2^6 ```

### A Perl Version

of this one as well...

File: powint-perl ```#! /usr/bin/env perl use feature 'say'; my \$one = 0; if (@ARGV && \$ARGV eq "--one") { \$one++; shift @ARGV; } my \$N = shift(@ARGV) || die 'Specify \$N'; die '\$N is not an integer' unless int(\$N) == \$N; die '\$N must be an integer larger than 1' unless \$N > 1; my \$match = 0; for my \$base (2 .. sqrt(\$N)) { my \$exp = 1; while (\$exp++) { my \$candidate = \$base ** \$exp; last if \$candidate > \$N; if (\$candidate == \$N) { say "\$base^\$exp"; \$match++; exit if \$one; } } } say 0 unless \$match; ```

And that's it.