素数筛法系列之3 减少筛次数

来源:互联网 发布:网络安全法的心得体会 编辑:程序博客网 时间:2024/06/10 14:51

//筛法加速
  接上一节, 筛某个素数的倍数的时候只需筛掉奇数倍数, 这样计算量可
可减少一般, 再进一步优化, 不筛3的倍数, 只筛6k+1, 6k+5 之类素数,
计算量只有原来2/3.

static void crossOutFactorMod6(uchar bitarray[], const uint64 start,
            const int leng, int factor)
{
  int s1 = factor - start % factor;
  if (s1 % 2 == 0) {
    s1 += factor;
  } else if (start <= factor) {
    s1 += 2 * factor;
  }

  //筛除3的倍数
  const int bits = leng >> 1;
  if (factor <= 3) {
    for (s1 >>= 1; s1 <= bits; s1 += factor) {
      SET_BIT(bitarray, s1);
    }
    return ;
  }

  const int mrid6 = ((start + s1) / factor) % 6;
  s1 >>= 1;

  int s2 = s1;
  if (mrid6 == 1) {
    s2 += factor * 2;
  } else if (mrid6 == 3) {
    s1 += factor;
    s2 += factor * 2;
  } else {
    s2 += factor;
  }

  //6k + 1, 6k + 5 number will be corssed out
  for (factor *= 3; s2 <= bits;) {
    SET_BIT(bitarray, s1); s1 += factor; //6k + 1
    SET_BIT(bitarray, s2); s2 += factor; //6k + 5
  }
  if (s1 <= bits) {
    SET_BIT(bitarray, s1);
  }
}

//比上面的模6进一步, 采用模30的筛法, 计算量再减小1/5.(1/3 ----> 8/30)
static void crossOutFactorMod30(uchar bitarray[], const uint64 start,
            const int leng, int factor)
{
  int offset = factor - start % factor;
  if (offset % 2 == 0) {
    offset += factor;
  } else if (start <= factor) {
    offset += 2 * factor;
  }

  //筛除3,5的倍数
  const int bits = leng >> 1;
  if (factor <= 5) {
    for (offset >>= 1; offset <= bits; offset += factor) {
      SET_BIT(bitarray, offset);
    }
    return ;
  }


  int rid30 = (offset + start) / factor % 30;

  //找到第一个数为30k + 1的数offset
  while (rid30 < 31 & offset < leng) {
    SET_BIT(bitarray, offset / 2); offset += factor * 2;
    rid30 += 2;
  }

  //按模30余1,7,11,13,1,19,23,29的筛
  offset >>= 1;
  while (offset + 15 * factor <= bits) {
    SET_BIT(bitarray, offset); offset += factor * 3; //30k + 1
    SET_BIT(bitarray, offset); offset += factor * 2; //30k + 7
    SET_BIT(bitarray, offset); offset += factor * 1; //30k + 11
    SET_BIT(bitarray, offset); offset += factor * 2; //30k + 13
    SET_BIT(bitarray, offset); offset += factor * 1; //30k + 17
    SET_BIT(bitarray, offset); offset += factor * 2; //30k + 19
    SET_BIT(bitarray, offset); offset += factor * 3; //30k + 23
    SET_BIT(bitarray, offset); offset += factor * 1; //30k + 29
  }

  //筛除剩下几个.
  uint m = 0x13212123;//模30余数, 4bit压缩
  while (offset <= bits) {
    SET_BIT(bitarray, offset); offset += factor * (m & 15);
    //循环移位
    m = (m >> 4) | (m << 28);
  }
}

  测试表明这两个函数实现比原来奇数版本快近1/3, 基本符合预期.
在循环里面每次筛的更多,减小循环也提高性能(相当于收到循环展开)

原创粉丝点击