Index: lucene/src/test/org/apache/lucene/util/TestBitUtil.java
===================================================================
--- lucene/src/test/org/apache/lucene/util/TestBitUtil.java	(revision 0)
+++ lucene/src/test/org/apache/lucene/util/TestBitUtil.java	(revision 0)
@@ -0,0 +1,136 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.lucene.util;
+
+public class TestBitUtil extends LuceneTestCase {
+
+  private static int slowNlz(long x) {
+    if (x == 0L) return 64;
+    int nlz = 0;
+    while ( ((x << nlz) & (1L << 63)) == 0) {
+      nlz++;
+    }
+    return nlz;
+  }
+
+  private void checkNlz(long x) {
+    assertEquals(slowNlz(x), BitUtil.nlz(x));
+    assertEquals(Long.numberOfLeadingZeros(x), BitUtil.nlz(x));
+  }
+  
+  public void testNlz() {
+    checkNlz(0L);
+    checkNlz(1L);
+    checkNlz(-1L);
+    for (int i = 1; i <= 63; i++) {
+      checkNlz(1L << i);
+      checkNlz((1L << i) + (1L << (i>>1)));
+    }
+  }
+
+  public void testBitUtils()
+  {
+    long num = 100000;
+    assertEquals( 5, BitUtil.ntz(num) );
+    assertEquals( 5, BitUtil.ntz2(num) );
+    assertEquals( 5, BitUtil.ntz3(num) );
+    
+    num = 10;
+    assertEquals( 1, BitUtil.ntz(num) );
+    assertEquals( 1, BitUtil.ntz2(num) );
+    assertEquals( 1, BitUtil.ntz3(num) );
+
+    for (int i=0; i<64; i++) {
+      num = 1L << i;
+      assertEquals( i, BitUtil.ntz(num) );
+      assertEquals( i, BitUtil.ntz2(num) );
+      assertEquals( i, BitUtil.ntz3(num) );
+    }
+  }
+
+
+  private long testArg(int shift) {
+    return (1L << shift) + (1L << (shift>>1));
+  }
+  
+  private long nlzBitUtilBasicLoop(int iters) {
+    long sumRes = 0;
+    while (iters-- >= 0) {
+      for (int i = 1; i <= 63; i++) {
+      	long a = testArg(i);
+	sumRes += BitUtil.nlz(a);
+	sumRes += BitUtil.nlz(a+1);
+	sumRes += BitUtil.nlz(a-1);
+	sumRes += BitUtil.nlz(a+10);
+	sumRes += BitUtil.nlz(a-10);
+      }
+    }
+    return sumRes;
+  }
+    
+  private long nlzLongBasicLoop(int iters) {
+    long sumRes = 0;
+    while (iters-- >= 0) {
+      for (int i = 1; i <= 63; i++) {
+      	long a = testArg(i);
+	sumRes += Long.numberOfLeadingZeros(a);
+	sumRes += Long.numberOfLeadingZeros(a+1);
+	sumRes += Long.numberOfLeadingZeros(a-1);
+	sumRes += Long.numberOfLeadingZeros(a+10);
+	sumRes += Long.numberOfLeadingZeros(a-10);
+      }
+    }
+    return sumRes;
+  }
+
+  public void tstPerfNlz() { // See LUCENE-3197, prefer to use Long.numberOfLeadingZeros() over BitUtil.nlz().
+    final long measureMilliSecs = 2000;
+    final int basicIters = 100000;
+    long startTime;
+    long endTime;
+    long curTime;
+    long dummy = 0; // avoid optimizing away
+
+    dummy = 0;
+    int bitUtilLoops = 0;
+    startTime = System.currentTimeMillis();
+    endTime = startTime + measureMilliSecs;
+    do {
+      dummy += nlzBitUtilBasicLoop(basicIters);
+      bitUtilLoops++;
+      curTime = System.currentTimeMillis();
+    } while (curTime < endTime);
+    int bitUtilPsTime = (int) (1000000000 * (curTime - startTime) / (basicIters * 5 * 63 * (float) bitUtilLoops));
+    System.out.println("BitUtil nlz time: " + (bitUtilPsTime/1) + " picosec/call, dummy: " + dummy);
+
+
+    dummy = 0;
+    int longLoops = 0;
+    startTime = System.currentTimeMillis();
+    endTime = startTime + measureMilliSecs;
+    do {
+      dummy += nlzLongBasicLoop(basicIters);
+      longLoops++;
+      curTime = System.currentTimeMillis();
+    } while (curTime < endTime);
+    int longPsTime = (int) (1000000000 * (curTime - startTime) / (basicIters * 5 * 63 * (float) longLoops));
+    System.out.println("Long    nlz time: " + longPsTime + " picosec/call, dummy: " + dummy);
+
+  }
+
+}
Index: lucene/src/test/org/apache/lucene/util/TestOpenBitSet.java
===================================================================
--- lucene/src/test/org/apache/lucene/util/TestOpenBitSet.java	(revision 1133498)
+++ lucene/src/test/org/apache/lucene/util/TestOpenBitSet.java	(working copy)
@@ -41,6 +41,20 @@
     } while (aa>=0);
   }
 
