5.8 KiB
id | title | challengeType | forumTopicId | dashedName |
---|---|---|---|---|
598eea87e5cf4b116c3ff81a | Фактори числа Мерсенна | 5 | 302264 | factors-of-a-mersenne-number |
--description--
Число Мерсенна - це число у вигляді 2P-1
.
Якщо P
є простим, то число Мерсенна може бути простим числом Мерсенна. (Якщо P
не є простим, число Мерсенна також не є простим.)
У пошуку простих чисел Мерсенна вигідно усунути експоненти, знайшовши невеликий фактор перед початком, потенційно довжину, [тест Лукас-Лемер](https://rosettacode.org/wiki/Lucas-Lehmer test "Lucas-Lehmer test").
Існують дуже ефективні алгоритми визначення, чи число ділиться на 2P-1
(або відповідно, якщо 2P мод (число) = 1
).
Деякі мови вже мають вбудовані реалізації цієї операції експонента і моду (так званої modPow або подібні).
Нижче зрозуміло, як реалізувати цей modPow самостійно:
Наприклад, обчислимо 223 мод 47
.
Перетворимо експонент 23 у двійковий, ви отримаєте 10111. Починаючи з квадрат = 1
, повторно піднести до квадрату.
Видаліть верхній біт степеня, і якщо його 1 помножити на square
на основу піднесення до степеня (2), потім обчислити квадрат модуль 47
.
Використовуйте результат модуля від останнього кроку як початкове значення square
в наступному кроці:
Видалити необов'язковий квадрат, помножений на 2 мод 47 ------------ ------- --- 1*1 = 1 0111 1*2 = 2 2*2 = 4 0 111 без 4 4*4 16 = 1 11 16*2 = 32 32*32 4*32 1024 1 1024*2 = 2048 27*2 = 7291 *2 = 1458 1*2 = 1458
Починаючи з 2 мод 47 = 1
, 47 є фактором 2P-1
.
(Щоб побачити це, відніміть 1 від обох сторін: 223-1 = 0 мод 47
)
Оскільки ми показали, що 47 це фактор, 223-1
не є простим.
Подальші властивості Мерсенного числа дозволяють нам ще більше вдосконалити процес.
Будь-який фактор, q
з 2P-1
повинен бути у вигляді 2kP+1
, k
це додатне ціле число або нуль. Крім того, q
має бути 1
або 7 mod 8
.
Нарешті будь-який потенційний множник q
має бути [prime](https://rosettacode.org/wiki/Primality by Trial Division "Primality by Trial Division").
Як і в інших алгоритмах пробного ділення, алгоритм припиняється, коли 2kP+1 > sqrt(N)
. Ці в першу чергу тести працюють лише з цифрами Мерсенна, де P
- це просте число. Наприклад, M4=15
не дає ніяких чинників, використовуючи ці технології, але фактори в 3 та 5, жоден з яких не відповідає 2kP+1
.
--instructions--
Використовуючи вказаний метод, знайти коефіцієнт 2р-1
.
--hints--
check_mersenne
має бути функцією.
assert(typeof check_mersenne === 'function');
check_mersenne(3)
має повернути рядок.
assert(typeof check_mersenne(3) == 'string');
check_mersenne(3)
повинен повертатися рядок M3 = 2^3-1 is prime
.
assert.equal(check_mersenne(3), 'M3 = 2^3-1 is prime');
check_mersenne(23)
повинен повертатися як рядок M23 = 2^23-1 is composite with factor 47
.
assert.equal(check_mersenne(23), 'M23 = 2^23-1 is composite with factor 47');
check_mersenne(929)
повинен повертати рядок M929 = 2^929-1 is composite with factor 13007
.
assert.equal(
check_mersenne(929),
'M929 = 2^929-1 is composite with factor 13007'
);
--seed--
--seed-contents--
function check_mersenne(p) {
}
--solutions--
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;
}