The Weekly Challenge ‐ Perl and Raku

CY's Take on The Weekly Challenge #147 Task 1 Truncatable Prime

If you want to challenge yourself on programming, especially on Perl and/or Raku, go to https://theweeklychallenge.org, code the latest challenges, submit codes on-time (by GitHub or email).

Do tell me, if I am wrong or you strongly oppose my statements!

It's time for challenges in Week #147 !


image info

This is the beginning of the second semester of my Postgraduate diploma in Information Technology; and I have finished all exams and assignments from the previous semester. Somehow I decided to try to play with programming languages. While Mohammad has said, having fun is important in learning, I tried to do the Weekly Challenge Task 1 in different programming languages which I thought I had been able to handle for "sightseeing purpose".

11 items were on the target list. They are:

awk bash
C++
Java Node.js(JavaScript) Julia
LISP PHP Perl Smalltalk
Befunge-93

I did 8 finally.

Task statement

Left Truncatable Prime

Write a script to generate first 20 left-truncatable prime numbers in base 10.

Supportive information:

In number theory, a left-truncatable prime is a prime number which, in a given base, contains no 0, and if the leading left digit is successively removed, then all resulting numbers are primes.

Example
9137 is one such left-truncatable prime since 9137, 137, 37 and 7 are all prime numbers.

Usually I would write a code which are extensible for TWC ‐ for instance, giving the user a permission to generate first n left-truncatable primes, but this time I chose to slack off and stick to the "20" of the task statement.

1. Julia

I started with the main language of my recent part-time work.

Two friends (one from astronomy research, one having a math background) have briefly expressed interest in Julia. I guess I gonna blog about it in details ‐ also as a gift of return for the Julia expert answering my question on https://discourse.julialang.org.

For the time being, I do not introduce or gossip on it. Let's see some important part of the code:

left_trun_primes = [2, 3, 5, 7]
primes = [2, 3, 5, 7]
index_ltp = [1, 5]

lastelement(array) = array[length(array)]
x_no_less_than_sqrt_y(x, y) = x  y


function grep(func, array)
    # See how I like the *ix-style functions?
    implementation details skipped here
    return Tuple(ans)
end
function is_prime(int)
    # return boolean; details skipped here
end


function append_ltp(digits)
    k = 0
    for d = 1:9
        for ind = index_ltp[digits-1]:(index_ltp[digits]-1)
            new_num = parse(Int64, string(d) * string(left_trun_primes[ind]))
            if is_prime(new_num)
                push!(left_trun_primes, new_num)
                k += 1
            end
        end
    end
    push!(index_ltp, lastelement(index_ltp) + k + 1)
end


function append_primes(min,max)
    for num = min:max
        if is_prime(num)
            push!(primes, num)
        end
    end
end

append_ltp(2)
append_primes(10,sqrt(999))
append_ltp(3)
println(left_trun_primes[1:20])
full code

This set the tone of procedures I would use for coding in the next language, our beloved Perl.

2. Perl

The index_ltp in the Julia code looked complicated to me, hence I modified my approach and made three arrays to store the left-truncatable primes.

my @ltp = ();
my @recent_ltp = (2,3,5,7);
my @new_ltp = ();

my @prime = (2,3,5,7);
sub is_prime {
    # trivial
    # implementation details skipped here
}



sub append_primes {
    # How much different is it compared to the append_primes(min,max) above?
    my $max = $_[0];
    HERE: for my $can ($prime[-1]+1..$max) {
        for my $p (@prime) {
            next HERE if $can % $p == 0;
            last if $p > sqrt($can);
        }
        push @prime, $can;
    }
}



sub append_ltp {
    my $target_size = $_[0];
    if ($target_size <= (scalar @ltp + scalar @recent_ltp)) {
        push @ltp, @recent_ltp;
        return;
    }
    for my $d (1..9) {
        for my $num (@recent_ltp) {
            my $new_num = $d . $num;
            push @new_ltp, $new_num if is_prime($new_num);
        }
    }
    push @ltp, @recent_ltp;
    @recent_ltp = @new_ltp;
    @new_ltp = ();
    append_ltp($target_size);   # Recursion!
}

Later I set two "game rules" for my solitaire: (1) start with the single digit primes; (2) generate list of primes up to 1000.

full code

3. Smalltalk

I got the cerificate in Java, and sometimes use it for creating math animations (with Processing); why didn't I write Java solution before Smalltalk solution? This is because I wanted to have something in object-oriented style, and the best way to implement [the style] is using a fully(or purely) object-oriented programming language, I thought.

It took me some time to get familiar back to the "outlook" of Smalltalk. It took me some time to get back familiarity of object-orientation paradigm. It took me MORE time to debug the program ‐ I feel I can blame on the quality of GNU Smalltalk error messages...

Smalltalk at: #Primes put: nil.

Ltp := OrderedCollection new.