+  void doPrevSetBit(BitSet a, OpenBitSet b) {
+    int aa=a.length();
+    int bb=aa;
+    do {
+      // aa = a.prevSetBit(aa-1);
+      aa--;
+      while ((aa >= 0) && (! a.get(aa))) {
+      	aa--;
+      }
+      bb = b.prevSetBit(bb-1);
+      assertEquals(aa,bb);
+    } while (aa>=0);
+  }
+
   // test interleaving different OpenBitSetIterator.next()/skipTo()
   void doIterate(BitSet a, OpenBitSet b, int mode) {
     if (mode==1) doIterate1(a, b);
@@ -123,6 +137,7 @@
       bb = (OpenBitSet)b.clone(); bb.clear(fromIndex,toIndex);
 
       doNextSetBit(aa,bb);  // a problem here is from clear() or nextSetBit
+      doPrevSetBit(aa,bb);
 
       fromIndex = random.nextInt(sz+80);
       toIndex = fromIndex + random.nextInt((sz>>1)+1);
@@ -130,6 +145,7 @@
       bb = (OpenBitSet)b.clone(); bb.set(fromIndex,toIndex);
 
       doNextSetBit(aa,bb);  // a problem here is from set() or nextSetBit     
+      doPrevSetBit(aa,bb);
 
 
       if (a0 != null) {
@@ -168,7 +184,7 @@
       b0=b;
     }
   }
-
+  
   // large enough to flush obvious bugs, small enough to run in <.5 sec as part of a
   // larger testsuite.
   public void testSmall() {
@@ -178,9 +194,8 @@
 
   public void testBig() {
     // uncomment to run a bigger test (~2 minutes).
-    // rand = newRandom();
-    // doRandomSets(2000,200000, 1);
-    // doRandomSets(2000,200000, 2);
+    //doRandomSets(2000,200000, 1);
+    //doRandomSets(2000,200000, 2);
   }
 
   public void testEquals() {
@@ -205,26 +220,6 @@
     assertFalse(b1.equals(new Object()));
   }
   
-  public void testBitUtils()
-  {
-    long num = 100000;
-    assertEquals( 5, BitUtil.ntz(num) );
-    assertEquals( 5, BitUtil.ntz2(num) );
-    assertEquals( 5, BitUtil.ntz3(num) );
-    
-    num = 10;
-    assertEquals( 1, BitUtil.ntz(num) );
-    assertEquals( 1, BitUtil.ntz2(num) );
-    assertEquals( 1, BitUtil.ntz3(num) );
-
-    for (int i=0; i<64; i++) {
-      num = 1L << i;
-      assertEquals( i, BitUtil.ntz(num) );
-      assertEquals( i, BitUtil.ntz2(num) );
-      assertEquals( i, BitUtil.ntz3(num) );
-    }
-  }
-
   public void testHashCodeEquals() {
     OpenBitSet bs1 = new OpenBitSet(200);
     OpenBitSet bs2 = new OpenBitSet(64);
@@ -233,6 +228,35 @@
     assertEquals(bs1, bs2);
     assertEquals(bs1.hashCode(), bs2.hashCode());
   } 
+
+  
+  private OpenBitSet makeOpenBitSet(int[] a) {
+    OpenBitSet bs = new OpenBitSet();
+    for (int e: a) {
+      bs.set(e);
+    }
+    return bs;
+  }
+
+  private BitSet makeBitSet(int[] a) {
+    BitSet bs = new BitSet();
+    for (int e: a) {
+      bs.set(e);
+    }
+    return bs;
+  }
+
+  private void checkPrevSetBitArray(int [] a) {
+    OpenBitSet obs = makeOpenBitSet(a);
+    BitSet bs = makeBitSet(a);
+    doPrevSetBit(bs, obs);
+  }
+
+  public void testPrevSetBit() {
+    checkPrevSetBitArray(new int[] {});
+    checkPrevSetBitArray(new int[] {0});
+    checkPrevSetBitArray(new int[] {0,2});
+  }
 }
 
 
