Perl Weekly Challenge 173.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 173.
Task 1: Esthetic Number
Submitted by: Mohammad S Anwar
You are given a positive integer, $n.
Write a script to find out if the given number is Esthetic
Number.
An esthetic number is a positive integer where every adjacent
digit differs from its neighbour by 1.
For example,
5456 is an esthetic number as |5 - 4| = |4 - 5| = |5 - 6| = 1
120 is not an esthetic numner as |1 - 2| != |2 - 0| != 1
I use List::Util
to check that all
pairs of adjacent
digits differ by ±1. This yields a simple oneliner.
perl -MList::Util=all -E 'foreach(@ARGV){($f,@a)=split ""; say "$_ ",
((all{($f,$t)=($_,abs($_-$f)==1); $t}(@a))? "is":"is not"), " an esthetic number"}
' 5456 120
Results:
5456 is an esthetic number
120 is not an esthetic number
This code fails when given some strings that are not quite numbers, as
perl -MList::Util=all -E 'foreach(@ARGV){($f,@a)=split ""; say "$_ ",
((all{($f,$t)=($_,abs($_-$f)==1); $t}(@a))? "is":"is not"), " an esthetic number"}
' a1b1
since, according to Perl, “a”-1==-1, 1-“b”==1, etc. Thus, in the full code I have to be more careful.
The full code is:
1 # Perl weekly challenge 173
2 # Task 1: Esthetic number
3 #
4 # See https://wlmb.github.io/2022/07/11/PWC173/#task-1-esthetic-number
5 use v5.36;
6 use List::Util qw(all);
7 say("Usage: ./ch-1.pl N1 [N2...]\nto check if N1, N2... are esthetic numbers"), exit
8 unless @ARGV;
9 foreach(@ARGV){
10 s/^\s*\+\s*//; # remove leading +, if present
11 say("Error: $_ is not a positive number"), next unless $_=~/^\d+$/;
12 my ($current,@rest)=split "";
13 my $test;
14 say "$_ ", (
15 (all {($current,$test)=($_, abs($_-$current)==1); $test}(@rest))
16 ? "is"
17 : "is not"
18 ), " an esthetic number";
19 }
Examples:
./ch-1.pl 5456 120
Results:
5456 is an esthetic number
120 is not an esthetic number
Other examples:
./ch-1.pl -123 +123 +125 +a1b1
Results:
Error: -123 is not a positive number
123 is an esthetic number
125 is not an esthetic number
Error: a1b1 is not a positive number
Task 2: Sylvester’s sequence
Submitted by: Mohammad S Anwar
Write a script to generate first 10 members of Sylvester's
sequence. For more informations, please refer to the wikipedia
page.
Output
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443
The n+1-th term Sn+1 in Sylvester’s sequence is the product of all the previous S1…Sn terms plus one. As Sn=S1×S2×…Sn-1+1 and Sn+1=S1×S2×…Sn-1×…Sn+1, we may write $Sn+1=Sn×(Sn-1)+1, so it is enough to keep the last result. This leads to a very simple one-liner:
perl -Mbigint -E '$s=2; say $s; say $s=$s*($s-1)+1 foreach(1..(shift)-1);' 10
Results:
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443
I had to use bigint, as the Sylverster numbers diverge double-exponentially. The full code is almost identical:
1 # Perl weekly challenge 173
2 # Task 2: Sylverster's sequence
3 #
4 # See https://wlmb.github.io/2022/07/11/PWC173/#task-2-sylvesters-sequence
5 use v5.36;
6 use bigint;
7 say("Usage: ./ch-2.pl N\nto print the first N numbers of Sylvester's sequence"), exit
8 unless @ARGV;
9 my $N=shift;
10 die "$N should be positive" unless $N>0;
11 my $s=2;
12 say "The first $N Sylvester's numbers are\n$s";
13 say $s=$s*($s-1)+1 foreach(1..$N-1);
Example:
./ch-2.pl 10
Results:
The first 10 Sylvester's numbers are
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443
A nice property of Sylvester’s sequence is that it yields the series of the type 1/n1+1/n2+1/n3… with ni integers, that converges the fastest towards 1, without actually arriving, starting from 1/2. Indeed, if you want to add something to 1/2 to arrive at 1, you would choose 1/2. But if instead you want to get as close as possible without arriving, you would add the smallest possible number to the denominator, 1, and then add 1/3. If now you want to add something to 1/2+1/3=5/6 to arrive at 1 you would choose 1/6, so if you want to get as close as possible without arriving you would add instead 1/7. As 1/2+1/3+1/7=(21+14+6)/42=41/42, the next number to add would be 1/43. It turns out that 1-(1/S1+1/S2+1/S3…+1/Sn)=1/(Sn+1-1) so it goes to zero double-exponentially. The first residues are
0.5
0.166666666667
0.0238095238095
5.53709856035e-4
3.06424934165e-7
9.38962115057e-14
8.81649853514e-27