by Arne Sommer

# Dividing Powers with Raku

[79] 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); # [1] my \$count = 0; # [2] my \$negate = \$M.sign != \$N.sign; # [3] my \$M-abs = \$M.abs; # [4] my \$N-abs = \$N.abs; # [4] while \$M-abs >= \$N-abs # [5] { \$M-abs -= \$N-abs; # [6] \$count++; # [7] say "M: \$M-abs N: \$N-abs = \$count (negate \$negate)" if \$verbose; } if \$negate # [8] { \$count = -\$count; # [9] \$count-- if \$M-abs; # [10] } say \$count; # [2] ``` We have to take care of two things; the sign and any remainder (but only if the sign is negative).

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

[2] The result.

[3] 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`).

[4] 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 [3].

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

[6] • subtract the divisor.

[7] • increase the count, which is the end result.

[8] Should the answer be negative?

[9] • negate it.

[10] • 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[0] 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) # [1] [2] { say 0; } multi sub MAIN (Int \$N where \$N > 1, :\$one) # [3] [2] { my \$match = 0; # [4] for 2 .. \$N.sqrt -> \$base # [5] { for 2 .. Inf -> \$exp # [6] { my \$candidate = \$base ** \$exp; # [7] last if \$candidate > \$N; # [8] (say "\$base^\$exp"; \$match++; exit if \$one) if \$candidate == \$N; # [9] } } say 0 unless \$match; # [10] } ```

[1] 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

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

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

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

[5] 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.

[6] The exponent, as an infinite loop.

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

[9] 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.

[10] 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[0] 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.