Perl Weekly Challenge 085

(Originally published on samirparikh.com.)

The latest installment of the Perl Weekly Challenge just dropped so I thought I would take a crack at it. Please note that the challenge is still currently open (as of date of publishing) in case you are participating.

Task #1

Task #1 asks the following:

You are given an array of real numbers greater than zero.

Write a script to find if there exists a triplet (a,b,c) such that 1 < a+b+c < 2. Print 1 if you succeed otherwise 0.

Example 1:

Input: @R = (1.2, 0.4, 0.1, 2.5)

Output: 1 as 1 < 1.2 + 0.4 + 0.1 < 2

Example 2:

Input: @R = (0.2, 1.5, 0.9, 1.1)

Output: 0

Example 3:

Input: @R = (0.5, 1.1, 0.3, 0.7)

Output: 1 as 1 < 0.5 + 1.1 + 0.3 < 2

For the purposes of this task, I assumed that the array of real numbers would be provided in quotes as an argument to the script when you run it:

$ ./ch-1.pl "0.5, 1.1, 0.3, 0.7, 0.1, 0.3, 0.2"

Therefore, to get the numbers into my @data array, I used the split operator on $ARGV[0].

I'm afraid I may have been a bit lazy on this challenge and just used a brute-force approach to go through all of the three-number combinations (e.g. k=3) using the CPAN module Algorithm::Combinatorics. Also, instead of just returning one combination that meets the triplet requirement, I decided to return all possible combinations if there are more than one. Putting it all together, I came up with:

#!/usr/local/bin/perl

use warnings;
use strict;
use feature 'say';
use Algorithm::Combinatorics qw/combinations permutations/;
use List::Util qw/sum/;

# run program as:
# $ ./ch-1.pl "0.5, 1.1, 0.3, 0.7"
my @data = split /, /, $ARGV[0];
my $citer = combinations(\@data, 3);
my $notFound = 1;

while (my $c = $citer->next) {
    if (sum(@$c) > 1 && sum(@$c) < 2) {
        say "found triplet such that 1 < ", join( " + ", @$c), " < 2";
        $notFound = 0;
    }
}

say "no triplets found such that 1 < a+b+c < 2" if $notFound;

Task #2

Task #2 says:

You are given a positive integer $N.

Write a script to find if it can be expressed as a ^ b where a > 0 and b > 1. Print 1 if you succeed otherwise 0.

Example 1:

Input: 8

Output: 1 as 8 = 2 ^ 3

Example 2:

Input: 15

Output: 0

Example 3:

Input: 125

Output: 1 as 125 = 5 ^ 3

Again, I'm not really proud of this effort as I just came up with another brute-force solution. For each number, I find the nth root (represented by the variable $b) from 2 up to the number itself. I then round the result (stored in the variable $a) down using the floor function and raise it back up to the power of $b. If the result equals the number we were given, we have found a solution and then print the result to STDOUT. This works because only roots that result in an integer equal the result of taking their floor.

The resulting script can be written as:

#!/usr/local/bin/perl

use v5.10;
use POSIX;
use strict;
use warnings;

my ($a, $b,);
my $number = $ARGV[0];
my $notFound = 1;

for (my $b = 2; $b < $number; $b++) {
    $a = $number ** (1 / $b);
    if (floor($a) ** $b == $number) {
        say floor($a), " ^ ", $b, " = ", $number;
        $notFound = 0;
    }
}

say "0" if $notFound;

I'll be interested in what others come up with as these solutions are not efficient for large numbers or arrays but they were easy to come up with, code and test. If you are interested in participating, please remember that the entry deadline is 23:59 GMT Sunday 08 November 2020. Good luck!

3 Comments

Can't all non-negative integers be represented as a^b? If so, here's a Perl script to do task 2:

print "1\n";

Ohhh, it means "to the power of". ^ is usually bitwise xor in Perl.

Leave a comment

About Samir Parikh

user-pic Someone who knows very little about programming and even less about Perl.