-
Notifications
You must be signed in to change notification settings - Fork 33
/
pisano_periods_efficient_algorithm.pl
executable file
·52 lines (37 loc) · 1.41 KB
/
pisano_periods_efficient_algorithm.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/usr/bin/perl
# Daniel "Trizen" Șuteu
# Date: 22 September 2018
# https://github.com/trizen
# Efficient algorithm for computing the Pisano period: period of Fibonacci
# numbers mod `n`, assuming that the factorization of `n` can be computed.
# See also:
# https://oeis.org/A001175
# https://oeis.org/A053031
# https://en.wikipedia.org/wiki/Pisano_period
# https://en.wikipedia.org/wiki/Wall%E2%80%93Sun%E2%80%93Sun_prime
use 5.020;
use strict;
use warnings;
use experimental qw(signatures);
use List::Util qw(first);
use ntheory qw(divisors factor_exp);
use Math::AnyNum qw(:overload kronecker fibmod lcm factorial);
sub pisano_period_pp ($p, $k = 1) {
$p**($k - 1) * first { fibmod($_, $p) == 0 } divisors($p - kronecker($p, 5));
}
sub pisano_period($n) {
return 0 if ($n <= 0);
return 1 if ($n == 1);
my $d = lcm(map { pisano_period_pp($_->[0], $_->[1]) } factor_exp($n));
foreach my $k (0 .. 2) {
my $t = $d << $k;
if ((fibmod($t, $n) == 0) and (fibmod($t + 1, $n) == 1)) {
return $t;
}
}
die "Conjecture disproved for n=$n";
}
say pisano_period(factorial(10)); #=> 86400
say pisano_period(factorial(30)); #=> 204996473853050880000000
say pisano_period(2**128 + 1); #=> 28356863910078205764000346543980814080
say join(', ', map { pisano_period($_) } 1 .. 20); #=> 1, 3, 8, 6, 20, 24, 16, 12, 24, 60, 10, 24, 28, 48, 40, 24, 36, 24, 18, 60