Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* author Bill Wood */
- use rayon::prelude::*;
- use std::io::Write;
- fn main() {
- let mut args = std::env::args()
- .skip(1)
- .map(|a| a
- .split('_')
- .fold("".to_string(), |a, s| a + s)
- .parse::<usize>());
- if args.len() <= 3 {
- if let (Ok(mut low), Ok(mut high), Ok(seg_size_kb), ) = (
- args.next().unwrap_or(Ok(1_000_000_000)),
- args.next().unwrap_or(Ok(2_000_000_000)),
- args.next().unwrap_or(Ok(64)),) {
- println!("S15: Finding sexy primes with args {} {} {}", low, high, seg_size_kb, );
- low = if low < 3 { 3 } else { low | 1 }; // lowest odd >= low
- high = (high - 1) | 1; // highest odd <= high
- // find sieving primes
- let sieve_primes = simple_sieve(high);
- // prepare for parallel segment sieve
- let mut candidates_per_seg = seg_size_kb*1024*8*2;
- while (high - low)/candidates_per_seg > 100_000_000 { // increase seg size to reduce mem usage
- candidates_per_seg *= 2;
- }
- let segs: Vec<(usize, usize)> = { low..=high }
- .step_by(candidates_per_seg)
- .map(|seg_low| {
- let seg_high = seg_low + candidates_per_seg - 2;
- (seg_low, if seg_high > high { high } else { seg_high } + 6)
- })
- .collect();
- // do parallel segment sieve
- let (sexy_count, nprimes) =
- segs.into_par_iter()
- .map(|(low, high)| {
- // sieve this segment
- let sieve_seg = seg_sieve(low, high, &sieve_primes);
- // find sexy primes in this segment
- let (mut sexy_count, mut nprimes) = (0_usize, 0_usize);
- for p in PrimesIter::new(low, high, &sieve_seg) {
- if p + 6 <= high {
- nprimes += 1;
- if !sieve_seg.get(((p - low) >> 1) + 6/2) {
- sexy_count += 1;
- }
- }
- }
- (sexy_count, nprimes)
- })
- .reduce(|| (0, 0),
- |a, b| (a.0 + b.0, a.1 + b.1));
- println!("{} of {} primes are sexy", sexy_count, nprimes);
- return;
- }
- }
- writeln!(std::io::stderr(), "Usage: sexy_primes [low [high [seg_size_kb]]]").unwrap();
- std::process::exit(1);
- }
- fn simple_sieve(mut high: usize) -> Vec<u32> {
- // x where x: odd and (x+2)^2 > high and x^2 < high
- high = (sqrt(high) - 1) | 1;
- let mut pvec = vec![false; (high + 1)/2];
- let mut primes = vec![];
- let n = high >> 1;
- let mut i = 3;
- while i*i <= high {
- if !pvec[i >> 1] {
- primes.push(i as u32);
- let mut j = (i*i) >> 1;
- while j <= n {
- pvec[j] = true;
- j += i;
- }
- }
- i += 2;
- }
- i >>= 1;
- while i <= n {
- if !pvec[i] {
- primes.push(((i << 1) | 1) as u32);
- }
- i += 1;
- }
- primes
- }
- fn seg_sieve(low: usize, high: usize, sieve_primes: &Vec<u32>) -> Bvec {
- let n = (high + 2 - low) >> 1;
- let mut sieve_seg = Bvec::new(false, n);
- for i in 0..sieve_primes.len() {
- let p = sieve_primes[i] as usize;
- let mut j = p*p;
- if j > high {
- break;
- }
- if j < low {
- // j = low - 1 + p - (low - 1)%p;
- // j += (low - 1 - j + p*2)/2/p*p*2;
- j = p*(((low - 1)/p + 1) | 1);
- }
- j = (j - low) >> 1;
- while j < n {
- sieve_seg.set(j, true);
- j += p;
- }
- }
- sieve_seg
- }
- fn sqrt(n: usize) -> usize {
- let (mut r1, mut r) = (n, n + 1);
- while r1 < r {
- r = r1;
- r1 = (r1 + n/r1) >> 1
- }
- r
- }
- struct Bvec {
- v: Vec<u8>
- }
- impl Bvec {
- fn new(val: bool, s: usize) -> Self {
- let valu8 = if val { 255 } else { 0 };
- Bvec { v: vec![valu8; (s >> 3) + if (s & 7) == 0 { 0 } else { 1 } ] }
- }
- #[inline(always)]
- fn get(&self, index: usize) -> bool {
- self.v[index >> 3] & 1 << (index & 7) != 0
- }
- #[inline(always)]
- fn set(&mut self, mut index: usize, val: bool) {
- let bitpos = 1 << (index & 7);
- index >>= 3;
- if val {
- self.v[index] |= bitpos;
- } else {
- self.v[index] &= !bitpos;
- }
- }
- }
- struct PrimesIter<'a> {
- sieve_index: usize,
- base: usize,
- low: usize,
- high: usize,
- cur_byte: u8,
- sieve: &'a [u8],
- }
- impl<'a> Iterator for PrimesIter<'a> {
- type Item = usize;
- #[inline(always)]
- fn next(&mut self) -> Option<Self::Item> {
- while self.cur_byte == 0 {
- if self.sieve_index >= self.sieve.len() {
- return None;
- }
- self.cur_byte = !self.sieve[self.sieve_index];
- self.base = (self.sieve_index << 4) + self.low;
- self.sieve_index += 1;
- }
- let trailing = self.cur_byte.trailing_zeros();
- self.cur_byte &= !(1 << trailing);
- let prime = self.base + (trailing << 1) as usize;
- if prime <= self.high {
- Some(prime)
- } else {
- None
- }
- }
- }
- impl<'a> PrimesIter<'a> {
- fn new(low: usize, high: usize, sieve: &'a Bvec) -> Self {
- PrimesIter { sieve_index: 0, base: 0, low, high, cur_byte: 0, sieve: &sieve.v }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement