Формула тестування первинності


30

Ваша мета - визначити, чи задане число nє простим у найменших байтах. Але ваш код повинен бути одним виразом Python 2 на числах, що складаються лише з

  • оператори
  • вхідна змінна n
  • цілих констант
  • круглі дужки

Ні циклів, ні призначень, ні вбудованих функцій, лише те, що перераховано вище. Так, це можливо.

Оператори

Ось список усіх операторів Python 2 , які включають арифметичні, побітові та логічні оператори:

+    adddition
-    minus or unary negation
*    multiplication
**   exponentiation, only with non-negative exponent
/    floor division
%    modulo
<<   bit shift left
>>   bit shift right
&    bitwise and
|    bitwise or
^    bitwise xor
~    bitwise not
<    less than
>    greater than
<=   less than or equals
>=   greater than or equals
==   equals
!=   does not equal

Всі проміжні значення є цілими числами (або False / True, що неявно дорівнює 0 і 1). Експоненція може не використовуватися з негативними показниками, оскільки це може призвести до поплавків. Зауважте, що /поділ на підлогу, на відміну від Python 3, //не потрібен.

Навіть якщо ви не знайомі з Python, оператори повинні бути досить інтуїтивними. Дивіться цю таблицю щодо пріоритетності оператора та цей розділ та нижче для детальної специфікації граматики. Ви можете запустити Python 2 на TIO .

I / O

Введення: додатне ціле число n, принаймні 2.

Вихід: 1, якщо nє простим, а 0 - інакше. Trueа Falseтакож можуть бути використані. Виграє найменше байт.

Оскільки ваш код є виразом, він буде фрагментом, очікуючи вхідне значення, збережене як n, і оцінку до потрібного результату.

Ваш код повинен працювати в nсторону як завгодно великих системних обмежень. Оскільки цілочисельний тип Python не обмежений, для операторів немає обмежень. Ваш код може зайняти скільки завгодно часу.


Можливо, це має мати тег python?
fəˈnɛtɪk

Відповіді:


35

43 байти

