aboutsummaryrefslogtreecommitdiff
path: root/challenge-175
diff options
context:
space:
mode:
authordrbaggy <js5@sanger.ac.uk>2022-07-30 01:07:04 +0100
committerdrbaggy <js5@sanger.ac.uk>2022-07-30 01:07:04 +0100
commit40550e1e6ea41dabe7a6a72e17f5f56de85fabcd (patch)
treee170a85111547d5b4e09224fe56ecf6788726a6f /challenge-175
parentd69c546a4fda62fcd899662f52a45e3ba03365c3 (diff)
parentc549a7288ca66b1b48e8518454806b538fd97568 (diff)
downloadperlweeklychallenge-club-40550e1e6ea41dabe7a6a72e17f5f56de85fabcd.tar.gz
perlweeklychallenge-club-40550e1e6ea41dabe7a6a72e17f5f56de85fabcd.tar.bz2
perlweeklychallenge-club-40550e1e6ea41dabe7a6a72e17f5f56de85fabcd.zip
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'challenge-175')
-rw-r--r--challenge-175/athanasius/perl/ch-1.pl148
-rw-r--r--challenge-175/athanasius/perl/ch-2.pl142
-rw-r--r--challenge-175/athanasius/raku/ch-1.raku111
-rw-r--r--challenge-175/athanasius/raku/ch-2.raku188
-rw-r--r--challenge-175/mohammad-anwar/java/theweeklychallenge/FirstPerfectTotient.java81
-rw-r--r--challenge-175/mohammad-anwar/perl/ch-2.pl68
-rw-r--r--challenge-175/mohammad-anwar/python/ch-2.py63
-rw-r--r--challenge-175/mohammad-anwar/raku/ch-2.raku61
-rw-r--r--challenge-175/mohammad-anwar/swift/ch-2.swift91
-rw-r--r--challenge-175/pokgopun/go/ch-2.go16
-rw-r--r--challenge-175/steven-wilson/perl/ch-1.pl25
11 files changed, 983 insertions, 11 deletions
diff --git a/challenge-175/athanasius/perl/ch-1.pl b/challenge-175/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..bf4458cf4f
--- /dev/null
+++ b/challenge-175/athanasius/perl/ch-1.pl
@@ -0,0 +1,148 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 175
+=========================
+
+TASK #1
+-------
+*Last Sunday*
+
+Submitted by: Mohammad S Anwar
+
+Write a script to list Last Sunday of every month in the given year.
+
+For example, for year 2022, we should get the following:
+
+ 2022-01-30
+ 2022-02-27
+ 2022-03-27
+ 2022-04-24
+ 2022-05-29
+ 2022-06-26
+ 2022-07-31
+ 2022-08-28
+ 2022-09-25
+ 2022-10-30
+ 2022-11-27
+ 2022-12-25
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Assumptions
+-----------
+All dates are interpreted according to the Gregorian calendar [1,3]. Dates
+prior to 15th October, 1582, when the Gregorian calendar was first introduced,
+are calculated according to the "proleptic Gregorian calendar" [3] which
+extends backwards to dates before the calendar was in use. However, dates prior
+to the year 1 AD are not supported.
+
+Solution
+--------
+The solution uses the CPAN module DateTime [2]. Its last_day_of_month()
+constructor automatically finds the last day of February as 28 or 29, according
+to whether or not the year is a leap year.
+
+Then, DateTime's day_of_the_week() method finds the weekday of the last day in
+the month: it "[r]eturns the day of the week as a number, from 1..7, with 1
+being Monday and 7 being Sunday." [2] If the last day is a Monday, then the
+last Sunday is one day prior; if a Tuesday, it is two days prior; and so on.
+Hence, the date of the last Sunday is calculated by subtracting from the date
+of the last day the weekday of the last day modulo 7.
+
+References
+----------
+[1] Claus Tøndering, "The Gregorian calendar", The Calendar FAQ,
+ https://www.tondering.dk/claus/cal/gregorian.php
+[2] Dave Rolsky, "DateTime", MetaCPAN, https://metacpan.org/pod/DateTime
+[3] "Gregorian calendar", Wikipedia,
+ https://en.wikipedia.org/wiki/Gregorian_calendar
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use DateTime;
+use Regexp::Common qw( number );
+
+const my $USAGE =>
+"Usage:
+ perl $0 <year>
+
+ <year> A year in the Gregorian calendar (AD)\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 175, Task #1: Last Sunday (Perl)\n\n";
+}
+
+#==============================================================================
+MAIN:
+#==============================================================================
+{
+ my $year = parse_command_line();
+
+ print "The last Sunday of each month in the year $year:\n\n";
+
+ for my $month (1 .. 12)
+ {
+ my $last_day_dt = DateTime->last_day_of_month
+ (
+ year => $year,
+ month => $month,
+ );
+ my $last_day = $last_day_dt->day;
+ my $day_of_week = $last_day_dt->day_of_week;
+ my $last_sun_dt = DateTime->new
+ (
+ year => $year,
+ month => $month,
+ day => $last_day - ($day_of_week % 7),
+ );
+
+ printf " %s\n", $last_sun_dt->ymd;
+ }
+}
+
+#------------------------------------------------------------------------------
+sub parse_command_line
+#------------------------------------------------------------------------------
+{
+ my $args = scalar @ARGV;
+ $args == 1 or error( "Expected 1 command line argument, found $args" );
+
+ my $year = $ARGV[ 0 ];
+
+ $year =~ / ^ $RE{num}{int} $ /x
+ or error( qq[Argument "$year" is not a valid integer] );
+
+ $year >= 1 or error( qq[Year "$year" is not AD] );
+
+ return $year;
+}
+
+#------------------------------------------------------------------------------
+sub error
+#------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+###############################################################################
diff --git a/challenge-175/athanasius/perl/ch-2.pl b/challenge-175/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..d2f832d4aa
--- /dev/null
+++ b/challenge-175/athanasius/perl/ch-2.pl
@@ -0,0 +1,142 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 175
+=========================
+
+TASK #2
+-------
+*Perfect Totient Numbers*
+
+Submitted by: Mohammad S Anwar
+
+Write a script to generate first 20 Perfect Totient Numbers. Please checkout
+[ https://en.wikipedia.org/wiki/Perfect_totient_number |wikipedia page] for
+more informations.
+
+Output
+
+ 3, 9, 15, 27, 39, 81, 111, 183, 243, 255, 327, 363, 471, 729,
+ 2187, 2199, 3063, 4359, 4375, 5571
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Totients and Iterated Totients
+------------------------------
+"In number theory, Euler's totient function counts the positive integers up to
+a given integer n that are relatively prime to n. ... In other words, it is the
+number of integers k in the range 1 ≤ k ≤ n for which the greatest common
+divisor gcd(n, k) is equal to 1." [5] For all n > 2, φ(n) is even.
+
+Since gcd(n, n) = n, it follows that, for all n > 1, φ(n) is at most n - 1
+(when happens when n is prime), so φ(n) < n. So when totients are iterated, the
+iterations always eventually decrease to 2, and then to 1.
+
+Perfect Totient Numbers
+-----------------------
+AFAICT, the definitions of Perfect Totient Numbers (PTNs) given in [6] and [2]
+imply that 1 is a PTN, which it is not. A more rigorous definition is given in
+[4], which specifies that a PTN must be > 2.
+
+"It is trivial that perfect totient numbers must be odd. It is easy to show
+that powers of 3 are perfect totient numbers." [2]
+
+Solution
+--------
+The CPAN module Math::Prime::Util [3] provides function euler_phi(), which cal-
+culates the totient of a given integer very quickly. (For a home-grown imple-
+mentation of euler_phi(), see the Raku solution to Task 2.)
+
+Subroutine iterated_totient_sum() calls euler_phi() repeatedly until the itera-
+tions reduce to 2. The iterations are summed progressively, and finally 1 is
+added for φ(2).
+
+The main routine calls iterated_totient_sum() repeatedly on successive odd
+numbers: those for which the iterated totient sum equals the number itself are
+PTNs. The search continues until $TARGET PTNs have been found and displayed.
+
+References
+----------
+[1] "A000010 Euler totient function phi(n): count numbers <= n and prime to
+ n.", OEIS, https://oeis.org/A000010
+[2] "A082897 Perfect totient numbers.", OEIS, https://oeis.org/A082897
+[3] Dana Jacobsen, "Math::Prime::Util", MetaCPAN,
+ https://metacpan.org/pod/Math::Prime::Util
+[4] Douglas E. Iannucci, Deng Moujie, and Graeme L. Cohen, "On Perfect Totient
+ Numbers", Journal of Integer Sequences, Vol. 6 (2003),
+ http://www.emis.de/journals/JIS/VOL6/Cohen2/cohen50.pdf
+[5] "Euler's totient function", Wikipedia,
+ https://en.wikipedia.org/wiki/Euler%27s_totient_function
+[6] "Perfect totient number", Wikipedia,
+ https://en.wikipedia.org/wiki/Perfect_totient_number
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use Math::Prime::Util qw( euler_phi );
+
+const my $TARGET => 20;
+const my $USAGE => "Usage:\n perl $0\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 175, Task #2: Perfect Totient Numbers (Perl)\n\n";
+}
+
+#==============================================================================
+MAIN:
+#==============================================================================
+{
+ my $args = scalar @ARGV;
+ $args == 0 or die 'ERROR: Expected 0 command line arguments, found ' .
+ "$args\n$USAGE";
+
+ print "The first $TARGET Perfect Totient Numbers:\n\n3";
+
+ my $count = 1;
+
+ for (my $n = 5; $count < $TARGET; $n += 2)
+ {
+ if (iterated_totient_sum( $n ) == $n)
+ {
+ print ", $n";
+ ++$count;
+ }
+ }
+
+ print "\n";
+}
+
+#------------------------------------------------------------------------------
+sub iterated_totient_sum
+#------------------------------------------------------------------------------
+{
+ my ($n) = @_;
+ my $sum = 0;
+
+ while ($n > 2)
+ {
+ $n = euler_phi( $n );
+ $sum += $n;
+ }
+
+ return ++$sum; # euler_phi(2) = 1
+}
+
+###############################################################################
diff --git a/challenge-175/athanasius/raku/ch-1.raku b/challenge-175/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..81586e5826
--- /dev/null
+++ b/challenge-175/athanasius/raku/ch-1.raku
@@ -0,0 +1,111 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 175
+=========================
+
+TASK #1
+-------
+*Last Sunday*
+
+Submitted by: Mohammad S Anwar
+
+Write a script to list Last Sunday of every month in the given year.
+
+For example, for year 2022, we should get the following:
+
+ 2022-01-30
+ 2022-02-27
+ 2022-03-27
+ 2022-04-24
+ 2022-05-29
+ 2022-06-26
+ 2022-07-31
+ 2022-08-28
+ 2022-09-25
+ 2022-10-30
+ 2022-11-27
+ 2022-12-25
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Assumptions
+-----------
+All dates are interpreted according to the Gregorian calendar [2,3]. Dates
+prior to 15th October, 1582, when the Gregorian calendar was first introduced,
+are calculated according to the "proleptic Gregorian calendar" [3] which
+extends backwards to dates before the calendar was in use. However, dates prior
+to the year 1 AD are not supported.
+
+Solution
+--------
+The solution uses Raku's native Date class [1]. Its constructor accepts a "*"
+as the argument to its "day" parameter: this gives the last day in the month,
+automatically finding the last day of February as 28 or 29, according to
+whether or not the year is a leap year.
+
+Then, Date's day-of-week() method finds the weekday of the last day in the
+month: it "[r]eturns the day of the week, where 1 is Monday, 2 is Tuesday and
+Sunday is 7." [1] If the last day is a Monday, then the last Sunday is one day
+prior; if a Tuesday, it is two days prior; and so on. Hence, the date of the
+last Sunday is calculated by subtracting from the date of the last day the
+weekday of the last day modulo 7.
+
+References
+----------
+[1] "class Date", Raku Documentation, https://docs.raku.org/type/Date
+[2] Claus Tøndering, "The Gregorian calendar", The Calendar FAQ,
+ https://www.tondering.dk/claus/cal/gregorian.php
+[3] "Gregorian calendar", Wikipedia,
+ https://en.wikipedia.org/wiki/Gregorian_calendar
+
+=end comment
+#==============================================================================
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 175, Task #1: Last Sunday (Raku)\n".put;
+}
+
+#==============================================================================
+sub MAIN
+(
+ UInt:D $year where * > 0 #= A year in the Gregorian calendar (AD)
+)
+#==============================================================================
+{
+ "The last Sunday of each month in the year $year:\n".put;
+
+ for 1 .. 12 -> UInt $month
+ {
+ my Date $last-day = Date.new: $year, $month, *;
+ my Date $last-sun = Date.new: $last-day - ($last-day.day-of-week % 7);
+
+ " { $last-sun.Str }".put;
+ }
+}
+
+#------------------------------------------------------------------------------
+sub USAGE()
+#------------------------------------------------------------------------------
+{
+ my Str $usage = $*USAGE;
+
+ $usage ~~ s/ ($*PROGRAM-NAME) /raku $0/;
+
+ $usage.put;
+}
+
+###############################################################################
diff --git a/challenge-175/athanasius/raku/ch-2.raku b/challenge-175/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..dea3154069
--- /dev/null
+++ b/challenge-175/athanasius/raku/ch-2.raku
@@ -0,0 +1,188 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 175
+=========================
+
+TASK #2
+-------
+*Perfect Totient Numbers*
+
+Submitted by: Mohammad S Anwar
+
+Write a script to generate first 20 Perfect Totient Numbers. Please checkout
+[ https://en.wikipedia.org/wiki/Perfect_totient_number |wikipedia page] for
+more informations.
+
+Output
+
+ 3, 9, 15, 27, 39, 81, 111, 183, 243, 255, 327, 363, 471, 729,
+ 2187, 2199, 3063, 4359, 4375, 5571
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Totients and Iterated Totients
+------------------------------
+"In number theory, Euler's totient function counts the positive integers up to
+a given integer n that are relatively prime to n. ... In other words, it is the
+number of integers k in the range 1 ≤ k ≤ n for which the greatest common
+divisor gcd(n, k) is equal to 1." [5] For all n > 2, φ(n) is even.
+
+Since gcd(n, n) = n, it follows that, for all n > 1, φ(n) is at most n - 1
+(when happens when n is prime), so φ(n) < n. So when totients are iterated, the
+iterations always eventually decrease to 2, and then to 1.
+
+Perfect Totient Numbers
+-----------------------
+AFAICT, the definitions of Perfect Totient Numbers (PTNs) given in [6] and [2]
+imply that 1 is a PTN, which it is not. A more rigorous definition is given in
+[4], which specifies that a PTN must be > 2.
+
+"It is trivial that perfect totient numbers must be odd. It is easy to show
+that powers of 3 are perfect totient numbers." [2]
+
+Solution
+--------
+Function euler-phi() calculates φ(n) using Euler's product formula [5]:
+
+ φ(n) = n ∏ (1 - 1/p) where p ranges over the distinct primes that divide n.
+
+The prime factors of n are calculated by the recursive function prime-factors()
+which in turn uses Raku's native is-prime() method.
+
+Subroutine iterated-totient-sum() calls euler-phi() repeatedly until the itera-
+tions reduce to 2. The iterations are summed progressively, and finally 1 is
+added for φ(2).
+
+The main routine calls iterated-totient-sum() repeatedly on successive odd
+numbers: those for which the iterated totient sum equals the number itself are
+PTNs. The search continues until $TARGET PTNs have been found and displayed.
+For $TARGET = 20, the complete search takes 14 seconds on my machine.
+
+References
+----------
+[1] "A000010 Euler totient function phi(n): count numbers <= n and prime to
+ n.", OEIS, https://oeis.org/A000010
+[2] "A082897 Perfect totient numbers.", OEIS, https://oeis.org/A082897
+[3] Dana Jacobsen, "Math::Prime::Util", MetaCPAN,
+ https://metacpan.org/pod/Math::Prime::Util
+[4] Douglas E. Iannucci, Deng Moujie, and Graeme L. Cohen, "On Perfect Totient
+ Numbers", Journal of Integer Sequences, Vol. 6 (2003),
+ http://www.emis.de/journals/JIS/VOL6/Cohen2/cohen50.pdf
+[5] "Euler's totient function", Wikipedia,
+ https://en.wikipedia.org/wiki/Euler%27s_totient_function
+[6] "Perfect totient number", Wikipedia,
+ https://en.wikipedia.org/wiki/Perfect_totient_number
+
+=end comment
+#==============================================================================
+
+my UInt constant $TARGET = 20;
+my Bool constant $TIME = False;
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 175, Task #2: Perfect Totient Numbers (Raku)\n".put;
+}
+
+#==============================================================================
+sub MAIN()
+#==============================================================================
+{
+ my Int $t0 = time if $TIME;
+
+ "The first $TARGET Perfect Totient Numbers:\n\n3".print;
+
+ my UInt $count = 1;
+
+ loop (my UInt $n = 5; $count < $TARGET; $n += 2)
+ {
+ if (iterated-totient-sum( $n ) == $n)
+ {
+ ", $n".print;
+ ++$count;
+ }
+ }
+
+ put();
+
+ "\n%d seconds\n".printf: time - $t0 if $TIME;
+}
+
+#------------------------------------------------------------------------------
+sub iterated-totient-sum( UInt:D $n where { $n > 1 } --> UInt:D )
+#------------------------------------------------------------------------------
+{
+ my UInt $i = $n;
+ my UInt $sum = 0;
+
+ while $i > 2
+ {
+ $i = euler-phi( $i );
+ $sum += $i;
+ }
+
+ return ++$sum; # euler-phi(2) = 1
+}
+
+#------------------------------------------------------------------------------
+sub euler-phi( UInt:D $n where { $n > 1 } --> UInt:D )
+#------------------------------------------------------------------------------
+{
+ # phi(n) = n * Product_{distinct primes p dividing n} (1 - 1/p)
+
+ my UInt @prime-factors = prime-factors( $n ).unique;
+ my Rat $phi = $n * [*] @prime-factors.map: { 1 - (1 / $_) };
+
+ return $phi.Int;
+}
+
+#------------------------------------------------------------------------------
+sub prime-factors( UInt:D $n where { $n > 1 } --> Array:D[UInt:D] )
+#------------------------------------------------------------------------------
+{
+ my UInt @prime-factors;
+
+ if $n.is-prime
+ {
+ @prime-factors.push: $n;
+ }
+ else
+ {
+ for 2, 3, 5, 7 ... * -> UInt $p
+ {
+ if $p.is-prime && $n %% $p
+ {
+ @prime-factors.push: $p, |prime-factors( ($n / $p).Int );
+ last;
+ }
+ }
+ }
+
+ return @prime-factors;
+}
+
+#------------------------------------------------------------------------------
+sub USAGE()
+#------------------------------------------------------------------------------
+{
+ my Str $usage = $*USAGE;
+
+ $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/;
+
+ $usage.put;
+}
+
+###############################################################################
diff --git a/challenge-175/mohammad-anwar/java/theweeklychallenge/FirstPerfectTotient.java b/challenge-175/mohammad-anwar/java/theweeklychallenge/FirstPerfectTotient.java
new file mode 100644
index 0000000000..2c8027e28c
--- /dev/null
+++ b/challenge-175/mohammad-anwar/java/theweeklychallenge/FirstPerfectTotient.java
@@ -0,0 +1,81 @@
+package theweeklychallenge;
+
+/*
+
+Week 175:
+
+ https://theweeklychallenge.org/blog/perl-weekly-challenge-175
+
+Task #2: Perfect Totient Numbers
+
+ Write a script to generate first 20 Perfect Totient Numbers.
+
+Compile and Run:
+
+ mohammad-anwar/java$ javac theweeklychallenge/FirstPerfectTotient.java
+ mohammad-anwar/java$ java theweeklychallenge.FirstPerfectTotient
+
+*/
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import junit.framework.TestCase;
+import static junit.framework.Assert.*;
+
+public class FirstPerfectTotient extends TestCase {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(
+ theweeklychallenge.FirstPerfectTotient.class);
+ }
+
+ public void testFirstPerfectTotient() {
+ Integer[] got = firstPerfectTotient(20);
+ Integer[] exp = {
+ 3, 9, 15, 27, 39, 81, 111, 183, 243,
+ 255, 327, 363, 471, 729, 2187, 2199,
+ 3063, 4359, 4375, 5571
+ };
+
+ assertEquals(Arrays.toString(exp), Arrays.toString(got));
+ }
+
+ public static int gcd(int m, int n) {
+ return n == 0 ? m : gcd(n, m % n);
+ }
+
+ public static boolean isCoprime(int m, int n) {
+ return gcd(m, n) == 1;
+ }
+
+ public static boolean isPerfectTotient(int n) {
+ int i = n;
+ int s = 0;
+ while (i >= 1) {
+ ArrayList<Integer> coprimes = new ArrayList<Integer>();
+ for (int j = 1; j < i; j++) {
+ if (isCoprime(j, i)) {
+ coprimes.add(j);
+ }
+ }
+ i = coprimes.size();
+ s = s + i;
+ }
+
+ return n == s;
+ }
+
+ public static Integer[] firstPerfectTotient(int n) {
+ ArrayList<Integer> fpt = new ArrayList<Integer>();
+
+ int i = 1;
+ while (fpt.size() < n) {
+ if (isPerfectTotient(i)) {
+ fpt.add(i);
+ }
+ i++;
+ }
+
+ return fpt.toArray(new Integer[fpt.size()]);
+ }
+}
diff --git a/challenge-175/mohammad-anwar/perl/ch-2.pl b/challenge-175/mohammad-anwar/perl/ch-2.pl
new file mode 100644
index 0000000000..47d464ad34
--- /dev/null
+++ b/challenge-175/mohammad-anwar/perl/ch-2.pl
@@ -0,0 +1,68 @@
+#!/usr/bin/perl
+
+=head1
+
+Week 175:
+
+ https://theweeklychallenge.org/blog/perl-weekly-challenge-175
+
+Task #2: Perfect Totient Numbers
+
+ Write a script to generate first 20 Perfect Totient Numbers.
+
+=cut
+
+use v5.36;
+use Test2::V0;
+
+is [
+ 3, 9, 15, 27, 39, 81, 111, 183, 243,
+ 255, 327, 363, 471, 729, 2187, 2199,
+ 3063, 4359, 4375, 5571
+ ], first_perfect_totient(20);
+
+done_testing;
+
+#
+#
+# METHODS
+
+sub is_coprime($a, $b) {
+ if ($a > $b) {
+ ($a, $b) = ($b, $a);
+ }
+ while ($a) {
+ ($a, $b) = ($b % $a, $a);
+ }
+ return $b == 1;
+}
+
+#
+# Simply coded as shown in the example in the wiki page:
+# https://en.wikipedia.org/wiki/Perfect_totient_number
+
+sub is_perfect_totient($n) {
+ my $i = $n;
+ my $s = 0;
+ while ($i >= 1) {
+ my @coprimes = ();
+ foreach (1 .. $i-1) {
+ push @coprimes, $_ if is_coprime $_, $i;
+ }
+ $i = @coprimes;
+ $s = $s + $i;
+ }
+
+ return $n == $s;
+}
+
+sub first_perfect_totient($n) {
+ my @pt = ();
+ my $i = 1;
+ while (@pt < $n) {
+ push @pt, $i if is_perfect_totient $i;
+ $i++;
+ }
+
+ return \@pt;
+}
diff --git a/challenge-175/mohammad-anwar/python/ch-2.py b/challenge-175/mohammad-anwar/python/ch-2.py
new file mode 100644
index 0000000000..70ff32d7e2
--- /dev/null
+++ b/challenge-175/mohammad-anwar/python/ch-2.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python3
+
+'''
+
+Week 175:
+
+ https://theweeklychallenge.org/blog/perl-weekly-challenge-175
+
+Task #2: Perfect Totient Numbers
+
+ Write a script to generate first 20 Perfect Totient Numbers.
+
+'''
+
+import math
+import unittest
+
+def isCoprime(a, b) -> bool:
+ return math.gcd(a, b) == 1
+
+#
+# Simply coded as shown in the example in the wiki page:
+# https://en.wikipedia.org/wiki/Perfect_totient_number
+
+def isPerfectTotient(n) -> bool:
+ i = n
+ s = 0
+ while i >= 1:
+ coprimes = []
+ for j in range(1, i):
+ if isCoprime(i, j):
+ coprimes.append(j)
+
+ i = len(coprimes)
+ s = s + i
+
+ return n == s
+
+def firstPerfectTotient(n):
+ pt = []
+ i = 1
+ while (len(pt) < n):
+ if isPerfectTotient(i):
+ pt.append(i)
+ i = i + 1
+
+ return pt
+
+#
+#
+# Unit test class
+
+class TestPerfectTotient(unittest.TestCase):
+ def test_firstPerfectTotient(self):
+ exp = [
+ 3, 9, 15, 27, 39, 81, 111, 183, 243,
+ 255, 327, 363, 471, 729, 2187, 2199,
+ 3063, 4359, 4375, 5571
+ ]
+ got = firstPerfectTotient(20)
+ self.assertEqual(exp, got)
+
+unittest.main()
diff --git a/challenge-175/mohammad-anwar/raku/ch-2.raku b/challenge-175/mohammad-anwar/raku/ch-2.raku
new file mode 100644
index 0000000000..58917a5d10
--- /dev/null
+++ b/challenge-175/mohammad-anwar/raku/ch-2.raku
@@ -0,0 +1,61 @@
+#!/usr/bin/env raku
+
+=begin pod
+
+Week 175:
+
+ https://theweeklychallenge.org/blog/perl-weekly-challenge-174
+
+Task #2: Perfect Totient Numbers
+
+ Write a script to generate first 20 Perfect Totient Numbers.
+
+=end pod
+
+use Test;
+
+is [
+ 3, 9, 15, 27, 39, 81, 111, 183, 243,
+ 255, 327, 363, 471, 729, 2187, 2199,
+ 3063, 4359, 4375, 5571
+ ], first-perfect-totient(20);
+
+done-testing;
+
+#
+#
+# METHODS
+
+sub is-coprime(Int $a, Int $b --> Bool) {
+ return ($a gcd $b) == 1;
+}
+
+#
+# Simply coded as shown in the example in the wiki page:
+# https://en.wikipedia.org/wiki/Perfect_totient_number
+
+sub is-perfect-totient(Int $n --> Bool) {
+ my Int $i = $n;
+ my Int $s = 0;
+ while $i >= 1 {
+ my Int @coprimes = ();
+ for 1..^$i {
+ @coprimes.push: $_ if is-coprime $_, $i;
+ }
+ $i = @coprimes.elems;
+ $s = $s + $i;
+ }
+
+ return $n == $s;
+}
+
+sub first-perfect-totient(Int $n --> Array[Int]) {
+ my Int @pt = ();
+ my Int $i = 1;
+ while @pt.elems < $n {
+ @pt.push: $i if is-perfect-totient $i;
+ $i++;
+ }
+
+ return @pt;
+}
diff --git a/challenge-175/mohammad-anwar/swift/ch-2.swift b/challenge-175/mohammad-anwar/swift/ch-2.swift
new file mode 100644
index 0000000000..32169f28b0
--- /dev/null
+++ b/challenge-175/mohammad-anwar/swift/ch-2.swift
@@ -0,0 +1,91 @@
+import Foundation
+
+/*
+
+Week 175:
+
+ https://theweeklychallenge.org/blog/perl-weekly-challenge-175
+
+Task #2: Perfect Totient Numbers
+
+ Write a script to generate first 20 Perfect Totient Numbers.
+
+ACTION:
+
+ $ swift ch-2.swift 20
+
+*/
+
+enum ParamError: Error {
+ case missingNumber
+ case invalidNumber
+}
+
+do {
+ let paramCount:Int = Int(CommandLine.argc)
+
+ if paramCount <= 1 {
+ throw ParamError.missingNumber
+ }
+
+ let num:Int = Int(CommandLine.arguments[1])!
+
+ if num >= 1 {
+ var i:Int = 0
+ var j:Int = 1
+ while i < num {
+ if isPerfectTotient(j) {
+ print(j)
+ i = i + 1
+ }
+ j = j + 1
+ }
+ }
+ else {
+ throw ParamError.invalidNumber
+ }
+}
+catch ParamError.missingNumber {
+ print("Missing number.")
+}
+catch ParamError.invalidNumber {
+ print("Invalid number.")
+}
+catch let error {
+ print(error)
+}
+
+//
+//
+// Functions
+
+func isCoprime(_ m: Int, _ n: Int) -> Bool {
+ var a: Int = 0
+ var b: Int = max(m, n)
+ var r: Int = min(m, n)
+
+ while r != 0 {
+ a = b
+ b = r
+ r = a % b
+ }
+
+ return b == 1
+}
+
+func isPerfectTotient(_ n:Int) -> Bool {
+ var i: Int = n
+ var s: Int = 0
+ while i >= 1 {
+ var coprimes:[Int] = []
+ for j in 1..<i {
+ if isCoprime(j, i) {
+ coprimes.append(j)
+ }
+ }
+ i = coprimes.count
+ s = s + i
+ }
+
+ return n == s
+}
diff --git a/challenge-175/pokgopun/go/ch-2.go b/challenge-175/pokgopun/go/ch-2.go
index 51106c56a2..a94463d9b3 100644
--- a/challenge-175/pokgopun/go/ch-2.go
+++ b/challenge-175/pokgopun/go/ch-2.go
@@ -12,6 +12,7 @@ Output
package main
import (
+ "fmt"
"io"
"os"
"strconv"
@@ -21,18 +22,11 @@ import (
)
func main() {
- var cntdwn uint = 20
- p := totient.New(cntdwn)
+ var count, start uint64 = 20, 3
+ fmt.Sscanf(strings.Join(os.Args[1:], " "), "%d %d", &count, &start)
var b strings.Builder
- for i := uint(3); i < 200_000; i += 2 {
- if p.IsPerfect(i) {
- b.WriteString(", " + strconv.FormatUint(uint64(i), 10))
- //fmt.Println(i)