@Test
  public void andtest4() {
    final RoaringBitmap rb = new RoaringBitmap();
    final RoaringBitmap rb2 = new RoaringBitmap();

    for (int i = 0; i < 200000; i += 4) rb2.add(i);
    for (int i = 200000; i < 400000; i += 14) rb2.add(i);

    // check or against an empty bitmap
    final RoaringBitmap andresult = RoaringBitmap.and(rb, rb2);
    final RoaringBitmap off = RoaringBitmap.and(rb2, rb);
    Assert.assertTrue(andresult.equals(off));

    Assert.assertEquals(0, andresult.getCardinality());

    for (int i = 500000; i < 600000; i += 14) rb.add(i);
    for (int i = 200000; i < 400000; i += 3) rb2.add(i);
    // check or against an empty bitmap
    final RoaringBitmap andresult2 = RoaringBitmap.and(rb, rb2);
    Assert.assertEquals(0, andresult.getCardinality());

    Assert.assertEquals(0, andresult2.getCardinality());
    for (int i = 0; i < 200000; i += 4) rb.add(i);
    for (int i = 200000; i < 400000; i += 14) rb.add(i);
    Assert.assertEquals(0, andresult.getCardinality());
    final RoaringBitmap rc = RoaringBitmap.and(rb, rb2);
    rb.and(rb2);
    Assert.assertEquals(rc.getCardinality(), rb.getCardinality());
  }
  @Test
  public void ANDtest() {
    final RoaringBitmap rr = new RoaringBitmap();
    for (int k = 4000; k < 4256; ++k) rr.add(k);
    for (int k = 65536; k < 65536 + 4000; ++k) rr.add(k);
    for (int k = 3 * 65536; k < 3 * 65536 + 9000; ++k) rr.add(k);
    for (int k = 4 * 65535; k < 4 * 65535 + 7000; ++k) rr.add(k);
    for (int k = 6 * 65535; k < 6 * 65535 + 10000; ++k) rr.add(k);
    for (int k = 8 * 65535; k < 8 * 65535 + 1000; ++k) rr.add(k);
    for (int k = 9 * 65535; k < 9 * 65535 + 30000; ++k) rr.add(k);

    final RoaringBitmap rr2 = new RoaringBitmap();
    for (int k = 4000; k < 4256; ++k) {
      rr2.add(k);
    }
    for (int k = 65536; k < 65536 + 4000; ++k) {
      rr2.add(k);
    }
    for (int k = 3 * 65536 + 2000; k < 3 * 65536 + 6000; ++k) {
      rr2.add(k);
    }
    for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) {
      rr2.add(k);
    }
    for (int k = 7 * 65535; k < 7 * 65535 + 1000; ++k) {
      rr2.add(k);
    }
    for (int k = 10 * 65535; k < 10 * 65535 + 5000; ++k) {
      rr2.add(k);
    }
    final RoaringBitmap correct = RoaringBitmap.and(rr, rr2);
    rr.and(rr2);
    Assert.assertTrue(correct.equals(rr));
  }
  @Test
  public void andtest() {
    final RoaringBitmap rr = new RoaringBitmap();
    for (int k = 0; k < 4000; ++k) {
      rr.add(k);
    }
    rr.add(100000);
    rr.add(110000);
    final RoaringBitmap rr2 = new RoaringBitmap();
    rr2.add(13);
    final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2);
    int[] array = rrand.toArray();

    Assert.assertEquals(array.length, 1);
    Assert.assertEquals(array[0], 13);
    rr.and(rr2);
    array = rr.toArray();
    Assert.assertEquals(array.length, 1);
    Assert.assertEquals(array[0], 13);
  }
  @SuppressWarnings("null")
  @Test
  public void flipTestBigA() {
    final int numCases = 1000000;
    System.out.println("flipTestBigA for " + numCases + " tests");
    final BitSet bs = new BitSet();
    final Random r = new Random(3333);
    int checkTime = 2;
    RoaringBitmap rb1 = new RoaringBitmap(), rb2 = null; // alternate
    // between
    // them

    for (int i = 0; i < numCases; ++i) {
      final int start = r.nextInt(65536 * 20);
      int end = r.nextInt(65536 * 20);
      if (r.nextDouble() < 0.1) end = start + r.nextInt(100);

      if ((i & 1) == 0) {
        rb2 = RoaringBitmap.flip(rb1, start, end);
        // tweak the other, catch bad sharing
        rb1.flip(r.nextInt(65536 * 20), r.nextInt(65536 * 20));
      } else {
        rb1 = RoaringBitmap.flip(rb2, start, end);
        rb2.flip(r.nextInt(65536 * 20), r.nextInt(65536 * 20));
      }

      if (start < end) bs.flip(start, end); // throws exception
      // otherwise
      // insert some more ANDs to keep things sparser
      if (r.nextDouble() < 0.2 && (i & 1) == 0) {
        final RoaringBitmap mask = new RoaringBitmap();
        final BitSet mask1 = new BitSet();
        final int startM = r.nextInt(65536 * 20);
        final int endM = startM + 100000;
        mask.flip(startM, endM);
        mask1.flip(startM, endM);
        mask.flip(0, 65536 * 20 + 100000);
        mask1.flip(0, 65536 * 20 + 100000);
        rb2.and(mask);
        bs.and(mask1);
      }

      if (i > checkTime) {
        System.out.println("check after " + i + ", card = " + rb2.getCardinality());
        final RoaringBitmap rb = (i & 1) == 0 ? rb2 : rb1;
        final boolean status = equals(bs, rb);
        Assert.assertTrue(status);
        checkTime *= 1.5;
      }
    }
  }
  @Test
  public void andtest3() {
    final int[] arrayand = new int[11256];
    int pos = 0;
    final RoaringBitmap rr = new RoaringBitmap();
    for (int k = 4000; k < 4256; ++k) rr.add(k);
    for (int k = 65536; k < 65536 + 4000; ++k) rr.add(k);
    for (int k = 3 * 65536; k < 3 * 65536 + 1000; ++k) rr.add(k);
    for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) rr.add(k);
    for (int k = 3 * 65536 + 7000; k < 3 * 65536 + 9000; ++k) rr.add(k);
    for (int k = 4 * 65536; k < 4 * 65536 + 7000; ++k) rr.add(k);
    for (int k = 6 * 65536; k < 6 * 65536 + 10000; ++k) rr.add(k);
    for (int k = 8 * 65536; k < 8 * 65536 + 1000; ++k) rr.add(k);
    for (int k = 9 * 65536; k < 9 * 65536 + 30000; ++k) rr.add(k);

    final RoaringBitmap rr2 = new RoaringBitmap();
    for (int k = 4000; k < 4256; ++k) {
      rr2.add(k);
      arrayand[pos++] = k;
    }
    for (int k = 65536; k < 65536 + 4000; ++k) {
      rr2.add(k);
      arrayand[pos++] = k;
    }
    for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) {
      rr2.add(k);
      arrayand[pos++] = k;
    }
    for (int k = 6 * 65536; k < 6 * 65536 + 1000; ++k) {
      rr2.add(k);
      arrayand[pos++] = k;
    }
    for (int k = 7 * 65536; k < 7 * 65536 + 1000; ++k) {
      rr2.add(k);
    }
    for (int k = 10 * 65536; k < 10 * 65536 + 5000; ++k) {
      rr2.add(k);
    }

    final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2);

    final int[] arrayres = rrand.toArray();

    for (int i = 0; i < arrayres.length; i++)
      if (arrayres[i] != arrayand[i]) System.out.println(arrayres[i]);

    Assert.assertTrue(Arrays.equals(arrayand, arrayres));
  }
  @Test
  public void flipTestBig() {
    final int numCases = 1000000;
    System.out.println("flipTestBig for " + numCases + " tests");
    final RoaringBitmap rb = new RoaringBitmap();
    final BitSet bs = new BitSet();
    final Random r = new Random(3333);
    int checkTime = 2;

    for (int i = 0; i < numCases; ++i) {
      final int start = r.nextInt(65536 * 20);
      int end = r.nextInt(65536 * 20);
      if (r.nextDouble() < 0.1) end = start + r.nextInt(100);
      rb.flip(start, end);
      if (start < end) bs.flip(start, end); // throws exception
      // otherwise
      // insert some more ANDs to keep things sparser
      if (r.nextDouble() < 0.2) {
        final RoaringBitmap mask = new RoaringBitmap();
        final BitSet mask1 = new BitSet();
        final int startM = r.nextInt(65536 * 20);
        final int endM = startM + 100000;
        mask.flip(startM, endM);
        mask1.flip(startM, endM);
        mask.flip(0, 65536 * 20 + 100000);
        mask1.flip(0, 65536 * 20 + 100000);
        rb.and(mask);
        bs.and(mask1);
      }
      // see if we can detect incorrectly shared containers
      if (r.nextDouble() < 0.1) {
        final RoaringBitmap irrelevant = RoaringBitmap.flip(rb, 10, 100000);
        irrelevant.flip(5, 200000);
        irrelevant.flip(190000, 260000);
      }
      if (i > checkTime) {
        System.out.println("check after " + i + ", card = " + rb.getCardinality());
        Assert.assertTrue(equals(bs, rb));
        checkTime *= 1.5;
      }
    }
  }
  @Test
  public void clearTest() {
    final RoaringBitmap rb = new RoaringBitmap();
    for (int i = 0; i < 200000; i += 7)
      // dense
      rb.add(i);
    for (int i = 200000; i < 400000; i += 177)
      // sparse
      rb.add(i);

    final RoaringBitmap rb2 = new RoaringBitmap();
    final RoaringBitmap rb3 = new RoaringBitmap();
    for (int i = 0; i < 200000; i += 4) rb2.add(i);
    for (int i = 200000; i < 400000; i += 14) rb2.add(i);

    rb.clear();
    Assert.assertEquals(0, rb.getCardinality());
    Assert.assertTrue(0 != rb2.getCardinality());

    rb.add(4);
    rb3.add(4);
    final RoaringBitmap andresult = RoaringBitmap.and(rb, rb2);
    final RoaringBitmap orresult = RoaringBitmap.or(rb, rb2);

    Assert.assertEquals(1, andresult.getCardinality());
    Assert.assertEquals(rb2.getCardinality(), orresult.getCardinality());

    for (int i = 0; i < 200000; i += 4) {
      rb.add(i);
      rb3.add(i);
    }
    for (int i = 200000; i < 400000; i += 114) {
      rb.add(i);
      rb3.add(i);
    }

    final int[] arrayrr = rb.toArray();
    final int[] arrayrr3 = rb3.toArray();

    Assert.assertTrue(Arrays.equals(arrayrr, arrayrr3));
  }
  @Test
  public void cardinalityTest() {
    final int N = 1024;
    for (int gap = 7; gap < 100000; gap *= 10) {
      for (int offset = 2; offset <= 1024; offset *= 2) {
        final RoaringBitmap rb = new RoaringBitmap();
        // check the add of new values
        for (int k = 0; k < N; k++) {
          rb.add(k * gap);
          Assert.assertEquals(rb.getCardinality(), k + 1);
        }
        Assert.assertEquals(rb.getCardinality(), N);
        // check the add of existing values
        for (int k = 0; k < N; k++) {
          rb.add(k * gap);
          Assert.assertEquals(rb.getCardinality(), N);
        }

        final RoaringBitmap rb2 = new RoaringBitmap();

        for (int k = 0; k < N; k++) {
          rb2.add(k * gap * offset);
          Assert.assertEquals(rb2.getCardinality(), k + 1);
        }

        Assert.assertEquals(rb2.getCardinality(), N);

        for (int k = 0; k < N; k++) {
          rb2.add(k * gap * offset);
          Assert.assertEquals(rb2.getCardinality(), N);
        }
        Assert.assertEquals(RoaringBitmap.and(rb, rb2).getCardinality(), N / offset);
        Assert.assertEquals(RoaringBitmap.or(rb, rb2).getCardinality(), 2 * N - N / offset);
        Assert.assertEquals(RoaringBitmap.xor(rb, rb2).getCardinality(), 2 * N - 2 * N / offset);
      }
    }
  }
  public void rTest(final int N) {
    System.out.println("rtest N=" + N);
    for (int gap = 1; gap <= 65536; gap *= 2) {
      final BitSet bs1 = new BitSet();
      final RoaringBitmap rb1 = new RoaringBitmap();
      for (int x = 0; x <= N; ++x) {
        bs1.set(x);
        rb1.add(x);
      }
      if (bs1.cardinality() != rb1.getCardinality()) throw new RuntimeException("different card");
      if (!equals(bs1, rb1)) throw new RuntimeException("basic  bug");
      for (int offset = 1; offset <= gap; offset *= 2) {
        final BitSet bs2 = new BitSet();
        final RoaringBitmap rb2 = new RoaringBitmap();
        for (int x = 0; x <= N; ++x) {
          bs2.set(x + offset);
          rb2.add(x + offset);
        }
        if (bs2.cardinality() != rb2.getCardinality()) throw new RuntimeException("different card");
        if (!equals(bs2, rb2)) throw new RuntimeException("basic  bug");

        BitSet clonebs1;
        // testing AND
        clonebs1 = (BitSet) bs1.clone();
        clonebs1.and(bs2);
        if (!equals(clonebs1, RoaringBitmap.and(rb1, rb2))) throw new RuntimeException("bug and");
        {
          final RoaringBitmap t = rb1.clone();
          t.and(rb2);
          if (!equals(clonebs1, t)) throw new RuntimeException("bug inplace and");
          if (!t.equals(RoaringBitmap.and(rb1, rb2))) {
            System.out.println(
                t.highlowcontainer.getContainerAtIndex(0).getClass().getCanonicalName());
            System.out.println(
                RoaringBitmap.and(rb1, rb2)
                    .highlowcontainer
                    .getContainerAtIndex(0)
                    .getClass()
                    .getCanonicalName());

            throw new RuntimeException("bug inplace and");
          }
        }

        // testing OR
        clonebs1 = (BitSet) bs1.clone();
        clonebs1.or(bs2);

        if (!equals(clonebs1, RoaringBitmap.or(rb1, rb2))) throw new RuntimeException("bug or");
        {
          final RoaringBitmap t = rb1.clone();
          t.or(rb2);
          if (!equals(clonebs1, t)) throw new RuntimeException("bug or");
          if (!t.equals(RoaringBitmap.or(rb1, rb2))) throw new RuntimeException("bug or");
          if (!t.toString().equals(RoaringBitmap.or(rb1, rb2).toString()))
            throw new RuntimeException("bug or");
        }
        // testing XOR
        clonebs1 = (BitSet) bs1.clone();
        clonebs1.xor(bs2);
        if (!equals(clonebs1, RoaringBitmap.xor(rb1, rb2))) {
          throw new RuntimeException("bug xor");
        }
        {
          final RoaringBitmap t = rb1.clone();
          t.xor(rb2);
          if (!equals(clonebs1, t)) throw new RuntimeException("bug xor");
          if (!t.equals(RoaringBitmap.xor(rb1, rb2))) throw new RuntimeException("bug xor");
        }
        // testing NOTAND
        clonebs1 = (BitSet) bs1.clone();
        clonebs1.andNot(bs2);
        if (!equals(clonebs1, RoaringBitmap.andNot(rb1, rb2))) {
          throw new RuntimeException("bug andnot");
        }
        clonebs1 = (BitSet) bs2.clone();
        clonebs1.andNot(bs1);
        if (!equals(clonebs1, RoaringBitmap.andNot(rb2, rb1))) {
          throw new RuntimeException("bug andnot");
        }
        {
          final RoaringBitmap t = rb2.clone();
          t.andNot(rb1);
          if (!equals(clonebs1, t)) {
            throw new RuntimeException("bug inplace andnot");
          }
          final RoaringBitmap g = RoaringBitmap.andNot(rb2, rb1);
          if (!equals(clonebs1, g)) {
            throw new RuntimeException("bug andnot");
          }
          if (!t.equals(g)) throw new RuntimeException("bug");
        }
        clonebs1 = (BitSet) bs1.clone();
        clonebs1.andNot(bs2);
        if (!equals(clonebs1, RoaringBitmap.andNot(rb1, rb2))) {
          throw new RuntimeException("bug andnot");
        }
        {
          final RoaringBitmap t = rb1.clone();
          t.andNot(rb2);
          if (!equals(clonebs1, t)) {
            throw new RuntimeException("bug andnot");
          }
          final RoaringBitmap g = RoaringBitmap.andNot(rb1, rb2);
          if (!equals(clonebs1, g)) {
            throw new RuntimeException("bug andnot");
          }
          if (!t.equals(g)) throw new RuntimeException("bug");
        }
      }
    }
  }