3

Suppose we have two BitSet objects in Java with values as

//<MSB....LSB>
B1:<11000101>
B2:<10111101>

How can we compare B1 and B2 to know that the value represented by B1 is greater than that by B2.

are logical operators (>,<,==) overloaded for BitSet? or Do I have to write my own implementation?

Update: just found that "The operator > is undefined for the argument type(s) java.util.BitSet, java.util.BitSet". Is there any built-in way to do so?

Mangat Rai Modi
  • 5,397
  • 8
  • 45
  • 75
  • 2
    there is not operator overloading in Java. you can write function or use predefined interface like Comparable – Adem Dec 06 '14 at 11:32

3 Answers3

10

You can do it by xor-ing the two sets together, and comparing the length of the result to lengths of bit sets:

  • If xor is empty, bit sets are equal. You can bypass this operation by calling equals()
  • Otherwise, the length of xor result will be equal to the position of the most significant bit that is different between the two values.
  • Whichever of the two operands has this bit set is the greater one of the two.

Here is a sample implementation:

int compare(BitSet lhs, BitSet rhs) {
    if (lhs.equals(rhs)) return 0;
    BitSet xor = (BitSet)lhs.clone();
    xor.xor(rhs);
    int firstDifferent = xor.length()-1;
    if(firstDifferent==-1)
            return 0;

    return rhs.get(firstDifferent) ? 1 : -1;
}

Demo.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • A good method to compare for equality. But I wanted to find the greater of the BitSet. – Mangat Rai Modi Dec 06 '14 at 11:45
  • @MangatRai Nope, this is not a comparison for equality - it tells you which bit set is larger, and it does not break when you have more than 63 bits. – Sergey Kalinichenko Dec 06 '14 at 11:47
  • 1
    My Bad, I understood the logic. It is simply brilliant. – Mangat Rai Modi Dec 06 '14 at 11:54
  • Just checked, lhs.xor(rhs) won't return BitSet. It is of type void. It will change lhs to be the result. Quite cumbersome, as now I have to make copies of the arguments, to not change the values. – Mangat Rai Modi Dec 06 '14 at 11:59
  • ah! Nevermind, It is the approach what matters and the one you mentioned was beautiful. But I really I think the API should return the value instead of being void – Mangat Rai Modi Dec 06 '14 at 12:02
  • 1
    @MangatRai The fact that `xor` is implemented as a destructive operation is much more salient here, changing the return type would not help with that. – Marko Topolnik Dec 06 '14 at 12:03
  • I didn't mean to change the return type. I am wondering why was XOR, OR etc. in BitWise were implemented in this fashion? – Mangat Rai Modi Dec 06 '14 at 12:09
  • @MangatRai probably because `BitSet` is inherently meant to be mutable and, as such, it can be assumed that all `void` methods will possibly be muting it one way or the other. –  Dec 06 '14 at 12:12
  • Interesting idea, and I thought that using length() was brilliant, however I found a counter example, that shows that unfortunately the implementation is broken: ideone.com/hCJZ1q -- "a" can't be less than "b" and "b" less than "a" at the same time -- all your examples set just one bit. – stivlo May 27 '15 at 12:57
  • @stivlo Thanks for finding this bug! I fixed the implementation to correct this problem. – Sergey Kalinichenko May 27 '15 at 13:06
  • perfect, it works! very nice and compact. xor gives the first different bit, and so lhs and rhs will have different values for that bit and you use that information to give an unique ordering. fantastic. – stivlo May 27 '15 at 13:16
1

No, the operators aren't overloaded, because a) there is no operator overloading in Java, b) what you expect is kind of wrong and illogical.

BitSet is, like the name signifies a set of bits. You can't tell a "greater" and "smaller" set - it's like saying one color is "bigger" than the other. If you want to compare bit sets, you have to create a comparison metric - I think what you want is to compare values of the integers created from bits - if that's the case, use the code from e.g. BitSet to and from integer/long, and then call

static int compare( BitSet bs1, BitSet bs2 ) {
  return Long.compare(Bits.convert(bs1),Bits.convert(bs2));
}

or, as a Comparator,

class BitSetComparator implements Comparator<BitSet> {
  int compare( BitSet bs1, BitSet bs2 ) {
    return Long.compare(Bits.convert(bs1),Bits.convert(bs2));
  }
}

Note that in this particular case both sets have to fit into long (63 bits max). Alternatively, assuming your metric is "the set with higher unsigned integer representation is bigger", you can use XORing, or loop through the bits, or any other construct that goes through all the bits -

int compare( BitSet bs1, BitSet bs2 ) {
  BitSet x = ((BitSet)bs1.clone()).xor(bs2);
  return ( x.isEmpty() ) ? 0 : ( x.length() == bs2.length() ? 1 : -1 );
}

but in all of those cases, if you're aiming at comparing your bits, your best bet is just to use long to store your data and then compare it directly as unsigned values, using https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html#compareUnsigned-long-long- - otherwise you're losing the space-time efficiency of bit storage with doing to-and-fro conversions to deal with a case that's based on using a class for things it's not designed for. Both BitSet#xor() & (especially) BitSet#length() aren't the light-weight operations you'd expect from bit ops, mainly due to recalculateWordsInUse();, checkInvariants(); & Long.numberOfLeadingZeros() used in them. All in all, all methods other than native integer use (especially any comparing code as shown above) will result in serious performance loss in any performance-dependent scenarios.

Community
  • 1
  • 1
  • You can use `Long.compare()` – fge Dec 06 '14 at 11:43
  • Thanks you for the explanation that why BitSet are not of Comparable type and the way to convert to/from integer was really elegant. – Mangat Rai Modi Dec 06 '14 at 11:47
  • @dasblinkenlight I've already noted that, `Note that in this particular case both sets have to fit into long (63 bits max).` –  Dec 06 '14 at 12:03
1

You can use the logical operator on bit basis (boolean values received from get()):

// Assumed equal length
boolean less(BitSet b1, BitSet b2) {
 int N = b1.length();

 for (int i = N-1; i >= 0; i--) {
    if (b1.get(i) ^ b2.get(i)) return b2.get(i);
 }

 return false;
}

Or you can have a comparator in place:

class BitsComparator implements Comparator<BitSet> {
  @Override
  int compare (BitSet b1, BitSet b2) {
    if (b1.length() > b2.length())
       return 1;
    if (b1.length() == b2.length()) {
      int N = b1.length();
      for (int i = N-1; i >= 0; i--) {
        if ((b1.get(i) ^ b2.get(i)) && b2.get(i)) return -1;
      }
      return 0;
    }
    return -1;
  }
}
nitishagar
  • 9,038
  • 3
  • 28
  • 40