找回密码
 欢迎注册
楼主: mathe

[擂台] 素数分解

[复制链接]
发表于 2008-6-27 13:10:33 | 显示全部楼层


呵呵

那复杂度也是迅速增加的

我不知道到底多小合适
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-6-28 06:53:16 | 显示全部楼层
昨天重新从和数$1.8*10^15$左右开始搜索,得到一个满足除了条件a)的解,也就是同时满足本身素数,17个素数和,45个素数和,979个素数和以及2007个素数和的条件的:
1814523290364469

平均来说,应该每50个左右这样的数可以找到一个3个素数和的情况。
如果找一个花费1天的时间,那么需要50天(或者100台机器花费半天)

评分

参与人数 1鲜花 +2 收起 理由
gxqcn + 2 祝贺祝贺!

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-6-28 08:23:46 | 显示全部楼层


并行应该没这么大加速比吧
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-6-28 09:12:19 | 显示全部楼层
还好,这个问题并行性很好,而且复杂度不算太高。100台机器运行半天只是有可能产生结果,但是不一定产生,如果运行时间更加长一些,比如一星期,出结果的可能性就非常大了。比如假设运行一天没找到结果概率为$e^-1$,那么运行一星期没有找到结果的概率就是$e^-7=0.1%$
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-6-28 09:23:23 | 显示全部楼层
刚刚查看一下,又产生了一个
1852547403117883
下面是完整的代码,其中START_V可以修改成任何小于$2*10^18$,从而程序会从不同位置开始运行

  1. // HugeCalcDemo.cpp : Defines the entry point for the console application.
  2. //

  3. // Project -> Setting -> C/C++ -> Code Generation --> Use run-time library:
  4. //  Win32 Debug:    Debug Multithreaded DLL
  5. //  Win32 Release:  Multithreaded DLL

  6. // 以下代码源自 mathe 的,略有修改

  7. #include <time.h>
  8. #include <iostream>
  9. #include <stdio.h>
  10. #include <list>
  11. using namespace std;
  12. #include "../../../HugeCalc_API/CppAPI/Include/HugeCalc.h"  // 公共接口
  13. #include "../../../HugeCalc_API/CppAPI/Include/HugeInt.h"   // 10进制系统
  14. #include "../../../HugeCalc_API/CppAPI/Include/HugeIntX.h"  // 16进制系统

  15. #pragma message( "automatic link to ../../../HugeCalc_API/CppAPI/Lib/HugeCalc.lib" )
  16. #pragma comment( lib, "../../../HugeCalc_API/CppAPI/Lib/HugeCalc.lib" )

  17. #if 1
  18.     #define _Test_HI
  19.     #define integer CHugeInt
  20. #else
  21.     #define _Test_HX
  22.     #define integer CHugeIntX
  23. #endif

  24. #define MAX_N  203280220
  25. unsigned int plist[MAX_N];

  26. #include "math.h"
  27. #include "memory.h"
  28. #include "windows.h"

  29. //**********************************************
  30. // n 不能大于L2 cache,否则效能很低
  31. DWORD Sift32(DWORD n,DWORD *primeTab)
  32. // 对0到n 之间(不包括n)的数进行筛选,返回质数的个数
  33. //**********************************************
  34. {
  35.         BYTE *pBuff= new BYTE[n];
  36.         if (pBuff==NULL)
  37.                 return 0;

  38.         DWORD i,sqrt_n,p;
  39.         DWORD pn;
  40.         //----------------------------
  41.         sqrt_n=(DWORD)(sqrt((double)n)+1);
  42.        
  43.         while (sqrt_n * sqrt_n >=n)
  44.                 sqrt_n--;
  45.        
  46.         memset(pBuff,1,n*sizeof(BYTE));
  47.         *pBuff=0;
  48.         *(pBuff+1)=0; //1不是质数
  49.         *(pBuff+2)=1; //2是质数

  50.         for ( i=4;i<n;i+=2) //筛去2的倍数,不包括2
  51.                 *(pBuff+i)=0;
  52.        
  53.         for (i=3;i<=sqrt_n;) //i 是质数
  54.         {
  55.                 for (p=i*i;p<n; p+=2*i)
  56.                         *(pBuff+p)=0; //筛去i 的奇数倍
  57.                 i+=2;
  58.                 while ( *(pBuff+i)==0 )
  59.                         i++; //前进到下一个质数
  60.         }
  61.         pn=0; //素数个数
  62.         for (i=2;i<n;i++)
  63.         {
  64.                 if (pBuff[i])
  65.                 {
  66.                         primeTab[pn++]=i;
  67.                 }
  68.         }
  69.         delete[] pBuff;
  70.         return pn;
  71. }

  72. #define L2_CACHE (2*1024*1024)
  73. static DWORD getSiftBuffLength()
  74. {
  75.         DWORD n=L2_CACHE * 3/4;
  76.         DWORD rem=n % 30;
  77.         if (rem !=0)
  78.                 n-=rem;
  79.         return n;   //n must times of 30
  80. }


  81. //**********************************************
  82. // copy prime from psrc to primeTab
  83. // mode can be 4 or 8
  84. // if mode==4, primeTab will be consider as DWORD array
  85. // if mode==8, primeTab will be conseder ad UINT64 array
  86. // return total prime Count
  87. //**********************************************
  88. int copyL1PrimeToArray(const DWORD *psrc,int srcCount,void *primeTab,int primeBuffLen, int mode)
  89. {
  90.         DWORD pr;
  91.         int i;
  92.         pr=0;
  93.         if (mode==4)
  94.         {
  95.                 DWORD *UINT32PrimeTab=(DWORD*)primeTab;
  96.                 for (i=0;i<srcCount && pr<primeBuffLen;i++)
  97.                 {
  98.                         UINT32PrimeTab[pr]=psrc[i];
  99.                         pr++;
  100.                 }
  101.                 for (;i<srcCount;i++ )
  102.                 {        pr++; }
  103.         }
  104.         else if (mode==8)
  105.         {
  106.                 UINT64 *UINT64PrimeTab=(UINT64*)primeTab;
  107.                 for (i=0;i<srcCount && pr<primeBuffLen;i++)
  108.                 {
  109.                         UINT64PrimeTab[pr]=(UINT64)psrc[i];
  110.                         pr++;
  111.                 }
  112.                 for (;i<srcCount;i++ )
  113.                 {        pr++; }
  114.         }
  115.         return pr;
  116. }
  117. //**********************************************
  118. // mode can be 4 or 8
  119. // if mode==4, primeTab will be consider as DWORD array
  120. // if mode==8, primeTab will be conseder ad UINT64 array
  121. // return total prime Count
  122. //**********************************************
  123. static UINT64 GetPrimeFromSiftBuff(const BYTE *siftBuff,UINT64 begin, UINT64 end,
  124.                                            void *primeTab,UINT64 currCount,UINT64 primeBuffLen, int mode)
  125. {
  126.         UINT64 pr;
  127.         int i;
  128.         pr=currCount;
  129.         DWORD *UINT32PrimeTab=(DWORD*)primeTab;
  130.         UINT64 *UINT64PrimeTab=(UINT64*)primeTab;
  131.         //-----------------------------------
  132.         if (mode==4)
  133.         {
  134.                 for (i=0;i<end-begin && pr < primeBuffLen;i++)
  135.                 {
  136.                         if (siftBuff[i]==1)
  137.                         {
  138.                                 UINT64 p=begin+(UINT64)i;
  139.                                 UINT32PrimeTab[pr]=(DWORD)p;
  140.                                 pr++;
  141.                         }
  142.                 }
  143.         }
  144.         else if (mode==8)
  145.         {
  146.                 for (i=0;i<end-begin && pr < primeBuffLen;i++)
  147.                 {
  148.                         if (siftBuff[i]==1)
  149.                         {
  150.                                 UINT64 p=begin+(UINT64)i;
  151.                                 UINT64PrimeTab[pr]=p;
  152.                                 pr++;
  153.                         }
  154.                 }
  155.         }
  156.        
  157.         for (;i<end-begin;i++)
  158.         {
  159.                 if (siftBuff[i]==1)
  160.                 {
  161.                         pr++;
  162.                 }
  163.         }
  164.         return pr;
  165. }

  166. DWORD L1PrimeBuffLen;
  167. DWORD *L1PrimeTab;
  168. DWORD L1PrimeCount;
  169. void initSift(UINT64 n)
  170. {
  171.     DWORD sqrt_n;
  172.     double f;
  173.     sqrt_n=(DWORD)(sqrt((double)n));
  174.     sqrt_n=(sqrt_n+29)/30*30;
  175.     f=(double)sqrt_n*10.0/9.0+32;
  176.         L1PrimeBuffLen= (DWORD)f;
  177.        
  178.         L1PrimeTab= new DWORD[L1PrimeBuffLen];

  179.         L1PrimeCount= Sift32(sqrt_n,L1PrimeTab);
  180. }

  181. //**********************************************
  182. // 使用普通分段筛的方法筛素数,
  183. // // mode can be 4 or 8
  184. // if mode==4, primeTab will be consider as DWORD array
  185. // if mode==8, primeTab will be conseder ad UINT64 array
  186. UINT64 generalSift(UINT64 begin, UINT64 end,void *primeTab, UINT64 primeTabLimtCount)
  187. // 对0到n 之间(不包括n)的数进行筛选,返回质数的个数
  188. //**********************************************
  189. {
  190.         DWORD  siftBuffLen;
  191.         UINT64  pr=0;

  192.         siftBuffLen=end-begin;
  193.         BYTE *siftBuff=new BYTE[siftBuffLen];
  194.         if (siftBuff==NULL)
  195.                 return 0;
  196.        
  197.         {
  198.                 DWORD dwPrime,endPrime;
  199.                 UINT64 begIndex;
  200.                 DWORD  endIdx;
  201.                 int idx,i;
  202.                
  203.                 endIdx=end-begin;

  204.                 memset(siftBuff,1,siftBuffLen);
  205.                 endPrime= (DWORD)sqrt((double)end)+1;
  206.                
  207.                 while (endPrime*endPrime>=end)
  208.                         endPrime--;
  209.                 i=0;
  210.                 while (true)
  211.                 {
  212.                         DWORD inc;
  213.                         UINT64 t;
  214.                         dwPrime=L1PrimeTab[i];
  215.                         if ((UINT64)dwPrime * dwPrime>=end)
  216.                                 break;
  217.                         t=(begin+dwPrime-1)/dwPrime;
  218.                         if ( t<dwPrime)
  219.                                 t=dwPrime;
  220.                        
  221.                         if (dwPrime==2)
  222.                         {
  223.                                 idx=(int)(t * dwPrime-begin);
  224.                                 while (idx<endIdx)
  225.                                 {
  226.                                         siftBuff[idx]=0;
  227.                                         idx+=dwPrime;
  228.                                 }
  229.                         }
  230.                         else
  231.                         {
  232.                                 if ( t % 2==0)
  233.                                         t++;                //素数的奇数倍
  234.                                 inc= dwPrime+dwPrime;
  235.                                 idx=(int)(t * dwPrime-begin);
  236.                                 while (idx<endIdx)
  237.                                 {
  238.                                         siftBuff[idx]=0;
  239.                                         idx+=inc;
  240.                                 }
  241.                         }
  242.                         i++;
  243.                 }
  244.                 pr=GetPrimeFromSiftBuff(siftBuff,begin,end,primeTab,pr,primeTabLimtCount,8);
  245.         }
  246.         delete[] siftBuff;
  247.         return pr;
  248. }


  249. int search_match_prime(unsigned value)
  250. {
  251.     int start=0,mid,end=MAX_N-1;
  252.     mid=(start+end)/2;
  253.     while(end-start>=2){
  254.         if(plist[mid]<value){
  255.             start=mid;
  256.         }else{
  257.             end=mid;
  258.         }
  259.         mid=(start+end)/2;
  260.     }
  261.     return mid;
  262. }

  263. bool is_list(int num, unsigned long long sum)
  264. {
  265.     unsigned long long aver=sum/num;
  266.     integer start(aver),end,sump(0);
  267.     start.NextPrime(start);
  268.     int prevc,nextc;
  269.     prevc=num/2;
  270.     nextc=num-1-prevc;
  271.     int i;
  272.     sump=end=start;
  273.     for(i=0;i<nextc;i++){
  274.         integer tmp(end);
  275.         end.NextPrime(tmp);
  276.         sump+=end;
  277.     }
  278.     for(i=0;i<prevc;i++){
  279.         integer tmp(start);
  280.         start.PreviousPrime(tmp);
  281.         sump+=start;
  282.     }
  283.     if(sump<integer(sum)){
  284.         while(sump<integer(sum)){
  285.             integer newp;
  286.             newp.NextPrime(end);
  287.             sump+=newp-start;
  288.             integer tmp(start);
  289.             start.NextPrime(tmp);
  290.             end=newp;
  291.         }
  292.     }else{
  293.         while(sump>integer(sum)){
  294.             integer newp;
  295.             newp.PreviousPrime(start);
  296.             sump-=end-newp;
  297.             integer tmp(end);
  298.             end.PreviousPrime(tmp);
  299.             start=newp;
  300.         }
  301.     }
  302.     return sump==integer(sum);
  303. }

  304. #define MF  979
  305. #define MS  45

  306. void candidate(unsigned long long x)
  307. {
  308.     integer y((unsigned long long)x);
  309.     if(!y.IsPrime())
  310.         return;
  311.     if(!is_list(45,x))
  312.         return;
  313.     printf("Cand45: %lld\n",x);
  314.     if(!is_list(17,x))
  315.         return;
  316.     printf("Cand17: %lld\n",x);
  317.     if(!is_list(3,x))
  318.         return;
  319.     printf("Find: %lld\n",x);
  320. }

  321. #define BLOCK_SIZE 10000000
  322. #define TAB_LEN 689388
  323. UINT64 primeTabMF[MF+TAB_LEN];
  324. UINT64 primeTabMS[MS+TAB_LEN];
  325. UINT64 pMFblock,pMSblock;
  326. UINT64 pMFcount,pMScount;
  327. void msNextBlock()
  328. {
  329.     memmove(primeTabMS,primeTabMS+pMScount-MS+1,(MS-1)*sizeof(UINT64));
  330. start:
  331.     pMSblock+=BLOCK_SIZE;
  332.     pMScount=generalSift(pMSblock,pMSblock+BLOCK_SIZE,primeTabMS+MS-1,TAB_LEN);
  333.     if(pMScount==0)goto start;
  334.     pMScount+=MS-1;
  335. }

  336. void mfNextBlock()
  337. {
  338.     memmove(primeTabMF,primeTabMF+pMFcount-MF+1,(MF-1)*sizeof(UINT64));   
  339. start:
  340.     pMFblock+=BLOCK_SIZE;
  341.     pMFcount=generalSift(pMFblock,pMFblock+BLOCK_SIZE,primeTabMF+MF-1,TAB_LEN);
  342.     if(pMFcount==0)goto start;
  343.     pMFcount+=MF-1;
  344. }

  345. #define START_V 1800000000000000LL
  346. int main(int argc, char* argv[])
  347. {
  348.     int i;
  349.     long long sumMF=0;
  350.     long long sumMS=0;
  351.     long long max_sum=2000000000000000000LL;
  352.     initSift(10000000000000000LL);
  353.         pMSblock = START_V/MS;
  354.         pMFblock = START_V/MF;
  355.     pMFcount=generalSift(pMFblock,pMFblock+BLOCK_SIZE,primeTabMF,TAB_LEN);
  356.     pMScount=generalSift(pMSblock,pMSblock+BLOCK_SIZE,primeTabMS,TAB_LEN);

  357.     printf("Init finished\n");
  358.     for(i=0;i<MS;i++){
  359.         sumMS+=primeTabMS[i];
  360.     }
  361.     for(i=0;i<MF;i++){
  362.         sumMF+=primeTabMF[i];
  363.     }
  364.     int iMF=0,iMS=0;
  365.     while(sumMF<=max_sum){
  366.         while(sumMS<sumMF){
  367.             sumMS+=primeTabMS[iMS+MS]-primeTabMS[iMS];
  368.             iMS++;
  369.             if(iMS>=pMScount-MS){
  370.                 msNextBlock();
  371.                 iMS=0;
  372.             }
  373.         }
  374.         if(sumMS==sumMF){
  375.             candidate(sumMF);
  376.         }
  377.         sumMF+=primeTabMF[iMF+MF]-primeTabMF[iMF];
  378.         iMF++;
  379.         if(iMF>=pMFcount-MF){
  380.             mfNextBlock();
  381.             iMF=0;
  382.         }
  383.     }
  384.     return 0;
  385. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-6-28 09:25:39 | 显示全部楼层
此外,素数筛选算法在这里非常重要,但是我挑选的不是liangbch提供的最快的版本,而是修改比较方便的版本,如果能够将它替换成更快的版本,应该还有更加好的效率
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-6-28 09:32:56 | 显示全部楼层
这个筛能否扩展到超过64位?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-6-28 09:42:23 | 显示全部楼层
粗略的看了你的代码

超过64位后
由于分段小
会遇到很多素数,其倍数根本是不在筛里
要白白计算其倍数

现在就有这个问题
但浪费的时间不会很大

但随之搜索范围的扩大,将越来越浪费
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-6-28 09:45:00 | 显示全部楼层
依赖于前面我们预先产生的素数表格的范围。在这个程序中,我预先产生的素数表格为$10^8$,也就是用筛选法,最多能够筛到$10^16$,而程序中长度为979和2007个连续素数和都用到这个筛选结果,所以这个和不能超过不超过$10^16$的最大的979个素数和,这应该是个接近$10^19$的范围,但是没有达到$10^19$
但是在这个程序里面其实$4*10^18$作为上界应该还是安全的,但是更加大一些可能会不安全,因为我们必须保证两个这么大的数相加不会溢出
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-6-28 09:52:04 | 显示全部楼层
Start_V改成输入
每隔10秒输出当前块的首数字

你程序搜索到$4 xx 10^18$
要多长时间?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-3 12:24 , Processed in 0.060791 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表