求10的10次方以内的所有素数

  朋友应聘一家公司的程序员,问卷中有一道题是求10的10次方以内的素数,要求运行时间不超过10个小时(可以不输出)。想了一天写出来的算法在我1.73G的本本上运行,10个小时内出不来……后来老吴在CSDN上发了贴,很多人回复,其中有一个算法真的很强,如果数字小的话,如1000000内的素数,在我本本上只需140毫秒。。。真的很打击人……他的这段代码是牺牲空间来满足时间,这样就会有一个很致命的弱点,万一内存不够就会很慢很慢,大部分时间都用在页面交换上,因为里面定义了一个char类型的数组作为标志位。显然,10的10次方的数组会占用10的10次方个字节,也就是需要分配10G的内存。天啊!!哪来那么大的内存!所以如果不优化的话就会花大量的时间在与虚拟内存的页面交换上。

  后来用了几个小时(工作效率很低……)优化。标志位其实只需1位即可,char类型中的其它7位就会很浪费!只需把这7位都利用上就可以把内存需求降至10/8 = 1.25G。第二步,很显然,除了2以外的所有偶数都不是素数,这样就又可以排除一半的空间需求,最终降到只需625MB内存。只要内存足够,不必用到硬盘上的虚拟内存的话就会速度惊人!在我本本1.73G CPU,1G内存之下计算(没有输出),只用了46分钟!!!这是运行时的输出结果:

   *** Calculate all the Primes that is less than 10000000000   ***
Program Started at: 2006.9.1 1:57:5
The total number is: 455052511
Elapsed Time = 2761781 ms
Program Ended at: 2006.9.1 2:43:7

  当然,万一内存不够,如只有512MB内存时,运行时间就会相差甚远。

  这是在网上找的一个算法,在此基础上优化好的代码如下:

 

#include <iostream>

#include <complex>

#include <windows.h>

using namespace std;

 

#define MAX 10000000000    //查找上限

 

// 一个字节的每一位作为一个数是否素数的标志位

// 除表示去掉偶数,因为除了以外任何偶数都不是素数

char shu[(MAX+1)/8/2+1]; //标志位数组,占用空间较大,已优化,节省空间

 

const byte bit[8] = { 0x01,

                      0x02,

                      0x04,

                      0x08,

                      0x10,

                      0x20,

                      0x40,

                      0x80 };

 

void main(void)

{

    // 输出程序开始的时间

    cout << "   *** Calculate all the Primes that is less than " << MAX << "   ***" << endl;

    SYSTEMTIME beginTime, endTime;

    GetLocalTime( &beginTime );

    cout << "Program Started at: " << beginTime.wYear << "." << beginTime.wMonth << "." << beginTime.wDay << " "

        << beginTime.wHour << ":" << beginTime.wMinute << ":" << beginTime.wSecond << endl;

    DWORD elapse = GetTickCount();

 

//===================  开始计算 ==================

 

    __int64 i = 0;

    __int64 notPrime = 0;

    __int64 step = 0;

    __int64 num = MAX/2;    // 记录素数个数

 

 

    shu[0] = shu[0] | bit[0];    // s[0]代表的是,不是素数

 

    num++;    // 2 是素数,但没被列入数组中,此处加

   

    for(i = 0; i < MAX / 4; i++)

    {

       int tmp1 = i / 8;      // tmp1个数组

       int tmp2 = i % 8;      // tmp2

       if(shu[tmp1] & bit[tmp2])

           continue;

 

       step = 2*i+1;

       for(notPrime = step + i; notPrime <= MAX/2; notPrime += step)

       {

           int tmp1 = notPrime / 8;      // tmp1个数组

           int tmp2 = notPrime % 8;      // tmp2

           if(!(shu[tmp1] & bit[tmp2]))    // 不输出时用来计算有多少个素数

              num--;

           shu[tmp1] = shu[tmp1] | bit[tmp2];

       }

    }

   

    // 输出结果,不需要输出则加注释

    //printf("2\n");

    //for(i = 1, notPrime = 1; i < MAX/2; i++)

    //{

    //  int tmp1 = i / 8;      // tmp1个数组

    //  int tmp2 = i % 8;      // tmp2

    //  if(!(shu[tmp1] & bit[tmp2]))

    //  {

    //     printf("%d\n", 2*i+1);

    //     notPrime++;    // 输出时计算有多少个素数

    //  }

    //}

 

    printf("The total number is: %d\n", num);

 

//===================  结束计算 ==================

 

    // 输出程序结束时的时间,并输出计算运行时间

    cout << "Elapsed Time = " << GetTickCount() - elapse << " ms" << endl;

    GetLocalTime( &endTime );

    cout << "Program Ended at: " << endTime.wYear << "." << endTime.wMonth << "." << endTime.wDay << " "

        << endTime.wHour << ":" << endTime.wMinute << ":" << endTime.wSecond << endl;

    FILE* file;

    if ( file = fopen( "log.txt", "w" ) )

    {

       char buffer[512];

       sprintf( buffer, "Program Started at: %d.%d.%d %d:%d:%d\n\n",

           beginTime.wYear, beginTime.wMonth, beginTime.wDay,

           beginTime.wHour, beginTime.wMinute, beginTime.wSecond );

       fputs( buffer, file );

       sprintf( buffer, "Program Ended at: %d.%d.%d %d:%d:%d\n\n",

           endTime.wYear, endTime.wMonth, endTime.wDay,

           endTime.wHour, endTime.wMinute, endTime.wSecond );

       fputs( buffer, file );

       sprintf( buffer, "Elapsed Time = %d ms", GetTickCount() - elapse );

       fputs( buffer, file );

       fclose( file );

    }

 

    // 为了避免程序运行完自动关闭控制台窗口

    char a;

    while ( true )

       cin>>a;

}

 

posted @ 2006-09-07 00:15  cxun  阅读(3904)  评论(6编辑  收藏  举报