aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2021-03-07 23:46:19 +0000
committerGitHub <noreply@github.com>2021-03-07 23:46:19 +0000
commit259ff4114d0d3e9599fa103ec0f81b502dbbf2a9 (patch)
tree6fb11a78217a9df8cdf4069f5f1b35200a7ca1f2
parent0bc69ba8f00534a5e7bcfadf2926518c004e74aa (diff)
parentfc922ab6b83e4082c1bf04132e91c685a22eb0d9 (diff)
downloadperlweeklychallenge-club-259ff4114d0d3e9599fa103ec0f81b502dbbf2a9.tar.gz
perlweeklychallenge-club-259ff4114d0d3e9599fa103ec0f81b502dbbf2a9.tar.bz2
perlweeklychallenge-club-259ff4114d0d3e9599fa103ec0f81b502dbbf2a9.zip
Merge pull request #3684 from dcw803/master
imported my solution's to this week's tasks
-rw-r--r--challenge-102/duncan-c-white/OptimizingTask150
-rw-r--r--challenge-102/duncan-c-white/README118
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1.pl69
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1a.pl73
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1b.pl88
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1c.pl129
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1d.pl144
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1e.pl148
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1f.pl159
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1g.pl165
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1h.pl175
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-1i.pl148
-rwxr-xr-xchallenge-102/duncan-c-white/perl/ch-2.pl85
-rwxr-xr-xchallenge-102/duncan-c-white/perl/run.sh5
14 files changed, 1472 insertions, 84 deletions
diff --git a/challenge-102/duncan-c-white/OptimizingTask1 b/challenge-102/duncan-c-white/OptimizingTask1
new file mode 100644
index 0000000000..f108fc1873
--- /dev/null
+++ b/challenge-102/duncan-c-white/OptimizingTask1
@@ -0,0 +1,50 @@
+tried some optimizations of task 1 (rare numbers). All times are for n==8 or 9
+I used Devel::NYTProf to profile each version, then made small optimizations,
+then reprofiled. See "run.sh" for how to run a particular version through
+the profiler, generate the report, and copy it into a web-accessible directory
+for viewing:
+
+ch-1.pl: the original, not optimized
+ time(8): 0:34.31
+ time(9): 5:56:10
+
+ch-1a.pl: observation from rare numbers webpage ("Properties of.."
+ section): rare numbers start with even top digit
+ time(8): 0:24.46
+ time(9): 4:10.61
+
+ch-1b.pl: only consider rare numbers starting with even top digit..
+ time(8): 0:15.35
+ time(9): 2:44.34
+
+ch-1c.pl: lots of optimizations, especially 3 separate rare block
+ functions: rareblock(), rareblock05() and rareblock2378().
+ time(8): 0:06.35
+ time(9): 1:06.64
+
+ch-1d.pl: lots more optimizations, especially: rather than generate x and
+ test x%10 == d, generate y (1/10th the range) and make
+ x = 10y + d: 1/10th the work, but same x's as before
+ time(8): 0:03.92
+ time(9): 0:40.21
+
+ch-1e.pl: inlined israre() into the slowest rareblock2378() func
+ time(8): 0:03.39
+ time(9): 0:34.49
+
+ch-1f.pl: inlined israre() into the next slowest rareblock05() func
+ time(8): 0:03.12
+ time(9): 0:31.47
+
+ch-1g.pl: inlined israre() into the last rareblock() func
+ time(8): 0:02.94
+ time(9): 0:28.79
+
+ch-1h.pl: inlined perfectsquare() everywhere
+ time(8): 0:02.15
+ time(9): 0:21.20
+
+ch-1i.pl: reintroduced israre() but with two inlined calls to perfectsquare()
+ sweet spot: clear, shows problem structure nicely, plus pretty fast
+ time(8): 0:03.23
+ time(9): 0:32.34
diff --git a/challenge-102/duncan-c-white/README b/challenge-102/duncan-c-white/README
index 32eaf793d3..77c6612c7d 100644
--- a/challenge-102/duncan-c-white/README
+++ b/challenge-102/duncan-c-white/README
@@ -1,104 +1,54 @@
-Task 1: "Pack a Spiral
-Submitted by: Stuart Little
+Task 1: "Rare Numbers
-You are given an array @A of items (integers say, but they can be anything).
+You are given a positive integer $N.
-Your task is to pack that array into an MxN matrix spirally
-counterclockwise, as tightly as possible.
+Write a script to generate all Rare numbers of size $N if exists. Please
+read http://www.shyamsundergupta.com/rare.htm for more information about it.
-'Tightly' means the absolute value |M-N| of the difference has to be as
-small as possible.
+Examples
-Example 1:
-
- Input: @A = (1,2,3,4)
-
- Output:
-
- 4 3
- 1 2
-
-Since the given array is already a 1x4 matrix on its own, but that's
-not as tight as possible. Instead, you'd spiral it counterclockwise into
-
- 4 3
- 1 2
-
-Example 2:
-
- Input: @A = (1..6)
-
- Output:
-
- 6 5 4
- 1 2 3
-
- or
-
- 5 4
- 6 3
- 1 2
-
- Either will do as an answer, because they're equally tight.
-
-Example 3:
-
- Input: @A = (1..12)
-
- Output:
-
- 9 8 7 6
- 10 11 12 5
- 1 2 3 4
-
- or
-
- 8 7 6
- 9 12 5
- 10 11 4
- 1 2 3
+(a) 2 digits: 65
+(b) 6 digits: 621770
+(c) 9 digits: 281089082
"
-My notes: ok, interesting question. First, need to find "tightest" MxN
-where abs(M-N) is minimum, easy. Second, need to build MxN array via
-a "counterclockwise spiral starting at bottom corner". Not trivial, but
-should be relatively easy. Hmmm.. actually, I can't see a particularly
-quick and easy way, I'm sure I'm missing something.
-
+My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No
+iff R + reverse(R) and R - reverse(R) are both perfect squares.
+So: generate and test time.
-Task 2: "Origin-containing Triangle
-Submitted by: Stuart Little
+SEE ALSO OptimizingTask1 for an account of a series of profiling-driven
+optimizations that I made to speed up finding rare numbers. Overall, my
+fastest version ran approx 18 times faster than the original.
-You are given three points in the plane, as a list of six co-ordinates:
-A=(x1,y1), B=(x2,y2) and C=(x3,y3).
-Write a script to find out if the triangle formed by the given three
-co-ordinates contain origin (0,0).
-Print 1 if found otherwise 0.
+Task 2: "Hash-counting String
-Example 1:
+You are given a positive integer $N.
- Input: A=(0,1), B=(1,0) and C=(2,2)
+Write a script to produce Hash-counting string of that length.
- Output: 0 because that triangle does not contain (0,0).
+The definition of a hash-counting string is as follows:
-Example 2:
+- the string consists only of digits 0-9 and hashes, '#'
- Input: A=(1,1), B=(-1,1) and C=(0,-3)
+- there are no two consecutive hashes: '##' does not appear in your string
+- the last character is a hash
+- the number immediately preceding each hash (if it exists) is the position
+ of that hash in the string, with the position being counted up from 1
- Output: 1 because that triangle contains (0,0) in its interior.
+It can be shown that for every positive integer N there is exactly one
+such length-N string.
-Example 3:
+Examples:
- Input: A=(0,1), B=(2,0) and C=(-6,0)
-
- Output: 1 because (0,0) is on the edge connecting B and C.
+ (a) "#" is the counting string of length 1
+ (b) "2#" is the counting string of length 2
+ (c) "#3#" is the string of length 3
+ (d) "#3#5#7#10#" is the string of length 10
+ (e) "2#4#6#8#11#14#" is the string of length 14
"
-My notes: oh, God. Geometry. I hate geometry. Intuitively I've no
-idea how to do this, so need to Google for solutions. Many different
-ways, vectors, cross products, etc. Easiest to understand is from
-www.geeksforgeeks.org/check-whether-a-given-point-lies-inside-a-triangle-or-not/
-and it seems to work (even it compares areas with "=="). Hmm, this seems
-easier than Task 1!
+My notes: ok, weird. Can we directly generate the single
+hash-counting-string of length N? I think we can.. Turns out to be easy.
+
diff --git a/challenge-102/duncan-c-white/perl/ch-1.pl b/challenge-102/duncan-c-white/perl/ch-1.pl
new file mode 100755
index 0000000000..2a7f9f177d
--- /dev/null
+++ b/challenge-102/duncan-c-white/perl/ch-1.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/perl
+#
+# Task 1: "Rare Numbers
+#
+# You are given a positive integer $N.
+#
+# Write a script to generate all Rare numbers of size $N if exists. Please
+# read http://www.shyamsundergupta.com/rare.htm for more information about it.
+#
+# Examples
+#
+# (a) 2 digits: 65
+# (b) 6 digits: 621770
+# (c) 9 digits: 281089082
+# "
+#
+# My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No
+# iff R + reverse(R) and R - reverse(R) are both perfect squares.
+# So: generate and test time. This is the simple version, almost no
+# optimisations.
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: rare-numbers [--debug] N\n"
+ unless GetOptions( "debug" => \$debug )
+ && @ARGV==1;
+
+my $n = shift;
+
+
+#
+# my $isperfect = perfectsquare( $n );
+# Return 1 iff $n is a perfect square, 0 otherwise.
+#
+fun perfectsquare( $n )
+{
+ #return 0 if $n<0;
+ my $s = int(sqrt($n));
+ return $n == $s * $s;
+}
+
+
+#
+# my $israre = israre( $x );
+# Return 1 iff $x is rare, 0 otherwise.
+#
+fun israre( $x )
+{
+ my $r = reverse $x;
+ return 0 if $r > $x; # cos x-r is negative, so not perfect square
+ return perfectsquare( $x + $r ) && perfectsquare( $x - $r );
+}
+
+
+my $from = 10**($n-1);
+my $to = 10**$n - 1;
+say "$from..$to" if $debug;
+
+foreach my $x ($from..$to)
+{
+ say "rare $x" if israre($x);
+}
diff --git a/challenge-102/duncan-c-white/perl/ch-1a.pl b/challenge-102/duncan-c-white/perl/ch-1a.pl
new file mode 100755
index 0000000000..f4cb160526
--- /dev/null
+++ b/challenge-102/duncan-c-white/perl/ch-1a.pl
@@ -0,0 +1,73 @@
+#!/usr/bin/perl
+#
+# Task 1: "Rare Numbers
+#
+# You are given a positive integer $N.
+#
+# Write a script to generate all Rare numbers of size $N if exists. Please
+# read http://www.shyamsundergupta.com/rare.htm for more information about it.
+#
+# Examples
+#
+# (a) 2 digits: 65
+# (b) 6 digits: 621770
+# (c) 9 digits: 281089082
+# "
+#
+# My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No
+# iff R + reverse(R) and R - reverse(R) are both perfect squares.
+# So: generate and test time. This is optimised version 1a: One optimization
+# (from "Properties of rare numbers" section of the webpage): rare numbers
+# start with an even top digit
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: rare-numbers [--debug] N\n"
+ unless GetOptions( "debug" => \$debug )
+ && @ARGV==1;
+
+my $n = shift;
+
+
+#
+# my $isperfect = perfectsquare( $n );
+# Return 1 iff $n is a perfect square, 0 otherwise.
+#
+fun perfectsquare( $n )
+{
+ return 0 if $n<0;
+ my $s = int(sqrt($n));
+ return $n == $s * $s;
+}
+
+
+#
+# my $israre = israre( $x );
+# Return 1 iff $x is rare, 0 otherwise.
+#
+fun israre( $x )
+{
+ my $r = reverse $x;
+ return 0 if $r > $x; # cos x-r is negative, so not perfect square
+ return perfectsquare( $x + $r ) && perfectsquare( $x - $r );
+}
+
+
+my $from = 10**($n-1);
+my $to = 10**$n - 1;
+say "$from..$to" if $debug;
+
+foreach my $x ($from..$to)
+{
+ say "rare $x" if
+ # for n==8, can save 10s (34s->24s) by adding the line:
+ substr("$x",0,1) % 2 == 0 && # even top digit
+ israre($x);
+}
diff --git a/challenge-102/duncan-c-white/perl/ch-1b.pl b/challenge-102/duncan-c-white/perl/ch-1b.pl
new file mode 100755
index 0000000000..52c3a542a1
--- /dev/null
+++ b/challenge-102/duncan-c-white/perl/ch-1b.pl
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+#
+# Task 1: "Rare Numbers
+#
+# You are given a positive integer $N.
+#
+# Write a script to generate all Rare numbers of size $N if exists. Please
+# read http://www.shyamsundergupta.com/rare.htm for more information about it.
+#
+# Examples
+#
+# (a) 2 digits: 65
+# (b) 6 digits: 621770
+# (c) 9 digits: 281089082
+# "
+#
+# My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No
+# iff R + reverse(R) and R - reverse(R) are both perfect squares.
+# So: generate and test time. This is optimised version 1b: Different way of
+# doing 1a's optimization (rare numbers start with even top digit). Skip
+# numbers with odd top digit altogether (so don't even consider 1...., 3....
+# etc! rareblock( 2 ) tests all 2.... numbers etc..
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: rare-numbers [--debug] N\n"
+ unless GetOptions( "debug" => \$debug )
+ && @ARGV==1;
+
+my $n = shift;
+
+
+#
+# my $isperfect = perfectsquare( $n );
+# Return 1 iff $n is a perfect square, 0 otherwise.
+#
+fun perfectsquare( $n )
+{
+ return 0 if $n<0;
+ my $s = int(sqrt($n));
+ return $n == $s * $s;
+}
+
+
+#
+# my $israre = israre( $x );
+# Return 1 iff $x is rare, 0 otherwise.
+#
+fun israre( $x )
+{
+ my $r = reverse $x;
+ return 0 if $r > $x; # cos x-r is negative, so not perfect square
+ return perfectsquare( $x + $r ) && perfectsquare( $x - $r );
+}
+
+
+#
+# rareblock( $m, $f );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# for rare-ness.
+#
+fun rareblock( $m, $f )
+{
+ my $from = $m * $f;
+ my $to = $m * ($f+1) - 1;
+
+ say "$from..$to" if $debug;
+
+ foreach my $x ($from..$to)
+ {
+ say "rare $x" if israre($x);
+ }
+}
+
+
+my $base = 10**($n-1);
+
+rareblock( $base, 2 );
+rareblock( $base, 4 );
+rareblock( $base, 6 );
+rareblock( $base, 8 );
diff --git a/challenge-102/duncan-c-white/perl/ch-1c.pl b/challenge-102/duncan-c-white/perl/ch-1c.pl
new file mode 100755
index 0000000000..84f1a4364f
--- /dev/null
+++ b/challenge-102/duncan-c-white/perl/ch-1c.pl
@@ -0,0 +1,129 @@
+#!/usr/bin/perl
+#
+# Task 1: "Rare Numbers
+#
+# You are given a positive integer $N.
+#
+# Write a script to generate all Rare numbers of size $N if exists. Please
+# read http://www.shyamsundergupta.com/rare.htm for more information about it.
+#
+# Examples
+#
+# (a) 2 digits: 65
+# (b) 6 digits: 621770
+# (c) 9 digits: 281089082
+# "
+#
+# My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No
+# iff R + reverse(R) and R - reverse(R) are both perfect squares.
+# So: generate and test time. This is optimized version 1c: loads more
+# optimizations, most especially the last digit constraints leading to
+# 3 separate rare block functions: rareblock(), rareblock05() and
+# rareblock2378().
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: rare-numbers [--debug] N\n"
+ unless GetOptions( "debug" => \$debug )
+ && @ARGV==1;
+
+my $n = shift;
+
+
+#
+# my $isperfect = perfectsquare( $n );
+# Return 1 iff $n is a perfect square, 0 otherwise.
+#
+fun perfectsquare( $n )
+{
+ my $s = int(sqrt($n));
+ return $n == $s * $s;
+}
+
+
+#
+# my $israre = israre( $x );
+# Return 1 iff $x is rare, 0 otherwise.
+#
+fun israre( $x )
+{
+ my $r = reverse $x;
+ return
+ $x >= $r && # otherwise x-r is negative
+ perfectsquare( $x + $r ) &&
+ perfectsquare( $x - $r );
+}
+
+
+#
+# rareblock( $m, $f, $lastdigit );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is $lastdigit for rare ness.
+#
+fun rareblock( $m, $f, $lastdigit )
+{
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+ foreach my $x ($from..$to)
+ {
+ my $x10 = $x%10;
+ next unless $x10 == $lastdigit;
+ next if $x10 > $f;
+ say "rare $x" if israre($x);
+ }
+}
+
+
+#
+# rareblock05( $m, $f );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is 0 or 5 for rare ness.
+#
+fun rareblock05( $m, $f )
+{
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+ foreach my $x ($from..$to)
+ {
+ next unless $x % 5 == 0;
+ next if $x % 10 > $f;
+ say "rare $x" if israre($x);
+ }
+}
+
+
+#
+# rareblock2378( $m, $f );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is 2, 3, 7 or 8 for rare ness.
+#
+fun rareblock2378( $m, $f )
+{
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+ foreach my $x ($from..$to)
+ {
+ my $y = $x % 10;
+ #next if $y > $f;
+ next unless $y==2 || $y==3 || $y==7 || $y==8;
+ say "rare $x" if israre($x);
+ }
+}
+
+
+my $base = 10**($n-1);
+
+rareblock( $base, 2, 2 );
+rareblock( $base, 4, 0 );
+rareblock05( $base, 6 );
+rareblock2378( $base, 8 );
diff --git a/challenge-102/duncan-c-white/perl/ch-1d.pl b/challenge-102/duncan-c-white/perl/ch-1d.pl
new file mode 100755
index 0000000000..94db736c2d
--- /dev/null
+++ b/challenge-102/duncan-c-white/perl/ch-1d.pl
@@ -0,0 +1,144 @@
+#!/usr/bin/perl
+#
+# Task 1: "Rare Numbers
+#
+# You are given a positive integer $N.
+#
+# Write a script to generate all Rare numbers of size $N if exists. Please
+# read http://www.shyamsundergupta.com/rare.htm for more information about it.
+#
+# Examples
+#
+# (a) 2 digits: 65
+# (b) 6 digits: 621770
+# (c) 9 digits: 281089082
+# "
+#
+# My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No
+# iff R + reverse(R) and R - reverse(R) are both perfect squares.
+# So: generate and test time. This is optimized version 1d: loads more
+# optimizations, most especially each rareblock function generates each
+# possible x and rejected all those where lastdigit(x) wasn't a particular
+# value (or one of a set of values). Instead: loop 1/10th the size
+# and APPEND the required digit..
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: rare-numbers [--debug] N\n"
+ unless GetOptions( "debug" => \$debug )
+ && @ARGV==1;
+
+my $n = shift;
+
+
+#
+# my $isperfect = perfectsquare( $n );
+# Return 1 iff $n is a perfect square, 0 otherwise.
+#
+fun perfectsquare( $n )
+{
+ my $s = int(sqrt($n));
+ return $n == $s * $s ? 1 : 0;
+}
+
+
+#
+# my $israre = israre( $x );
+# Return 1 iff $x is rare, 0 otherwise.
+#
+fun israre( $x )
+{
+ my $r = reverse $x;
+ return
+ $x>=$r && # otherwise x-r is negative, so not perfect square
+ perfectsquare( $x + $r ) &&
+ perfectsquare( $x - $r );
+}
+
+
+#
+# rareblock( $m, $f, $lastdigit );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is $lastdigit for rare ness.
+#
+fun rareblock( $m, $f, $lastdigit )
+{
+ return if $lastdigit > $f; # reverse(y) > y => y not rare
+
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+
+ $from /= 10;
+ $to /= 10;
+
+ foreach my $y ($from..$to)
+ {
+ my $x = $y*10 + $lastdigit;
+ say "rare $x" if israre($x);
+ }
+}
+
+
+#
+# rareblock05( $m, $f );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is 0 or 5 for rare ness.
+#
+fun rareblock05( $m, $f )
+{
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+
+ $from /= 10;
+ $to /= 10;
+
+ foreach my $y ($from..$to)
+ {
+ my $x = $y*10;
+ say "rare $x" if israre($x);
+ $x += 5;
+ say "rare $x" if israre($x);
+ }
+}
+
+
+#
+# rareblock2378( $m, $f );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is 2, 3, 7 or 8 for rare ness.
+#
+fun rareblock2378( $m, $f )
+{
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+ $from /= 10;
+ $to /= 10;
+
+ foreach my $y ($from..$to)
+ {
+ # try appending 2, 3, 7 and 8 and checking for rareness
+ foreach my $d (2,3,7,8)
+ {
+ my $x = $y * 10 + $d;
+ say "rare $x" if israre($x);
+ }
+ }
+}
+
+
+my $base = 10**($n-1);
+
+rareblock( $base, 2, 2 );
+rareblock( $base, 4, 0 );
+rareblock05( $base, 6 );
+rareblock2378( $base, 8 );
diff --git a/challenge-102/duncan-c-white/perl/ch-1e.pl b/challenge-102/duncan-c-white/perl/ch-1e.pl
new file mode 100755
index 0000000000..cc38e0dcbc
--- /dev/null
+++ b/challenge-102/duncan-c-white/perl/ch-1e.pl
@@ -0,0 +1,148 @@
+#!/usr/bin/perl
+#
+# Task 1: "Rare Numbers
+#
+# You are given a positive integer $N.
+#
+# Write a script to generate all Rare numbers of size $N if exists. Please
+# read http://www.shyamsundergupta.com/rare.htm for more information about it.
+#
+# Examples
+#
+# (a) 2 digits: 65
+# (b) 6 digits: 621770
+# (c) 9 digits: 281089082
+# "
+#
+# My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No
+# iff R + reverse(R) and R - reverse(R) are both perfect squares.
+# So: generate and test time. This is optimized version 1e:
+# I inlined israre() into rareblock2378(), the slowest one.
+# saves about 0.5 seconds.
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: rare-numbers [--debug] N\n"
+ unless GetOptions( "debug" => \$debug )
+ && @ARGV==1;
+
+my $n = shift;
+
+
+#
+# my $isperfect = perfectsquare( $n );
+# Return 1 iff $n is a perfect square, 0 otherwise.
+#
+fun perfectsquare( $n )
+{
+ my $s = int(sqrt($n));
+ return $n == $s * $s ? 1 : 0;
+}
+
+
+#
+# my $israre = israre( $x );
+# Return 1 iff $x is rare, 0 otherwise.
+#
+fun israre( $x )
+{
+ my $r = reverse $x;
+ return
+ $x>=$r && # otherwise x-r is negative, so not perfect square
+ perfectsquare( $x + $r ) &&
+ perfectsquare( $x - $r );
+}
+
+
+#
+# rareblock( $m, $f, $lastdigit );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is $lastdigit for rare ness.
+#
+fun rareblock( $m, $f, $lastdigit )
+{
+ return if $lastdigit > $f; # reverse(y) > y => y not rare
+
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+
+ $from /= 10;
+ $to /= 10;
+
+ foreach my $y ($from..$to)
+ {
+ my $x = $y*10 + $lastdigit;
+ say "rare $x" if israre($x);
+ }
+}
+
+
+#
+# rareblock05( $m, $f );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is 0 or 5 for rare ness.
+#
+fun rareblock05( $m, $f )
+{
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+
+ $from /= 10;
+ $to /= 10;
+
+ foreach my $y ($from..$to)
+ {
+ my $x = $y*10;
+ say "rare $x" if israre($x);
+ $x += 5;
+ say "rare $x" if israre($x);
+ }
+}
+
+
+#
+# rareblock2378( $m, $f );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is 2, 3, 7 or 8 for rare ness.
+#
+fun rareblock2378( $m, $f )
+{
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+ $from /= 10;
+ $to /= 10;
+
+ foreach my $y ($from..$to)
+ {
+ # try appending 2, 3, 7 and 8 and checking for rareness
+ foreach my $d (2,3,7,8)
+ {
+ my $x = $y * 10 + $d;
+
+ # inline israre() into: say "rare $x" if israre($x);
+ my $r = reverse $x;
+ say "rare $x" if
+ $x>=$r && # otherwise x-r is negative
+ perfectsquare( $x + $r ) &&
+ perfectsquare( $x - $r );
+ }
+ }
+}
+
+
+my $base = 10**($n-1);
+
+rareblock( $base, 2, 2 );
+rareblock( $base, 4, 0 );
+rareblock05( $base, 6 );
+rareblock2378( $base, 8 );
diff --git a/challenge-102/duncan-c-white/perl/ch-1f.pl b/challenge-102/duncan-c-white/perl/ch-1f.pl
new file mode 100755
index 0000000000..0f6b959aff
--- /dev/null
+++ b/challenge-102/duncan-c-white/perl/ch-1f.pl
@@ -0,0 +1,159 @@
+#!/usr/bin/perl
+#
+# Task 1: "Rare Numbers
+#
+# You are given a positive integer $N.
+#
+# Write a script to generate all Rare numbers of size $N if exists. Please
+# read http://www.shyamsundergupta.com/rare.htm for more information about it.
+#
+# Examples
+#
+# (a) 2 digits: 65
+# (b) 6 digits: 621770
+# (c) 9 digits: 281089082
+# "
+#
+# My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No
+# iff R + reverse(R) and R - reverse(R) are both perfect squares.
+# So: generate and test time. This is optimized version 1f:
+# inlined israre() into rareblock05().
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: rare-numbers [--debug] N\n"
+ unless GetOptions( "debug" => \$debug )
+ && @ARGV==1;
+
+my $n = shift;
+
+
+#
+# my $isperfect = perfectsquare( $n );
+# Return 1 iff $n is a perfect square, 0 otherwise.
+#
+fun perfectsquare( $n )
+{
+ my $s = int(sqrt($n));
+ return $n == $s * $s ? 1 : 0;
+}
+
+
+#
+# my $israre = israre( $x );
+# Return 1 iff $x is rare, 0 otherwise.
+#
+fun israre( $x )
+{
+ my $r = reverse $x;
+ return
+ $x>=$r && # otherwise x-r is negative, so not perfect square
+ perfectsquare( $x + $r ) &&
+ perfectsquare( $x - $r );
+}
+
+
+#
+# rareblock( $m, $f, $lastdigit );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is $lastdigit for rare ness.
+#
+fun rareblock( $m, $f, $lastdigit )
+{
+ return if $lastdigit > $f; # reverse(y) > y => y not rare
+
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+
+ $from /= 10;
+ $to /= 10;
+
+ foreach my $y ($from..$to)
+ {
+ my $x = $y*10 + $lastdigit;
+ say "rare $x" if israre($x);
+ }
+}
+
+
+#
+# rareblock05( $m, $f );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is 0 or 5 for rare ness.
+#
+fun rareblock05( $m, $f )
+{
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+
+ $from /= 10;
+ $to /= 10;
+
+ foreach my $y ($from..$to)
+ {
+ my $x = $y*10;
+
+ # inline israre() into: say "rare $x" if israre($x);
+ my $r = reverse $x;
+ say "rare $x" if
+ $x>=$r && # otherwise x-r is negative
+ perfectsquare( $x + $r ) &&
+ perfectsquare( $x - $r );
+ $x += 5;
+
+ # inline israre() into: say "rare $x" if israre($x);
+ $r = reverse $x;
+ say "rare $x" if
+ $x>=$r && # otherwise x-r is negative
+ perfectsquare( $x + $r ) &&
+ perfectsquare( $x - $r );
+ }
+}
+
+
+#
+# rareblock2378( $m, $f );
+# Check all numbers in range $f * $m .. ($f+1) * $m - 1
+# whose last digit is 2, 3, 7 or 8 for rare ness.
+#
+fun rareblock2378( $m, $f )
+{
+ my $from = $f * $m;
+ my $to = ($f+1) * $m - 1;
+ say "$from..$to" if $debug;
+ $from /= 10;
+ $to /= 10;
+
+ foreach my $y ($from..$to)
+ {
+ # try appending 2, 3, 7 and 8 and checking for rareness
+ foreach my $d (2,3,7,8)
+ {
+ my $x = $y * 10 + $d;
+
+ # inline israre() into: say "rare $x" if israre($x);
+ my $r = reverse $x;
+ say "rare $x" if
+ $x>=$r && # otherwise x-r is negative
+ perfectsquare( $x + $r ) &&
+ perfectsquare( $x - $r );
+ }
+ }
+}
+
+
+my $base = 10**($n-1);
+
+rareblock( $base, 2, 2 );
+rareblock( $base, 4, 0 );
+rareblock05( $base, 6 );
+rareblock2378( $base, 8 );
diff --git a/challenge-102/duncan-c-white/perl/ch-1g.pl b/challenge-102/duncan-c-white/perl/ch-1g.pl
new file mode 100755
index 0000000000..a1be0f5dac
--- /dev/null
+++ b/challenge-102/duncan-c-white/perl/ch-1g.pl
@@ -0,0 +1,165 @@
+#!/usr/bin/perl
+#
+# Task 1: "Rare Numbers
+#
+# You are given a positive integer $N.
+#
+# Write a script to generate all Rare numbers of size $N if exists. Please
+# read http://www.shyamsundergupta.com/rare.htm for more information about it.
+#
+# Examples
+#
+# (a) 2 digits: 65
+# (b) 6 digits: 621770
+# (c) 9 digits: 281089082
+# "
+#
+# My notes: ok, interesting question. In summary: R (a +ve no) is a Rare No
+# iff R + reverse(R) and R - reverse(R) are both perfect squares.
+# So: generate and test time. This is optimized version 1g:
+# inlined israre() into rareblock(), and commented out israre().
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: rare-numbers [--debug] N\n"
+ unless GetOptions( "debug" => \$debug )
+ && @ARGV==1;
+
+my $n = shift;
+
+
+#
+# my $isperfect = perfectsquare( $n );
+# Return 1 iff $n is a perfect square, 0 otherwise.
+#
+fun perfectsquare( $n )
+{
+ my $s = int(sqrt($n));
+ return $n == $s * $s ? 1 : 0;
+}
+
+
+#
+# my $israre = israre( $x );
+# Return 1 iff $x is rare, 0 otherwise.
+#
+#fun israre( $x )
+#{
+# my $r = reverse $x;
+# return
+# $x>=$r && # otherwise x-r is negative, so not perfect square