by Arne Sommer

Add the Table (or not) with Raku

 Published 28. November 2021.

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

You are given two decimal-coded binary numbers, \$a and \$b.

Write a script to simulate the addition of the given binary numbers.

Example 1:
Input: \$a = 11; \$b = 1;
Output: 100
Example 2:
Input: \$a = 101; \$b = 1;
Output: 110
Example 3:
Input: \$a = 100; \$b = 11;
Output: 111

#! /usr/bin/env raku

subset DCB of Int where \$_ ~~ /^1<>*\$/;     # 

unit sub MAIN (DCB \$a, DCB \$b, :v(:\$verbose));  # [1a]

my \$length = max(\$a.chars, \$b.chars);           # [5a]

say ": Max lenght: \$length" if \$verbose;

my @a = \$a.comb.reverse;                        # 
my @b = \$b.comb.reverse;                        # 

my \$carry = 0;                                  # 

my @result;                                     # 

for ^\$length -> \$index                          # 
{
my \$aa  = @a.shift // 0;                      # 
my \$bb  = @b.shift // 0;                      # 
my \$sum = \$carry + \$aa + \$bb;                 # 

say ": a:\$aa b:\$bb c:\$carry -> \$sum";

if    \$sum == 3 { \$sum = 1; \$carry = 1; }     # 
elsif \$sum == 2 { \$sum = 0; \$carry = 1; }     # 
elsif \$sum == 1 {           \$carry = 0; }     # 
elsif \$sum == 0 {           \$carry = 0; }     # 

@result.push: \$sum;                           # 
}

@result.push: \$carry if \$carry;                 # 

say @result.join.flip;                          # 

 Set up a custom type (with subset) for the input (allowing «0» and «1» only). Note that the first digit must be «1», thus disallowing leading zeroes. (And also disallowing «0» as a value. Oh well.)

 Reverse the values, as arrays, as we want to work from the right hand side (because of carrying).

 Carrying.

 The result goes here, digit by digit.

 Iterate over the longest number (as computed in [5a]).

 Get the next digit, for both numbers. If none use a zero (to compensate for a situation where they do not have the same lnegth.)

 Add them all togeter, incluing the carry(over from the previous digit calculation).

 3 x «1» gives «11» (i.e. a «1» and a carry).

 2 x «1» gives «10» (i.e. a «0» and a carry).

 A single «1» gives «1» (and no carry).

 «0» gives «0» (and no carry)..

 Add the digit to the list.

 Do we have a leftover carry? If so, add it.

 We reversed the numbers initially (in ), so now we have to de-reverisfy the result.

Running it:

100

110

111

Challenge #140.2: Multiplication Table

You are given 3 positive integers, \$i, \$j and \$k.

Write a script to print the \$kth element in the sorted multiplication table of \$i and \$j.

Example 1:
Input: \$i = 2; \$j = 3; \$k = 4
Output: 3

Since the multiplication of 2 x 3 is as below:

1 2 3
2 4 6

The sorted multiplication table:

1 2 2 3 4 6

Now the 4th element in the table is "3".
Example 2:
Input: \$i = 3; \$j = 3; \$k = 6
Output: 4

Since the multiplication of 3 x 3 is as below:

1 2 3
2 4 6
3 6 9

The sorted multiplication table:

1 2 2 3 3 4 6 6 9

Now the 6th element in the table is "4".
File: multab
#! /usr/bin/env raku

subset PosInt of Int where \$_ > 0;                               # 

unit sub MAIN (PosInt \$i, PosInt \$j, PosInt \$k, :v(:\$verbose));  # [1a]

my @result;                                                      # 

for 1 .. \$i -> \$ii                                               # 
{
for 1 .. \$j -> \$jj                                             # 
{
@result.push: \$ii * \$jj;                                     # 
}
}

my @sorted = @result.sort;                                       # 

say ": Sorted: @sorted[]" if \$verbose;

say @sorted[\$k -1] // "";                                        # 

 Set up a custom type ensuring positive integers, and apply it on the arguments (1a).

 We are only interested in the result, not the matrix, so store everything in a simple array.

 Iterate over the two dimensions.

 • Add the product to the array.

 Sort the array.

 Print the required element. Note the -1 to compensate for arrays starting at index 0. The challenge does not say how to handle an out of bounds situation (i.e. \$k > \$i * \$j), so we print an empty string in that case.

Running it:

\$ ./multab 2 3 4
3

\$ ./multab 3 3 6
: Sorted: 1 2 2 3 3 4 6 6 9
4

Looking good.

With verbose mode:

\$ ./multab -v 2 3 4
: Sorted: 1 2 2 3 4 6
3

\$ ./multab -v 3 3 6
: Sorted: 1 2 2 3 3 4 6 6 9
4

The error situation handled by  abvove can be done in [1a] instead:

File: multitab2
#! /usr/bin/env raku

subset PosInt of Int where \$_ > 0;

unit sub MAIN (PosInt \$i, PosInt \$j, PosInt \$k where 1 <= \$k <= \$i * \$j, # 
:v(:\$verbose));

my @result;

for 1 .. \$i -> \$ii
{
for 1 .. \$j -> \$jj
{
@result.push: \$ii * \$jj;
}
}

my @sorted = @result.sort;

say ": Sorted: @sorted[]" if \$verbose;

say @sorted[\$k -1];                                                      # 

 Note the where clause, that can be used like this and not only in combination with subset as above.

 The // error handling has gone now.

Running the programs with an out of bounds \$k value:

\$ ./multab 3 3 10

\$ ./multab2 3 3 10
Usage:
./multab2 [-v|--verbose[=Any]] <i> <j> <k>

And that's it.