I’ve been doing the Weekly
Challenges. The
latest
involved date calculations and number theory. (Note that this is
open until 31 July 2022.)
Task 1: Last Sunday
Write a script to list last sunday of every month in the given year.
Date calculations are one of those things like cryptography with all
sorts of traps for the unwary, so I've used system libraries wherever
possible. For Perl I used the good library rather than the older
built-ins:
use DateTime;
sub lastsunday($year) {
my @o;
foreach my $month (1..12) {
my $dt = DateTime->last_day_of_month(year => $year,
month => $month);
my $dl = $dt->day_of_week();
if ($dl != 7) {
$dt->subtract(days => $dl);
}
push @o,$dt->strftime('%Y-%m-%d');
}
return \@o;
}
Raku's built-in Date
class also offers a last-date-in-month: it
works slightly differently, but the basic idea is the same. For the
other languages, which don't have this, I bodged it by going back a
day from the first day of the next month, as in this Kotlin (which
uses the LocalDate and Period libraries from Java):
fun lastsunday(year0: Int): List<String> {
var year = year0
var o = ArrayList<String>()
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
for (month0 in 2..13) {
var month = month0
if (month0 == 13) {
year += 1
month -= 12
}
var dt = LocalDate.of(year,month,1).minusDays(1)
val dl = dt.dayOfWeek.getValue()
if (dl < 7) {
dt = dt.minusDays(dl.toLong())
}
o.add(dt.format(formatter))
}
return o
}
Some languages give a Sunday as 0 in their day-of-week function, which
lets me remove the test on dl
.
Lua can convert date-times back and forth to an internal
representation, but can't do much with them: on Unix it uses seconds
since the epoch as that representation, but there's no guarantee of
the size or base of the unit elsewhere, so I'd have had to write
day-of-the-week code from scratch. So I didn't write a Lua version of
this.
Of course, PostScript has even less date support, but as it turns out
I'd already written a Julian day number conversion library (originally
for challenge #132), which does the job nicely here. (I suspect I
should write a sprintf
/ strftime
-style formatting function.)
Task 2: Perfect Totient Numbers
Write a script to generate first 20 Perfect Totient Numbers.
Given the speed of modern languages and machines, I didn't bother with
much optimisation. It would be faster (though of course it would use
more memory) to keep a map of iterated totient values to avoid
repeated calculation; but it was hot and I felt little enthusiasm for
writing that across multiple languages.
Here's the Python for the Euler totient (I've written gcd
functions
before for languages that need them):
def eulertotient(n):
return sum(1 for k in range(1,n+1) if gcd(n,k) == 1)
Then the iterated version (with an optimisation you should remove if
you actually want the iterated totient value for some reason - p > n0
implies that p
is not equal to n0
and since that's all we care
about we needn't calculate it further).
def iteratedtotient(n0):
p = 0
n = n0
while True:
n = eulertotient(n)
p += n
if n == 1:
break
if p > n0:
break
return p
Finally the list-building top-level function:
def perfecttotient(ct):
o = []
n = 1
while len(o) < ct:
n += 1
if iteratedtotient(n) == n:
o.append(n)
return o
The algorithm in other languages is basically the same.
Full code on
github.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.