Index: lucene/src/java/org/apache/lucene/util/BitUtil.java
===================================================================
--- lucene/src/java/org/apache/lucene/util/BitUtil.java	(revision 1133498)
+++ lucene/src/java/org/apache/lucene/util/BitUtil.java	(working copy)
@@ -778,7 +778,29 @@
    return n - (y & 1);
   }
 
+  /** table of number of leading zeros in a byte */
+  public static final byte[] nlzTable = {8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 
+  /** Returns the number of leading zero bits.
+   */
+  public static int nlz(long x) {
+   int n = 0;
+   // do the first step as a long
+   int y = (int)(x>>>32);
+   if (y==0) {n+=32; y = (int)(x); }
+   if ((y & 0xFFFF0000) == 0) { n+=16; y<<=16; }
+   if ((y & 0xFF000000) == 0) { n+=8; y<<=8; }
+   return n + nlzTable[y >>> 24];
+ /* implementation without table:
+   if ((y & 0xF0000000) == 0) { n+=4; y<<=4; }
+   if ((y & 0xC0000000) == 0) { n+=2; y<<=2; }
+   if ((y & 0x80000000) == 0) { n+=1; y<<=1; }
+   if ((y & 0x80000000) == 0) { n+=1;}
+   return n;
+  */
+  }
+
+
   /** returns true if v is a power of two or zero*/
   public static boolean isPowerOfTwo(int v) {
     return ((v & (v-1)) == 0);
Index: lucene/src/java/org/apache/lucene/util/OpenBitSet.java
===================================================================
--- lucene/src/java/org/apache/lucene/util/OpenBitSet.java	(revision 1133498)
+++ lucene/src/java/org/apache/lucene/util/OpenBitSet.java	(working copy)
@@ -659,8 +659,32 @@
   }
 
 
+  /** Returns the index of the first set bit starting downwards at
+   *  the index specified.
+   *  -1 is returned if there are no more set bits.
+   */
+  public int prevSetBit(int index) {
+    if (index < 0) return -1;
+    int i = index>>6;
+    if (i>=wlen) i = wlen - 1;
+    int subIndex = index & 0x3f;      // index within the word
+    long word = (bits[i] << (63-subIndex));  // skip all the bits to the left of index
 
+    if (word!=0) {
+      return (i<<6) + subIndex - Long.numberOfLeadingZeros(word); // See LUCENE-3197
+    }
 
+    while (--i >= 0) {
+      word = bits[i];
+      if (word!=0) return (i<<6) + 63 - Long.numberOfLeadingZeros(word);
+    }
+
+    return -1;
+  }
+
+
+
+
   @Override
   public Object clone() {
     try {
