无心人 发表于 2008-6-27 13:10:33

:lol

呵呵

那复杂度也是迅速增加的

我不知道到底多小合适

mathe 发表于 2008-6-28 06:53:16

昨天重新从和数$1.8*10^15$左右开始搜索,得到一个满足除了条件a)的解,也就是同时满足本身素数,17个素数和,45个素数和,979个素数和以及2007个素数和的条件的:
1814523290364469
:lol
平均来说,应该每50个左右这样的数可以找到一个3个素数和的情况。
如果找一个花费1天的时间,那么需要50天(或者100台机器花费半天)

无心人 发表于 2008-6-28 08:23:46

:)

并行应该没这么大加速比吧

mathe 发表于 2008-6-28 09:12:19

还好,这个问题并行性很好,而且复杂度不算太高。100台机器运行半天只是有可能产生结果,但是不一定产生,如果运行时间更加长一些,比如一星期,出结果的可能性就非常大了。比如假设运行一天没找到结果概率为$e^-1$,那么运行一星期没有找到结果的概率就是$e^-7=0.1%$:lol

mathe 发表于 2008-6-28 09:23:23

刚刚查看一下,又产生了一个
1852547403117883
下面是完整的代码,其中START_V可以修改成任何小于$2*10^18$,从而程序会从不同位置开始运行
// HugeCalcDemo.cpp : Defines the entry point for the console application.
//

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

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

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

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

#if 1
    #define _Test_HI
    #define integer CHugeInt
#else
    #define _Test_HX
    #define integer CHugeIntX
#endif

#define MAX_N203280220
unsigned int plist;

#include "math.h"
#include "memory.h"
#include "windows.h"

//**********************************************
// n 不能大于L2 cache,否则效能很低
DWORD Sift32(DWORD n,DWORD *primeTab)
// 对0到n 之间(不包括n)的数进行筛选,返回质数的个数
//**********************************************
{
        BYTE *pBuff= new BYTE;
        if (pBuff==NULL)
                return 0;

        DWORD i,sqrt_n,p;
        DWORD pn;
        //----------------------------
        sqrt_n=(DWORD)(sqrt((double)n)+1);
       
        while (sqrt_n * sqrt_n >=n)
                sqrt_n--;
       
        memset(pBuff,1,n*sizeof(BYTE));
        *pBuff=0;
        *(pBuff+1)=0; //1不是质数
        *(pBuff+2)=1; //2是质数

        for ( i=4;i<n;i+=2) //筛去2的倍数,不包括2
                *(pBuff+i)=0;
       
        for (i=3;i<=sqrt_n;) //i 是质数
        {
                for (p=i*i;p<n; p+=2*i)
                        *(pBuff+p)=0; //筛去i 的奇数倍
                i+=2;
                while ( *(pBuff+i)==0 )
                        i++; //前进到下一个质数
        }
        pn=0; //素数个数
        for (i=2;i<n;i++)
        {
                if (pBuff)
                {
                        primeTab=i;
                }
        }
        delete[] pBuff;
        return pn;
}

#define L2_CACHE (2*1024*1024)
static DWORD getSiftBuffLength()
{
        DWORD n=L2_CACHE * 3/4;
        DWORD rem=n % 30;
        if (rem !=0)
                n-=rem;
        return n;   //n must times of 30
}


