求小于N的素数解决方案

求小于N的素数最近写了个求小于N的素数的程序,感觉效率一般。在i3处理器上求小于100万的素数15秒,小于1千万

求小于N的素数
最近写了个求小于N的素数的程序,感觉效率一般。在i3处理器上求小于100万的素数15秒,小于1千万的素数要5分钟。哪位大神帮改进一下,或者有什么更效率的算法,指点一下。
下面是源代码:
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <time.h>

typedef unsigned long long ULL;
using namespace std;

int main(int args, char *argv[])
{
clock_t start, finish;
double time;
unsigned long long m, n, i;
short f = 1;
vector<ULL> prime;
vector<ULL>::iterator p;
prime.push_back(2);
cin >> n;
i = 3;
start = clock();
while (i <= n)
{
f = 1;
m = sqrtl(i);
for (p = prime.begin(); *p <= m; p++)
{
if(0 == i % *p)
{
f = 0;
break;
}
}
if (0 == f)
{
f = 1;
i += 2;
}
else
{
prime.push_back(i);
i += 2;
}
}
finish = clock();
time = (double)(finish - start) / CLOCKS_PER_SEC;
//for(p = prime.begin(); p != prime.end(); p++)
//{
//cout << *p << "\n";
//}
cout << endl;
cout << prime.size() << endl;
cout << time << endl;
return 0;
}

[解决办法]
是什么原因? 就因为我的是i7的Mac? 1000w,我才5.26366秒啊。

就是你的代码。
[解决办法]
更效率的算法
--------------
1.以空间换时间
2.WitNess算法,判断素数
[解决办法]
你可以研究一下欧拉筛法
[解决办法]
http://blog.csdn.net/creazierhit/article/details/7792571
楼主看看这个,我也是别人那儿找的,挺好的所以收藏啦!
[解决办法]

探讨

引用:

是什么原因? 就因为我的是i7的Mac? 1000w,我才5.26366秒啊。

就是你的代码。

我用2个4核处理器的主机还要12秒呢,你那电脑太牛逼了!

[解决办法]
百度 Miller-Robbin 素数测试算法。 目前最快的素数测试算法, 基于概率论 和 佛洛依德生日悖论的 因子碰撞思想, 暴力破解密码的 基础算法之一。。。


[解决办法]
探讨

引用:

你可以研究一下欧拉筛法

这个我知道,但是我不清楚这个方法要怎么写程序才能高效率。

[解决办法]
对于一个输入N, 计算是否为素数的代码。。。 然后你可以吧其中计算过程提取出来放到你的0-N的循环中, 然后比较一下1000w的运行时间,, 看看能否赶上他的I7, 看看 数学算法能否 战胜 硬件???

