with Raku

This is my response to the Perl Weekly Challenge #167.

Write a script to find out first *A circular prime is a prime number with the property that the number generated at each
intermediate step when cyclically permuting its (base 10) digits will also be prime.*

0utput:

`10 circular primes`

having at least 3
digits (base 10).
Please checkout wikipedia for more information.

0utput:

113, 197, 199, 337, 1193, 3779, 11939, 19937, 193939, 199933

113 is a circular prime because it is a prime, as is 131 and 311 (the «cyclically permuting» versions). Note that 131 and 311 are not part of the sequence, as they are permutations of the original one (with the lowest value).

File: circular-prime#! /usr/bin/env raku
unit sub MAIN (Int $c where $c > 1 = 10); # [1]
my $cp := (100 .. *).grep({ is-circular($_) }); # [2]
sub is-circular ($number) # [4]
{
state %seen; # [5]
return if %seen{$number}; %seen{$number} = True; # [5]
return unless $number ~~ /^<[1379]>+$/; # [6]
return unless $number.is-prime; # [7]
my @digits = $number.comb; # [8]
for (1 .. @digits.elems -1) -> $skew # [9]
{
my $rotated = @digits.rotate($skew).join; # [10]
return if %seen{$rotated}; # [11]
return unless $rotated.is-prime; # [12]
}
return True; # [13]
}
say $cp[^$c].join(", "); # [3]

[1] The number of circular primes to print, if the default 10 does not suit you.

[2] A sequence of the circular primes, using a cutsom procedure to sort out the member values.

[3] Print the first `$c`

values from the sequence, with commas between them.

[4] Is the current number a circular prime?.

[5] Using a state variable to store the visited values (i.e. 113, so that we can get rid of 131 and 311 later on).

See
docs.raku.org/syntax/state for
more information about the variable declarator `state`

.

[6] The number cannot have any other digits that 1, 3, 7 and 9 (any amount of them).

[7] It has to be a prime.

[8] Get the individual digits (as rotation is easier on a list than on a string).

[9] As many times as necessary to get all the rotational variants of the number.

[10] Do the rotation (with `rotate`

).

See
docs.raku.org/routine/rotate for
more information about `rotate`

[11] Return (with an implicit False) if we have seen the number before (as described in [5]).

[12] Return (with an implicit False) if it is not a prime.

[13] It did not fail, tahn we have succeeded - and it is a circular prime.

Running it:

$ ./circular-prime
113, 197, 199, 337, 1193, 3779, 11939, 19937, 193939, 199933
$ ./circular-prime 6
113, 197, 199, 337, 1193, 3779

We should, perhaps, show this very fast version:

File: circular-prime-stupid#! /usr/bin/env raku
say "113, 197, 199, 337, 1193, 3779, 11939, 19937, 193939, 199933";

Does it satisfy the «find out» clause?

Probably not.

(But it is easy to translate this program to virtually any other programming language.)

Implement subroutine `gamma()`

using the
Lanczos approximation method.

print gamma(3); # 1.99
print gamma(5); # 24
print gamma(7); # 719.99

We do not *actually* have to implement
anything, as the GNU Scientific
Library has done so for us. This library is available in Raku as «Math::Libgsl::Function»,
using the Nativecall interface.

#! /usr/bin/env raku
use Math::Libgsl::Function :ALL; # [1]
unit sub MAIN (Int :u(:$upto) where $upto > 0 = 10); # [2]
say "$_ -> { gamma($_) }" for 1 .. $upto; # [3]

[1] Load the library, and import everything (`:ALL`

).

[2] Print the values from 1 up to 10, unless another upto value is specified.

[3] GNU does the job for us.

Running it:

$ ./gamma-function
1 -> 1
2 -> 1
3 -> 2
4 -> 6
5 -> 24
6 -> 120
7 -> 720
8 -> 5040
9 -> 40320
10 -> 362880

We did not get the *exact* same result as specified in the challenge (for 3 and 7),
but I assume that Raku is correct - as it has much better rounding error prevention than
Perl.

$ ./gamma-function -u=20
1 -> 1
2 -> 1
3 -> 2
4 -> 6
5 -> 24
6 -> 120
7 -> 720
8 -> 5040
9 -> 40320
10 -> 362880
11 -> 3628800
12 -> 39916800
13 -> 479001600
14 -> 6227020800
15 -> 87178291200
16 -> 1307674368000
17 -> 20922789888000
18 -> 355687428096000
19 -> 6.402373705728e+15
20 -> 1.21645100408832e+17

Very large values do give rounding errors (using the e+ Scientific notation), but we can avoid that by telling Raku to stick with integers.

File: gamma-function-int```
#! /usr/bin/env raku
use Math::Libgsl::Function :ALL;
unit sub MAIN (Int :u(:$upto) where $upto > 0 = 10);
say "$_ -> { gamma($_).Int }" for 1 .. $upto; # [1]
```

[1] Coerce the value to integer with `.Int`

.

See
docs.raku.org/routine/Int
for more information about the `Int`

coercer.

Running it:

$ ./gamma-function-int -u=20
1 -> 1
2 -> 1
3 -> 2
4 -> 6
5 -> 24
6 -> 120
7 -> 720
8 -> 5040
9 -> 40320
10 -> 362880
11 -> 3628800
12 -> 39916800
13 -> 479001600
14 -> 6227020800
15 -> 87178291200
16 -> 1307674368000
17 -> 20922789888000
18 -> 355687428096000
19 -> 6402373705728000
20 -> 121645100408832000

And that's it.