Perl Weekly Challenge 105: Nth Root and The Name Game
These are some answers to the Week 105 of the Perl Weekly Challenge organized by Mohammad S. Anwar.
Spoiler Alert: This weekly challenge deadline is due in a couple of days (March 28, 2021). This blog post offers some solutions to this challenge, please don’t read on if you intend to complete the challenge on your own.
Task 1: Nth Root
You are given positive numbers $N
and $k
.
Write a script to find out the $Nth
root of $k
. For more information, please take a look at the wiki page.
Example:
Input: $N = 5, $k = 248832
Output: 12
Input: $N = 5, $k = 34
Output: 2.02
The $n
th root of the number $k
can usually be expressed as the number $k
raised to the 1/N
th power: $k ** (1/$n)
, with $n > 0
.
Nth Root in Raku
We just implement the formula above and compute the first to the tenth root of the input value:
use v6;
my $input = @*ARGS[0] // 248832;
for 1..10 -> $i {
printf "%2i\t%10.3f\n", $i, $input ** (1/$i);
}
Running this script with no parameter yields the results for the defgault value:
$ raku root.raku
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
And providing another integer as a command-line parameter displays the following output:
$ raku root.raku 400
1 400.000
2 20.000
3 7.368
4 4.472
5 3.314
6 2.714
7 2.354
8 2.115
9 1.946
10 1.821
Nth Root in Perl
This a direct port to Perl of the above Raku program:
use strict;
use warnings;
use feature "say";
my $input = $ARGV[0] // 248832;
for my $i (1..10) {
printf "%2i\t%10.3f\n", $i, $input ** (1/$i);
}
Output with the default value:
$ perl root.pl
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
Output with a command-line parameter:
$ perl root.pl 400
1 400.000
2 20.000
3 7.368
4 4.472
5 3.314
6 2.714
7 2.354
8 2.115
9 1.946
10 1.821
Nth Root in Scala
Again, a simple port to Scala:
object root extends App {
val in: Int = if (args.size == 1) args(0).toInt else 248832
for (i <- 1 to 10) {
val root = scala.math.pow(in, (1 / i.toDouble))
println(f"$i%2d $root%10.3f")
}
}
Note the in Scala, a division between two integers yields the Euclidean division (or integer division) so that 1 / i
would return 0 for all integer values from 2 to 10. That is why the program converts i
to a double
before performing the division. Replacing 1 by 1.0 would also do the trick.
Output:
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
Nth Root in Python
Port of the same program to Python:
#!/usr/bin/python
import sys
input = int(sys.argv[1]) if len(sys.argv) > 1 else 248832
for i in range(1, 11):
root = input ** (1/i)
print('{:2d}'.format(i), " ", root)
Output with default value::
$ python3 root.py
1 248832.0
2 498.8306325798367
3 62.89779346101351
4 22.33451661845039
5 12.000000000000002
6 7.930812913000375
7 5.899887726224536
8 4.725940818339814
9 3.976904267210367
10 3.464101615137755
Please note that my real output is single-spaced. I have no idea why my mark-down file produces double-space rendering here and in two more entries below.
Output with a command-line parameter:
$ python3 root.py 400
1 400.0
2 20.0
3 7.368062997280773
4 4.47213595499958
5 3.3144540173399872
6 2.7144176165949063
7 2.353546893650252
8 2.114742526881128
9 1.9458877175763887
10 1.8205642030260802
Note that I haven’t tried to format the roots: either Python is bad at formatting numbers, or I did not understand its formatting system. Note that I’ll not try very hard to pretty-print the results in the coming guest languages.
Nth Root in Other Languages
Some languages don’t have the **
exponentiation operator. In some cases, the exponenciation operator may be ^
. In others, you might have to use a built-in or an imported pow
function. Or possibly to use logarithms (like in bc). Or yet some other construct. Also, in a number of the languages examples below, I did not try to get argument from the command-lin, but preferred to hard code the input value. In some cases, I did not try to pretty-print the results.
In the C Programming Language
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define DEFAULT_IN 248832
int main(int argc, char *argv[]) {
printf("%s\n", argv[1]);
int in = argc == 2 ? atoi( argv[1]) : DEFAULT_IN;
for (int i = 1; i <= 10; i++) {
printf("%2i %10.3f \n", i, pow (in, 1.0/i));
};
return 0;
}
Output:
$ a.out
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
$ a.out 10000
1 10000.000
2 100.000
3 21.544
4 10.000
5 6.310
6 4.642
7 3.728
8 3.162
9 2.783
10 2.512
In the D Programming Language
After C, comes D (just as C came after B, which itself came after BCPL). More seriously, D was designed as a successor to C (although D is object oriented and might better qualified as a successor to C++),same ideas and simular syntax, but supposedly more robust.
import std.stdio;
import std.math;
void main() {
auto input = 248832;
for (int i = 1; i <= 8; i++) {
double root = pow(input, 1.0/i);
writeln(i, " ", root);
}
}
Output:
1 248832
2 498.831
3 62.8978
4 22.3345
5 12
6 7.93081
7 5.89989
8 4.72594
In Awk
# run e.g. as: $ awk -v input=120 -f root.awk
BEGIN {
for (i = 1; i <= 10; i++) {
printf "%2i ¨%10.3f\n", i, input ** (1/i);
}
}
Output:
$ awk -v input=248832 -f root.awk
1 ¨248832.000
2 ¨ 498.831
3 ¨ 62.898
4 ¨ 22.335
5 ¨ 12.000
6 ¨ 7.931
7 ¨ 5.900
8 ¨ 4.726
9 ¨ 3.977
10 ¨ 3.464
We don’t really need to store the awk script in a file and can use an awk one-liner:
$ awk -v input=248832 ' BEGIN { for (i = 1; i <= 6; i++) {
print i, "\t", input ** (1/i); } } '
1 248832
2 498.831
3 62.8978
4 22.3345
5 12
6 7.93081
In Bc
The Unix/Linux bc utility is aimed at performing simple numeric calculations, so it should presumably be ideal for our numeric tasK. However, its name stands for “basic calculator,” and it is so basic that it doesn’t have an exponentiation operator for non-integer exponents. We can work around that issue, though. Using the -l
command line option enables a math library that provides the l
natural logarithm and e
exponential functions. The nth root of k
can be computed as the exponential of the logarithm of k
divided by n
, which is written e(l(k)/n)
in the bc syntax. We can run our program as a one-liner:
$ echo 'a = 248832; for(i=1;i<=5;i++) { print i; print " "; print e(l(a)/i); print "\n"}' | bc -l
1 248831.99999999999999787313
2 498.83063257983666053377
3 62.89779346101351857080
4 22.33451661845039037442
5 11.99999999999999999988
Of course, using logarithm and exponential reduces somewhat the accuracy.
In Gembase
Gembase is a little known proprietary language for database access. You may find some information about it on my blog post of last week. It should be quite easy to understand this code once you know that variable names start with a “sigil”: #
.
PROCEDURE_FORM ROOT (#in)
if (#in = "")
#input = 248832
else
#input = #in
end_if
#i = 1
while(#i <= 10)
#root = #input ^ (1.0/#i)
error /text_only (mask("!-@@", #i) & mask("!-@@@@@@@@@@0.@@@", #root))
#i = #i + 1
end_while
END_FORM
Output:
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
In Ruby
$input = 248832
for i in 1 .. 8 do
root = $input ** (1.0/i)
puts "#{i} #{root}"
end
print "\n"
Output:
1 248832.0
2 498.8306325798367
3 62.89779346101351
4 22.33451661845039
5 12.000000000000002
6 7.930812913000375
7 5.899887726224536
8 4.725940818339814
In Dart
import 'dart:math';
void main() {
var input = 248832;
for (int i = 1; i <= 8; i++) {
var root = pow(input, (1/i));
print("$i $root");
}
}
Output:
1 248832
2 498.8306325798367
3 62.89779346101351
4 22.33451661845039
5 12.000000000000002
6 7.930812913000375
7 5.899887726224536
8 4.725940818339814
In Visual Basic
Module VBModule
Sub Main()
for i as Integer = 1 to 5
Console.WriteLine(248832 ^ (1/i))
next
End Sub
End Module
Output:
248832
498.830632579837
62.8977934610135
22.3345166184504
12
In Kotlin
fun main() {
val input = 248832;
for (i in 1..10) {
val root = "%12.3f".format(Math.pow(input * 1.0, 1.0/i))
val formatted_i = "%2d".format(i)
println("$formatted_i $root")
}
}
Output:
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
In Lua
input = 248832
for i = 1, 10 do
print (string.format("%2d %10.3f", i, input ^ (1/i)))
end
Output:
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
In Go
package main
import (
"fmt"
"math"
)
func main() {
const input = 248832
for i := 1; i <= 10; i++ {
fmt.Printf("%2d\t%10.3f\n", i, math.Pow(input, 1.0/float64(i)))
}
}
Output:
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
In Java
class Main {
public static void main(String args[]) {
double input = Double.parseDouble(args[0]);
for (int i = 1; i <= 10; i++) {
double root = Math.pow(input, 1.0 / i );
System.out.format("%2d %10.3f\n", i, root);
}
}
}
Output:
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
In Nim
Nim uses Python-like code indentation.
import math
var input = 248832.0
for i in 1..8:
var root = pow(input, 1.0 / float(i))
echo i, " ", root
Output:
1 248832.0
2 498.8306325798367
3 62.89779346101351
4 22.33451661845039
5 12.0
6 7.930812913000375
7 5.899887726224536
8 4.725940818339814
In Julia
input = 248832
for i = 1:10
@printf("%2d %10.3f\n", i, input ^ (1/i) )
end
Output:
$ julia root.jl
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
In Rust
fn main() {
let input = 248832f64;
for i in 1..11 {
let root = input.powf(1.0/i as f64);
println!("{:2} {:10.3}", i, root);
}
}
Output:
1 248832.000
2 498.831
3 62.898
4 22.335
5 12.000
6 7.931
7 5.900
8 4.726
9 3.977
10 3.464
Task 2: The Name Game
You are given a $name
.
Write a script to display the lyrics to the Shirley Ellis song The Name Game. Please checkout the wiki page for more information.
Example:
Input: $name = "Katie"
Output:
Katie, Katie, bo-batie,
Bonana-fanna fo-fatie
Fee fi mo-matie
Katie!
The Name Game is apparently very well known in the United States, but I haven’t lived there and the rules are not entirely clear to me, so I’ll base my programs on my best understanding of those rules.
The Name Game in Raku
We’ll use a here-doc for producing the lyrics of the song, with variable interpolation. So, the only difficulty is to populate these variables with the right values in accordance with rules laid out in the Wikipedia page referred to above.
use v6;
my $name = prompt "Please enter the name: ";
my $vowels = Set.new(<a e i o u>);
my $consonants = Set.new('a'..'z') (-) $vowels;
my ($start, $suffix) = ($0, $1) if $name ~~ /(\w)(\w+)/;
my @y;
if $start.lc (elem) $consonants {
@y[0] = $start eq 'B' ?? "bo-$suffix" !! "bo-b$suffix";
@y[1] = $start eq 'F' ?? "fo-$suffix" !! "fo-f$suffix";
@y[2] = $start eq 'M' ?? "mo-$suffix" !! "mo-m$suffix";
} else {
@y = "bo-$suffix", "fo-$suffix", "mo-$suffix";
}
say qq:to/END/;
$name, $name, @y[0]
Bonana-fanna @y[1]
Fee fi @y[2])
$name!
END
Examples of output:
$ ./raku name-game.raku
Please enter the name: Katie
Katie, Katie, bo-batie
Bonana-fanna fo-fatie
Fee fi mo-matie)
Katie!
$ ./raku name-game.raku
Please enter the name: Billy
Billy, Billy, bo-illy
Bonana-fanna fo-filly
Fee fi mo-milly)
Billy!
$ ./raku name-game.raku
Please enter the name: Anna
Anna, Anna, bo-nna
Bonana-fanna fo-nna
Fee fi mo-nna)
Anna!
The Name Game in Perl
This a port to Perl of the Raku program above:
use strict;
use warnings;
use feature "say";
say "Please enter the name: ";
my $name = <STDIN>;
chomp $name;
my %vowels = map { $_ => 1} qw<a e i o u>;
my ($start, $suffix) = ($1, $2) if $name =~ /(\w)(\w+)/;
my @y;
if (exists $vowels{lc $start}) {
@y = ("bo-$suffix", "fo-$suffix", "mo-$suffix");
} else {
$y[0] = $start eq 'B' ? "bo-$suffix" : "bo-b$suffix";
$y[1] = $start eq 'F' ? "fo-$suffix" : "fo-f$suffix";
$y[2] = $start eq 'M' ? "mo-$suffix" : "mo-m$suffix";
}
say "\n", <<~EOF;
$name, $name, $y[0]
Bonana-fanna $y[1]
Fee fi $y[2])
$name!
EOF
Examples of output:
$ perl name-game.pl
Please enter the name:
Katie
Katie, Katie, bo-batie
Bonana-fanna fo-fatie
Fee fi mo-matie)
Katie!
$ perl name-game.pl
Please enter the name:
Anna
Anna, Anna, bo-nna
Bonana-fanna fo-nna
Fee fi mo-nna)
Anna!
$ perl name-game.pl
Please enter the name:
Billy
Billy, Billy, bo-illy
Bonana-fanna fo-filly
Fee fi mo-milly)
Billy!
The Name Game in Scala
object nameGame extends App {
val in: String = if (args.size == 1) args(0) else "Katie"
val start = in.substring(0, 1)
val suffix = in.substring(1)
val vowels = Map("A" -> 1, "E" -> 1, "I" -> 1, "O" -> 1, "U" -> 1)
val bosuffix = if (start == 'B' || vowels.contains(start))
s"bo-$suffix" else s"bo-b$suffix"
val fosuffix = if (start == 'F' || vowels.contains(start))
s"fo-$suffix" else s"fo-f$suffix"
val mosuffix = if (start == 'M' || vowels.contains(start))
s"mo-$suffix" else s"mo-m$suffix"
println(s"$in, $in, $bosuffix")
println(s"Bonana-fanna $fosuffix")
println(s"Fee fi $mosuffix")
println(s"$in!")
}
Example output:
Katie, Katie, bo-batie
Bonana-fanna fo-fatie
Fee fi mo-matie
Katie!
The Name Game in Python
import sys
input = sys.argv[1] if len(sys.argv) > 1 else "Katie"
start = input[0]
suffix = input[1:]
vowels = { "A", "E", "I", "O", "U"}
bosuffix = f'bo-{suffix}' if (start == 'B' or start in vowels) else f'bo-b{suffix}'
fosuffix = f'fo-{suffix}' if (start == 'F' or start in vowels) else f'fo-f{suffix}'
mosuffix = f'mo-{suffix}' if (start == 'M' or start in vowels) else f'mo-m{suffix}'
print(f'{input}, {input}, {bosuffix}')
print(f'Bonana-fanna {fosuffix}')
print(f'Fee fi {mosuffix}')
print(f'{input}!')
Output:
$ python3 name-game.py
Katie, Katie, bo-batie
Bonana-fanna fo-fatie
Fee fi mo-matie
Katie!
Wrapping up
The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on Sunday, April 4, 2021. And, please, also spread the word about the Perl Weekly Challenge if you can.
Leave a comment