//**********************************************
// copy prime from psrc to primeTab
// mode can be 4 or 8
// if mode==4, primeTab will be consider as DWORD array
// if mode==8, primeTab will be conseder ad UINT64 array
// return total prime Count
//**********************************************
int copyL1PrimeToArray(const DWORD *psrc,int srcCount,void *primeTab,int primeBuffLen, int mode)
{
        DWORD pr;
        int i;
        pr=0;
        if (mode==4)
        {
                DWORD *UINT32PrimeTab=(DWORD*)primeTab;
                for (i=0;i<srcCount && pr<primeBuffLen;i++)
                {
                        UINT32PrimeTab=psrc;
                        pr++;
                }
                for (;i<srcCount;i++ )
                {        pr++; }
        }
        else if (mode==8)
        {
                UINT64 *UINT64PrimeTab=(UINT64*)primeTab;
                for (i=0;i<srcCount && pr<primeBuffLen;i++)
                {
                        UINT64PrimeTab=(UINT64)psrc;
                        pr++;
                }
                for (;i<srcCount;i++ )
                {        pr++; }
        }
        return pr;
}
//**********************************************
// mode can be 4 or 8
// if mode==4, primeTab will be consider as DWORD array
// if mode==8, primeTab will be conseder ad UINT64 array
// return total prime Count
//**********************************************
static UINT64 GetPrimeFromSiftBuff(const BYTE *siftBuff,UINT64 begin, UINT64 end,
                                           void *primeTab,UINT64 currCount,UINT64 primeBuffLen, int mode)
{
        UINT64 pr;
        int i;
        pr=currCount;
        DWORD *UINT32PrimeTab=(DWORD*)primeTab;
        UINT64 *UINT64PrimeTab=(UINT64*)primeTab;
        //-----------------------------------
        if (mode==4)
        {
                for (i=0;i<end-begin && pr < primeBuffLen;i++)
                {
                        if (siftBuff==1)
                        {
                                UINT64 p=begin+(UINT64)i;
                                UINT32PrimeTab=(DWORD)p;
                                pr++;
                        }
                }
        }
        else if (mode==8)
        {
                for (i=0;i<end-begin && pr < primeBuffLen;i++)
                {
                        if (siftBuff==1)
                        {
                                UINT64 p=begin+(UINT64)i;
                                UINT64PrimeTab=p;
                                pr++;
                        }
                }
        }
       
        for (;i<end-begin;i++)
        {
                if (siftBuff==1)
                {
                        pr++;
                }
        }
        return pr;
}

DWORD L1PrimeBuffLen;
DWORD *L1PrimeTab;
DWORD L1PrimeCount;
void initSift(UINT64 n)
{
    DWORD sqrt_n;
    double f;
    sqrt_n=(DWORD)(sqrt((double)n));
    sqrt_n=(sqrt_n+29)/30*30;
    f=(double)sqrt_n*10.0/9.0+32;
        L1PrimeBuffLen= (DWORD)f;
       
        L1PrimeTab= new DWORD;

        L1PrimeCount= Sift32(sqrt_n,L1PrimeTab);
}

//**********************************************
// 使用普通分段筛的方法筛素数,
// // mode can be 4 or 8
// if mode==4, primeTab will be consider as DWORD array
// if mode==8, primeTab will be conseder ad UINT64 array
UINT64 generalSift(UINT64 begin, UINT64 end,void *primeTab, UINT64 primeTabLimtCount)
// 对0到n 之间(不包括n)的数进行筛选,返回质数的个数
//**********************************************
{
        DWORDsiftBuffLen;
        UINT64pr=0;

        siftBuffLen=end-begin;
        BYTE *siftBuff=new BYTE;
        if (siftBuff==NULL)
                return 0;
       
        {
                DWORD dwPrime,endPrime;
                UINT64 begIndex;
                DWORDendIdx;
                int idx,i;
               
                endIdx=end-begin;

                memset(siftBuff,1,siftBuffLen);
                endPrime= (DWORD)sqrt((double)end)+1;
               
                while (endPrime*endPrime>=end)
                        endPrime--;
                i=0;
                while (true)
                {
                        DWORD inc;
                        UINT64 t;
                        dwPrime=L1PrimeTab;
                        if ((UINT64)dwPrime * dwPrime>=end)
                                break;
                        t=(begin+dwPrime-1)/dwPrime;
                        if ( t<dwPrime)
                                t=dwPrime;
                       
                        if (dwPrime==2)
                        {
                                idx=(int)(t * dwPrime-begin);
                                while (idx<endIdx)
                                {
                                        siftBuff=0;
                                        idx+=dwPrime;
                                }
                        }
                        else
                        {
                                if ( t % 2==0)
                                        t++;                //素数的奇数倍
                                inc= dwPrime+dwPrime;
                                idx=(int)(t * dwPrime-begin);
                                while (idx<endIdx)
                                {
                                        siftBuff=0;
                                        idx+=inc;
                                }
                        }
                        i++;
                }
                pr=GetPrimeFromSiftBuff(siftBuff,begin,end,primeTab,pr,primeTabLimtCount,8);
        }
        delete[] siftBuff;
        return pr;
}


int search_match_prime(unsigned value)
{
    int start=0,mid,end=MAX_N-1;
    mid=(start+end)/2;
    while(end-start>=2){
      if(plist<value){
            start=mid;
      }else{
            end=mid;
      }
      mid=(start+end)/2;
    }
    return mid;
}

