回复内容:
x贴一个优化得比较过分的线性筛。用位模式保存状态,直接绕过2和3的倍数。
#include #include #include #include #define PRIME_LIM 10000000 #define N 100000000 int primes [ PRIME_LIM ] = { 0 }; int flags [ N / 96 + 1 ] = { 0 }; int get_prime () { int nu = 5 , to = 0 ; primes [ 0 ] = 2 ; primes [ 1 ] = 2 , primes [ 2 ] = 3 ; for ( int i = 0 ; nu N ; i ++ ) { if ( ! ( flags [ i >> 5 ] & ( 1 ( i & 31 )))) primes [ ++ primes [ 0 ]] = nu ; for ( int j = 3 ; j primes [ 0 ] && primes [ j ] * nu N ; j ++ ) { to = ( nu * primes [ j ] - 5 ) >> 1 ; to -= to / 3 ; flags [ to >> 5 ] |= 1 ( to & 31 ); if ( ! ( nu % primes [ j ])) break ; } nu += 2 + (( i & 1 ) 1 ); } return primes [ 0 ]; } int main () { clock_t t = clock (); printf ( "%d \n " , get_prime ()); printf ( "Time:%f \n " , 1.0 * ( clock () - t ) / CLOCKS_PER_SEC ); for ( int i = 1 ; primes [ i ] 100 ; i ++ ) { printf ( "%d \n " , primes [ i ]); } return 0 ; }【多种方法比较,长文慎入】
看到各位大神用各种语言写的代码,我这个外行人也跃跃欲试了。
鉴于大家已经给出了C,C++,Python,Mathmatica等的实现过程,那我就用 Java吧 。
我不会流氓地直接用各种Prime函数(那样对问题讨论毫无意义),还是给出完整实现过程 吧。
算法一般,还有待改进,欢迎各位大神指正:
我用的是筛法,稍稍做了优化(把偶数单独列出来筛),代码如下:
1、初始版代码:
class Prime { public static int calculateNumber ( int Nmax ){ boolean [] isPrime = new boolean [ Nmax + 1 ]; for ( int i = 3 ; i Nmax ; i += 2 ) isPrime [ i ]= true ; isPrime [ 2 ]= true ; for ( int i = 3 ; i Math . sqrt ( Nmax ); i += 2 ){ if ( isPrime [ i ]== true ){ for ( int j = i * i ; j Nmax ; j += 2 * i ) isPrime [ j ]= false ; } } int primeNum = 0 ; for ( int i = 1 ; i Nmax ; i ++){ if ( isPrime [ i ]== true ) primeNum ++; } return primeNum ; } public static void main ( String [] args ){ final int Nmax = 2000000 ; double startTime = System . currentTimeMillis (); int primeNum = Prime . calculateNumber ( Nmax ); double timeSpent =( System . currentTimeMillis ()- startTime )/ 1000 ; System . out . println ( "The prime numbers from 1 to " + Nmax + " is " + primeNum ); System . out . println ( "Time spent : " + timeSpent + " s" ); } }如果题主希望得到的答案仅限于筛法,那基本上线性筛从复杂度上已经是最优的了,只剩下各种优化了。特别是如果要死扣最后那么点性能,就必然是面向体系结构的优化了,比如多线程优化、根据intel的体系结构如何选择各类指令的分布、用类似prefetch之类的指令降低存储器访问延迟等等。
至于算法层面,从标题来看只是求质数个数,而并不需要枚举所有质数。于是存在比线性更优的算法,可以参考:素数计数函数 。其时间复杂度为O(x^(2/3)/log(x)),空间复杂度为O(x^(1/3)log(x)^2)
具体代码实现可以围观:kimwalisch/primecount · GitHub 。
当然最后运行时间对于两百万这个“小”数据基本是可以忽略不计的( Mathematica可以在0.012001秒解出来。 Mathematica可以在0.012001秒解出来。 http:// quartergeek.com/sieve-p rime-in-linear-time/
线性筛法 我来终结此问题。
计算素数个数被数学家和ACMer玩烂了,没啥优化的空间了。
用C语言,计算200万以内素数个数,100次实验取平均
用埃氏筛法,0.035620 seconds
用欧拉筛法,0.025630 seconds
计算1亿以内素数个数,10次实验取平均
用埃氏筛法,2.890600 seconds
用欧拉筛法,1.473400 seconds
运行机器:32位XP
#include #include #include #include const int N = 2000000 ; bool b [ N + 1 ]; int c [ N + 1 ]; void Era_select (){ // Eratosthenes memset ( b , 0 , N + 1 ); int q = ( int ) sqrt ( N ); int i , j , cnt = 0 ; for ( i = 2 ; i q ; ++ i ){ if ( ! b [ i ] ){ for ( j = i 1 ; j N ; j += i ){ b [ j ] = true ; } } } for ( i = 2 ; i N ; ++ i ){ if ( ! b [ i ] ){ ++ cnt ; } } //printf("%d\n", cnt); } void Euler_select (){ memset ( b , 0 , N + 1 ); int i , j , cnt = 0 , t ; for ( i = 2 ; i N ; ++ i ){ if ( ! b [ i ] ){ c [ cnt ++ ] = i ; } for ( j = 0 ; j cnt ; ++ j ){ t = i * c [ j ]; if ( t > N ){ break ; } b [ t ] = true ; if ( i % c [ j ] == 0 ){ break ; } } } //printf("%d\n", cnt); } int main (){ int i , num = 100 ; clock_t start ; start = clock (); for ( i = 0 ; i num ; ++ i ){ Era_select (); } printf ( "%lf seconds \n " , ( double )( clock () - start ) / CLOCKS_PER_SEC / num ); start = clock (); for ( i = 0 ; i num ; ++ i ){ Euler_select (); } printf ( "%lf seconds \n " , ( double )( clock () - start ) / CLOCKS_PER_SEC / num ); return 0 ; }stackoverflow上有个关于用python求解最快算法的讨论(optimization ),如果用纯python语言的话,最快的算法是下面这个:
def rwh_primes2 ( n = 10 ** 6 ): # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188 """ Input n>=6, Returns a list of primes, 2 correction = ( n % 6 > 1 ) n = { 0 : n , 1 : n - 1 , 2 : n + 4 , 3 : n + 3 , 4 : n + 2 , 5 : n + 1 }[ n % 6 ] sieve = [ True ] * ( n / 3 ) sieve [ 0 ] = False for i in xrange ( int ( n ** 0.5 ) / 3 + 1 ): if sieve [ i ]: k = 3 * i + 1 | 1 sieve [ (( k * k ) / 3 ) :: 2 * k ] = [ False ] * (( n / 6 - ( k * k ) / 6 - 1 ) / k + 1 ) sieve [( k * k + 4 * k - 2 * k * ( i & 1 )) / 3 :: 2 * k ] = [ False ] * (( n / 6 - ( k * k + 4 * k - 2 * k * ( i & 1 )) / 6 - 1 ) / k + 1 ) return [ 2 , 3 ] + [ 3 * i + 1 | 1 for i in xrange ( 1 , n / 3 - correction ) if sieve [ i ]]很多人说我是喷子,我不同意
对于治病救人,我有时候有不同的理解,这很正常。
看到有人在吃屎,安全的做法是告诉他慢慢吃别噎着,加点油盐酱醋味精啥的,再端碗鸡汤,然后皆大欢喜,大家都很高兴。
虽然我倡导diversity,但我对这种行为异常鄙夷,我认为,你他妈应该立即打断啊。。。(当然,我知道有人是嗜粪的,所以因为我每次都打断所以有时候我也会犯错,但这种情况还是罕见的)
如果不是我必须表现得礼貌,我会说你写的这些东西还不如一坨屎
这是一段根本没法运行的代码,whese is is_prime()??? 100000用1e6,我不知道你是什么心态?如果装逼,则可以叉出去了,如果不知道可以直接用200000.....尼玛32位数4294967296是常识吧?更应该叉出去了 乱取名字,竟敢覆盖list,真坑爹 好好的math.sqrt不用,用什么**0.5,什么心态 你那么喜欢所谓“黑科技”优化,为啥不用xrange? 乱用列表推倒,列表没推倒,你自己先倒了 你那么喜欢省代码行数讨厌回车,我推荐你用c语言,用那个可以写成一行 哪有这样写python的? 你觉得跑了21秒的程序有必要写清楚型号配置吗? 如果不是我必须表现得礼貌,我会问你觉得这种垃圾有必要双配置对比吗? 你们可以说他不懂,但这种眼高手低,搞两个名词,乱来一气的做法,跟《小时代》受众在性质上也差不离,人家郭敬明的粉丝也不懂啦
如果你随便玩玩,忽略这些话
如果想好好学,那么建议摆正心态,脚踏实地,不要走火入魔,误入歧途。想要成功,要牢记3点,1是切忌南辕北辙,2是不能说太多, 如果不要求准确值的话,用估算好了,x/ln(x)
以前为了算某个群号,曾经计算了八千万以内的素数,花了两秒钟。群里有个人0.2秒,觉得很牛逼,始终没明白是怎么做的。
我的做法很简单,给出八千万个bool(其实可以去掉偶数)。一开始拿出2,把2的倍数都true了。下一个false的是3,把3的倍数都true了。下一个false的是5,把5的倍数都true了。一只做到完。
查看更多关于如何编程最快速度求出两百万以内素数个数(不限语言和算法)?的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did83274