拭目以待,,,
C/C++ code
#include <iostream>  #include <stdlib.h>  #include <time.h>  #include <math.h>    using namespace std;    typedef unsigned long long TYPE;    // 产生随机数  static bool bInitRandom = false;  TYPE GetRandomi(TYPE Begin, TYPE End)  {      if (!bInitRandom)      {          bInitRandom = true;          srand((unsigned int) time(NULL));      }        return Begin + rand() % (End - Begin);  }    // a*b % n求模  TYPE MultiplyMod(TYPE a, TYPE b, TYPE n)  {      TYPE nReturn = 0 , i ;       a %= n;       b %= n;      for (i = b; i > 0; a = (a << 1) % n, i >>= 1)      {          if (i & 1)           {              nReturn = (nReturn + a) % n;          }      }        return nReturn;  }      // 获取2进制序列  int GetBinarySet(bool* pBinarySet, TYPE nNum)  {      int nLen = 0;        while(nNum)      {          pBinarySet[nLen ++] = nNum & 1;          nNum >>= 1;      }        return nLen;  }    // 如果结果不为1,则一定是合数,如果结果为1,可能为素数  TYPE ModularExponetiation(TYPE bigDigit, TYPE b, TYPE n)  {     // 整形变量最多32位,所以可以用32字节存储2进制串, nLen存储长度     TYPE nReturn = 1;        int nLen = 0;     bool szbBinarySet[64] = { 0 };           // 获取b的二进制串     nLen = GetBinarySet(szbBinarySet, b);     for (int i = nLen - 1; i >= 0; i --)     {         nReturn = MultiplyMod(nReturn, nReturn , n);         //nReturn = nReturn * nReturn %  n;         if (szbBinarySet[i])         {             nReturn = MultiplyMod(nReturn, bigDigit, n);             //nReturn = nReturn * bigDigit % n;         }     }       return nReturn;  }    bool Witness(TYPE bigDigit, TYPE n)  {      TYPE u = 0, t = 0, x, y, i;      // 初始化 u,t      // 产生一个奇数u,使得 n - 1 == 2^t * u, t >= 1        int nLen = 0;      TYPE tmp = n - 1;      while(tmp)      {          nLen ++;          tmp >>= 1;      }        for (t = nLen -1; t >= 0; t --)      {          i = 1;          for(int j = 0; j < t; j ++)          {              i <<= 1;          }            if ((n - 1) % i == 0 ) // 若 n -1可以整除  2^t           {              u = (n - 1) / i;                // 如果u是奇数则停止              if(u % 2 == 1)              {                  break;              }          }      }        x = ModularExponetiation(bigDigit, u, n);      // 测试 x是否为伪素数      for (i = 0; i <= t; i ++)      {          y = MultiplyMod(x, x, n);          //y = x * x %  n;            if (x == 1 && y != 1 && y != n -1)          {              return true;          }            x = y;      }        if (x != 1)      {          return true;      }        return false;  }    bool MillerRabin(TYPE llValue, int nTime)  {     for(int i = 0; i < nTime; i ++)     {        TYPE a = GetRandomi(1, llValue - 1);                //a = 20280;        if(Witness(a, llValue))           return false;  // 肯定是合数     }          return true; // 可能是素数  }      int main()  {     int n;     cin >> n;       TYPE llValue;     bool* pIsPrim = new bool[n];     memset(pIsPrim, 0, sizeof(bool) * n);          for(int i = 0; i < n; i ++)     {        cin >> llValue;          if (llValue == 2)        {            pIsPrim[i] = true;            continue;        }        else        {            if(MillerRabin(llValue, 10)) // 10次蒙特卡洛算法,正确率在99%以上            {               pIsPrim[i] = true;            }        }     }          for(int i = 0; i < n; i ++)     {        if(pIsPrim[i])        {           cout << "Yes" << endl;        }        else        {           cout << "No" << endl;        }     }            delete[] pIsPrim;     return 0;  } 


[解决办法]
之前寫的欧拉筛法

C/C++ code
#ifndef SOE_HPP#define SOE_HPP#include <bitset>#include <chrono>#include <cmath>#include <iostream>inline void test_sieve_of_eratosthenes(){    typedef std::chrono::time_point<std::chrono::system_clock> TimePoint;    TimePoint start = std::chrono::system_clock::now();    size_t const SIZE = 1000000;    std::bitset<SIZE> result;    result.flip();    result.reset(0);    result.reset(1);    size_t const finalBit = sqrt(static_cast<double>(SIZE) ) + 1;    for(size_t i = 2; i != finalBit; ++i)    {        if(result[i])        {            for(size_t j = i * 2; j < SIZE; j += i)                result.reset(j);        }    }    TimePoint end = std::chrono::system_clock::now();    int elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>                                 (end-start).count();    std::cout << "elapsed seconds = " << elapsed_seconds << std::endl;    }#endif // SOE_HPP
[解决办法]
探讨
但是!!!!!!!!!!!!!!!!!!!!!!!!
运算结果不准确,小于10^7的素数有664579个,该程序的运算结果是664687!
结果不对,速度再快也使没用。


[解决办法]
判断一个数是不是素数有很多定理的
只测试那些可能是素数的数,用通相公式做一个生成器
比如(4n+1), (4n-1)比较容易是素数

然后根据适用范围选择不同的生成器
[解决办法]
记 N = 2*3*5*7*11*13 , 对大于N的数X可以表示为 X = A*N + B , 显然 X 为素数的必要条件是 
GCD( N , B ) == 1 

起多个线程对不同的 B 做筛法, 完成 100亿以内的筛法在 i5 级别的机器上运行时间应该小于两秒.
2001 年 intfree 的那个筛法程序运行在 PII 500M的机器上, 求100亿以内的素数, 运行时间是 50秒.

求一定范围内的素数个数有 O(N^2/3) 的算法, 求1000亿以内的素数个数也可以秒出.

[解决办法]
探讨

引用:
但是!!!!!!!!!!!!!!!!!!!!!!!!
运算结果不准确,小于10^7的素数有664579个,该程序的运算结果是664687!
结果不对,速度再快也使没用。



正解。

程序,首先是 正确, 其次才是谈性能。

可以验证的,【小于10^7的素数有664579个】,

验证一下
9/13/12 18:18:10 In[9]:……

[解决办法]
探讨

引用:

结贴的时候多给我点分啊,为了你的问题,我的i7都成为靶子了~~~


帮测试一下我新改的代码。
我测试10^8用时31.61

#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <ti……