-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_fib-tzn.pl
297 lines (222 loc) · 5.57 KB
/
test_fib-tzn.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#!/usr/bin/perl
# Daniel "Trizen" Șuteu
# Date: 02 August 2017
# Edit: 30 November 2019
# https://github.com/trizen
# A very strong primality test (v4), inspired by Fermat's Little Theorem and the AKS test.
# Known counter-example to the weak version:
# 83143326880201568435669099604552661
# When combined with a strong Fermat base-2 primality test, no counter-examples are known.
use 5.020;
use strict;
use warnings;
no warnings 'recursion';
use ntheory qw(is_prime powmod random_prime urandomm is_strong_pseudoprime);
use experimental qw(signatures);
sub mulmod {
my ($n, $k, $mod) = @_;
ref($mod)
? ((($n % $mod) * $k) % $mod)
: ntheory::mulmod($n, $k, $mod);
}
#~ Three counter-examples only:
#~ [1, 1, -503, 13],
#~ [2, 1, 233, -103],
#~ [3, 1, 107, -857],
#~ [4, 1, -29, 359],
#~ [5, 1, -373, -2],
# One large counter-example:
#~ [1, 1, 617, -127],
#~ [2, 1, -647, 163],
#~ [3, 1, -967, 953],
#~ [4, 1, -263, -691],
#~ [5, 1, -743, 241],
# Two large counter-examples:
#~ [1, 1, 17, -547],
#~ [2, 1, -137, 359],
#~ [3, 1, 157, -31],
#~ [4, 1, -7, -467],
#~ [5, 1, 947, 373],
# Two large counter-examples:
#~ [1, 1, -421, -149],
#~ [2, 1, 647, 223],
#~ [3, 1, -859, -61],
#~ [4, 1, -691, 149],
#~ [5, 1, 359, 397],
# One very large counter-example:
#~ [1, 1, 271, 191],
#~ [2, 1, -983, -911],
#~ [3, 1, 149, 83],
#~ [4, 1, -353, -829],
#~ [5, 1, -461, -491],
#~ Original:
#~ [1, 1, 4, 5],
#~ [2, 1, 2, -93],
#~ [3, 1, -11, 19],
#~ [4, 1, 23, -101],
#~ [5, 1, -23, -29],
#my @list = ([1, 1, 4, 5]);
my @list;
foreach my $k (1 .. 5) {
push @list, [$k, 1, (-1)**urandomm(2) * random_prime(1e3), (-1)**urandomm(2) * random_prime(1e3)];
}
say "";
foreach my $entry (@list) {
local $" = ", ";
say "[@{$entry}],";
}
say "";
#
## Creates the `modulo_test*` subroutines.
#
foreach my $g (
#@list
[1, 1, 271, 191],
[2, 1, -983, -911],
[3, 1, 149, 83],
[4, 1, -353, -829],
[5, 1, -461, -491],
) {
no strict 'refs';
*{__PACKAGE__ . '::' . 'modulo_test' . $g->[0]} = sub ($n, $mod) {
my %cache;
sub ($n) {
$n == 0 && return $g->[1];
$n == 1 && return $g->[2];
if (exists $cache{$n}) {
return $cache{$n};
}
my $k = $n >> 1;
#<<<
$cache{$n} = (
$n % 2 == 0
? (mulmod(__SUB__->($k), __SUB__->($k), $mod) - mulmod(mulmod($g->[3], __SUB__->($k-1), $mod), __SUB__->($k-1), $mod)) % $mod
: (mulmod(__SUB__->($k), __SUB__->($k+1), $mod) - mulmod(mulmod($g->[3], __SUB__->($k-1), $mod), __SUB__->($k), $mod)) % $mod
);
#>>>
}
->($n - 1);
};
}
sub is_probably_prime($n) {
$n <= 1 && return 0;
foreach my $p (2, 3, 5, 7, 11, 17, 19, 23, 43, 79, 181, 1151, 6607, 14057) {
if ($n == $p) {
return 1;
}
}
is_strong_pseudoprime($n, 2) || return 0;
my $r1 = modulo_test1($n, $n);
#(($n % 4 == 3) ? ($r1 == $n-1) : ($r1 == 1)) or return 0;
($r1 == 1) or ($r1 == $n - 1) or return 0;
my $r2 = modulo_test2($n, $n);
($r2 == 1) or ($r2 == $n - 1) or return 0;
my $r3 = modulo_test3($n, $n);
($r3 == 1) or ($r3 == $n - 1) or return 0;
my $r4 = modulo_test4($n, $n);
($r4 == 1) or ($r4 == $n - 1) or return 0;
my $r5 = modulo_test5($n, $n);
($r5 == 1) or ($r5 == $n - 1) or return 0;
}
say ":: Testing small numbers...";
foreach my $n (1 .. 1000) {
if (is_probably_prime($n)) {
if (not is_prime($n)) {
say "Counter-example: $n";
}
}
elsif (is_prime($n)) {
say "Missed a prime: $n";
}
}
say ":: Testing large composites...";
use Math::GMPz;
foreach my $n (
sort { $a <=> $b }
map { Math::GMPz->new($_) }
qw(
1027334881
208969201
260245228321
359505020161
30304281601
30680814529
373523673601
377555665201
120871699201
83143326880201568435669099604552661
5902446537594114481
13938032454972692851
176639720841995571276421
8273838687436582743601
5057462719726630861278061
1543272305769601
25214682289344970125061
594984649904873169943321
986308202881
11674038748806721
9049836479041
52451136349921
122570307044209
5151560903656250449
10021721082510591541
64296323802158793601
99270776480238208441
1574601601
3711456001
58891472641
860293156801
9173203300801
774558925921
40395626998273
27192146983681
539956339242241
1428360123889921
360570785364001
26857102685439041
9599057610241
598963244103226621
6615533841841
512617191379440810961
32334452526861101
39671149333495681
934216077330841537
9610653088766378881
74820786179329
227291059980601
7954028515441
1738925896140049
23562188821
3226057632001
6477654268801
46843949912257
5539588182853381
1352358402913
443372888629441
921259517831137
842526563598720001
2380296518909971201
3188618003602886401
843347325974413121
883253991797747461
229386598589242644481
3104745148145953757281
407333160866845741098841
1107852524534142074314801
)
) {
say "Known counter-example: $n" if is_probably_prime(Math::GMPz->new("$n"));
}
say ":: Pre-test done...";
while (<>) {
next if /^\h*#/;
/\S/ or next;
my $n = (split(' ', $_))[-1];
$n || next;
if ($n >= ((~0) >> 1)) {
$n = Math::GMPz->new("$n");
}
if (is_probably_prime($n)) {
warn "New counter-example: $n\n";
}
}