1

I have two BitSets which have to be initialized randomly with the length of 20 bits.

I am trying to achieve that by initializing the BitSets with 20 bits each and within a for loop iterating through the BitSets and call nextBoolean() of the Random class. However, the length is not always 20. So, I have been playing around with it, and figured it that it might be because it does not count the false bits as part of the length. In case I understand it correctly, how do I force it to have 20 random bits always?

public static void generate() {

        BitSet set1 = new BitSet(20);
        BitSet set2 = new BitSet(20);

        Random r = new SecureRandom();
        for (int i = 0; set1.length() < 20 && set2.length() < 20; i++) {
            set1.set(i, r.nextBoolean());
            set2.set(i, r.nextBoolean());
        }

        StringBuilder s = new StringBuilder();
        for (int i = 0; i < set1.length(); i++) {
            s.append(temp1.get(i) == true ? 1 : 0);
        }

        System.out.println(s + " " + s.length() + " " + set1.length() + " "+ set2.length());
}

Thanks in advance.

John McClane
  • 3,498
  • 3
  • 12
  • 33
Bab
  • 433
  • 5
  • 12
  • if you always want 20 as your size, why not use a constant? Something like `final int size = 20;`. Then you can replace all occurrences of `20` with `size` – user3170251 Nov 20 '18 at 14:51
  • Thanks for you suggestion. I have tried that, but it did not resolve the problem, unfortunately. The length is still inconsistent and now it goes above 20 sometimes – Bab Nov 20 '18 at 14:59
  • Take a look at https://stackoverflow.com/a/69148389/139985. Basically, the `Bitset` class model represents a bitset with an infinite number of bits. The "logical length" returned by `length()` denotes the position of the rightmost ONE bit. So your idea of a bitset with precisely 20 bits randomly 0 or 1 does not fit the model. (Or to put it another way, its `length()` may not be 20.) – Stephen C Sep 12 '21 at 05:54

3 Answers3

1

Why not use Bitset.valueOf(byte[] array) to initialize the bit set from a random byte array?

Something like:

public BitSet getBits(SecureRandom sr, int size) {
    byte[] ar = new byte[(int) Math.ceil(size / 8F)];
    sr.nextBytes(ar);
    return BitSet.valueOf(ar).get(0, size);
}
Guss
  • 30,470
  • 17
  • 104
  • 128
0

In case I understand it correctly, how do I force it to have 20 random bits always?

Change your for-loops to:

for (int i = 0; i < 20; i++) {
    set1.set(i, r.nextBoolean());
    set2.set(i, r.nextBoolean());
}

...

for (int i = 0; i < 20; i++) {
    s.append(temp1.get(i) == true ? 1 : 0);
}

A BitSet is backed by a long[] and all bits are initially set to false, so calling BitSet#length will not return the value 20 unless the 19th bit happens to be set, as stated by its documentation:

Returns the "logical size" of this BitSet: the index of the highest set bit in the BitSet plus one. Returns zero if the BitSet contains no set bits.

By using the value 20 as the condition in your for-loops, you're ensuring that the first 20 bits will have the opportunity of being set randomly.

Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • So even if I change my for loops and print the BitSet length, I won't always get 20 bits? An example of my print: `10101001110111111110 20 19 20`. 20 is the length of the StringBuilder, 19 is the length of the first BitSet and 20 is the length of the second BitSet – Bab Nov 20 '18 at 16:12
  • There's a 50% chance you'll get a length of `20`, as it depends on the last bit set by the for-loop. But if you use `20` as the condition in the for-loop, you can be sure that the first `20` bits will be set randomly, even if `BitSet#length` doesn't return `20`. – Jacob G. Nov 20 '18 at 16:14
  • I see. What must I do in order to ensure that there are exactly 20 random bits then? i.e. 20 in length – Bab Nov 20 '18 at 16:41
  • By just changing the for-loop condition. `BitSet#length` depends on the last bit set, so don't rely on its value, as you're setting bits randomly. – Jacob G. Nov 20 '18 at 16:44
  • Maybe I am misunderstanding you; I understand that I have to change the for loops, but what confuses me then is that when I print the length of the BitSet after the for loops, it is inconsistent. I do understand that if I print `s` I will get 20, but that is not the real BitSet's length. Would an if statement, which always sets the 20th bit to true help? – Bab Nov 20 '18 at 16:52
  • You would have to set the bit at index `19` to `true` for `BitSet#length` to return `20` (assuming no bit after that has been set). But I would think that defeats the purpose of what you're trying to do. Even if `BitSet#length` does not return `20`, you're still setting the first `20` bits to `true` or `false` randomly. For that reason, DO NOT depend on what `BitSet#length` returns. – Jacob G. Nov 20 '18 at 16:53
  • Ahh, I was trying to set the bit at index 20 to true. Oversaw that it is LESS than 20 - Back to basics. However, it does not defeat the purpose of what I am trying to do as I need the length to be exactly 20 – Bab Nov 20 '18 at 17:02
0

If you are using Java 7, you can initialize a random byte array with Random.nextBytes(byte[]) then use the static BitSet.valueOf(byte[]) method to create a BitSet from the same byte array.

Random rnd = new Random();
// ...
byte[] randomBytes = new byte[NUM_BYTES];
rnd.nextBytes(randomBytes);
return BitSet.valueOf(randomBytes);

Credits for: https://stackoverflow.com/a/8566871/5133329

Josemy
  • 810
  • 1
  • 12
  • 29