找回密码
 欢迎注册
楼主: 无心人

[原创] 10^28开始的10^14个整数的素性概率性测试算法实践报告

[复制链接]
 楼主| 发表于 2020-12-9 14:06:26 | 显示全部楼层
决定了,程序内不做并发了~,同步太麻烦了~
2.5G主频,非并发,46秒~~~

开始时间: 15:24:58
初始化结束: 15:24:59
筛结束: 15:25:02
测试结束: 15:25:45
通过筛的数字: 12090362
可能素数: 1552676

点评

总体来说,筛的时间很少的,而模形式的测试时间占比很大,现在可以考虑用更大的素数筛,降低预选数字个数  发表于 2020-12-9 15:41
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2020-12-9 15:14:21 | 显示全部楼层
无心人 发表于 2020-12-9 14:06
决定了,程序内不做并发了~,同步太麻烦了~
2.5G主频,非并发,46秒~~~

说一下我的程序问题
我把ord除以2的原因是,sieve事实上是乘过2的
sieve增加1的意思是,我们筛的数字大小加2
这样可以节省一部分内存占用。

另外,才发现,BPSW真的好慢好慢
//一次MillerRabin不用BPSW
    Finished release [optimized] target(s) in 6.27s
     Running `target/release/fermat`
from=10000000000000000000000000001,len=500
10000000000000000000099999979.0,1552676,12.651374079s
//用一次BPSW
   Compiling fermat v0.1.0 (/me/fermat)
    Finished release [optimized] target(s) in 6.84s
     Running `target/release/fermat`
from=10000000000000000000000000001,len=500
10000000000000000000099999979.1552676,0,29.689700734s

点评

只是二次域快不过BPSW吧……如果6次Miller-Rabin,大概耗时22s,frobenius应该快不过这个的  发表于 2020-12-9 15:42
你试试1+sqrt(C)形式的frobenius测试,这个测试是BPSW的二次域形式  发表于 2020-12-9 15:40
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2020-12-9 16:11:26 | 显示全部楼层
筛掉素数平方后,待测试素数从1209万降低到1046万,我是10000内素数的筛,3不参与筛,但是筛9的倍数
2.5G处理器, 初始化和筛,1秒左右,测试39秒

平方数测试涉及到以下几个
1、3不筛3*(2k+1),但是筛3的平方9的倍数
2、1093,3511的平方不筛
3、假设筛是s个连续整数,超过sqrt(s/2)的素数,在筛的范围内平方倍数且是奇数的数字可能并不都能筛掉未筛除数字的,是不是做,需要考虑

刚测试,因为我筛是10^8,sqrt(50000000)=7071.1, 实际只筛小于等于7071的平方,和全筛,筛出来的需要做模幂测试的个数是一样的

点评

这时候用fwrite跟fread正合适……  发表于 2020-12-9 22:40
初始化10^8内素数,不知道写成.c文件,编译器会不会崩  发表于 2020-12-9 19:29
可以把初始化结果写进源代码的。我初始化大概几毫秒就够了  发表于 2020-12-9 17:20
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2020-12-9 19:48:28 | 显示全部楼层
真郁闷,暴力算1000亿,结果回来远程进去发现,服务器重启了~~~
现在缺少个任务分配平台,暴力塞了1000任务过去,压力太大,崩了服务器
不知道有什么平台,能批量均匀的分配任务,并且自己回收输出
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2020-12-9 22:41:28 | 显示全部楼层
本帖最后由 .·.·. 于 2020-12-10 04:43 编辑
无心人 发表于 2020-12-9 19:48
真郁闷,暴力算1000亿,结果回来远程进去发现,服务器重启了~~~
现在缺少个任务分配平台,暴力塞了1000任 ...

直接python?
随便找个threadpool之类的东西自己写一写subprocess.popen就好

