Perl Weekly Challenge 139.

My solutions (task 1, and task 2 ) to the The Weekly Challenge - 139.

Task 1: JortSort

Submitted by: Mohammad S Anwar
You are given a list of numbers.

Write a script to implement JortSort. It should return
true/false depending if the given list of numbers are already
sorted.

Example 1:
Input: @n = (1,2,3,4,5)
Output: 1

Since the array is sorted, it prints 1.
Example 2:
Input: @n = (1,3,2,4,5)
Output: 0

Since the array is NOT sorted, it prints 0.

I just have to move along the array comparing consecutive elements and quiting when I find a pair out of order. If I reach the end, the array is sorted. I can use none from List::Util to test pairs. I use variables $x, $y to keep the previous and current value.

perl -MList::Util=none -E 'say "Input: ", join " ",@ARGV; $y=shift @ARGV;
      say "Output: ", (none {($x,$y)=($y,$_); $x>$y}@ARGV)?1:0' 1 2 3 4 5
perl -MList::Util=none -E 'say "Input: ", join " ",@ARGV; $y=shift @ARGV;
      say "Output: ", (none {($x,$y)=($y,$_); $x>$y}@ARGV)?1:0' 1 3 2 4 5

Results:

Input: 1 2 3 4 5
Output: 1
Input: 1 3 2 4 5
Output: 0

I check the edge cases of only one element in the list or none.

perl -MList::Util=none -E 'say "Input: ", join " ",@ARGV; $y=shift @ARGV;
      say "Output: ", (none {($x,$y)=($y,$_); $x>$y}@ARGV)?1:0' 1
perl -MList::Util=none -E 'say "Input: ", join " ",@ARGV; $y=shift @ARGV;
      say "Output: ", (none {($x,$y)=($y,$_); $x>$y}@ARGV)?1:0'

Results:

Input: 1
Output: 1
Input:
Output: 1

I believe it is correct to consider these cases as sorted, as there is no pair of consecutive values out of order.

The full version would be almost identical.

# Perl weekly challenge 139
# Task 1: JortSort
#
# See https://wlmb.github.io/2021/11/16/PWC139/#task-1-jortsort
use v5.12;
use warnings;
use List::Util qw(none);
say "Input: (", (join " ",@ARGV), ")";
my $x; # previous element
my $y=shift @ARGV; # current element
say "Output: ", (none {($x,$y)=($y,$_); $x>$y}@ARGV)?1:0;

Examples:

./ch-1.pl 1 2 3 4 5
./ch-1.pl 1 3 2 4 5
./ch-1.pl 1
./ch-1.pl

Results:

Input: (1 2 3 4 5)
Output: 1
Input: (1 3 2 4 5)
Output: 0
Input: (1)
Output: 1
Input: ()
Output: 1

I read somewhere that the jortsort algorithm first sorts the list and then compares the two lists, but it seems that is more work than needed. Anyway, it is simple enough to merit a onliner.

perl -MList::Util=all -MList::MoreUtils=pairwise -E '
  @a=@ARGV; say "Input: ", join " ",@a; @s=sort {$a<=>$b}@a;
  say "Output: ", (all {$_} pairwise{$a==$b}@a, @s)?1:0' 1 2 3 4 5
perl -MList::Util=all -MList::MoreUtils=pairwise -E '
  @a=@ARGV; say "Input: ", join " ",@a; @s=sort {$a<=>$b}@a;
  say "Output: ", (all {$_} pairwise{$a==$b}@a, @s)?1:0' 1 3 2 4 5

Results:

Input: 1 2 3 4 5
Output: 1
Input: 1 3 2 4 5
Output: 0

Task 2: Long Primes

Submitted by: Mohammad S Anwar
Write a script to generate first 5 Long Primes.

A prime number (p) is called Long Prime if (1/p) has an
infinite decimal expansion repeating every (p-1) digits.

Example
7 is a long prime since 1/7 = 0.142857142857...
The repeating part (142857) size is 6 i.e. one less than the
prime number 7.

Also 17 is a long prime since 1/17 =
0.05882352941176470588235294117647...
The repeating part (0588235294117647) size is 16 i.e. one less
than the prime number 17.

Another example, 2 is not a long prime as 1/2 = 0.5.
There is no repeating part in this case.

The succesive digits of 1/p may be obtained using long division, i.e., we start dividing 10/p using integer arithmetic to get a residue r1, then we divide 10r1/p to obtain the residue r2, which is also the residue of 100/p, 10r2/p to obtain r3, the residue of 1000/p, and so on. If some residue becomes 0, we terminate. If some residue repeats itself after n divisions, then we have an infinite repeating cycle of length n. As the residues cannot exceed p, their possible values are 0,1,…p-1. If p is a long prime, then the sequence of residues has to take all values 1,2,…p-1 once before repeating, though not generally in order. Thus, to check if the prime p is a long prime, it would be enough to check that 10p-1 has a residue 1 when divided by p and that there are no shorter cycles, i.e., that 10q for 0<q<p-1 doesn’t have a residue of 1.

