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


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в базе которая не делится на , сделает следующую (менее значимую) цифру ненулевой (если эта «следующая цифра» не находится в дробной части), тогда выполняется a с битовой маской для проверьте, если любая цифра в нечетной позиции отлична от нуля. n2nn(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n

Длинная форма

Пусть будет числом, имеющим представление этого базового , то есть , а будет цифрой в «позиции» в базе представление. b a n b n + + a 1 b 1 + a 0 b 0 a i 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 .

Потому что (с с) - целое число, и , = , n 2 n - 1 2 n2n×4n211+2n=2n(2n1)×(4n)n14n1=[2n1,0,2n1,0,2n1,0]2nn 2n1[2n-1,0,2n-1,0,2n-1,0]2n2n1+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

4n2=(2n)2n , поэтому %4**n**2усекаем число до последних цифр - это исключает (который равен 1), но включает все другие биномиальные коэффициенты.2n(nn)

О себе /n:

  • Если простое число, результатом будет . Все цифры в нечетной позиции равны нулю.n[(nn1)/n,0,,0,(n1)/n,0,0]2n

  • Если не простое число:n

    Пусть будет наибольшим целым числом таким, что ( ). Переписать дивиденд какan(na)n>a>0

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

    Первое слагаемое имеет все цифры, кратные , а цифра в позиции равна нулю.n2a1

    Второе слагаемое имеет самую значимую цифру (в позиции ), не делимую на и (основание) , поэтому при делении этого числа на будет иметь место цифра в позиции отличная от нуля.2an2n>nn2a1

    Следовательно, конечный результат ( (4**n+1)**n%4**n**2/n) должен иметь цифру ( конечно, основание ) в позиции отличной от нуля.2n2a+1

Наконец, побитовое И ( &) выполняет векторизованное побитовое И для цифр в базе (потому что основание является степенью 2), и потому для всех , равно нулю, если все цифры в первых нечетных позициях равны нулю - что эквивалентно простому .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
Предложения по сокращению доказательства приветствуются.
user202729

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

Попробуйте онлайн!

Это доказательство правильности концепции , что эта задача выполнима только с арифметическими операторами, в частности , без побитового |, &или ^. Код использует побитовые операторы и операторы сравнения только для игры в гольф, и их можно легко заменить арифметическими эквивалентами.

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

Основная идея - сделать выражение для факториала, что позволяет нам сделать тест на первичность теоремы Вильсона где является оператором по модулю.n!(n1)!%n>n2%

Мы можем сделать выражение для биномиального коэффициента , который состоит из факториалов

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

Но не ясно, как извлечь только один из этих факториалов. Хитрость заключается в том, чтобы разбить на частисделав действительно огромным.n!m

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

Таким образом, если мы допустим, чтобы было произведением , мы имеемc(11m)(12m)(1n1m)

n!=mn(mn)c

Если бы мы могли просто игнорировать , мы бы сделали. В остальной части этого поста рассказывается, насколько нам нужно сделать чтобы это можно было сделать.cm

Обратите внимание, что приближается к снизу как . Нам просто нужно сделать достаточно большим, чтобы пропуск дал нам значение с целой частьютак что мы можем вычислитьc1mmcn!

n!=mn(mn)

Для этого достаточно иметьчтобы избежать отношения передачи следующего целого числа .1c<1/n!n!+1

Заметим, что является произведением из членов, наименьшее из которых равно . Итак, мы имеемcn(1n1m)

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

что означает . Так как мы ищемдостаточно взять .1c<n2m1c<1/n!mn!n2

В коде мы используем . Так как теорема Вильсона используетнам нужно только . Легко видеть, что удовлетворяет оценке для малых значений и быстро асимптотически перерастает правую часть, скажем, в приближении Стирлинга .m=nn(n1)!m(n1)!(n1)2m=nn


3

В этом ответе не используется теоретический номер. Он спамит побитовые операторы Python, чтобы создать руководство «для цикла», проверяя все пары чтобы узнать, .1i,j<ni×j=n

Python 2, слишком много байтов (278 спасибо Джо Кингу в комментариях!)

((((((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))

Попробуйте онлайн!

Это намного больше байтов, чем другие ответы, поэтому я пока оставлю это без присмотра. Приведенный ниже фрагмент кода содержит функции и назначение переменных для ясности, но подстановка превращает isPrime (n) в одно выражение Python.

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

Почему это работает?

Я сделаю тот же алгоритм здесь в базе 10 вместо двоичного. Посмотрите на эту аккуратную фракцию:

1.09992=1.002003004005

Если мы поместим большую степень 10 в числитель и используем деление по полу в Python, это даст перечисление чисел. Например, с разделением по этажам, перечисляя числа .1015/(9992)=10020030041,2,3,4

Допустим, мы умножаем два числа, как это, с разными расстояниями от нуля. Я буду вводить запятые в продукт.

1002003004×1000000000002000000000003000000000004=
1002003004,002004006008,003006009012,004008012016

Продукт перечисляет в трехзначной последовательности таблицу умножения до 4 раз. Если мы хотим проверить, является ли число 5 простым, нам просто нужно проверить, появляется ли где-нибудь в этом продукте.005

Для этого мы XOR вышеупомянутого продукта по номеру , а затем вычитаем число . Назовите результат . Если появилось в перечислении таблицы умножения, это приведет к переносу вычитания и положит в соответствующее место в .005005005005001001001001d005999d

Чтобы проверить это переполнение, мы вычисляем AND для и число . Результат равен нулю тогда и только тогда, когда 5 - простое число.d900900900900


1
Быстрая печать выражения помещает это в 278 байтов (хотя я уверен, что многие круглые скобки не нужны)
Джо Кинг,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.