话说这玩意难道不应该均分成20个任务提交给20个不同的程序吗?
---
update:fermat正式退出历史舞台
  1. #![feature(slice_fill)]
  2. use rug::{Assign, Integer};
  3. const SIEVE_SIZE_DIV_2:i32=100000;
  4. //const SIEVE_SIZE:i32=SIEVE_SIZE_DIV_2<<1;//the true sieve size, never used.
  5. const PRIME_SIZE:usize=include!("final.txt").len();
  6. const PRIME_MAP:[[i32;2];PRIME_SIZE]=include!("final.txt");
  7. fn main() {
  8.     let mut cumsum=0u32;
  9.     let now=std::time::Instant::now();
  10.     let arguments: Vec<String> = std::env::args().collect();
  11.     let begin=if let Some(x)=arguments.get(2){x.parse::<u128>().unwrap_or(0)}else{0};
  12.     let len=if let Some(x)=arguments.get(1){x.parse::<u128>().unwrap_or(500)}else{500};
  13.     let start=10000000000000000000000000000u128+begin*len;
  14.     let mut am1=Integer::from(start);
  15.     let mut a=Integer::from(start+1);
  16.     println!("from={},len={}",a,len);
  17.     let mut b=Integer::from(2);
  18.     let mut am1d=Integer::from(0);
  19.     let mut prime=0u64;
  20.     let mut psp=0u64;
  21.     let mut sieve=[true;SIEVE_SIZE_DIV_2 as usize];
  22.     let mut prime_curr=[0;PRIME_SIZE];
  23.     let mut prime_order=[0;PRIME_SIZE];
  24.     let [mut total,mut tests]=[0;2];
  25.     for i in 0..PRIME_SIZE{
  26.         let t=(start%PRIME_MAP[i][0] as u128) as i32;
  27.         let next= if t==0{
  28.             start+PRIME_MAP[i][0] as u128
  29.         }else{
  30.             let mut tmp=start-(t as u128)+PRIME_MAP[i][0] as u128;
  31.             if tmp%2==0{tmp+=PRIME_MAP[i][0] as u128}
  32.             tmp
  33.         };
  34.         let count=next/PRIME_MAP[i][0] as u128;
  35.         prime_curr[i]=((next-start)>>1) as i32;
  36.         if PRIME_MAP[i][1]==-1{// for p^2, should never put 1093^2 and 3511^2 into prime_map.
  37.             prime_order[i]=-1;// if o is order of 2 mod p , op is the order of 2 mod p^2(except p=1093,3511...), thus, if 2^(qp^2-1)=1 mod p^2, op|qp^2-1 , p|-1, which is not possible.
  38.         }else{
  39.             prime_order[i]=PRIME_MAP[i][1]-((count>>1)%PRIME_MAP[i][1] as u128) as i32
  40.         }
  41.     }
  42.     for _i in 0..len{
  43.         sieve.fill(true);
  44.         for (i,&[prime,order]) in PRIME_MAP.iter().enumerate(){
  45.             let mut cur=prime_curr[i];
  46.             let mut ord=prime_order[i];
  47.             while cur<SIEVE_SIZE_DIV_2{
  48.                 if ord==0{
  49.                     ord=order
  50.                 }else{
  51.                     sieve[cur as usize]=false
  52.                 }
  53.                 cur+=prime;
  54.                 ord-=1
  55.             }
  56.             prime_curr[i]=cur-SIEVE_SIZE_DIV_2;
  57.             prime_order[i]=ord
  58.         }
  59.         for test in &sieve{
  60.             total+=1;
  61.             if *test{
  62.                 tests+=1;
  63.                 a+=cumsum;
  64.                 am1+=cumsum;
  65.                 cumsum=0;
  66.                 let aa=am1.find_one(0).unwrap().min(6);
  67.                 am1d.assign(&am1>>aa);
  68. //                if {b.assign(CONSTARR[aa as usize]);let _=b.pow_mod_mut(&am1d,&a);b==1u8}{psp+=1;//Fermat
  69.                     if {b.assign(2u8);//Miller-Rabin
  70.                         let aa=a.find_one(0).unwrap();
  71.                         am1d.assign(&am1>>aa);
  72.                         let _=b.pow_mod_mut(&am1d,&a);
  73.                         (b==1 || b==am1 )||{
  74.                             let mut f=false;
  75.                             for _ in 0..aa{
  76.                                 let _=b.pow_mod_mut(&Integer::from(2),&a);
  77.                                 if b==am1{f=true;break}
  78.                             }
  79.                             if b==1{f=false;println!("{} is PSP(2)",a);psp+=1}
  80.                             f
  81.                         }
  82.                     }{
  83.                         psp+=1;
  84.                         prime+=1;
  85.                         //if a.is_probably_prime(5)==rug::integer::IsPrime::No{
  86.                         //    println!("{} is SPSP(2)",a)
  87.                         //}else{prime+=1}
  88.                     }
  89. //                }//Fermat
  90.             }
  91.             cumsum+=2;
  92.         }
  93.     }
  94.     println!("last={},prime={},diff={},total={},miller={},cost={:?}",a,prime,psp-prime,total,tests,now.elapsed());
  95. }