perl -Mbignum=a,50 -MMath::Prime::Util=next_prime -MList::Util=first -E '
  $p=2;$c=0; while($c<5){$p=next_prime($p); say("$p, as 1/$p=",1./$p),++$c
  if (first {$x=10**$_%$p; $x==1}(1..$p-1))==$p-1}'

Results:

7, as 1/7=0.14285714285714285714285714285714285714285714285714
17, as 1/17=0.058823529411764705882352941176470588235294117647059
19, as 1/19=0.052631578947368421052631578947368421052631578947368
23, as 1/23=0.043478260869565217391304347826086956521739130434783
29, as 1/29=0.034482758620689655172413793103448275862068965517241

I used the bignum package so that I can go beyond the built in precision. I used the Math::Prime::Util package to generate consecutive primes. Finally, I used the List::Util package to look for the first repetition and check it coincides with the (p-1)-th.

The full version follows.

# Perl weekly challenge 139
# Task 2: Long Primes
#
# See https://wlmb.github.io/2021/11/16/PWC139/#task-2-long-primes
use v5.12;
use warnings;
use bignum;
use Math::Prime::Util qw(next_prime);
use List::Util qw(first);
use Text::Wrap qw(wrap $columns $break);
$columns=62;
$break=qr/\s|_/;
my $max_count=shift @ARGV//5; # get number of long primes from command line
my $prime=2; #current prime (will skip '2')
my $count=0;
my @lines;
while($count<$max_count){
    $prime=next_prime($prime);
    my $length=$prime-1; # expected length of large cycle
    Math::BigFloat->accuracy(3.5*$length); # allow 3+ repetitions
    my @groups= grep {$_} split /(\d{$length})/, 1./$prime; # groups of digits
    pop @groups; # throw away last (guard) repetition (posibly inexact)
     ++$count, push @lines,
                    "long_prime[$count] is $prime",
		    "       as 1/$prime = " . shift(@groups) . join "_", @groups,"..."
        if (first # if cycle doesn't stop early
           {my $x=10**$_%$prime; $x==1||$x==0}
           (1..$prime-1))
	   == $prime-1
}
say wrap("", "                  _", $_) for @lines;

I used the join...split... trick to mark explicitly the beginning and end of each cycle. I chose an accuracy of 3+ repetitions to display three full repetitions and throw away the last, which could have rounding errors. I used Text::Wrap to manage the large lines expected for large repetition cycles.

Example: Print the first 10 long primes.

./ch-2.pl 10

Results:

1-th long prime is 7
       as 1/7 = 0.142857_142857_142857_...
2-th long prime is 17
       as 1/17 = 0.0588235294117647_0588235294117647
		  _0588235294117647_...
3-th long prime is 19
       as 1/19 = 0.052631578947368421_052631578947368421
		  _052631578947368421_...
4-th long prime is 23
       as 1/23 = 0.0434782608695652173913
		  _0434782608695652173913
		  _0434782608695652173913_...
5-th long prime is 29
       as 1/29 = 0.0344827586206896551724137931
		  _0344827586206896551724137931
		  _0344827586206896551724137931_...
6-th long prime is 47
       as 1/47 =
		  _0.0212765957446808510638297872340425531914
		  _893617
		  _021276595744680851063829787234042553191489
		  _3617
		  _021276595744680851063829787234042553191489
		  _3617_...
7-th long prime is 59
       as 1/59 =
		  _0.0169491525423728813559322033898305084745
		  _762711864406779661
		  _016949152542372881355932203389830508474576
		  _2711864406779661
		  _016949152542372881355932203389830508474576
		  _2711864406779661_...
8-th long prime is 61
       as 1/61 =
		  _0.0163934426229508196721311475409836065573
		  _77049180327868852459
		  _016393442622950819672131147540983606557377
		  _049180327868852459
		  _016393442622950819672131147540983606557377
		  _049180327868852459_...
9-th long prime is 97
       as 1/97 =
		  _0.0103092783505154639175257731958762886597
		  _938144329896907216494845360824742268041237
		  _11340206185567
		  _010309278350515463917525773195876288659793
		  _814432989690721649484536082474226804123711
		  _340206185567
		  _010309278350515463917525773195876288659793
		  _814432989690721649484536082474226804123711
		  _340206185567_...
10-th long prime is 109
       as 1/109 =
		  _0.0091743119266055045871559633027522935779
		  _816513761467889908256880733944954128440366
		  _97247706422018348623853211
		  _009174311926605504587155963302752293577981
		  _651376146788990825688073394495412844036697
		  _247706422018348623853211
		  _009174311926605504587155963302752293577981
		  _651376146788990825688073394495412844036697
		  _247706422018348623853211_...
Written on November 16, 2021