欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

如何编程最快速度求出两百万以内素数个数(不限语言和算法)?

程序员文章站 2024-01-26 13:10:58
...

回复内容:

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;iNmax;i+=2)
			isPrime[i]=true;
		isPrime[2]=true;
		for(int i=3;iMath.sqrt(Nmax);i+=2){
			if(isPrime[i]==true){
				for(int j=i*i;jNmax;j+=2*i)
					isPrime[j]=false;
			}
		}
		int primeNum=0;
		for(int i=1;iNmax;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秒解出来。 quartergeek.com/sieve-p
线性筛法 我来终结此问题。
计算素数个数被数学家和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; iq; ++i ){
		if ( ! b[i] ){
			for ( j=i1; jN; j+=i ){
				b[j] = true;
			}
		}
	}
	for ( i=2; iN; ++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; iN; ++i ){
		if ( ! b[i] ){
			c[cnt++] = i;
		}
		for ( j=0; jcnt; ++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; inum; ++i ){
		Era_select();
	}
	printf("%lf seconds\n", (double)(clock()-start) / CLOCKS_PER_SEC / num);
	start = clock();
	for ( i=0; inum; ++i ){
		Euler_select();
	}
	printf("%lf seconds\n", (double)(clock()-start) / CLOCKS_PER_SEC / num);
	return 0;
}
*上有个关于用python求解最快算法的讨论(optimization),如果用纯python语言的话,最快的算法是下面这个:
def rwh_primes2(n = 10**6):
    # http://*.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了。一只做到完。

如何编程最快速度求出两百万以内素数个数(不限语言和算法)?

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

相关文章

相关视频


网友评论

文明上网理性发言,请遵守 新闻评论服务协议

我要评论
  • 如何编程最快速度求出两百万以内素数个数(不限语言和算法)?
  • 专题推荐

    作者信息
    如何编程最快速度求出两百万以内素数个数(不限语言和算法)?

    认证0级讲师

    推荐视频教程
  • 如何编程最快速度求出两百万以内素数个数(不限语言和算法)?javascript初级视频教程
  • 如何编程最快速度求出两百万以内素数个数(不限语言和算法)?jquery 基础视频教程
  • 视频教程分类