(Updated October 2, 2024)
8,000,000 possible numbers.
8M bits in 1M bytes.
byte[] ba = new byte[1000000];
  ba[0]    ba[1]    ba[2]    ba[3]
| byte0  | byte 1 | byte 2 | ...
 01234567 01234567 01234567
        ^                 ^
        |                 |
     2000007           2000023
 byte 0
01234567
^^^^^^^^      
|||||||└ 2000007
||||||└ 2000006
|||||└ 2000005
||||└ 2000004
|||└ 2000003
||└ 2000002
|└ 2000001
└ 2000000
0x80 == 10000000
    10110000
  | 10000000   0x80
  ----------
    10110000
    00100101 start
  | 10000000 mask
  ----------
    10100101 result
-------------------------------
Reading from the input file and populating the bitmap array...
2000176 - 2000000 -> 176
176 / 8 -> byte 22
176 % 8 -> bit 0
2000007 - 2000000 -> 7 / 8 -> 0
7%8 -> 7
     2 R 7
   ---
8 | 23
   -16
   ----
    7 Remainder
0x80 >>> 0 -> 10000000
0x80 >>> 3 -> 00010000
0x80 >>> 7 -> 00000001
2000023 - 2000000 -> 23 / 8 -> 2
23 % 8 -> 7
ba[2] = ba[2] | 0x80 >>> 7;
pn = pn - 2000000;
pnbyte = pn / 8;
pnbit = pn % 8;
2000007 / 8 -> 250000
2000007 % 8 -> 7
ba[250000]
9999999 / 8 -> 1,249,999
9999999 - 2000000 -> 7999999 / 8 -> 999,999
-------------------------------
Writing back to the output file...
    00100101 start
  & 10000000 mask
  ----------
    00000000 result
    00100101 start
  & 01000000 mask
  ----------
    00000000 result
    00100101 start
  & 00100000 mask
  ----------
    00100000 result
This translates to:
  if ( (ba[x] & mask) != 0)
    // write the number to file.
0x80 >>> 1 -> 01000000 >>> 1 -> 00100000 >>> 1 -> 00010000 The code roughly translates to:
For the range of bytes
  For the range of bits
    if ( (ba[by] & (0x80 >>> bit)) != 0) {
      pn = 2000000 + by * 8 + bit;
      // write the number to the output file.
    }