找回密码
 欢迎注册
楼主: 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. while (sqrt_n * sqrt_n >=n)
  43. sqrt_n--;
  44. memset(pBuff,1,n*sizeof(BYTE));
  45. *pBuff=0;
  46. *(pBuff+1)=0; //1不是质数
  47. *(pBuff+2)=1; //2是质数
  48. for ( i=4;i<n;i+=2) //筛去2的倍数,不包括2
  49. *(pBuff+i)=0;
  50. for (i=3;i<=sqrt_n;) //i 是质数
  51. {
  52. for (p=i*i;p<n; p+=2*i)
  53. *(pBuff+p)=0; //筛去i 的奇数倍
  54. i+=2;
  55. while ( *(pBuff+i)==0 )
  56. i++; //前进到下一个质数
  57. }
  58. pn=0; //素数个数
  59. for (i=2;i<n;i++)
  60. {
  61. if (pBuff[i])
  62. {
  63. primeTab[pn++]=i;
  64. }
  65. }
  66. delete[] pBuff;
  67. return pn;
  68. }
  69. #define L2_CACHE (2*1024*1024)
  70. static DWORD getSiftBuffLength()
  71. {
  72. DWORD n=L2_CACHE * 3/4;
  73. DWORD rem=n % 30;
  74. if (rem !=0)
  75. n-=rem;
  76. return n; //n must times of 30
  77. }
  78. //**********************************************
  79. // copy prime from psrc to primeTab
  80. // mode can be 4 or 8
  81. // if mode==4, primeTab will be consider as DWORD array
  82. // if mode==8, primeTab will be conseder ad UINT64 array
  83. // return total prime Count
  84. //**********************************************
  85. int copyL1PrimeToArray(const DWORD *psrc,int srcCount,void *primeTab,int primeBuffLen, int mode)
  86. {
  87. DWORD pr;
  88. int i;
  89. pr=0;
  90. if (mode==4)
  91. {
  92. DWORD *UINT32PrimeTab=(DWORD*)primeTab;
  93. for (i=0;i<srcCount && pr<primeBuffLen;i++)
  94. {
  95. UINT32PrimeTab[pr]=psrc[i];
  96. pr++;
  97. }
  98. for (;i<srcCount;i++ )
  99. { pr++; }
  100. }
  101. else if (mode==8)
  102. {
  103. UINT64 *UINT64PrimeTab=(UINT64*)primeTab;
  104. for (i=0;i<srcCount && pr<primeBuffLen;i++)
  105. {
  106. UINT64PrimeTab[pr]=(UINT64)psrc[i];
  107. pr++;
  108. }
  109. for (;i<srcCount;i++ )
  110. { pr++; }
  111. }
  112. return pr;
  113. }
  114. //**********************************************
  115. // mode can be 4 or 8
  116. // if mode==4, primeTab will be consider as DWORD array
  117. // if mode==8, primeTab will be conseder ad UINT64 array
  118. // return total prime Count
  119. //**********************************************
  120. static UINT64 GetPrimeFromSiftBuff(const BYTE *siftBuff,UINT64 begin, UINT64 end,
  121. void *primeTab,UINT64 currCount,UINT64 primeBuffLen, int mode)
  122. {
  123. UINT64 pr;
  124. int i;
  125. pr=currCount;
  126. DWORD *UINT32PrimeTab=(DWORD*)primeTab;
  127. UINT64 *UINT64PrimeTab=(UINT64*)primeTab;
  128. //-----------------------------------
  129. if (mode==4)
  130. {
  131. for (i=0;i<end-begin && pr < primeBuffLen;i++)
  132. {
  133. if (siftBuff[i]==1)
  134. {
  135. UINT64 p=begin+(UINT64)i;
  136. UINT32PrimeTab[pr]=(DWORD)p;
  137. pr++;
  138. }
  139. }
  140. }
  141. else if (mode==8)
  142. {
  143. for (i=0;i<end-begin && pr < primeBuffLen;i++)
  144. {
  145. if (siftBuff[i]==1)
  146. {
  147. UINT64 p=begin+(UINT64)i;
  148. UINT64PrimeTab[pr]=p;
  149. pr++;
  150. }
  151. }
  152. }
  153. for (;i<end-begin;i++)
  154. {
  155. if (siftBuff[i]==1)
  156. {
  157. pr++;
  158. }
  159. }
  160. return pr;
  161. }
  162. DWORD L1PrimeBuffLen;
  163. DWORD *L1PrimeTab;
  164. DWORD L1PrimeCount;
  165. void initSift(UINT64 n)
  166. {
  167. DWORD sqrt_n;
  168. double f;
  169. sqrt_n=(DWORD)(sqrt((double)n));
  170. sqrt_n=(sqrt_n+29)/30*30;
  171. f=(double)sqrt_n*10.0/9.0+32;
  172. L1PrimeBuffLen= (DWORD)f;
  173. L1PrimeTab= new DWORD[L1PrimeBuffLen];
  174. L1PrimeCount= Sift32(sqrt_n,L1PrimeTab);
  175. }
  176. //**********************************************
  177. // 使用普通分段筛的方法筛素数,
  178. // // mode can be 4 or 8
  179. // if mode==4, primeTab will be consider as DWORD array
  180. // if mode==8, primeTab will be conseder ad UINT64 array
  181. UINT64 generalSift(UINT64 begin, UINT64 end,void *primeTab, UINT64 primeTabLimtCount)
  182. // 对0到n 之间(不包括n)的数进行筛选,返回质数的个数
  183. //**********************************************
  184. {
  185. DWORD siftBuffLen;
  186. UINT64 pr=0;
  187. siftBuffLen=end-begin;
  188. BYTE *siftBuff=new BYTE[siftBuffLen];
  189. if (siftBuff==NULL)
  190. return 0;
  191. {
  192. DWORD dwPrime,endPrime;
  193. UINT64 begIndex;
  194. DWORD endIdx;
  195. int idx,i;
  196. endIdx=end-begin;
  197. memset(siftBuff,1,siftBuffLen);
  198. endPrime= (DWORD)sqrt((double)end)+1;
  199. while (endPrime*endPrime>=end)
  200. endPrime--;
  201. i=0;
  202. while (true)
  203. {
  204. DWORD inc;
  205. UINT64 t;
  206. dwPrime=L1PrimeTab[i];
  207. if ((UINT64)dwPrime * dwPrime>=end)
  208. break;
  209. t=(begin+dwPrime-1)/dwPrime;
  210. if ( t<dwPrime)
  211. t=dwPrime;
  212. if (dwPrime==2)
  213. {
  214. idx=(int)(t * dwPrime-begin);
  215. while (idx<endIdx)
  216. {
  217. siftBuff[idx]=0;
  218. idx+=dwPrime;
  219. }
  220. }
  221. else
  222. {
  223. if ( t % 2==0)
  224. t++; //素数的奇数倍
  225. inc= dwPrime+dwPrime;
  226. idx=(int)(t * dwPrime-begin);
  227. while (idx<endIdx)
  228. {
  229. siftBuff[idx]=0;
  230. idx+=inc;
  231. }
  232. }
  233. i++;
  234. }
  235. pr=GetPrimeFromSiftBuff(siftBuff,begin,end,primeTab,pr,primeTabLimtCount,8);
  236. }
  237. delete[] siftBuff;
  238. return pr;
  239. }
  240. int search_match_prime(unsigned value)
  241. {
  242. int start=0,mid,end=MAX_N-1;
  243. mid=(start+end)/2;
  244. while(end-start>=2){
  245. if(plist[mid]<value){
  246. start=mid;
  247. }else{
  248. end=mid;
  249. }
  250. mid=(start+end)/2;
  251. }
  252. return mid;
  253. }
  254. bool is_list(int num, unsigned long long sum)
  255. {
  256. unsigned long long aver=sum/num;
  257. integer start(aver),end,sump(0);
  258. start.NextPrime(start);
  259. int prevc,nextc;
  260. prevc=num/2;
  261. nextc=num-1-prevc;
  262. int i;
  263. sump=end=start;
  264. for(i=0;i<nextc;i++){
  265. integer tmp(end);
  266. end.NextPrime(tmp);
  267. sump+=end;
  268. }
  269. for(i=0;i<prevc;i++){
  270. integer tmp(start);
  271. start.PreviousPrime(tmp);
  272. sump+=start;
  273. }
  274. if(sump<integer(sum)){
  275. while(sump<integer(sum)){
  276. integer newp;
  277. newp.NextPrime(end);
  278. sump+=newp-start;
  279. integer tmp(start);
  280. start.NextPrime(tmp);
  281. end=newp;
  282. }
  283. }else{
  284. while(sump>integer(sum)){
  285. integer newp;
  286. newp.PreviousPrime(start);
  287. sump-=end-newp;
  288. integer tmp(end);
  289. end.PreviousPrime(tmp);
  290. start=newp;
  291. }
  292. }
  293. return sump==integer(sum);
  294. }
  295. #define MF 979
  296. #define MS 45
  297. void candidate(unsigned long long x)
  298. {
  299. integer y((unsigned long long)x);
  300. if(!y.IsPrime())
  301. return;
  302. if(!is_list(45,x))
  303. return;
  304. printf("Cand45: %lld\n",x);
  305. if(!is_list(17,x))
  306. return;
  307. printf("Cand17: %lld\n",x);
  308. if(!is_list(3,x))
  309. return;
  310. printf("Find: %lld\n",x);
  311. }
  312. #define BLOCK_SIZE 10000000
  313. #define TAB_LEN 689388
  314. UINT64 primeTabMF[MF+TAB_LEN];
  315. UINT64 primeTabMS[MS+TAB_LEN];
  316. UINT64 pMFblock,pMSblock;
  317. UINT64 pMFcount,pMScount;
  318. void msNextBlock()
  319. {
  320. memmove(primeTabMS,primeTabMS+pMScount-MS+1,(MS-1)*sizeof(UINT64));
  321. start:
  322. pMSblock+=BLOCK_SIZE;
  323. pMScount=generalSift(pMSblock,pMSblock+BLOCK_SIZE,primeTabMS+MS-1,TAB_LEN);
  324. if(pMScount==0)goto start;
  325. pMScount+=MS-1;
  326. }
  327. void mfNextBlock()
  328. {
  329. memmove(primeTabMF,primeTabMF+pMFcount-MF+1,(MF-1)*sizeof(UINT64));
  330. start:
  331. pMFblock+=BLOCK_SIZE;
  332. pMFcount=generalSift(pMFblock,pMFblock+BLOCK_SIZE,primeTabMF+MF-1,TAB_LEN);
  333. if(pMFcount==0)goto start;
  334. pMFcount+=MF-1;
  335. }
  336. #define START_V 1800000000000000LL
  337. int main(int argc, char* argv[])
  338. {
  339. int i;
  340. long long sumMF=0;
  341. long long sumMS=0;
  342. long long max_sum=2000000000000000000LL;
  343. initSift(10000000000000000LL);
  344. pMSblock = START_V/MS;
  345. pMFblock = START_V/MF;
  346. pMFcount=generalSift(pMFblock,pMFblock+BLOCK_SIZE,primeTabMF,TAB_LEN);
  347. pMScount=generalSift(pMSblock,pMSblock+BLOCK_SIZE,primeTabMS,TAB_LEN);
  348. printf("Init finished\n");
  349. for(i=0;i<MS;i++){
  350. sumMS+=primeTabMS[i];
  351. }
  352. for(i=0;i<MF;i++){
  353. sumMF+=primeTabMF[i];
  354. }
  355. int iMF=0,iMS=0;
  356. while(sumMF<=max_sum){
  357. while(sumMS<sumMF){
  358. sumMS+=primeTabMS[iMS+MS]-primeTabMS[iMS];
  359. iMS++;
  360. if(iMS>=pMScount-MS){
  361. msNextBlock();
  362. iMS=0;
  363. }
  364. }
  365. if(sumMS==sumMF){
  366. candidate(sumMF);
  367. }
  368. sumMF+=primeTabMF[iMF+MF]-primeTabMF[iMF];
  369. iMF++;
  370. if(iMF>=pMFcount-MF){
  371. mfNextBlock();
  372. iMF=0;
  373. }
  374. }
  375. return 0;
  376. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 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-12-22 17:12 , Processed in 0.026820 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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