最有效且最短代码的前n个质数列表


27

规则很简单:

  • 第一n素数(未引发(prime)下面Ñ),应打印到标准输出由分离的换行(素数应的代码内产生)
  • 素数不能通过内置函数或库来生成,即,使用诸如prime = get_nth_prime(n),is_a_prime(number)或factorlist = list_all_factors(number)之类的内置函数或库函数不会很有创意。
  • 评分-假设我们定义得分 = f([代码中的字符数]),Of(n))是算法的复杂度,其中n是找到的素数。因此,例如,如果您有一个复杂度为O(n ^ 2)的300个字符代码,则分数为300 ^ 2 = 90000,对于具有O(n * ln(n))的300个字符,分数将变为300 * 5.7 = 1711.13(为了简单起见,假设所有日志都是自然日志)

  • 使用任何现有编程语言,得分最低

编辑:由于对O(f(n))中的“ n”是什么感到困惑,所以问题已从查找“前1000000个素数”更改为“前n个素数”,n是找到的素数(查找素数为问题在这里,所以问题的复杂性取决于找到的素数)

注意:为了澄清一些复杂性,如果'n'是找到的素数,而'N'是找到的第n个素数,则复杂度就n为,而N不等价,即O(f(n))! = O(f(N)) as,f(N)!=常数* f(n)和N!=常数* n,因为我们知道第n个素数函数不是线性的,尽管我发现了'n'素数复杂度应易于用“ n”表示。

正如Kibbee所指出的,您可以访问此网站来验证您的解决方案(此处是旧的google文档列表)

请在您的解决方案中包括这些-

  • 您的程序有什么复杂性(如果不琐碎,请包括基本分析)

  • 字符长度

  • 最终计算出的分数

这是我的第一个CodeGolf问题,因此,如果以上规则有误或漏洞,请指出。



