freeCodeCamp/curriculum/challenges/english/08-coding-interview-prep/rosetta-code/factors-of-a-mersenne-numbe...

6.2 KiB

title id challengeType
Factors of a Mersenne number 598eea87e5cf4b116c3ff81a 5

Description

A Mersenne number is a number in the form of 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 1

Since 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 primality 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.

Task:

Using the above method find a factor of 2929-1 (aka M929)

Related tasks: count in factors prime decomposition factors of an integer Sieve of Eratosthenes primality by trial division trial factoring of a Mersenne number partition an integer X into N primes sequence of primes by Trial Division Computers in 1948: 2¹²⁷-1

Instructions

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;
}