TL;DR

Here we are with TASK #1 from The Weekly Challenge #157. Enjoy!

# The challenge

You are given a set of integers.

Write a script to compute all three Pythagorean Means i.e Arithmetic Mean, Geometric Mean and Harmonic Mean of the given set of integers. Please refer to wikipedia page for more informations.

Example 1:

>Input: @n = (1,3,5,6,9)
>Output: AM = 4.8, GM = 3.9, HM = 2.8


Example 2:

>Input: @n = (2,4,6,8,10)
>Output: AM = 6.0, GM = 5.2, HM = 4.4


Example 3:

>Input: @n = (1,2,3,4,5)
>Output: AM = 3.0, GM = 2.6, HM = 2.2


# The questions

One initial question would be about the ranges of the input:

• how many numbers will we be getting?
• is there a maximum?
• is there a minimum?

Then a question about the expected result: should that be an integer as the inputs? (The examples seem to indicate that no, it should not be).

Last, why not… are they going to be sorted?

# The solution

This seems an excellent puzzle to prompt for studying numerical analysis. Alas, this would anyway prevent me from doing two things I love: being lazy and reinventing wheels.

Hence, I’ll be ignoring any consideration and just code the functions in the most straightforward way I can think of. Let’s start with Raku:

#!/usr/bin/env raku
use v6;
sub MAIN (*@args) {
my @inputs = @args ?? @args !! (1, 3, 5, 6, 9);
@inputs.say;
"AM = %.1f, GM = %.1f, HM = %.1f\n".printf(
arithmetic-mean(@inputs),
geometric-mean(@inputs),
harmonic-mean(@inputs)
);
}

sub arithmetic-mean (@n) { @n.sum / @n.elems }
sub geometric-mean  (@n) { ([*] @n).abs ** (1 / @n.elems) }
sub harmonic-mean   (@n) { 1 / arithmetic-mean(@n.map: 1 / *) }


I love how the hyperoperation [*] addresses the product nicely for the geometric-mean function. The harmonic mean is the reciprocal of the arithmetic mean of the reciprocals… and it’s coded like that!

The translation into Perl is amazingly matching, thanks to List::Util which is in CORE and just a use away:

#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';
use List::Util qw< sum product >;

my @inputs = @ARGV ? @ARGV : (1, 3, 5, 6, 9);
printf "AM = %.1f, GM = %.1f, HM = %.1f\n",
arithmetic_mean(@inputs),
geometric_mean(@inputs),
harmonic_mean(@inputs);

sub arithmetic_mean (@n) { sum(@n) / @n }
sub geometric_mean  (@n) { abs(product(@n)) ** (1 / @n) }
sub harmonic_mean   (@n) { 1 / arithmetic_mean(map { 1 / $_ } @n) }  I was lucky to look in the docs for product and actually find it there! Otherwise, I would probably have coded the geometric_mean in terms of reduce (in List::Util): ... use List::Util 'reduce'; sub gmalt (@n) { (reduce {$a * \$b} @n) ** (1 / @n) }


I think the version with product is more readable though, so I’ll stick with it.

Stay safe!