|
首先发一个Pari/GP的代码- c=0;for(i=1,oo,k=(2*i-1)*105;if(isprime(k-4),if(isprime(k-2),if(isprime(k+2),if(isprime(k+4),if(k>2^32,break);c+=1;print((k-5)/10))))))
复制代码 如果只准备计数的话,可以用这个- for(t=1,32,c=1/*notice that 11,13,17,19 was not calculated*/;for(i=1,oo,k=(2*i-1)*105;if(isprime(k-4),if(isprime(k-2),if(isprime(k+2),if(isprime(k+4),if(k>2^t,break);c+=1;/*print((k-5)/10)*/)))));print([t,c-(t<=3)]))
复制代码 过一会儿写筛法&&多线程
初步计数的结果[n,小于2^n的满足k+1,k+3,k+7,k+9均为素数的k]如下:- 19:57:48> for(t=1,32,c=1/*notice that 11,13,17,19 was not calculated*/;for(i=1,oo,k=(2*i-1)*105;if(isprime(k-4),if(isprime(k-2),if(isprime(k+2),if(isprime(k+4),if(k>2^t,break);c+=1;/*print((k-5)/10)*/)))));print([t,c-(t<=3)]))[1, 0][2, 0][3, 0][4, 1][5, 1][6, 1][7, 2][8, 2][9, 2][10, 2][11, 2][12, 4][13, 4][14, 6][15, 8][16, 11][17, 13][18, 18][19, 31][20, 53][21, 109][22, 160][23, 266][24, 424][25, 709][26, 1227][27, 2039][28, 3421][29, 5826][30, 10130][31, 17511][32, 30633]cpu time = 26,537 ms, real time = 26,572 ms.
复制代码 update: (naive)Rust
首先放一个头文件,miller-rabin.rs,用witness进行素性判定- fn mod_exp(mut x: u64, mut d: u64, n: u64) -> u64 { let mut ret: u64 = 1; if n<4294967296{ while d != 0 { if d & 1 == 1 { ret = (ret*x)%n } d >>= 1; x = (x*x)%n; } }else{ while d != 0 { if d & 1 == 1 { ret = ((ret as u128*x as u128)%n as u128) as u64 } d >>= 1; x = ((x as u128*x as u128)%n as u128) as u64; } } ret}pub fn miller_rabin(n: u64) -> bool { // we have a strict upper bound, so we can just use the witness // table of Pomerance, Selfridge & Wagstaff and Jeaschke to be as // efficient as possible, without having to fall back to // randomness. const WITNESSES: &[(u64, &[u64])] = &[(2_046, &[2]), (1_373_652, &[2, 3]), (9_080_190, &[31, 73]), (25_326_000, &[2, 3, 5]), (4_759_123_140, &[2, 7, 61]), (1_112_004_669_632, &[2, 13, 23, 1662803]), (2_152_302_898_746, &[2, 3, 5, 7, 11]), (3_474_749_660_382, &[2, 3, 5, 7, 11, 13]), (341_550_071_728_320, &[2, 3, 5, 7, 11, 13, 17]), (0xFFFF_FFFF_FFFF_FFFF, &[2, 3, 5, 7, 11, 13, 17, 19, 23]) ]; let mut d = n - 1; let mut s = 0; while d & 1 == 0 { d /= 2; s += 1 } let witnesses = WITNESSES.iter().find(|&&(hi, _)| hi >= n) .map(|&(_, wtnss)| wtnss).unwrap(); 'next_witness: for &a in witnesses.iter() { let mut power = mod_exp(a, d, n); assert!(power < n); if power == 1 || power == n - 1 { continue 'next_witness } if n<4294967296{ for _r in 0..s { power = (power*power)%n; if power == 1 { return false } if power == n - 1 { continue 'next_witness } } }else{ for _r in 0..s { power = ((power as u128*power as u128)%n as u128) as u64; if power == 1 { return false } if power == n - 1 { continue 'next_witness } } } return false } true}
复制代码 程序:- include!{"miller-rabin.rs"}fn main() { let mut i=0u64.wrapping_sub(1); let mut n=1; let mut ctr=1; let mut limit=1<<n; loop{ i+=2; let j=i*105; if j>limit { println!("{:?}",[n,ctr-(n<=3) as i32]); limit<<=1; n+=1; if n>34{break}else{continue} } if miller_rabin(j-4) && miller_rabin(j-2) && miller_rabin(j+2) && miller_rabin(j+4) { ctr+=1 } }}
复制代码 update2: naive Rust的变种(向Rayon以及筛法靠拢)- include!{"miller-rabin.rs"}//use rayon::prelude::*;fn main() { let mut prepare=vec![105]; let mut prepare_len=210; println!("total:{}",1+(0..(1u64<<32)/prepare_len).into_iter().fold(0,|s,i|s+{ let start=prepare_len*i; prepare.iter().map(|&x|x+start).fold(0,|s,j|{ if miller_rabin(j-4) && miller_rabin(j-2) && miller_rabin(j+2) && miller_rabin(j+4) { s+1 }else{ s } }) }))}
复制代码 Rayon+筛法,为了保证计算效率,程序计数最好停止在筛的边界(而非之前随便写的那个边界)- include!{"miller-rabin.rs"}extern crate rayon;use rayon::prelude::*;fn not_divide(d:u64,n:u64)->bool{ (n/d)*d!=n}fn sieve(v:&mut Vec<u64>,len:&mut u64,prime:u64){ let mut vv=v.par_iter().copied().fold(||Vec::new(),|mut s,x|{s.append(&mut (0..prime).map(|p|*len*p+x).filter(|&x|not_divide(prime,x-4)&¬_divide(prime,x-2)&¬_divide(prime,x+2)&¬_divide(prime,x+4)).collect());s}) .reduce(||Vec::new(),|mut s,mut x|{s.append(&mut x);s}); *len*=prime; vv.shrink_to_fit(); vv.sort_unstable(); println!("{:?}",vv.len()); *v=vv}fn main() { let end = 12; let mut prepare=vec![105]; let mut prepare_len=210; sieve(&mut prepare,&mut prepare_len,11); sieve(&mut prepare,&mut prepare_len,13); sieve(&mut prepare,&mut prepare_len,17); sieve(&mut prepare,&mut prepare_len,19); sieve(&mut prepare,&mut prepare_len,23); sieve(&mut prepare,&mut prepare_len,29); sieve(&mut prepare,&mut prepare_len,31); println!("total:{:?}(from 0 to {})",1+(0u64..end).into_par_iter().fold(||0,|s,i|s+{ let start=prepare_len*i; prepare.iter().map(|&x|x+start).fold(0,|s,j|{ if miller_rabin(j-4) && miller_rabin(j-2) && miller_rabin(j+2) && miller_rabin(j+4) { s+1 }else{ s } }) }).reduce(||0,|a,b|a+b),end*prepare_len)}
复制代码 算得- $ rustc main.rs -C panic=abort -C opt-level=3 -C target-cpu=native -C codegen-units=1 -C lto -L ../target/release/deps -o main && time ./main763819122852334155835375total:326240(from 0 to 77636318760)real 0m19.608suser 3m26.773ssys 0m0.110s
复制代码 以及- $ rustc main.rs -C panic=abort -C opt-level=3 -C target-cpu=native -C codegen-units=1 -C lto -L ../target/release/deps -o main && time ./main763819122852334155835375157555125total:5907339(from 0 to 2406725881560)real 12m9.250suser 126m49.848ssys 0m4.234s
复制代码 不知道大家还有什么神奇优化技巧
补充内容 (2021-1-28 13:58):
筛法筛错了……少了两个该筛的数字,比如vec![105];应该是vec![15,105,195]; |
|