RecentLtp := OrderedCollection with: 2 with: 3 with: 5 with: 7.

NewLtp := OrderedCollection new.

my_Primes := OrderedCollection with: 2 with: 3 with: 5 with: 7.

Smalltalk at: #Primes put: my_Primes.
Number extend [
    inc [
        ^(self+1)
    ]
    dec [
        ^(self-1)
    ]
    sqrt [  "behavior of sqrt is strange in GNU Smalltalk, so I overrided it;"
    "a better name should be something like sqrt_int"
        |smallNum|
        smallNum := 1.
        [smallNum squared > self] whileFalse: [smallNum := smallNum inc].
        ^(smallNum dec)
    ]
    isPrime [
        |b i|
        i := 1.
        [ (b := self \\ (Primes at: i) ~= 0) & (((Primes at: i) > self sqrt) not) ] whileTrue: [i := i inc].
         ^b
    ]
]



p := 10.

[p < 1000] whileTrue: [
    (p isPrime) ifTrue: [my_Primes add: p. Smalltalk at: #Primes put: my_Primes.].
    p := p inc
].



[Ltp size + RecentLtp size >= 20] whileFalse: [
    1 to: 9 do: [ :D |
        RecentLtp do: [ :Num |
            |NewNum|
            NewNum := ((D asString, Num asString) asInteger).
            (NewNum isPrime) ifTrue: [NewLtp add: NewNum]
        ].
    ].
    Ltp addAll: RecentLtp.
    RecentLtp := NewLtp.
    NewLtp := OrderedCollection new.
].

Ltp addAll: RecentLtp.

(Ltp copyFrom: 1 to: 20) printNl.

ObjectMemory quit.

Anyway, after writing the Smalltalk code, I have gained more understanding on "Wrapper class" and "primitive types" in the Java terminology. I was tired and it was the Friday 4:30am in Hong Kong.

full submitted code

4. Java

I woke up at 10am or 11am Friday. Then started to code in Java.

import java.util.*;

public class LeftTruncatablePrime
{
    public static List<Integer> Primes;
    public static List<Integer> LTPrimes;
    public static List<Integer> recentLTPrimes;
    public static List<Integer> newLTPrimes;

    public static void main(String... args)
    {
        Integer[] singleDigitPrimes = {2, 3, 5, 7};
        Primes = new ArrayList<Integer>();
        Collections.addAll(Primes, singleDigitPrimes);

        LTPrimes = new ArrayList<Integer>();
        recentLTPrimes = new ArrayList<Integer>();
        Collections.addAll(recentLTPrimes, singleDigitPrimes);
        newLTPrimes = new ArrayList<Integer>();
        appendPrimes(1000);
        appendLTPrimes(20);

        for (int i = 0; i < 20; i++)
            System.out.println(LTPrimes.get(i));
    }

    public static boolean isPrime(Integer x)
    {
        Integer p = 0;
        for (int i = 0; p <= Math.sqrt(x) ; i++ )
        {
            p = Primes.get(i);
            if (x % p == 0)
                return false;
        }
        return true;
    }
    public static void appendPrimes(Integer max)
    {
        Integer i = Primes.get(Primes.size()-1)+1;
        while (Primes.get(Primes.size()-1) < max)
        {
            if (isPrime(i))
                Primes.add(i);
            i++;
        }
    }


    public static void appendLTPrimes(Integer targetSize)
    {
        if (targetSize <= LTPrimes.size() + recentLTPrimes.size())
        {
            LTPrimes.addAll(recentLTPrimes);
            return;
        }
        for (int d = 1; d <= 9; d++) {
            for (Integer num : recentLTPrimes)
            {
                int newNum = Integer.parseInt(d + "" + num);
                if (isPrime(newNum)) {
                    newLTPrimes.add(newNum);
                }
            }
        }
        LTPrimes.addAll(recentLTPrimes);
        recentLTPrimes = (List)((ArrayList)newLTPrimes).clone();
        //the toughest part for someone who has been used to dynamically typed languages
        //(through "type" and "object class" are different concepts) 
        // The code can be simplified as: ...  = (ArrayList)newLTPrimes.clone();  
        //if the lists are declared as _ArrayList_ instead of _List_ in the beginning

        newLTPrimes.clear();
        appendLTPrimes(targetSize);
    }
}

full submitted code

5. C++

Soon I picked Java's enemy(?)(the war was ended some time ago?? Everyone is talking about ABC now: AI, Big Data, Cloud).

Actually I practiced C++ before Java and Perl. The original motivation was writing math programs ‐ "acting" as an "ameteur mathematician", not becoming a "hacker".

Since the logic of the piece of C++ code is so close to that of Java, here only function append_ltp is shown:

void append_ltp(int target_size) {
    if (target_size <= ltp.size() + recent_ltp.size() ) {
        ltp.insert( ltp.end(), recent_ltp.begin(), recent_ltp.end() );
        return;
    }
    for (int d = 1; d <= 9; d++) {
        for (int r = 0; r < recent_ltp.size(); r++ ) {
            char str[20];
            int num = recent_ltp.at(r);
            sprintf(str, "%d%d", d, num);
            int new_num = atoi(str);
            if (is_prime(new_num))
                new_ltp.push_back(new_num);
        }
    }
    ltp.insert( ltp.end(), recent_ltp.begin(), recent_ltp.end() );
    recent_ltp = new_ltp;
    new_ltp = {};
    append_ltp(target_size);
}

full code

6. Node.js / JavaScript

I have just learnt JavaScript in "Internet and Web Applications" class in the Postgraduate diploma in IT program mentioned. The class covered from HTML5, CSS, JavaScript, php, and php with MySQL. The instructor taught jQuery, CSS bootstrap and Ajax as well (but not in exam scope). It felt like going from junior high school math to calculus within two months. But I was overestimating myself and did not work hard. I learnt to use border collapse after losing marks in exam. I think I am not fit for web programming as the web technology evolves too fast for me, and comparing the display and JavaScript in different broswers under different operating systems would drive me mad.

full code

Why not PHP?

I failed to handle the scope of variables in PHP. And I don't want to memorize array_xxxxx functions. And, maybe I like @ sigil for arrays in Perl too much.

I do appreciate how PHP can be inserted into HTML anyway.

Why not Befunge-93?

Befunge-93 program for Week #140 Task 2

(Stepwise)run on
http://befungius.aurlien.net .
Quick result on
https://amicloud.github.io/fungide/

Task statement

$i = 1, $j = 9, $k = 8


$i = 3, $j = 3, $k = 9


$i = 7, $j = 9, $k = 9

I wrote one in Week #140. It demostrates that why loop is called loop!

I wrote the logic going to use, but then I decided to let go(!= give up) as writing in Befunge-93 is such time-consuming. Later I think I can use the logic for Awk and bash.

7. Awk (slow implementation)

As mentioned, the logic is exactly like what in bash which the readers are going to see, but Awk programs "look like" Perl. :) I don't display the code here.

