I’ve been doing the Perl Weekly
Challenges. The
latest
involved integer differences and decimal expansion. (Note that this is
open until 4 April 2021.)
TASK #1 › Maximum Gap
You are given an array of integers @N
.
Write a script to display the maximum difference between two
successive elements once the array is sorted.
If the array contains only 1 element then display 0.
I can't see any short-cuts here: we have to subtract every pair of
numbers. (I mean, given a sorted list I suppose one might be able to
bracket it and skip some comparisons, but it would probably be more
work than just doing the calculation.)
A straightforward procedure, therefore: sort the input list, set
max-difference to zero, do each subtraction, set max-difference to it
if it's higher. Let's have that in Raku:
sub mg(**@aa) {
my @a=@aa.sort;
my $g=0;
for (0..@a.elems-2) -> $i {
my $d=abs(@a[$i]-@a[$i+1]);
if ($d>$g) {
$g=$d;
}
}
return $g;
}
and the other languages all look very much the same.
TASK #2 › Decimal String
You are given numerator and denominator i.e. $N
and $D
.
Write a script to convert the fraction into decimal string. If the
fractional part is recurring then put it in parenthesis.
Clearly the hard part here is working out whether you have a recurring
decimal. I had a look at prime-factoring the numbers (any remaining
factors that aren't 2 or 5 means an infinite expansion) but then came
across this convenient algorithm – so I
reimplemented that in Perl (with some tweaks, like using arrays rather
than strings where it made sense), then translated the Perl version in
the other languages. (It does assume the inputs are positive.)
Let's have that in Perl:
sub ds {
my $n=shift;
my $d=shift;
my $quotient=sprintf('%d.',$n/$d);
my $c=10*($n % $d);
while ($c > 0 && $c < $d) {
$c *= 10;
$quotient .= "0";
}
my @digits;
my %passed;
my $i=0;
while (1) {
if (exists $passed{$c}) {
my @cycle=@digits[$passed{$c}..$#digits];
my $result=$quotient . join('',@digits[0..$passed{$c}-1]);
if (scalar @cycle > 1 || $cycle[0] != 0) {
$result .= '('.join('',@cycle).')';
}
if (substr($result,-1,1) eq '.') {
substr($result,-1,1)='';
}
return $result;
}
my $q=int($c/$d);
my $r=$c % $d;
$passed{$c}=$i;
push @digits,$q;
$i++;
$c=10*$r;
}
}
The other versions look much the same, except for the tweaks needed to
shift around between digits and strings.
Full code on
github.