5.2 KiB
5.2 KiB
title | id | challengeType |
---|---|---|
Factors of a Mersenne number | 598eea87e5cf4b116c3ff81a | 5 |
Description
2P-1
.
If P
is prime, the Mersenne number may be a Mersenne prime. (If P
is not prime, the Mersenne number is also not prime.)
In the search for Mersenne prime numbers it is advantageous to eliminate exponents by finding a small factor before starting a, potentially lengthy, Lucas-Lehmer test.
There are very efficient algorithms for determining if a number divides 2P-1
(or equivalently, if 2P mod (the number) = 1
).
Some languages already have built-in implementations of this exponent-and-mod operation (called modPow or similar).
The following is how to implement this modPow yourself:
For example, let's compute 223 mod 47
.
Convert the exponent 23 to binary, you get 10111. Starting with square = 1
, repeatedly square it.
Remove the top bit of the exponent, and if it's 1 multiply square
by the base of the exponentiation (2), then compute square modulo 47
.
Use the result of the modulo from the last step as the initial value of square
in the next step:
Remove Optional square top bit multiply by 2 mod 47 ------------ ------- ------------- ------ 1*1 = 1 1 0111 1*2 = 2 2 2*2 = 4 0 111 no 4 4*4 = 16 1 11 16*2 = 32 32 32*32 = 1024 1 1 1024*2 = 2048 27 27*27 = 729 1 729*2 = 1458 1Since
223 mod 47 = 1
, 47 is a factor of 2P-1
.
(To see this, subtract 1 from both sides: 223-1 = 0 mod 47
.)
Since we've shown that 47 is a factor, 223-1
is not prime.
Further properties of Mersenne numbers allow us to refine the process even more.
Any factor q
of 2P-1
must be of the form 2kP+1
, k
being a positive integer or zero. Furthermore, q
must be 1
or 7 mod 8
.
Finally any potential factor q
must be prime.
As in other trial division algorithms, the algorithm stops when 2kP+1 > sqrt(N)
.These primarily tests only work on Mersenne numbers where P
is prime. For example, M4=15
yields no factors using these techniques, but factors into 3 and 5, neither of which fit 2kP+1
.
Instructions
2929-1
(aka M929)
Tests
tests:
- text: <code>check_mersenne</code> is a function.
testString: assert(typeof check_mersenne === 'function', '<code>check_mersenne</code> is a function.');
- text: <code>check_mersenne(3)</code> should return a string.
testString: assert(typeof check_mersenne(3) == 'string', '<code>check_mersenne(3)</code> should return a string.');
- text: <code>check_mersenne(3)</code> should return "M3 = 2^3-1 is prime".
testString: assert.equal(check_mersenne(3),"M3 = 2^3-1 is prime",'<code>check_mersenne(3)</code> should return "M3 = 2^3-1 is prime".');
- text: <code>check_mersenne(23)</code> should return "M23 = 2^23-1 is composite with factor 47".
testString: assert.equal(check_mersenne(23),"M23 = 2^23-1 is composite with factor 47",'<code>check_mersenne(23)</code> should return "M23 = 2^23-1 is composite with factor 47".');
- text: <code>check_mersenne(929)</code> should return "M929 = 2^929-1 is composite with factor 13007
testString: assert.equal(check_mersenne(929),"M929 = 2^929-1 is composite with factor 13007",'<code>check_mersenne(929)</code> should return "M929 = 2^929-1 is composite with factor 13007');
Challenge Seed
function check_mersenne(p) {
// Good luck!
}
Solution
function check_mersenne(p){
function isPrime(value){
for (let i=2; i < value; i++){
if (value % i == 0){
return false;
}
if (value % i != 0){
return true;
}
}
}
function trial_factor(base, exp, mod){
let square, bits;
square = 1;
bits = exp.toString(2).split('');
for (let i=0,ln=bits.length; i<ln; i++){
square = Math.pow(square, 2) * (bits[i] == 1 ? base : 1) % mod;
}
return (square == 1);
}
function mersenne_factor(p){
let limit, k, q;
limit = Math.sqrt(Math.pow(2,p) - 1);
k = 1;
while ((2*k*p - 1) < limit){
q = 2*k*p + 1;
if (isPrime(q) && (q % 8 == 1 || q % 8 == 7) && trial_factor(2,p,q)){
return q; // q is a factor of 2**p-1
}
k++;
}
return null;
}
let f, result;
result="M"+p+" = 2^"+p+"-1 is ";
f = mersenne_factor(p);
result+=f == null ? "prime" : "composite with factor "+f;
return result;
}