bool is_list(int num, unsigned long long sum)
{
    unsigned long long aver=sum/num;
    integer start(aver),end,sump(0);
    start.NextPrime(start);
    int prevc,nextc;
    prevc=num/2;
    nextc=num-1-prevc;
    int i;
    sump=end=start;
    for(i=0;i<nextc;i++){
      integer tmp(end);
      end.NextPrime(tmp);
      sump+=end;
    }
    for(i=0;i<prevc;i++){
      integer tmp(start);
      start.PreviousPrime(tmp);
      sump+=start;
    }
    if(sump<integer(sum)){
      while(sump<integer(sum)){
            integer newp;
            newp.NextPrime(end);
            sump+=newp-start;
            integer tmp(start);
            start.NextPrime(tmp);
            end=newp;
      }
    }else{
      while(sump>integer(sum)){
            integer newp;
            newp.PreviousPrime(start);
            sump-=end-newp;
            integer tmp(end);
            end.PreviousPrime(tmp);
            start=newp;
      }
    }
    return sump==integer(sum);
}

#define MF979
#define MS45

void candidate(unsigned long long x)
{
    integer y((unsigned long long)x);
    if(!y.IsPrime())
      return;
    if(!is_list(45,x))
      return;
    printf("Cand45: %lld\n",x);
    if(!is_list(17,x))
      return;
    printf("Cand17: %lld\n",x);
    if(!is_list(3,x))
      return;
    printf("Find: %lld\n",x);
}

#define BLOCK_SIZE 10000000
#define TAB_LEN 689388
UINT64 primeTabMF;
UINT64 primeTabMS;
UINT64 pMFblock,pMSblock;
UINT64 pMFcount,pMScount;
void msNextBlock()
{
    memmove(primeTabMS,primeTabMS+pMScount-MS+1,(MS-1)*sizeof(UINT64));
start:
    pMSblock+=BLOCK_SIZE;
    pMScount=generalSift(pMSblock,pMSblock+BLOCK_SIZE,primeTabMS+MS-1,TAB_LEN);
    if(pMScount==0)goto start;
    pMScount+=MS-1;
}

void mfNextBlock()
{
    memmove(primeTabMF,primeTabMF+pMFcount-MF+1,(MF-1)*sizeof(UINT64));   
start:
    pMFblock+=BLOCK_SIZE;
    pMFcount=generalSift(pMFblock,pMFblock+BLOCK_SIZE,primeTabMF+MF-1,TAB_LEN);
    if(pMFcount==0)goto start;
    pMFcount+=MF-1;
}

#define START_V 1800000000000000LL
int main(int argc, char* argv[])
{
    int i;
    long long sumMF=0;
    long long sumMS=0;
    long long max_sum=2000000000000000000LL;
    initSift(10000000000000000LL);
        pMSblock = START_V/MS;
        pMFblock = START_V/MF;
    pMFcount=generalSift(pMFblock,pMFblock+BLOCK_SIZE,primeTabMF,TAB_LEN);
    pMScount=generalSift(pMSblock,pMSblock+BLOCK_SIZE,primeTabMS,TAB_LEN);

    printf("Init finished\n");
    for(i=0;i<MS;i++){
      sumMS+=primeTabMS;
    }
    for(i=0;i<MF;i++){
      sumMF+=primeTabMF;
    }
    int iMF=0,iMS=0;
    while(sumMF<=max_sum){
      while(sumMS<sumMF){
            sumMS+=primeTabMS-primeTabMS;
            iMS++;
            if(iMS>=pMScount-MS){
                msNextBlock();
                iMS=0;
            }
      }
      if(sumMS==sumMF){
            candidate(sumMF);
      }
      sumMF+=primeTabMF-primeTabMF;
      iMF++;
      if(iMF>=pMFcount-MF){
            mfNextBlock();
            iMF=0;
      }
    }
    return 0;
}

mathe 发表于 2008-6-28 09:25:39

此外,素数筛选算法在这里非常重要,但是我挑选的不是liangbch提供的最快的版本,而是修改比较方便的版本,如果能够将它替换成更快的版本,应该还有更加好的效率:lol

无心人 发表于 2008-6-28 09:32:56

这个筛能否扩展到超过64位?

无心人 发表于 2008-6-28 09:42:23

粗略的看了你的代码

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

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

但随之搜索范围的扩大,将越来越浪费

mathe 发表于 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$
要多长时间?
页: 1 2 3 4 5 6 [7] 8 9
查看完整版本: 素数分解