원시성 테스트 공식


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

모든 중간 값은 정수 (또는 암시 적으로 0과 1 인 False / True)입니다. 부수를 생성 할 수 있으므로 음수 지수와 함께 지수를 사용할 수 없습니다. 참고 /파이썬 3는 달리, 바닥 부문 않기 때문에 //필요하지 않습니다.

파이썬에 익숙하지 않더라도 연산자는 매우 직관적이어야합니다. 참조 연산자 우선 순위에 대한이 테이블이 섹션 아래를 문법에 대한 자세한 사양에 대해. TIO에서 Python 2를 실행할 수 있습니다 .

I / O

입력 :n 2 이상의 양의 정수

출력 :n 소수 이면 1 , 그렇지 않으면 0 TrueFalse 또한 사용될 수있다. 가장 적은 바이트가 이깁니다.

코드는 표현식이므로 입력 값이으로 저장되어 n원하는 출력을 평가 하는 스 니펫이됩니다 .

코드는 n임의로 큰 시스템 제한을 위해 작동해야합니다 . 파이썬의 정수 유형은 제한이 없으므로 연산자에는 제한이 없습니다. 그러나 코드를 실행하는 데 시간이 오래 걸릴 수 있습니다.


어쩌면 이것은 파이썬 태그가 있어야합니까?
fəˈnɛtɪk

답변:


35

43 바이트

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

온라인으로 사용해보십시오!

이 방법은 Dennis의 두 번째 (삭제 된) 답변과 비슷하지만이 답변은 더 쉽게 증명할 수 있습니다.

증명

짧은 형식

가장 중요한 자리 (4**n+1)**n%4**n**2베이스에 로 나누어 아닌 N 의 다음 (덜 중요한) 자리 할 것이다 후 (즉, "다음의 숫자는"소수 부분에 있지 않은 경우)를 제로하는 비트 마스크와2nn(4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n 확인하기 위해 실행된다 홀수 위치의 숫자가 0이 아닌 경우

긴 형태

하자 이베이스 갖는 숫자 B의 표현, 즉, N의 B , N + + 1 B 1 + 0 B 0 에 숫자 일 " 베이스 b 표현 에서의 위치 " i .[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

2 n × 4 n 21 이므로(n2n-1s 포함)은 정수이며,2n2n×4n211+2n=2n(2n1)×(4n)n14n1=[2n1,0,2n1,0,2n1,0]2nn 2n1, =[2n-1,0,2n-1,0,2n-1,0]2n.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

그렇게까지의 숫자를 잘라야한다 2 N 마지막 자리 - 것을 제외합니다 ( N4n2=(2n)2n%4**n**22n (1)이지만 다른 모든 이항 계수를 포함합니다.(nn)

소개 /n:

  • 경우 소수이고, 결과가 될 것입니다 [ ( Nn. 홀수 위치의 모든 숫자는 0입니다.[(nn1)/n,0,,0,(n1)/n,0,0]2n

  • 이 소수가 아닌 경우 :n

    하자 그 가장 큰 정수 등의 수 N ( Na (n>a>0). 배당을 다음과 같이 다시 작성하십시오.n(na)n>a>0

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

    첫 번째 소환수는 모든 자릿수를 있으며 위치 2 a - 1 의 숫자는0입니다.n2a1

    제 피가수는 (위치에서 가장 중요한 자리 갖는 로 나누어 생략) N 및 (베이스) (2) N > N 의한 나눈 때문에 지수를 해당 위치에 자리 할 것이다 2 - 1 제로한다.2an2n>nn2a1

    따라서 최종 결과 ( (4**n+1)**n%4**n**2/n)는 위치 2 a + 1 이 아닌 0 (숫자 )이어야합니다 .2n2a+1

마지막으로, 비트 단위 AND은 ( &) 자료 벡터화 비트 AND 숫자에 행하는 (염기는 2의 제곱이기 때문에) 때문 & 0 = 0 , ( 2 N - 1 ) = 모든 0 a < 2 n 이면 0입니다. iff 첫 번째 n 홀수 위치의 모든 자릿수 0을 갖습니다. 이는 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
Would (4**n+1)**n%2**n**2/n&2**n**2/-~2**n<1 work?
Dennis

11
If it's easy to prove correct, could you include the proof in the answer? We have MathJax now, so it's relatively easy to make proofs legible, and I can't see an obvious reason for the division by n not to cause unwanted interactions between the digits base 4**n.
Peter Taylor

3
"I have discovered a truly remarkable proof of this answer which this comment is too small to contain..."
Digital Trauma

1
증거 단축을위한 제안은 환영합니다.
user202729

1
잘 했어요! 이것은 내가 생각해 낸 것과 동일한 솔루션입니다. 나는 몇 바이트를 잘라낼 수 있음을 발견했다 (4**n+1)**n%4**n**2/n<<n&4**n**2/-~2**n<1. 비트 연산자 없이이 도전이 가능한지 궁금합니다.
xnor

6

파이썬 2 , 56 바이트

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

온라인으로 사용해보십시오!

이 개념 증명이 도전은 비트없이 특히, 단지 산술 연산자와 행할 수 있다는 것입니다 |, &또는를 ^. 이 코드는 골프 용으로 비트 단위 및 비교 연산자를 사용하며 산술 등가로 쉽게 대체 할 수 있습니다.

However, the solution is extremely slow, and I haven't been able to run n=6`, thanks to two-level exponents like 2nn.

The main idea is to make an expression for the factorial n!, which lets us do a Wilson's Theorem primality test (n1)!%n>n2 where % is the modulo operator.

We can make an expression for the binomial coefficient, which is made of factorials

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

But it's not clear how to extract just one of these factorials. The trick is to hammer apart n! by making m really huge.

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

So, if we let c be the product (11m)(12m)(1n1m), we have

n!=mn(mn)c

If we could just ignore c, we'd be done. The rest of this post is looking how large we need to make m to be able to do this.

Note that c approaches 1 from below as m. We just need to make m huge enough that omitting c gives us a value with integer part n! so that we may compute

n!=mn(mn)

For this, it suffices to have 1c<1/n! to avoid the ratio passing the next integer n!+1.

Observe that c is a product of n terms of which the smallest is (1n1m). So, we have

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

which means 1c<n2m. Since we're looking to have 1c<1/n!, it suffices to take mn!n2.

In the code, we use 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.