复制代码
fermat.7z (92.53 KB, 下载次数: 0)
(去掉is_probable_prime之后得到)
from=10000000000000000000000000001,len=500
last=10000000000000000000099999979,prime=1552676,diff=0,total=50000000,miller=8377755,cost=10.800631943s
共8377755个数字需要继续送miller-rabin进行计算

点评

那想要PSP(2)就得不到了么?  发表于 2020-12-10 08:16
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2020-12-10 09:08:47 | 显示全部楼层
时间降不下来,发现筛出后,标记合数的只做fermat也不行,降不下来时间,不过候选素数从1000+万降低到600+万

Start Time: 09:11:55
init Time: 09:11:55
start number: 10000000000000000000000000000
sieve Time: 09:11:56
test Time: 09:12:36
to test PSP: 4375043, to test primility 6087984
primes: 1552676

4375043里,我怀疑3的倍数占很大比例

  1. #include<gmp.h>
  2. #include<stdbool.h>
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<time.h>
  6. #define NULL_TERMINATED                0

  7. bool fermatTest( const mpz_t n, unsigned long b)
  8. {
  9.     mpz_t r, b1, ns1;
  10.    
  11.     mpz_inits(r, ns1, NULL_TERMINATED);
  12.     mpz_init_set_ui(b1, b);
  13.    
  14.     mpz_sub_ui(ns1, n, 1);
  15.     mpz_powm(r, b1, ns1, n);
  16.    
  17.     bool result = mpz_cmp_ui(r, 1) == 0;
  18.     mpz_clears(r, b1, ns1, NULL_TERMINATED);
  19.     return result;
  20. }

  21. bool millerrabinTest( const mpz_t n, unsigned long b )
  22. {
  23.     mpz_t ns1, t, b1, r;
  24.     unsigned long s;
  25.     bool result;

  26.     mpz_inits(ns1, t, r, NULL_TERMINATED);
  27.     mpz_init_set_ui(b1, b);// b1=b

  28.     mpz_sub_ui(ns1, n, 1);// ns1=n-1
  29.     s = mpz_scan1(ns1, 0);
  30.     mpz_tdiv_q_2exp(t, ns1, s);// ns1=2^s*t, t%2=1

  31.     mpz_powm(r, b1, t, n);
  32.     if (mpz_cmp_ui(r, 1) == 0 || mpz_cmp(r, ns1) == 0)
  33.         result = true;
  34.     else
  35.     {
  36.         result = false;
  37.         for (unsigned long i = 1; i < s; i ++)
  38.         {
  39.             mpz_powm_ui(r, r, 2, n);
  40.             if (mpz_cmp(r, ns1) == 0)
  41.             {
  42.                 result = true;
  43.                 break;
  44.             }
  45.         }
  46.     }
  47.     mpz_clears(ns1, t, b1, r, NULL_TERMINATED);
  48.     return result;
  49. }

  50. const unsigned long step = 100000000;
  51. char  *buff;
  52. unsigned long cnt = 0, pcnt = 0, pscnt = 0;
  53. unsigned long small[1227][2];
  54. unsigned long p100[] = { 2,  3,  5,  7, 11,
  55.                         13, 17, 19, 23, 29,
  56.                         31, 37, 41, 43, 47,
  57.                         53, 59, 61, 67, 71,
  58.                         73, 79, 83, 89, 97};

  59. //p < 10000
  60. unsigned long ord(unsigned long p)
  61. {
  62.     unsigned long factor[16];
  63.     unsigned long s = 0;
  64.     unsigned long n = p - 1;
  65.     mpz_t b, tmp, mp;
  66.     mpz_init_set_ui(b, 2);
  67.     mpz_init_set_ui(mp, p);
  68.     mpz_init(tmp);
  69.     for (int i = 0; i < 25; i ++)
  70.     {
  71.         if (n%p100[i] == 0)
  72.             do
  73.             {
  74.                 factor[s++] = p100[i];
  75.                 n /= p100[i];
  76.             } while (n%p100[i] == 0);
  77.     }

  78.     n = p - 1;
  79.     for (int i = 0; i < s; i++)
  80.     {
  81.         mpz_powm_ui(tmp, b, n / factor[i], mp);
  82.         if (mpz_cmp_ui(tmp, 1) == 0)
  83.             n /= factor[i];
  84.     }
  85.     if (n%2==1)
  86.         n*=2;
  87.     mpz_clears(b, tmp, mp, NULL_TERMINATED);
  88.     return n;
  89. }

  90. // 实际测试值=base + index*step + [1..step]
  91. void init( mpz_t base, unsigned long index )
  92. {
  93.     mpz_t tmp, tmp1;
  94.     mpz_set_ui(base, 10);
  95.     mpz_pow_ui(base, base, 28);
  96.     mpz_init_set_ui(tmp, step);
  97.     mpz_mul_ui(tmp, tmp, index);
  98.     mpz_add(base, base, tmp);

  99.     buff = (char *)malloc(step);
  100.     for (long i = 0; i < step; i += 2)
  101.         buff[i] = 0;
  102.     for (long i = 1; i < step; i += 2)
  103.         buff[i] = 3; //3 = 位组合0:素数 1:PSP(2)
  104.       
  105.     unsigned long i = 0;
  106.     mpz_init_set_ui(tmp1, 3);
  107.     while (i < 1227)
  108.     {
  109.         mpz_nextprime(tmp, tmp1);
  110.         mpz_set(tmp1, tmp);
  111.         small[i][0] = mpz_get_ui(tmp);
  112.         small[i][1] = ord(small[i][0]);
  113.         i++;
  114.     }

  115.     mpz_clears(tmp, tmp1, NULL_TERMINATED);
  116. }

  117. bool quickTest( mpz_t n )
  118. {
  119.     unsigned long b[] = {3, 5, 7, 11, 13};
  120.     for (int i = 0; i < sizeof(b)/sizeof(unsigned long); i++)
  121.         if (!millerrabinTest(n, b[i]))
  122.             return false;
  123.     return true;
  124. }

  125. void sieve( mpz_t base, long idx )
  126. {
  127.     mpz_t q, r, q1;
  128.     unsigned long r1, q2;

  129.     mpz_inits(q, r, q1, NULL_TERMINATED);

  130.     //置位奇数中3的倍数为非素数
  131.     mpz_mod_ui(q1, base, 3);
  132.     q2 = mpz_get_ui(q1);
  133.     q2 = 3 - q2;
  134.     if (q2%2==0)
  135.         q2 += 3;
  136.     while (q2 < step)
  137.     {
  138.         buff[q2] &= 2;
  139.         q2 += 6;
  140.     }


  141.     for (long i = 0; i < 1227; i ++)
  142.     {
  143.         //合数形如pm, 素数p对2的次数是k, 筛掉不满足m=nk+1的,因为只需要考虑m是奇数,所以,对k不是偶数的,已经乘以2了
  144.         mpz_fdiv_qr_ui(q, r, base, small[i][0]);
  145.         mpz_mod_ui(q1, q, small[i][1]);
  146.         q2 = mpz_get_ui(q1);
  147.         r1 = mpz_get_ui(r);
  148.         r1 = small[i][0] - r1;
  149.         q2 = (q2+1)%small[i][1];
  150.         if (r1%2==0)
  151.         {
  152.             r1 += small[i][0];
  153.             q2 = (q2+1)%small[i][1];
  154.         }
  155.         while (r1 < step)
  156.         {
  157.             buff[r1] &= 2; //非素数
  158.             if (q2 != 1)
  159.             {
  160.                 buff[r1] = 0; //非PSP(2)
  161.             }
  162.             r1 += 2*small[i][0];
  163.             q2 = (q2+2)%small[i][1];
  164.         }
  165.         
  166.         //筛掉满足p^2的倍数,其中p是素数且不等于1093,3511
  167.         unsigned long sq = small[i][0];
  168.         if (sq != 1093 && sq != 3511 && sq <= 7071)
  169.         {
  170.             sq *= sq;
  171.             mpz_mod_ui(q1, base, sq);
  172.             q2 = mpz_get_ui(q1);//取模
  173.             q2 = sq - q2;//加sq,得到第一个奇数倍数,如果q2=0,结果也是对的
  174.             if (q2%2==0)
  175.                 q2 += sq;
  176.             while (q2 < step)
  177.             {
  178.                 buff[q2] = 0; //非PSP(2)
  179.                 q2 += 2*sq;
  180.             }
  181.         }
  182.     }

  183.     //筛掉奇数中9的倍数
  184.     mpz_mod_ui(q1, base, 9);
  185.     q2 = mpz_get_ui(q1);
  186.     q2 = 9 - q2;
  187.     if (q2%2==0)
  188.         q2 += 9;
  189.     while (q2 < step)
  190.     {
  191.         buff[q2] = 0;
  192.         q2 += 18;
  193.     }

  194.     mpz_clears(q, r, q1, NULL_TERMINATED);
  195. }

  196. //位标0:素数 1:PSP(2)
  197. int check(mpz_t base, long i)
  198. {
  199.     mpz_t n;
  200.     int result;
  201.     mpz_init(n);
  202.     mpz_add_ui(n, base, i);
  203.     if (fermatTest(n, 2))
  204.     {
  205.         if (millerrabinTest(n, 2))
  206.         {
  207.             if (quickTest(n))
  208.             {
  209.                 result = 3;   
  210.                 cnt ++;
  211.             }
  212.             else
  213.                 result = 2;            
  214.         }
  215.         else
  216.             result = 1;
  217.     }
  218.     else
  219.         result = 0;
  220.     if (result > 0 && result < 3)
  221.     {
  222.         gmp_printf("%Zd type: %d\n", n, result);
  223.     }   
  224.    
  225.     mpz_clear(n);
  226.     return result;
  227. }

  228. void test( mpz_t base, long idx )
  229. {
  230.     for (long i = 1; i < step; i += 2)
  231.         if (buff[i] == 3) //未筛的数字
  232.         {
  233.             pcnt ++;
  234.             buff[i] = check(base, i);
  235.         }
  236.         else
  237.         if (buff[i] == 2) //判定非素数,且可能PSP(2)的数字
  238.         {
  239.             mpz_t n;
  240.             pscnt++;
  241.             mpz_init_set_ui(n, i);
  242.             mpz_add(n, n, base);
  243.             if (fermatTest( n, 2))
  244.                 gmp_printf("%Zd: PSP(2)\n", n);
  245.             mpz_clear(n);
  246.         }
  247. }

  248. void clear( void )
  249. {
  250.     free(buff);
  251. }

  252. void showTime(char * pref)
  253. {
  254.   time_t rawtime;
  255.   struct tm * timeinfo;
  256.   char buffer [16];
  257.   time (&rawtime);
  258.   timeinfo = localtime (&rawtime);
  259.   strftime (buffer, 16 ,"%X", timeinfo);   
  260.   printf("%s: %s\n", pref, buffer);
  261. }

  262. int main( int argc, char * argv[] )
  263. {
  264.     mpz_t base;
  265.     mpz_init(base);
  266.     long idx = 0;
  267.     char * ptr;
  268.     if (argc > 1)
  269.         idx = strtol(argv[1], &ptr, 10);
  270.     showTime("Start Time");
  271.    
  272.     init( base, idx );
  273.     showTime(" init Time");
  274.     gmp_printf("start number: %Zd\n", base);
  275.     sieve( base, idx );
  276.     showTime("sieve Time");
  277.    
  278.     test( base, idx );
  279.     showTime(" test Time");
  280.    
  281.     printf("to test PSP: %d, to test primility %d\n", pscnt, pcnt);
  282.     printf("primes: %d\n", cnt);
  283.     mpz_clear(base);
  284.     clear();
  285.     return 0;
  286. }
