简体   繁体   English

翻译这个Eratosthenes筛网的Java实现?

[英]Translating this java implementation of Sieve of Eratosthenes?

This is a program in Java which implements the Sieve or Eratosthenes by storing the array of booleans as an array of bits. 这是Java中的程序,通过将布尔数组存储为位数组来实现Sieve或Eratosthenes。 I have never coded in Java before, but the general idea is easy to understand. 我以前从未用Java编写过代码,但是总体思路很容易理解。 However, I cannot understand how the getBit and setBit functions work? 但是,我不明白getBitsetBit函数如何工作? I am guessing that the getBit function creates a bitmask with the bit i set to 1 and does bitwise AND between the mask and the array? 我猜想getBit函数会创建一个将其设置为1的位掩码,并且在掩码和数组之间按位AND吗? However, I'm not really understanding the details (eg. why i is right shifted by 4 before being passed as index to array, and why MEMORY_SIZE is equal to MAX right shifted by 4). 但是,我并不是很了解细节(例如,为什么在作为索引传递给数组之前右移4,以及为什么MEMORY_SIZE等于右移4的MAX )。 Please explain the each step of getBit and setBit in words, and if possible an equivalent implementation in Python? 请用语言解释getBitsetBit的每个步骤,如果可能的话,请在Python中等效的实现?

private static final long MAX = 1000000000L;
private static final long SQRT_MAX = (long) Math.sqrt(MAX) + 1;
private static final int MEMORY_SIZE = (int) (MAX >> 4);
private static byte[] array = new byte[MEMORY_SIZE];
//--//
for (long i = 3; i < SQRT_MAX; i += 2) {
  if (!getBit(i)) {
    long j = (i * i);
    while (j < MAX) {
      setBit(j);
      j += (2 * i);
    }
  }
}
//--//
public static boolean getBit(long i) {
  byte block = array[(int) (i >> 4)];
  byte mask = (byte) (1 << ((i >> 1) & 7));
  return ((block & mask) != 0);
}

public static void setBit(long i) {
  int index = (int) (i >> 4);
  byte block = array[index];
  byte mask = (byte) (1 << ((i >> 1) & 7));
  array[index] = (byte) (block | mask);
} 

Some notes in advance: 提前注意事项:

  • (i >> 4) divides i by 16, which is the index of the block (of 8 bits) in array that contains the i -th bit (i >> 4)i除以16,这是包含第i位的array中(8位)块的索引
  • (i >> 1) divides i by 2 (i >> 1)i除以2
  • 7 in binary code is 111 二进制代码中的7111
  • ((i >> 1) & 7) means "the three rightmost bits of i / 2 ", which is a number between 0 and 7 (inclusive) ((i >> 1) & 7)表示“ i / 2最右边三个位”,它是介于0和7之间(包括0和7)的数字
  • (1 << ((i >> 1) & 7)) is a bit shifted to the left between 0 and 7 times ( 00000001 , 00000010 , ..., 10000000 ). (1 << ((i >> 1) & 7))是0至7倍比特向左移位( 0000000100000010 ,..., 10000000 )。 This is the bit mask to set/get the bit of interest from the selected block. 这是位掩码,用于设置/从所选块中获取感兴趣的位。

getBit(i) explained getBit(i)解释

  1. First line selects the 8-bit-block (ie a byte ) in which the bit of interest is located. 第一行选择感兴趣的位所在的8位块(即byte )。
  2. Second line calculates a bit mask with exactly one bit set. 第二行计算的位掩码恰好设置了一位。 The position of the set bit is the same as the one of the bit of interest within the 8-bit-block. 设置的位的位置与8位块中感兴趣的位之一相同。
  3. Third line extracts the bit of interest using an bitwise AND, returning true if this bit is 1 . 第三行使用按位AND提取感兴趣的位,如果该位为1 ,则返回true

setBit(i) explained setBit(i)解释

  1. Calculation of the 8-bit-block and the bit mask is equivalent to getBit 8位块和位掩码的计算等效于getBit
  2. The difference is that a bitwise OR is used to set the bit of interest. 不同之处在于,按位或用于设置感兴趣的位。

Edit 编辑

To your first question: 第一个问题:

It almost makes sense now, can you please explain why we are able to find the position of the bit cooresponding to the number i by shifting a bit left ((i >> 1) & 7) times? 现在几乎可以理解,您能否解释一下为什么我们能够通过向左移((i >> 1)&7)次来找到与数字i对应的位的位置? In other words, i understand what the operation is doing, but why does this give us the correct bit position? 换句话说,我理解该操作在做什么,但是为什么这会给我们正确的位位置呢?

I think this is because of the optimized nature of the algorithm. 我认为这是由于算法的优化性质。 Since i is incremented in steps of 2, it is sufficient to use half of the bits (since the others would be set anyway). 因为i以2的步长递增,所以使用一半的位就足够了(因为其他位还是会被设置)。 Thus, i can be divided by 2 to calculate the number of necessary bit shifts. 因此, i可以被2除以计算必要的位移位数。

Regarding your second question: 关于第二个问题:

Also, just to clarify, the reason we increment j by 2*i after each call to setBit is because we only need to set the bits cooresponding to odd multiples of i, right? 另外,为了澄清起见,在每次调用setBit之后将j增加2 * i的原因是因为我们只需要设置与i的奇数倍对应的位,对吗?

Yes, because according to https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes : 是的,因为根据https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

Another refinement is to initially list odd numbers only, (3, 5, ..., n), and count in increments of 2p in step 3, thus marking only odd multiples of p. 另一种改进是最初仅列出奇数(3、5,...,n),并在步骤3中以2p的增量计数,因此仅标记p的奇数倍。

Your algorithm starts with 3, increments i by 2, and counts in increments of 2*i . 您的算法以3开头, i递增2,并以2*i递增。

I hope this helps! 我希望这有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM