Trying to write Pari code to solve the above question.
-
What problems are you running into? Presumably you don't want us to simply write the code for you? – Mark Dickinson May 24 '20 at 11:13
1 Answers
I've got no experience in using Pari, but here's some useful advice:
n
is Carmichael if and only if it is composite and, for all a
with 1 < a < n
which are relatively prime to n
, the congruence a^(n-1) = 1 (mod n)
holds. To use this definition directly, you need:
1) An efficient way to test if a
and n
are relatively prime
2) An efficient way to compute a^(n-1) (mod n)
For the first -- use the Euclidean algorithm for greatest common divisors. It is most efficiently computed in a loop, but can also be defined via the simple recurrence gcd(a,b) = gcd(b,a%b)
with basis gcd(a,0) = a
. In C this is just:
unsigned int gcd(unsigned int a, unsigned int b){
return b == 0? a : gcd(b, a%b);
}
For the second point -- almost the worst possible thing you can do when computing a^k (mod n)
is to first compute a^k
via repeated multiplication and to then mod the result by n
. Instead -- use exponentiation by squaring, taking the remainder (mod n
) at intermediate stages. It is a divide-and-conquer algorithm based on the observation that e.g. a^10 = (a^5)^2
and a^11 = (a^5)^2 * a
. A simple C implementation is:
unsigned int modexp(unsigned int a, unsigned int p, unsigned int n){
unsigned long long b;
switch(p){
case 0:
return 1;
case 1:
return a%n;
default:
b = modexp(a,p/2,n);
b = (b*b) % n;
if(p%2 == 1) b = (b*a) % n;
return b;
}
}
Note the use of unsigned long long
to guard against overflow in the calculation of b*b
.
To test if n
is Carmichael, you might as well first test if n
is even and return 0
in that case. Otherwise, step through numbers, a
, in the range 2
to n-1
. First check if gcd(a,n) == 1
Note that if n
is composite then you must have at least one a
before you reach the square root of n
with gcd(a,n) > 1
). Keep a Boolean flag which keeps track of whether or not such an a
has been encountered and if you exceed the square root without finding such an a
, return 0
. For those a
with gcd(a,n) == 1
, compute the modular exponentiation a^(n-1) (mod n)
. If this is ever different from 1, return 0
. If your loop finishes checking all a
below n
without returning 0
, then the number is Carmichael, so return 1. An implementation is:
int is_carmichael(unsigned int n){
int a,s;
int factor_found = 0;
if (n%2 == 0) return 0;
//else:
s = sqrt(n);
a = 2;
while(a < n){
if(a > s && !factor_found){
return 0;
}
if(gcd(a,n) > 1){
factor_found = 1;
}
else{
if(modexp(a,n-1,n) != 1){
return 0;
}
}
a++;
}
return 1; //anything that survives to here is a carmichael
}
A simple driver program:
int main(void){
unsigned int n;
for(n = 2; n < 100000; n ++){
if(is_carmichael(n)) printf("%u\n",n);
}
return 0;
}
output:
C:\Programs>gcc carmichael.c
C:\Programs>a
561
1105
1729
2465
2821
6601
8911
10585
15841
29341
41041
46657
52633
62745
63973
75361
This only takes about 2 seconds to run and matches the initial part of this list.
This is probably a somewhat practical method for checking if numbers up to a million or so are Carmichael numbers. For larger numbers, you should probably get yourself a good factoring algorithm and use Korseldt's criterion as described in the Wikipedia entry on Carmichael numbers.

- 1,044
- 9
- 20