full code

8. bash (slow implementation)

target_size=20
prime=(2 3 5 7)

i=4
for ((n=10; n<1000; n=$n+1));
do
    loop=1
    for ((k=2;k<=n/3; k=$k+1));
    do
        if [[ $n%$k -eq 0 ]];
        then
            loop=0
            break
        fi
    done
    if [[ $loop -eq 1 ]];
    then
        prime[$((i))]=$n
        i=$i+1
    fi
done

i=0
n=0
while [ $((prime[$n])) -le 900 ]  # 997 or above will return error
                        #  ^^^   a bit cheating here
do
    loop=0
    k=0
    for ((k=0; $((prime[$k]))<=996; k=$k+1));
    do
        if [[ $((prime[$n]))%10 -eq $((prime[$k])) ]];
        then
            loop=$loop+1
        fi
        if [[ $((prime[$n]))%100 -eq $((prime[$k])) ]];
        then
            loop=$loop+1
        fi
    done
    if [[ $loop -eq 2 ]];
    then
        echo $((prime[$n]))
        i=$i+1
    fi
    n=$n+1
    if [[ $i -gt $target_size ]]
    then
        exit
    fi
done

The process of coding the above has made me realize that I don't really learn bash. If I want to be a programmer specializing in Linux platform, I need to study on bash seriously.

full code

Why no LISP?

I haven't written codes in LISP for a long time. (In addition, I haven't learnt macro in LISP yet.) But you can see the tendency of using lists from the Perl codes, which I think it is learnt from my LISP experience.

Summary

Anyway...

My favorite class now is "Project Management and Quality Management". Once it mentions the idea of triple constraints: Schedule (time), Resources ($, labour, energy) and Scope (requirements). I think I grow to a point that time cannot be over-spoiled for fun (and I should be glad with my duties). So I have lowered my goal(requirements from oneself) for this little project "Task 1 in Many Programming Languages, TWC Week #147". Let me have a complete break on Sunday, haha.

Recently I have found a very good tweet and think it can be applied for coding: here.

The most eye-catching line for me is "Always Stay a Student".

"Say Little, Do Much".

Stay alert and healthy! □


The image of group of people having push-ups together is found on Wikimedia Commons and the author is David McSpadden. It is licensed under Creative Commons Attribution 2.0 Generic license. See the license details here.

Except from images and codes from other personnels, the content of this blogpost is released under a copyleft spirit. One may share (full or partial) content of this blogpost on other platform if you share it under the free and open content spirit.

link for CY's full codes: Overview page on GitHub.


Contact on twitter: @e7_87.

Discuss via GitHub issues: here.

Email: fungcheokyin at gmail.com

Created Date: 15th January, 2022.

Latest Update: 16th January, 2022. 13:52 HKT.