素数测试公式


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,操作员也应该非常直观。有关运算符优先级的信息,请参见下表;有关语法的详细说明,请参见节和下文。您可以在TIO上运行Python 2

输入输出

输入:n至少为2的正整数。

输出:如果n为质数则为1,否则为0。True并且False也可以使用。最少的字节数获胜。

由于您的代码是一个表达式,因此它将是一个代码段,期望输入值存储为n,并评估所需的输出。

您的代码必须适用于n任意大的系统限制。由于Python的整数类型是无界的,因此对运算符没有限制。您的代码可能需要花费很长时间才能运行。


也许这应该有python标签?
fəˈnɛtɪk

Answers:


35

43字节

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

在线尝试!

该方法类似于丹尼斯的第二个(已删除)答案,但是更容易证明该答案是正确的。

证明

简写

不能被n整除的(4**n+1)**n%4**n**2基数中的最高有效数字将使下一个(较低有效)数字为非零(如果“下一位”不在小数部分),则执行带位掩码的a 进行检查如果奇数位置的任何数字不为零。2nn(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 0a 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

因为(与Ñ2Ñ-1s)为一个整数,并2Ñ2n×4n211+2n=2n(2n1)×(4n)n14n1=[2n1,0,2n1,0,2n1,0]2nn 2n1, =[2Ñ-102Ñ-102Ñ-10]2Ñ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 数字-不包括 n4n2=(2n)2n%4**n**22n(为1),但包括所有其他二项式系数。(nn)

关于/n

  • 如果是素数,则结果为[ nn。奇数位置的所有数字均为零。[(nn1)/n,0,,0,(n1)/n,0,0]2n

  • 如果不是素数:n

    是最大的整数,ñ ñan>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

    The first summand has all digits divisible by n, and the digit at position 2a1 zero.

    The second summand has its most significant digit (at position 2a) not divisible by n and (the base) 2n>n, so the quotient when dividing that by n would have the digit at position 2a1 nonzero.

    Therefore, the final result ((4**n+1)**n%4**n**2/n) should have the digit (base 2n, of course) at position 2a+1 nonzero.

&2na&0=0,a&(2n1)=a for all 0a<2n, (4**n+1)**n%4**n**2/n&2**(2*n*n+n)/-~2**n is zero iff (4**n+1)**n%4**n**2/n has all digits in first n odd positions zero - which is equivalent to n being prime.


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
Suggestions for shortening the proof are welcome.
user202729

1
Nicely done! This is the same solution I had come up with. I found a couple of bytes can be cut with (4**n+1)**n%4**n**2/n<<n&4**n**2/-~2**n<1. I'm curious if this challenge is possible without bitwise operators.
xnor

6

Python 2, 56 bytes

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

Try it online!

This is a proof-of-concept that this challenge is doable with only arithmetic operators, in particular without bitwise |, &, or ^. The code uses bitwise and comparison operators only for golfing, and they can easily be replaced with arithmetic equivalents.

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.