复制代码

点评

话说,现在进度如何?  发表于 2020-12-22 16:19
if b==1{f=false;println!("{} is PSP(2)",a);psp+=1}改miller rabin能得到psp的  发表于 2020-12-10 17:26
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2020-12-10 18:02:17 | 显示全部楼层
无心人 发表于 2020-12-10 09:08
时间降不下来,发现筛出后,标记合数的只做fermat也不行,降不下来时间,不过候选素数从1000+万降低到600+ ...

话说你不会把全体小于5*10^7的素数都扔进去筛素数了吧……
可怕……

点评

先折腾我的服务器,Server2019不支持WSL2,我想办法更新到20270版本~  发表于 2020-12-11 18:36
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2020-12-22 17:23:15 | 显示全部楼层
筛到100万内素数,总时间从40秒降低到35秒

点评

还有,我在考虑是不是不筛1093和3511,似乎筛不筛这俩的结果都一样的,时间差距很小  发表于 2020-12-23 08:43
还没有,修改幅度有点大,所以是逐步优化的~  发表于 2020-12-23 08:40
删过fermat法了吗?miller-rabin自带一个fermat,可以修改miller-rabin直接判断出fermat伪素数的  发表于 2020-12-23 01:31
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2020-12-23 09:46:59 | 显示全部楼层
  1. #include<gmp.h>
  2. #include<stdbool.h>
  3. #include<stdint.h>
  4. #include<stdio.h>
  5. #include<stdlib.h>
  6. #include<time.h>
  7. #define NULL_TERMINATED                0
  8. #define primesize 78494

  9. const uint64_t step = 100000000;
  10. uint64_t cnt = 0, pcnt = 0, pscnt = 0;
  11. uint64_t small[primesize][2];
  12. char * buff;

  13. // 实际测试值=base + index*step + [1..step]
  14. int init( mpz_t base, uint64_t index )
  15. {
  16.     char line[64];
  17.     FILE *ordFile = fopen("ord6raw.txt", "r");
  18.     if (ordFile == NULL)
  19.     {
  20.         printf("file ord6raw not find!\n");
  21.         return -1;
  22.     }
  23.     uint64_t i = 0;
  24.     while (fgets(line, 64, ordFile))
  25.     {
  26.         uint64_t p, o;
  27.         sscanf(line, "%lu%lu", &p, &o);
  28.         small[i][0] = p;
  29.         small[i++][1] = o;
  30.         if (i >= primesize)
  31.             break;
  32.     }
  33.     fclose(ordFile);  
  34.     mpz_t tmp;
  35.     mpz_set_ui(base, 10);
  36.     mpz_pow_ui(base, base, 28);
  37.     mpz_init_set_ui(tmp, step);
  38.     mpz_mul_ui(tmp, tmp, index);
  39.     mpz_add(base, base, tmp);
  40.     mpz_clear(tmp);

  41.     buff = (char *)malloc(step);
  42.     for (long i = 0; i < step; i += 2)
  43.         buff[i] = 0;
  44.     for (long i = 1; i < step; i += 2)
  45.         buff[i] = 3; //3 = 位组合0:素数 1:PSP(2)
  46. }

  47. bool fermatTest( const mpz_t n, uint64_t b)
  48. {
  49.     mpz_t r, b1, ns1;
  50.    
  51.     mpz_inits(r, ns1, NULL_TERMINATED);
  52.     mpz_init_set_ui(b1, b);
  53.    
  54.     mpz_sub_ui(ns1, n, 1);
  55.     mpz_powm(r, b1, ns1, n);
  56.    
  57.     bool result = mpz_cmp_ui(r, 1) == 0;
  58.     mpz_clears(r, b1, ns1, NULL_TERMINATED);
  59.     return result;
  60. }

  61. bool millerrabinTest( const mpz_t n, uint64_t b )
  62. {
  63.     mpz_t ns1, t, b1, r;
  64.     uint64_t s;
  65.     bool result;

  66.     mpz_inits(ns1, t, r, NULL_TERMINATED);
  67.     mpz_init_set_ui(b1, b);// b1=b

  68.     mpz_sub_ui(ns1, n, 1);// ns1=n-1
  69.     s = mpz_scan1(ns1, 0);
  70.     mpz_tdiv_q_2exp(t, ns1, s);// ns1=2^s*t, t%2=1

  71.     mpz_powm(r, b1, t, n);
  72.     if (mpz_cmp_ui(r, 1) == 0 || mpz_cmp(r, ns1) == 0)
  73.         result = true;
  74.     else
  75.     {
  76.         result = false;
  77.         for (uint64_t i = 1; i < s; i ++)
  78.         {
  79.             mpz_powm_ui(r, r, 2, n);
  80.             if (mpz_cmp(r, ns1) == 0)
  81.             {
  82.                 result = true;
  83.                 break;
  84.             }
  85.         }
  86.     }
  87.     mpz_clears(ns1, t, b1, r, NULL_TERMINATED);
  88.     return result;
  89. }

  90. bool quickTest( mpz_t n )
  91. {
  92.     uint64_t b[] = {3, 5, 7, 11, 13};
  93.     for (int i = 0; i < sizeof(b)/sizeof(uint64_t); i++)
  94.         if (!millerrabinTest(n, b[i]))
  95.             return false;
  96.     return true;
  97. }

  98. void sievep( mpz_t base, uint64_t p, uint64_t o)
  99. {
  100.     mpz_t q, r, q1;
  101.     uint64_t r1, q2;

  102.     mpz_inits(q, r, q1, NULL_TERMINATED);

  103.     //合数形如pm, 素数p对2的次数是o, 筛掉不满足m=no+1的,因为只需要考虑m是奇数,所以,对o不是偶数的,已经乘以2了
  104.     mpz_fdiv_qr_ui(q, r, base, p);
  105.     mpz_mod_ui(q1, q, o);
  106.     q2 = mpz_get_ui(q1);
  107.     r1 = mpz_get_ui(r);
  108.     r1 = p - r1;
  109.     q2 = (q2+1)%o;
  110.     if (r1%2==0)
  111.     {
  112.         r1 += p;
  113.         q2 = (q2+1)%o;
  114.     }
  115.     while (r1 < step)
  116.     {
  117.         buff[r1] &= 2; //非素数
  118.         if (q2 != 1)
  119.         {
  120.             buff[r1] = 0; //非PSP(2)
  121.         }
  122.         r1 += 2*p;
  123.         q2 = (q2+2)%o;
  124.     }
  125.    
  126.     mpz_clears(q, r, q1, NULL_TERMINATED);
  127. }

  128. void sievep2( mpz_t base, uint64_t sp )
  129. {
  130.     mpz_t q1;
  131.     uint64_t q2;
  132.     mpz_init(q1);
  133.    
  134.     mpz_mod_ui(q1, base, sp);
  135.     q2 = mpz_get_ui(q1);//取模
  136.     q2 = sp - q2;//加sq,得到第一个奇数倍数,如果q2=0,结果也是对的
  137.     if (q2%2==0)
  138.         q2 += sp;
  139.     while (q2 < step)
  140.     {
  141.         buff[q2] = 0; //非PSP(2)
  142.         q2 += 2*sp;
  143.     }

  144. }

  145. void sieve( mpz_t base )
  146. {
  147.     mpz_t q1;
  148.     uint64_t q2;

  149.     mpz_init(q1);

  150.     //置位奇数中3的倍数为非素数
  151.     mpz_mod_ui(q1, base, 3);
  152.     q2 = mpz_get_ui(q1);
  153.     q2 = 3 - q2;
  154.     if (q2%2==0)
  155.         q2 += 3;
  156.     while (q2 < step)
  157.     {
  158.         buff[q2] &= 2;
  159.         q2 += 6;
  160.     }


  161.     for (long i = 0; i < primesize; i ++)
  162.         sievep( base, small[i][0], small[i][1] );
  163.    
  164.     sievep( base, 1093, 364 );
  165.     sievep( base, 3511, 3510 );
  166.    
  167.     //筛掉奇数中9的倍数
  168.     sievep2( base, 9 );

  169.     //筛掉满足p^2的倍数,其中p是小于sqrt(step)素数且不等于1093,3511
  170.     //筛选范围内有大于sqrt(step)的素数的平方的因子的数字很少
  171.     for (long i = 0; i < 1227; i ++)
  172.         sievep2( base, small[i][0] * small[i][0]);

  173.     mpz_clear(q1);
  174. }

  175. //位标0:素数 1:PSP(2)
  176. int check(mpz_t base, long i)
  177. {
  178.     mpz_t n;
  179.     int result;
  180.     mpz_init(n);
  181.     mpz_add_ui(n, base, i);
  182.     if (fermatTest(n, 2))
  183.     {
  184.         if (millerrabinTest(n, 2))
  185.         {
  186.             if (quickTest(n))
  187.             {
  188.                 result = 3;   
  189.                 cnt ++;
  190.             }
  191.             else
  192.                 result = 2;            
  193.         }
  194.         else
  195.             result = 1;
  196.     }
  197.     else
  198.         result = 0;
  199.     if (result > 0 && result < 3)
  200.     {
  201.         gmp_printf("%Zd type: %d\n", n, result);
  202.     }   
  203.    
  204.     mpz_clear(n);
  205.     return result;
  206. }

  207. void test( mpz_t base, long idx )
  208. {
  209.     for (long i = 1; i < step; i += 2)
  210.         if (buff[i] == 3) //未筛的数字
  211.         {
  212.             pcnt ++;
  213.             buff[i] = check(base, i);
  214.         }
  215.         else
  216.         if (buff[i] == 2) //判定非素数,且可能PSP(2)的数字
  217.         {
  218.             mpz_t n;
  219.             pscnt++;
  220.             mpz_init_set_ui(n, i);
  221.             mpz_add(n, n, base);
  222.             if (fermatTest( n, 2))
  223.                 gmp_printf("%Zd: PSP(2)\n", n);
  224.             mpz_clear(n);
  225.         }
  226. }

  227. void clear( void )
  228. {
  229.     free(buff);
  230. }

  231. void showTime(char * pref)
  232. {
  233.   time_t rawtime;
  234.   struct tm * timeinfo;
  235.   char buffer [16];
  236.   time (&rawtime);
  237.   timeinfo = localtime (&rawtime);
  238.   strftime (buffer, 16 ,"%X", timeinfo);   
  239.   printf("%s: %s\n", pref, buffer);
  240. }

  241. int main( int argc, char * argv[] )
  242. {
  243.     mpz_t base;
  244.     mpz_init(base);
  245.     uint64_t idx = 0;
  246.     char * ptr;
  247.     if (argc > 1)
  248.         idx = strtol(argv[1], &ptr, 10);
  249.     showTime("Start Time");

  250.     if (init( base, idx ) == -1)
  251.         exit(-1);
  252.         
  253.     showTime(" init Time");
  254.     gmp_printf("start number: %Zd\n", base);
  255.     sieve( base );
  256.     showTime("sieve Time");
  257.    
  258.     test( base, idx );
  259.     showTime(" test Time");
  260.    
  261.     printf("to test PSP: %lu, to test primility %lu\n", pscnt, pcnt);
  262.     printf("primes: %lu\n", cnt);
  263.     mpz_clear(base);
  264.     clear();

  265.     return 1;
  266. }
复制代码


Start Time: 01:44:11
init Time: 01:44:11
start number: 10000000000000000000000000000
sieve Time: 01:44:14
test Time: 01:44:46
to test PSP: 2920776, to test primility 4062724
primes: 1552676

用素数模2的阶筛100万内素数,然后筛掉1万内素数(不包含1093,3511)的平方
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2020-12-23 09:57:47 | 显示全部楼层
小素数范围需要测试的疑似PSP 需要测试的其他数字 时间
10万 3503020 4874685 37
100万2920776 406272435
10000万2187737 3044791 34

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

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

GMT+8, 2024-11-21 21:03 , Processed in 0.052068 second(s), 24 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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