Odd question, some advanced concepts, but then some logic gaps as well.
Still, if you want bitsets for each value, do the same thing (as tokhi suggested) anyway:
int size = 1 << bits;
ArrayList<BitSet> results = new ArrayList<>(size);
for (int val = 1; val < size; val++) {
BitSet bs = new BitSet(bits);
results.add(bs);
for (int b = 0; b < bits; b++) {
if ( ((val >>> b) & 1) == 1) {
bs.set(b);
}
}
}
EDIT
After some 'chat' about whether recursion or loops are better, I have put together this test...
I have modified my code above to be slightly more efficient, but, I have made relatively large changes to Dukeling's code so that it returns all BitSets instead of just modifying one and not storing the results.
Note that there is a 'bug' in the recursive code because it returns the no-bits-set value which is not supposed to be part of the results.....
Anyway, this is just food for thought.
Here's my test code:
import java.util.ArrayList;
import java.util.BitSet;
public class Junk {
private static final ArrayList<BitSet> loop(final int bits) {
int size = 1 << bits;
ArrayList<BitSet> results = new ArrayList<>(size);
for (int val = 1; val < size; val++) {
BitSet bs = new BitSet(bits);
results.add(bs);
int v = val;
int b = 0;
while (v != 0) {
if ( (v & 1) == 1) {
bs.set(b);
}
b++;
v >>>= 1;
}
}
return results;
}
private static final ArrayList<BitSet> recurse(final int bits) {
ArrayList<BitSet> retval = new ArrayList<BitSet>();
BitSet bitset = new BitSet(bits);
fill(bitset, 0, bits, retval);
return retval;
}
private static final void fill(final BitSet bs, final int k, final int n, final ArrayList<BitSet> results)
{
if (k == n) {
results.add((BitSet)bs.clone());
return;
}
bs.set(k, false);
fill(bs, k+1, n, results);
bs.set(k, true);
fill(bs, k+1, n, results);
}
private static final void exercise(final int bits) {
double acnt = 0;
double bcnt = 0;
long atime = 0L;
long btime = 0L;
for (int i = 0; i < 1000; i++) {
final long as = System.nanoTime();
acnt += recurse(bits).size();
atime += System.nanoTime() - as;
final long bs = System.nanoTime();
bcnt += loop(bits).size();
btime += System.nanoTime() - bs;
}
acnt /= 1000;
bcnt /= 1000;
System.out.printf(" Bits %d: ms/call -> recurse %.3fms loop %3fms (recurse %.1f/%d loop %f.1/%d\n",
bits, atime / 1000000.0, btime / 1000000.0, acnt, 1<<bits, bcnt, (1 << bits) - 1);
}
public static void main(String[] args) {
System.out.println("warmup");
exercise(3);
exercise(2);
exercise(1);
System.out.println("real runs");
exercise(1);
exercise(2);
exercise(3);
exercise(4);
exercise(5);
exercise(6);
exercise(7);
exercise(8);
exercise(9);
exercise(10);
exercise(11);
}
}
here's the output on my machine:
warmup
Bits 3: ms/call -> recurse 12.324ms loop 7.109403ms (recurse 8.0/8 loop 7.000000.1/7
Bits 2: ms/call -> recurse 2.949ms loop 2.392226ms (recurse 4.0/4 loop 3.000000.1/3
Bits 1: ms/call -> recurse 1.681ms loop 1.038053ms (recurse 2.0/2 loop 1.000000.1/1
real runs
Bits 1: ms/call -> recurse 1.743ms loop 0.865739ms (recurse 2.0/2 loop 1.000000.1/1
Bits 2: ms/call -> recurse 1.996ms loop 0.261967ms (recurse 4.0/4 loop 3.000000.1/3
Bits 3: ms/call -> recurse 3.150ms loop 0.544942ms (recurse 8.0/8 loop 7.000000.1/7
Bits 4: ms/call -> recurse 4.876ms loop 0.932031ms (recurse 16.0/16 loop 15.000000.1/15
Bits 5: ms/call -> recurse 6.128ms loop 1.775841ms (recurse 32.0/32 loop 31.000000.1/31
Bits 6: ms/call -> recurse 9.937ms loop 3.209335ms (recurse 64.0/64 loop 63.000000.1/63
Bits 7: ms/call -> recurse 21.005ms loop 7.221974ms (recurse 128.0/128 loop 127.000000.1/127
Bits 8: ms/call -> recurse 38.715ms loop 16.410275ms (recurse 256.0/256 loop 255.000000.1/255
Bits 9: ms/call -> recurse 69.904ms loop 41.330404ms (recurse 512.0/512 loop 511.000000.1/511
Bits 10: ms/call -> recurse 132.053ms loop 88.952120ms (recurse 1024.0/1024 loop 1023.000000.1/1023
Bits 11: ms/call -> recurse 255.921ms loop 193.370808ms (recurse 2048.0/2048 loop 2047.000000.1/2047