Search over Int/Long using bit hacks

Правка en3, от wrick, 2016-07-07 16:43:55

If you are binary searching over Ints (or Longs), there is a neat trick you can use to quickly find the answer in exactly 32 (or 64 for Longs) operations. This code is simple to write, less error prone than binary search (off by 1 mistakes) and in practice often faster.

import java.util.OptionalLong;
import java.util.function.LongPredicate;
import java.util.stream.LongStream;

/**
 * Find the largest long that satisfies the predicate f using exactly 64 bit-wise operations: O(64 * O(f))
 *
 * @param f Monotonous predicate
 * @return The largest number that satisfies f
 */
static OptionalLong binarySearch(LongPredicate f) {
    long p = 0L, n = Long.MIN_VALUE;
    for(long t = n >>> 1; t > 0; t >>= 1) {
      if (f.test(p|t)) p |= t;
      if (f.test(n|t)) n |= t;
    }
    return LongStream.of(p, n).filter(f).findFirst();
}

If you only want to search over non-negative numbers, its even simpler (showing with Ints instead of Longs):

static OptionalInt binarySearch(IntPredicate f) {
    int p = 0;
    for(int t = Integer.MIN_VALUE >>> 1; t > 0; t >>= 1) {
      if (f.test(p|t)) p |= t;
    }
    return f.test(p) ? OptionalInt.of(p) : OptionalInt.empty();
}

How does it work: There are only 64-bits in a long. Just toggle them one by one from left to right depending on whether the predicate is satisfied or not.

Exercise for reader: Modify code to search for smallest instead of largest.

Теги bit manipulation, binary seach, java 8, java

История

 
 
 
 
Правки
 
 
  Rev. Язык Кто Когда Δ Комментарий
en4 Английский wrick 2016-07-08 00:12:36 47
en3 Английский wrick 2016-07-07 16:43:55 7
en2 Английский wrick 2016-07-07 16:43:07 85
en1 Английский wrick 2016-07-07 16:39:43 1487 Initial revision (published)