2
我对此的1[\p:i.78498回答是我对此的回答1[\p:i.1000000。即使假设J的内部主要算法是O(n ^ 2)我的成绩也只不过是196
加雷

2
似乎没有人设法正确地计算其复杂性。关于n素数的数量还是最大素数存在混淆,每个人都忽略了范围内的数字相加0..nO(logn),并且乘法和除法甚至更昂贵的事实。我建议您提供一些示例算法及其正确的复杂性。
ugoren

3
当前最有名的k位数素数测试为O-tilde(k^6)。这意味着任何人声称自己的跑步时间要比O-tilde(n ln n (ln(n ln n))^6)误解了一部分问题要好。以及O-tilde在计分中应如何处理复杂性的问题。
彼得·泰勒

2
没有人指出,在复杂度方面,O(n)等于O(kn)(对于常数k),但在得分方面却不等。例如,假设我的复杂度为O(n ^ 10)。那相当于O(n ^ 10 * 1E-308),而我仍然可以通过复杂而又庞大的程序来赢得挑战。
JDL

Answers:


10

Python(129个字元,O(n * log log n),分数203.948)

我想说的是Eratosthenes筛子是要走的路。非常简单,相对较快。

N=15485864
a=[1]*N
x=xrange
for i in x(2,3936):
 if a[i]:
  for j in x(i*i,N,i):a[j]=0
print [i for i in x(len(a))if a[i]==1][2:]

改进了以前的代码。

蟒(191 156 152个字符,O(N * log日志N)(?),得分252.620(?))

我根本无法计算复杂度,这是我能给出的最佳近似值。

from math import log as l
n=input()
N=n*int(l(n)+l(l(n)))
a=range(2,N)
for i in range(int(n**.5)+1):
 a=filter(lambda x:x%a[i] or x==a[i],a)
print a[:n]

n*int(l(n)+l(l(n)))上边界的的n个素数。


1
复杂度(因而得分)的计算是基于上限,n而不是基于素数的。因此,我认为分数必须更高。请参阅上面的评论。
霍华德

上限n?那是什么?
beary605

上限是N=15485864。对于基于的复杂度计算n=1000000,您可以说N=n*log(n)(由于质数的密度)。
ugoren 2012年

如果我的分数需要修正,请为我修正。我仍然对计分系统不太了解。
beary605

@ beary605如果我将问题修改为找到前n个素数就可以了吗?这将解决很多关于复杂性和O(f(n))中n的困惑
Optimus

7

Haskell,n ^ 1.1经验增长率,89个字符,得分139(?)

当先前使用的通用库已加载时,GHCi会提示以下内容。打印基于1的第n个素数:

let s=3:minus[5,7..](unionAll[[p*p,p*p+2*p..]|p<-s])in getLine>>=(print.((0:2:s)!!).read)

这是Eratosthenes的无限筛,使用通用库来存储有序列表。经验素数介于100,000至200,000个素数之间O(n^1.1)。适合 O(n*log(n)*log(log n))

关于复杂度估算

余测量100K和200K的素数,然后计算运行时间logBase 2 (t2/t1),这产生n^1.09。定义g n = n*log n*log(log n),计算logBase 2 (g 200000 / g 100000)得出n^1.12

然后89**1.1 = 139,尽管g(89) = 600。- (?)

似乎为了计分,应该使用估计的增长率而不是复杂度函数本身。例如,g2 n = n*((log n)**2)*log(log n)比更好n**1.5,但是对于100个字符,两个字符分别产生3239和的得分1000。这是不对的。在200k / 100k范围内的估算得出logBase 2 (g2 200000 / g2 100000) = 1.2,因此得分为100**1.2 = 251

另外,我不尝试打印所有素数,而仅打印第n个素数。

没有进口,240个字符。n ^ 1.15经验增长率,得分546。

main=getLine>>=(print.s.read)
s n=let s=3:g 5(a[[p*p,p*p+2*p..]|p<-s])in(0:2:s)!!n
a((x:s):t)=x:u s(a$p t)
p((x:s):r:t)=(x:u s r):p t
g k s@(x:t)|k<x=k:g(k+2)s|True=g(k+2)t
u a@(x:r)b@(y:t)=case(compare x y)of LT->x:u r b;EQ->x:u r t;GT->y:u a t

5

Haskell,72 89个字符,O(n ^ 2),得分7921

每个字符数最高的分数获胜了吗?修改为前N个。同样,我显然不能使用计算器,因此我的分数没有我想像的那么糟糕。(使用下面的源中的基本试验划分的复杂性)。

根据Will Ness,以下内容并不是完整的Haskell程序(它实际上依赖于REPL)。以下是带有伪筛的更完整的程序(导入实际上保存了一个字符,但我不喜欢代码高尔夫中的导入)。

main=getLine>>= \x->print.take(read x).(let s(x:y)=x:s(filter((>0).(`mod`x))y)in s)$[2..]

此版本无疑是(n ^ 2)。该算法只是天真的``筛'的高尔夫版本,看到这里 老ghci的1衬垫

getLine>>= \x->print.take(read x)$Data.List.nubBy(\x y->x`mod`y==0)[2..]

留下旧的,作弊的答案,因为它链接到的库非常好。

print$take(10^6)Data.Numbers.Primes.primes

有关实现方法和时间复杂性的信息,请参见此处。不幸的是,轮子有一个log(n)查找时间,使我们的速度降低了一个因素。


•不能通过内置函数或库生成图素
beary605

@walpen我'对不起,我修改了规则,恕不另行通知,请进行更改,您认为合适
擎天柱

复杂度不是O((n ln n)^ 1.5 ln(n ln n)^ 0.585)吗?(或O((n ln n)^ 1.5 ln(n ln n)),如果Haskell使用幼稚的除法,而不是我假设的Karatsuba)
Peter Taylor

不,因为那给了我一个可怕的分数:/。但是我确定你是对的。看起来就像是审判部门,这就是审判部门的时间复杂度(也许,根据我对可能错误来源的理解不佳),所以我选择了这一点。现在,我将我的分数命名为NaN,这似乎很安全。
walpen 2012年

我假设(我的Haskell可以忽略不计,但是我知道在SML中这样做很自然...),您只是按较小的素数进行试除,在这种情况下,P上的试除确实为O( P ^ 0.5 / ln P)除法。但是如果P有k位,则除法需要O(k ^ 1.585)(Karatsuba)或O(k ^ 2)(天真)时间,并且您需要遍历O(n lg n)个长度为O(ln( n lg n))位。
彼得·泰勒

5

C#,447个字符,字节452,得分?

using System;namespace PrimeNumbers{class C{static void GN(ulong n){ulong primes=0;for (ulong i=0;i<(n*3);i++){if(IP(i)==true){primes++;if(primes==n){Console.WriteLine(i);}}}}static bool IP(ulong n){if(n<=3){return n>1;}else if (n%2==0||n%3==0){return false;}for(ulong i=5;i*i<=n;i+=6){if(n%i==0||n%(i+2)==0){return false;}}return true;}static void Main(string[] args){ulong n=Convert.ToUInt64(Console.ReadLine());for(ulong i=0;i<n;i++){GN(i);}}}}

scriptcs变体,381个字符,385字节,得分?

using System;static void GetN(ulong n){ulong primes=0;for (ulong i=0;i<(n*500);i++){if(IsPrime(i)==true){primes++;if(primes==n){Console.WriteLine(i);}}}}public static bool IsPrime(ulong n){if(n<=3){return n>1;}else if (n%2==0||n%3==0){return false;}for(ulong i=5;i*i<=n;i+=6){if(n%i==0||n%(i+2)==0){return false;}}return true;}ulong n=Convert.ToUInt64(Console.ReadLine());for(ulong i=0;i<n;i++){GetN(i);}

如果安装脚本,则可以运行它。

PS我在Vim中写的 :D


2
您可以通过删除一些不必要的空格来保存一些字符。例如,没有必要在=and <符号周围加上空格。另外,我认为此代码的字节和字符没有区别-它是548个字符和548个字节。
ProgramFOX

2
哦,谢谢,这是我的第一个CodeGolf!
XiKuuKy 2015年

4

GolfScript(45个字符,得分约为7708)

~[]2{..3${1$\%!}?={.@\+\}{;}if)1$,3$<}do;\;n*

这可以按素数进行简单的试验除法。如果在Ruby的最前沿(即使用1.9.3.0),则该算法使用Toom-Cook 3乘法,因此试除法为O(n ^ 1.465),除法的总成本为O((n ln n)^1.5 ln (n ln n)^0.465) = O(n^1.5 (ln n)^1.965)†。但是,在GolfScript中,向数组添加元素需要复制该数组。我对此进行了优化,以仅在找到新素数时才复制素数列表,因此n总共只能复制一次。每个复制操作都是† O(n)大小的项目O(ln(n ln n)) = O(ln n),给出O(n^2 ln n)

这就是男孩和女孩的原因,这就是为什么将GolfScript用于打高尔夫球而不是用于认真编程的原因。

O(ln (n ln n)) = O(ln n + ln ln n) = O(ln n)。在评论各种帖子之前,我应该已经发现了这一点。


4

甚至我的文本编辑器也可以做到这一点!

Vim:143次击键(115次操作):O(n ^ 2 * log(n)):得分:101485.21

提交内容:

qpqqdqA^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"ddmpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0qqpmp"aywgg@dqgg@p

输入:N应该在空白文档的第一行。完成此操作后,从2到N的每个素数将是单独的行。

运行命令:

首先,请注意,任何前面带有尖号的命令都意味着您需要按住Ctrl并键入下一个字母(例如^ V is Ctrl-v和^ R is Ctrl-r)。

这将覆盖@ a,@ b,@ d和@p寄存器中的所有内容。

因为它使用q命令,所以不能将其放置在宏中。但是,这里有一些运行它的技巧。

  • qpqqdq 只是清除寄存器
  • A^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"dd将创建数字2到N + 1的列表。这是两个主要部分之间的一个突破,因此一旦完成,您就无需再做一次
  • mpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0qqpmp"aywgg@dqgg@p确实需要一键输入。尽量避免退格,因为它可能会使某些东西弄坏。
    • 如果输入有误,请键入,qdqqpq然后重试此行。

对于大N,这非常慢。N = 5000耗时约27分钟;考虑一下自己被警告。

算法:

这使用基本的递归算法来查找素数。给定一个介于1和A之间的所有质数的列表,如果A + 1不能被质数列表中的任何数字整除,则为质数。从A = 2开始,然后将素数添加到列表中。进行N次递归后,列表将包含不超过N的所有素数。

复杂

该算法的复杂度为O(nN),其中N为输入数,n为不超过N的素数。每个递归测试n个数,执行N次递归,得出O(nN)。

但是,N〜n * log(n),最终的复杂度为O(n 2 * log(n))(https://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number

说明

从vim命令识别程序流程并不容易,因此我按照相同的流程在Python中重写了它。像Vim代码一样,python代码到达末尾时将出错。Python不喜欢太多的递归;如果您尝试使用N> 150左右的代码,它将达到最大递归深度

N = 20
primes = range(2, N+1)

# Python needs these defined.
mark_p = b = a = -1

# Check new number for factors. 
# This macro could be wrapped up in @d, but it saves space to leave it separate.
def p():
    global mark_d, mark_p, primes, a
    mark_d = 0
    print(primes)
    a = primes[mark_p]
    d()      

# Checks factor and determine what to do next
def d():
    global mark_d, mark_p, a, b, primes
    b = primes[mark_d]
    if(a == b): # Number is prime, check the next number
        mark_p += 1
        p()
    else:
        if(a%b == 0): # Number is not prime, delete it and check next number
            del(primes[mark_p])
            p()
        else: # Number might be prime, try next possible factor
            mark_d += 1
            d()

mark_p = 0 #Start at first number         
p()

现在,分解实际的按键!

  • qpqqdq清除@d和@p寄存器。这将确保在设置这些递归宏时不执行任何操作。

  • A^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"dd将输入变成2到N + 1的数字列表。N + 1项被删除,这是设置@d宏的副作用。

    • 具体来说,编写一个递增数字的宏,然后将其复制到下一行,然后写入1并执行该宏N次。
  • mpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0q编写@d宏,该宏实现了上面的d()函数。在Vim中实现“ If”语句很有趣。通过使用搜索运算符*,可以选择要遵循的特定路径。进一步分解命令,我们得到

    • mpqd在此处设置p标记并开始记录@d宏。需要设置p标记,以便在运行时有一个已知点跳至
    • o^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc> 写入if / else语句文本
    • 0*w*wyiWdd@0 实际执行if语句。
    • 在执行此命令之前,该行将包含 @a @b 0 0 `pj@p @a 0 (@a%@b) `pdd@p 0 `dj@d
    • 0 将光标移到行首
    • *w*w 将光标移至要执行的代码

      1. 如果@a == @b,即`pj@p,它将移至@a的下一个数字并在其上运行@p。
      2. 如果@a!= @b和@ a%@ b == 0,即`pdd@p删除当前数字@a,然后对下一个运行@p。
      3. 如果@a!= @b和@ a %% b!= 0,即`dj@d,它检查@b的下一个数字以查看是否是@a的因数
    • yiWdd@0 将命令拖入0寄存器,删除行并运行命令

    • q 结束@d宏的记录
  • 第一次运行时,将运行该`pdd@p命令,并删除N + 1行。

  • qpmp"aywgg@dq 写入@p宏,该宏将数字保存在光标下,然后转到第一项并在其上运行@d。

  • gg@p 实际上执行@p,以便它将遍历整个文件。


3

QBASIC,98个字符,复杂度N Sqrt(N),得分970

I=1
A:I=I+2
FOR J=2 TO I^.5
    IF I MOD J=0 THEN GOTO A
NEXT
?I
K=K+1
IF K=1e6 THEN GOTO B
GOTO A
B:

我对问题陈述进行了一些修改,现在可以找到第一个“ n”素数,对于没有通知,我们感到抱歉
Optimus 2012年

我想我们可以假定该程序的“源代码”输入;也就是说,输入是紧随其后的数字IF K=(因此程序长度将不包括数字)。就目前情况而言,程序将打印不包括2的前n个素数,可以通过?2在开头添加并更改K=...为来固定K=...-1。该程序还可以通过取出来的空间来golfed位J=2 TOJ=0 THENK=...-1 THEN,并通过删除缩进。我相信这会产生一个96个字符的程序。
2012年

3

Scala 263个字符

已更新以适应新要求。代码的25%用于寻找合理的上限来计算下面的素数。

object P extends App{
def c(M:Int)={
val p=collection.mutable.BitSet(M+1)
p(2)=true
(3 to M+1 by 2).map(p(_)=true)
for(i<-p){
var j=2*i;
while(j<M){
if(p(j))p(j)=false
j+=i}
}
p
}
val i=args(0).toInt
println(c(((math.log(i)*i*1.3)toInt)).take(i).mkString("\n"))
}

我也有一个筛子。

这是计算成本的实证检验,未进行分析:

object PrimesTo extends App{
    var cnt=0
    def c(M:Int)={
        val p=(false::false::true::List.range(3,M+1).map(_%2!=0)).toArray
        for (i <- List.range (3, M, 2)
            if (p (i))) {
                var j=2*i;
                while (j < M) {
                    cnt+=1
                    if (p (j)) 
                        p(j)=false
                    j+=i}
            }
        (1 to M).filter (x => p (x))
    }
    val i = args(0).toInt
    /*
        To get the number x with i primes below, it is nearly ln(x)*x. For small numbers 
        we need a correction factor 1.13, and to avoid a bigger factor for very small 
        numbers we add 666 as an upper bound.
    */
    val x = (math.log(i)*i*1.13).toInt+666
    println (c(x).take (i).mkString("\n"))
    System.err.println (x + "\tcount: " + cnt)
}
for n in {1..5} ; do i=$((10**$n)); scala -J-Xmx768M P $i ; done 

导致以下计数:

List (960, 1766, 15127, 217099, 2988966)

我不确定如何计算分数。是否值得再写5个字符?

scala> List(4, 25, 168, 1229, 9592, 78498, 664579, 5761455, 50847534).map(x=>(math.log(x)*x*1.13).toInt+666) 
res42: List[Int] = List(672, 756, 1638, 10545, 100045, 1000419, 10068909, 101346800, 1019549994)

scala> List(4, 25, 168, 1229, 9592, 78498, 664579, 5761455, 50847534).map(x=>(math.log(x)*x*1.3)toInt) 
res43: List[Int] = List(7, 104, 1119, 11365, 114329, 1150158, 11582935, 116592898, 1172932855)

对于更大的n,它会使该范围内的计算减少约16%,但是对于分数公式而言,我们不考虑常数因素吗?

Big-O的新注意事项:

为了找到1 000、10 000、100 000个素数,依此类推,我使用一个关于素数密度x =>(math.log(x)* x * 1.3的公式)来确定我正在运行的外循环。

因此,对于1到6中的值i => NPrimes(10 ^ i)运行9399、133768 ...乘以外循环。

我在彼得·泰勒(Peter Taylor)的评论的帮助下迭代地找到了这个O函数,他提出了更高的求幂值,而不是他建议的1.5:1.5

def O(n:Int) = (math.pow((n * math.log (n)), 1.01)).toLong

O:(n:整数)长

val ns = List(10, 100, 1000, 10000, 100000, 1000*1000).map(x=>(math.log(x)*x*1.3)toInt).map(O) 

ns:List [Long] =列表(102、4152、91532、1612894、25192460、364664351)

 That's the list of upper values, to find primes below (since my algorithm has to know this value before it has to estimate it), send through the O-function, to find similar quotients for moving from 100 to 1000 to 10000 primes and so on: 

(ns.head /: ns.tail)((a, b) => {println (b*1.0/a); b})
40.705882352941174
22.045279383429673
17.62109426211598
15.619414543051187
14.47513863274964
13.73425213148954

如果我使用1.01作为指数,这就是商。这是计数器凭经验得出的结果:

ns: Array[Int] = Array(1628, 2929, 23583, 321898, 4291625, 54289190, 660847317)

(ns.head /: ns.tail)((a, b) => {println (b*1.0/a); b})
1.799140049140049
8.051553431205189
13.649578085909342
13.332251210010625
12.65003116535112
12.172723833234572

前两个值是离群值,因为我为小值(最大为1000)的估计公式进行了常数校正。

彼得·泰勒斯(Peter Taylors)的建议是1.5,它看起来像:

245.2396265560166
98.8566987153728
70.8831374743478
59.26104390040363
52.92941829568069
48.956394784317816

现在,根据我的价值,我可以:

O(263)
res85: Long = 1576

但是我不确定,我的O函数能与观测值有多接近。


抱歉,我对问题说明进行了一些更改,以减少与复杂性有关的歧义,(我相信您的解决方案不会有太大变化)
Optimus 2012年

这实际上是素数的试验除法。通过内部循环的次数为O(M^1.5 / ln M),并且每次完成O(ln M)工作(累加)的总次数为O(M^1.5) = O((n ln n)^1.5)
彼得·泰勒

用^ 1.02而不是^ 1.5,def O(n:Int) = (math.pow((n * math.log (n)), 1.02)).toLong我可以更接近这些值,这是通过我的计数器凭经验发现的。我将发现插入我的帖子中。
用户未知

3

红宝石66个字符,O(n ^ 2)得分-4356

lazy自Ruby 2.0起可用,并且1.0/0是获得无限范围的绝妙技巧:

(2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j==0}}.take(n).to_a

1
您可以通过将其更改为(2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j<1}}.take(n).to_a
Qqwy 2015年

甚至:(这使解决方案的效率降低,但不会更改O(n²)的上限)(2..(1.0/0)).lazy.select{|i|(2..i).one?{|j|i%j<1}}.take(n).to_a。这样可以刮掉另外两个字符。
2015年

很好地将其更改为(2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j<1}}.first(n)61个字符。
Richie '18

2

Ruby,84个字符,84个字节,得分?

对于这些部分来说,这可能是个新手,但是我玩得很开心。它简单地循环直到f(找到的素数)等于n,找到所需的素数。

有趣的是,对于每个循环,它创建的数组比要检查的数字少2到1。然后,它将数组中的每个元素映射为原始数字和元素的模数,并检查是否有任何结果为零。

另外,我也不知道如何得分。

更新资料

代码经过压缩,并包含一个(完全任意的)值 n

n,f,i=5**5,0,2
until f==n;f+=1;p i if !(2...i).to_a.map{|j|i%j}.include?(0);i+=1;end

原版的

f, i = 0, 2
until f == n
  (f += 1; p i) if !(2...i).to_a.map{|j| i % j}.include?(0)
  i += 1
end

i += 1点点的until循环是我需要改进的地方,但在这个轨道上,我有点卡住了。无论如何,思考很有趣。


2

Scala,124个字符

object Q extends App{Stream.from(2).filter(p=>(2 to p)takeWhile(i=>i*i<=p)forall{p%_!= 0})take(args(0)toInt)foreach println}

简单的试算法最多可达平方根。因此复杂度应为O(n ^(1.5 + epsilon))

124 ^ 1.5 <1381,所以我猜这是我的分数吗?


1

Perl-94个字符,O(n log(n))-得分:427

perl -wle '$n=1;$t=1;while($n<$ARGV[0]){$t++;if((1x$t)!~/^1?$|^(11+?)\1+$/){print $t;$n++;}}'

Python-113个字符

import re
z = int(input())
n=1
t=1
while n<z:
    t+=1
    if not re.match(r'^1?$|^(11+?)\1+$',"1"*t):
        print t
        n+=1

1

AWK,96 86字节

字幕:看妈妈!仅添加和一些簿记!

档案fsoe3.awk

{for(n=2;l<$1;){if(n in L)p=L[n]
else{print p=n;l++}
for(N=p+n++;N in L;)N+=p
L[N]=p}}

跑:

$ awk -f fsoe3.awk <<< 5
2
3
5
7
11
$ awk -f fsoe3.awk <<< 1000 | wc -l
1000

BASH,133字节

档案x.bash

a=2
while((l<$1));do if((b[a]))
then((c=b[a]));else((c=a,l++));echo $a;fi;((d=a+c))
while((b[d]));do((d+=c));done
((b[d]=c,a++));done

跑:

$ bash x.bash 5
2
3
5
7
11
$ bash x.bash 1000 | wc -l
1000

通过使已经找到的素数跳到“正整数带”上来计算素数。基本上,它是Eratosthenes的序列化筛。

from time import time as t

L = {}
n = 2
l = 0

t0=t()

while l<1000000:

        if n in L:
                P = L[n]
        else:
                P = n
                l += 1
                print t()-t0

        m = n+P
        while m in L:
                m += P
        L[m] = P

        n += 1

...与Python中的算法相同,并打印出l找到第-个素数的时间,而不是素数本身的时间。

使用绘制的输出结果gnuplot如下:

在此处输入图片说明

由于将缓冲的数据写入磁盘,因此跳转可能与文件I / O延迟有关。

使用大得多的质数来查找,将给游戏带来更多与系统有关的延迟,例如,代表“正整数带”的数组不断增长,迟早将使每台计算机都为更多的RAM哭泣(或稍后交换)。

...因此,通过查看实验数据来了解复杂性并没有太大帮助... :-(


现在计算找到n素数所需的添加量:

cells = {}
current = 2
found = 0

additons = 0

while found < 10000000:

        if current in cells:
                candidate = cells[current]
                del cells[current] # the seen part is irrelevant
        else:
                candidate = current
                found += 1 ; additons += 1
                print additons

        destination = current + candidate ; additons += 1
        while destination in cells:
                destination += candidate ; additons += 1
        cells[destination] = candidate

        current += 1 ; additons += 1

在此处输入图片说明


您如何制作这些图表?

1
Gnuplot使用set term xterm,然后是xterm的图形窗口(可能是几乎被遗忘的功能)的屏幕截图。;-)


0

Python 3中,117个 106字节

这个解决方案有点琐碎,因为它输出0而不是质数,但无论如何我都会发布它:

r=range
for i in[2]+[i*(not 0 in[i%j for j in r(3,int(i**0.5)+1,2)])for i in r(3,int(input()),2)]:print(i)

另外,我不确定如何计算算法的复杂性。因此,请勿投票。相反,请保持友善并评论我如何解决。另外,请告诉我如何缩短此时间。


我想你可以把print(i)在同一行的for循环,并在空格去掉in [2]0 if0 in [i%j+1,2)] else
acrolith '16

@daHugLenny哇,非常感谢!我将在几秒钟内编辑我的帖子。:-D
0WJYxW9FMN

@daHugLenny您是否会知道如何计算效率?
0WJYxW9FMN

不,对不起 (评论必须至少为15个字符)
Acrolith

不管怎么说,还是要谢谢你。您已使我的程序成为最短的程序!
0WJYxW9FMN


0

Perl 6,152字节,O(n log n log(n log n)log(log(n log n)))(?),9594.79点

根据此页面,找到直到n的所有素数的位复杂度为O(n log n log log n); 上面的复杂度使用了第n个素数与n log n成正比的事实。

my \N=+slurp;my \P=N*(N.log+N.log.log);my @a=1 xx P;for 2..P.sqrt ->$i {if @a[$i] {@a[$_*$i]=0 for $i..P/$i}};say $_[1] for (@a Z ^P).grep(*[0])[2..N+1]

没有资格,这样做在Wentel资格
noɥʇʎԀʎzɐɹƆ

原谅,但是你是什么意思呢?
bb94

赏金(fiiiiiiiiilerrrrr)
2013年

0

Groovy(50字节)-O(n * sqrt(n))-得分353.553390593

{[1,2]+(1..it).findAll{x->(2..x**0.5).every{x%it}}​}​

接受n并输出从1到n的所有素数。

我选择的算法仅输出质数n> 2,因此需要在开始处添加1,2。

分解

x%it -如果不是不可分割的,则隐含真相;如果不是,则隐式。

(2..x**0.5).every{...}-对于2到sqrt(x)之间的所有值,请确保它们不可整除,以使其返回true,但必须为each返回true 。

(1..it).findAll{x->...} -对于介于1和n之间的所有值,找到满足2和sqrt(n)之间不可除的标准的所有值。

{[1,2]+...}​ -加1和2,因为它们始终是素数,并且永远不会被算法覆盖。


0

拍框155字节

(let p((o'(2))(c 3))(cond[(>=(length o)n)(reverse o)][(ormap(λ(x)(= 0(modulo c x)))
(filter(λ(x)(<= x(sqrt c)))o))(p o(add1 c))][(p(cons c o)(add1 c))]))

它保留找到的素数的列表,并根据已找到的素数检查每个下一个数的可除性。而且,它仅检查直到被测数字的平方根,因为这就足够了。

取消高尔夫:

(define(nprimes n)
  (let loop ((outl '(2))                   ; outlist having primes being created
             (current 3))                  ; current number being tested
  (cond
    [(>= (length outl) n) (reverse outl)]  ; if n primes found, print outlist.
    [(ormap (λ(x) (= 0 (modulo current x))) ; test if divisible by any previously found prime
            (filter                         ; filter outlist till sqrt of current number
             (λ(x) (<= x (sqrt current)))
             outl))
     (loop outl (add1 current)) ]           ; goto next number without adding to prime list
    [else (loop (cons current outl) (add1 current))] ; add to prime list and go to next number
    )))

测试:

(nprimes 35)

输出:

'(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149)

0

awk 45(复杂度N ^ 2)

另一个awk,最多可使用100次,像这样

awk '{for(i=2;i<=sqrt(NR);i++) if(!(NR%i)) next} NR>1' <(seq 100)

编码高尔夫计数部分是

{for(i=2;i<=sqrt(NR);i++)if(!(NR%i))next}NR>1

可以将其放在脚本文件中并以 awk -f prime.awk <(seq 100)


0

Javascript,61个字符

f=(n,p=2,i=2)=>p%i?f(n,p,++i):i==p&&n--&alert(p)||n&&f(n,++p)

比O(n ^ 2)还差一点,对于大n来说,堆栈空间不足。

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.