(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n<1

Спробуйте в Інтернеті!

Метод подібний до другої (видаленої) відповіді Денніса, але цю відповідь легше довести правильною.

Доказ

Коротка форма

Найбільш значуща цифра (4**n+1)**n%4**n**2бази яка не ділиться на n , зробить наступну (менш значущу) цифру в ненульовій точці (якщо "наступна цифра" відсутня у дробовій частині), то для перевірки виконується бітмаска якщо будь-яка цифра у непарній позиції не є нульовою.2nn(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n

Довга форма

Нехай бути числом , що має , що підстава б уявлення, тобто п б п + + 1 б 1 + 0 б 0 , і я б цифра в " положення " i в базі b представлення.[an,,a1,a0]bbanbn++a1b1+a0b0aiib

  • .2**(2*n*n+n)/-~2**n=2(2n+1)n1+2n=4n2×2n1+2n=(4n21)×2n1+2n+2n1+2n

Тому що n22n×4n211+2n=2n(2n1)×(4n)n14n1=[2n1,0,2n1,0,2n1,0]2nn s) - ціле число, а2 n2n1, =[2n-1,0,2n-1,0,2n1+2n=02**(2*n*n+n)/-~2**n .[2n1,0,2n1,0,2n1,0]2n

Далі розглянемо

(4**n+1)**n=(4n+1)n=(n0)40n+(n1)41n++(nn)4n2=[(nn),0,,0,(n1),0,(n0)]2n

, тому числобуде урізано до 24n2=(2n)2n%4**n**2останніх n цифр - що виключає ( n2n (що дорівнює 1), але включають усі інші біноміальні коефіцієнти.(nn)

Про /n:

  • Якщо є простим, результат будеn . Усі цифри у непарному положенні дорівнюють нулю.[(nn1)/n,0,,0,(n1)/n,0,0]2n

  • Якщо не є простим:n

    Нехай - найбільше ціле число таке, що n a (нn(na) ). Перепишіть дивіденд якn>a>0

    [(nn1),0,(nn2),0,,(na+1),0,0,0,,0,0,0]2n+[(na),0,(na1),0,,(n0)]2n

    Перша сума має всі цифри, що поділяються на n , а цифра у позиції нуль.2a1

    Другий підсумок має свою найбільш значущу цифру (у позиції ), не поділяється на n і (основу) 2 n > n , тому коефіцієнт при діленні на цей n повинен мати цифру в позиції 2 a - 1 ненульовий.2an2n>nn2a1

    Тому підсумковий результат ( (4**n+1)**n%4**n**2/n) повинен мати цифру (база , звичайно) у позиції 2 a + 1 ненульової.2n2a+1

Нарешті, порозрядний AND ( &) виконує векторизований порозрядний AND на цифрах бази (тому що основа є потужністю 2), а тому, що a & 0 = 0 , a & ( 2 n - 1 ) = a для всіх 0 a < 2 n , дорівнює нулю, якщо iff має всі цифри в перших n непарних позиціях нуль - що еквівалентно n, що є простим.2na&0=0,a&(2n1)=a0a<2n(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n(4**n+1)**n%4**n**2/nnn


2
Було б (4**n+1)**n%2**n**2/n&2**n**2/-~2**n<1працювати?
Денніс

11
Якщо легко довести правильність, ви могли б включити довідку у відповідь? Зараз у нас є MathJax, тому порівняно легко зробити докази розбірливими, і я не бачу очевидної причини поділу, nщоб не викликати небажаних взаємодій між базами цифр 4**n.
Пітер Тейлор

3
"Я виявив справді чудовий доказ цієї відповіді, який цей коментар є занадто малим, щоб містити ..."
Digital Trauma

1
Пропозиції щодо скорочення доказів вітаються.
користувач202729

1
Чудово зроблено! Це те саме рішення, що я придумав. Я знайшов пару байтів, з якими можна вирізати (4**n+1)**n%4**n**2/n<<n&4**n**2/-~2**n<1. Мені цікаво, чи можливий цей виклик без побітних операторів.
xnor

6

Python 2 , 56 байт

n**(n*n-n)/(((2**n**n+1)**n**n>>n**n*~-n)%2**n**n)%n>n-2

Спробуйте в Інтернеті!

Це доказ правильності концепції , що це завдання здійсненне лише з арифметичними операторами, зокрема , без побітового |, &або ^. Код використовує бітові та порівняльні оператори лише для гольфу, і їх можна легко замінити арифметичними еквівалентами.

Однак рішення надзвичайно повільне, і мені не вдалося запустити `, завдяки дворівневим показникам, як 2 n nn=62nn .

Основна ідея - скласти вираз для факторської , що дозволяє нам зробити тест первісності Теореми Вілсона ( n - 1 ) ! % n > n - 2, де % - оператор модуля.n!(n1)!%n>n2%

Ми можемо скласти вираз для двочленного коефіцієнта , який складається з факторіалів

(mn) =m!n!(mn)!

Але незрозуміло, як витягти лише одну з цих фабрик. Хитрість полягає в тому, щоб розбити роблячи m дійсно величезним.n!m

(mn) =m(m1)(mn+1)n!=mnn!(11m)(12m)(1n1m)

Отже, якщо дозволити добуток ( 1 -c(11m)(12m)(1n1m) , маємо

n!=mn(mn)c

Якби ми могли просто ігнорувати , ми б зробили це. Решта цієї публікації виглядає як велике нам потрібно зробити mcm щоб мати змогу це зробити.

Зауважте, що підходить 1 знизу як m . Нам просто потрібно зробити m достатньо величезним, щоб опущення c дало нам значення з цілою частиною n ! щоб ми могли обчислитиc1mmcn!

n!=mn(mn)

Для цього досить мати щоб уникнути відношення, що передає наступне ціле n1c<1/n!n!+1.

Зауважте, що - добуток з n доданків, найменший яких ( 1 - n - 1cn(1n1m). So, we have

c>(1n1m)n>1n1mn>1n2m,

1c<n2m1c<1/n!mn!n2.

m=nn. Since Wilson's Theorem uses (n1)!, we actually only need m(n1)!(n1)2. It's easy to see that m=nn satisfies the bound for the small values and quickly outgrows the right hand side asymptotically, say with Stirling's approximation.


3

This answer doesn't use any number-theoretic cleverness. It spams Python's bitwise operators to create a manual "for loop", checking all pairs 1i,j<n to see whether i×j=n.

Python 2, way too many bytes (278 thanks to Jo King in the comments!)

((((((2**(n*n)/(2**n-1)**2)*(2**((n**2)*n)/(2**(n**2)-1)**2))^((n*((2**(n*n-n)/(2**n-1))*(2**((n**2)*(n-1))/(2**n**2-1))))))-((2**(n*n-n)/(2**n-1))*(2**((n**2)*(n-1))/(2**(n**2)-1))))&(((2**(n*(n-1))/(2**n-1))*(2**((n**2)*(n-1))/(2**(n**2)-1)))*(2**(n-1)))==0))|((1<n<6)&(n!=4))

Try it online!

This is a lot more bytes than the other answers, so I'm leaving it ungolfed for now. The code snippet below contains functions and variable assignment for clarity, but substitution turns isPrime(n) into a single Python expression.

def count(k, spacing):
    return 2**(spacing*(k+1))/(2**spacing - 1)**2
def ones(k, spacing):
    return 2**(spacing*k)/(2**spacing - 1)

def isPrime(n):
    x = count(n-1, n)
    y = count(n-1, n**2)
    onebits = ones(n-1, n) * ones(n-1, n**2)
    comparison = n*onebits
    difference = (x*y) ^ (comparison)
    differenceMinusOne = difference - onebits
    checkbits = onebits*(2**(n-1))
    return (differenceMinusOne & checkbits == 0 and n>1)or 1<n<6 and n!=4

Why does it work?

I'll do the same algorithm here in base 10 instead of binary. Look at this neat fraction:

1.09992=1.002003004005

If we put a large power of 10 in the numerator and use Python's floor division, this gives an enumeration of numbers. For example, 1015/(9992)=1002003004 with floor division, enumerating the numbers 1,2,3,4.

Let's say we multiply two numbers like this, with different spacings of zeroes. I'll place commas suggestively in the product.

1002003004×1000000000002000000000003000000000004=
1002003004,002004006008,003006009012,004008012016

The product enumerates, in three-digit sequences, the multiplication table up to 4 times 4. If we want to check whether the number 5 is prime, we just have to check whether 005 appears anywhere in that product.

To do that, we XOR the above product by the number 005005005005, and then subtract the number 001001001001. Call the result d. If 005 appeared in the multiplication table enumeration, it will cause the subtraction to carry over and put 999 in the corresponding place in d.

To test for this overflow, we compute an AND of d and the number 900900900900. The result is zero if and only if 5 is prime.


1
A quick print of the expression puts this at 278 bytes (though I'm sure a lot of the parenthesises aren't necessary)
Jo King
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.