diff --git a/arraycontainer.go b/arraycontainer.go
index 602069b6..eecb90cb 100644
--- a/arraycontainer.go
+++ b/arraycontainer.go
@@ -65,10 +65,26 @@ func (ac *arrayContainer) minimum() uint16 {
 	return ac.content[0] // assume not empty
 }
 
+func (ac *arrayContainer) safeMinimum() (uint16, error) {
+	if len(ac.content) == 0 {
+		return 0, errors.New("empty array")
+	}
+
+	return ac.minimum(), nil
+}
+
 func (ac *arrayContainer) maximum() uint16 {
 	return ac.content[len(ac.content)-1] // assume not empty
 }
 
+func (ac *arrayContainer) safeMaximum() (uint16, error) {
+	if len(ac.content) == 0 {
+		return 0, errors.New("empty array")
+	}
+
+	return ac.maximum(), nil
+}
+
 func (ac *arrayContainer) getSizeInBytes() int {
 	return ac.getCardinality() * 2
 }
@@ -975,35 +991,40 @@ func (ac *arrayContainer) realloc(size int) {
 // Ex: target=4 ac=[2,3,4,6,7] returns 4
 // Ex: target=5 ac=[2,3,4,6,7] returns 4
 // Ex: target=6 ac=[2,3,4,6,7] returns 6
+// Ex: target=8 ac=[2,3,4,6,7] returns 7
 // Ex: target=1 ac=[2,3,4,6,7] returns -1
+// Ex: target=0 ac=[2,3,4,6,7] returns -1
 func (ac *arrayContainer) previousValue(target uint16) int {
 	result := binarySearchUntil(ac.content, target)
 
+	if result.index == len(ac.content) {
+		return int(ac.maximum())
+	}
+
 	if result.outOfBounds() {
 		return -1
 	}
+
 	return int(result.value)
 }
 
 // previousAbsentValue returns either the target if not found or the next larger missing value.
 // If the target is out of bounds a -1 is returned
-// Ex: target=4 ac=[1,2,3,4,6,7] returns -1
+// Ex: target=4 ac=[1,2,3,4,6,7] returns 0
 // Ex: target=5 ac=[1,2,3,4,6,7] returns 5
 // Ex: target=6 ac=[1,2,3,4,6,7] returns 5
-// Ex: target=8 ac=[1,2,3,4,6,7] returns -1
+// Ex: target=8 ac=[1,2,3,4,6,7] returns 8
 func (ac *arrayContainer) previousAbsentValue(target uint16) int {
 	cardinality := len(ac.content)
 
 	if cardinality == 0 {
-		return -1
+		return int(target)
 	}
 
-	if target <= ac.minimum() {
-		return -1
-	}
 	if target > ac.maximum() {
-		return -1
+		return int(target)
 	}
+
 	result := binarySearchPast(ac.content, target)
 
 	if result.notFound() {
@@ -1017,7 +1038,7 @@ func (ac *arrayContainer) previousAbsentValue(target uint16) int {
 		}
 	}
 
-	low := 0
+	low := -1
 	high := result.index
 
 	// This uses the pigeon-hole principle.
@@ -1037,11 +1058,8 @@ func (ac *arrayContainer) previousAbsentValue(target uint16) int {
 		}
 	}
 
-	if low == 0 {
-		if high == 1 {
-			return -1
-		}
-		return int(ac.content[high] - 1)
+	if high == 0 {
+		return int(ac.minimum()) - 1
 	}
 
 	return int(ac.content[high] - 1)
@@ -1051,16 +1069,18 @@ func (ac *arrayContainer) previousAbsentValue(target uint16) int {
 // If the target is out of bounds a -1 is returned
 // Ex: target=4 ac=[1,2,3,4,6,7] returns 5
 // Ex: target=5 ac=[1,2,3,4,6,7] returns 5
-// Ex: target=0 ac=[1,2,3,4,6,7] returns -1
-// Ex: target=8 ac=[1,2,3,4,6,7] returns -1
+// Ex: target=0 ac=[1,2,3,4,6,7] returns 0
+// Ex: target=8 ac=[1,2,3,4,6,7] returns 8
 func (ac *arrayContainer) nextAbsentValue(target uint16) int {
 	cardinality := len(ac.content)
-	if target < ac.minimum() {
-		return -1
+
+	if cardinality == 0 {
+		return int(target)
 	}
-	if target > ac.maximum() {
-		return -1
+	if target < ac.minimum() {
+		return int(target)
 	}
+
 	result := binarySearchPast(ac.content, target)
 
 	if result.notFound() {
@@ -1102,26 +1122,33 @@ func (ac *arrayContainer) nextAbsentValue(target uint16) int {
 
 // nextValue returns either the target if found or the next larger value.
 // if the target is out of bounds a -1 is returned
+//
 // Ex: target=4 ac=[1,2,3,4,6,7] returns 4
 // Ex: target=5 ac=[1,2,3,4,6,7] returns 6
 // Ex: target=6 ac=[1,2,3,4,6,7] returns 6
+// Ex: target=0 ac=[1,2,3,4,6,7] returns 1
+// Ex: target=100 ac=[1,2,3,4,6,7] returns -1
 func (ac *arrayContainer) nextValue(target uint16) int {
 	cardinality := len(ac.content)
 	if cardinality == 0 {
 		return -1
 	}
 
-	if target < ac.minimum() {
-		return -1
-	}
-	if target > ac.maximum() {
-		return -1
-	}
+	//if target < ac.minimum() {
+	//	return -1
+	//}
+	//if target > ac.maximum() {
+	//		return -1
+	//	}
 
 	result := binarySearchUntil(ac.content, target)
 	if result.exactMatch {
 		return int(result.value)
 	}
+
+	if !result.exactMatch && result.index == -1 {
+		return int(ac.content[0])
+	}
 	if result.outOfBounds() {
 		return -1
 	}
diff --git a/arraycontainer_test.go b/arraycontainer_test.go
index e797107b..112c3103 100644
--- a/arraycontainer_test.go
+++ b/arraycontainer_test.go
@@ -435,92 +435,178 @@ func TestArrayContainerResetTo(t *testing.T) {
 	})
 }
 
-func TestNextPrevious(t *testing.T) {
-	t.Run("small range", func(t *testing.T) {
+func TestNextValueArray(t *testing.T) {
+	t.Run("Java Port 1", func(t *testing.T) {
+		// [Example 1]  https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableArrayContainer.java#L495
 		ac := newArrayContainer()
-		ac.iaddRange(1, 10)
-		assert.Equal(t, 1, ac.nextValue(1))
-		assert.Equal(t, 6, ac.nextValue(6))
-		assert.Equal(t, 9, ac.nextValue(9))
-		assert.Equal(t, -1, ac.nextValue(10))
-		assert.Equal(t, -1, ac.nextValue(20))
-		ac.iaddRange(12, 20)
-		// 10 and 11 are now missing
+		ac.iaddRange(64, 129)
+		assert.Equal(t, 64, ac.nextValue(0))
+		assert.Equal(t, 64, ac.nextValue(64))
+		assert.Equal(t, 65, ac.nextValue(65))
+		assert.Equal(t, 128, ac.nextValue(128))
+		assert.Equal(t, -1, ac.nextValue(129))
+		assert.Equal(t, -1, ac.nextValue(5000))
+	})
 
-		assert.Equal(t, -1, ac.previousValue(0))
-		assert.Equal(t, 1, ac.previousValue(1))
-		assert.Equal(t, 9, ac.previousValue(11))
-		assert.Equal(t, -1, ac.previousValue(22))
-
-		assert.Equal(t, -1, ac.nextAbsentValue(0))
-		assert.Equal(t, 10, ac.nextAbsentValue(1))
-		assert.Equal(t, 10, ac.nextAbsentValue(9))
-		assert.Equal(t, 10, ac.nextAbsentValue(10))
-		assert.Equal(t, 11, ac.nextAbsentValue(11))
-		assert.Equal(t, 20, ac.nextAbsentValue(12))
-		assert.Equal(t, -1, ac.nextAbsentValue(21))
-
-		assert.Equal(t, -1, ac.previousAbsentValue(0))
-		assert.Equal(t, -1, ac.previousAbsentValue(1))
-		assert.Equal(t, -1, ac.previousAbsentValue(9))
-		assert.Equal(t, 10, ac.previousAbsentValue(10))
-		assert.Equal(t, 11, ac.previousAbsentValue(11))
-		assert.Equal(t, 11, ac.previousAbsentValue(12))
-		assert.Equal(t, 11, ac.previousAbsentValue(15))
+	t.Run("Java Port 2", func(t *testing.T) {
+		// [Example 2]  https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableArrayContainer.java#L507
+		ac := newArrayContainer()
+		ac.iaddRange(64, 129)
+		ac.iaddRange(256, 321)
+		assert.Equal(t, 64, ac.nextValue(0))
+		assert.Equal(t, 64, ac.nextValue(63))
+		assert.Equal(t, 64, ac.nextValue(64))
+		assert.Equal(t, 65, ac.nextValue(65))
+		assert.Equal(t, 128, ac.nextValue(128))
+		assert.Equal(t, 256, ac.nextValue(129))
+		assert.Equal(t, -1, ac.nextValue(512))
+	})
+
+	t.Run("Java Port 3", func(t *testing.T) {
+		// [Example 3]  https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableArrayContainer.java#L525
+		ac := newArrayContainer()
+		ac.iaddRange(64, 129)
+		ac.iaddRange(200, 501)
+		ac.iaddRange(5000, 5201)
+
+		assert.Equal(t, 64, ac.nextValue(0))
+		assert.Equal(t, 64, ac.nextValue(63))
+		assert.Equal(t, 64, ac.nextValue(64))
+		assert.Equal(t, 65, ac.nextValue(65))
+		assert.Equal(t, 128, ac.nextValue(128))
+		assert.Equal(t, 200, ac.nextValue(129))
+		assert.Equal(t, 200, ac.nextValue(199))
+		assert.Equal(t, 200, ac.nextValue(200))
+		assert.Equal(t, 250, ac.nextValue(250))
+		assert.Equal(t, 5000, ac.nextValue(2500))
+		assert.Equal(t, 5000, ac.nextValue(5000))
+		assert.Equal(t, 5200, ac.nextValue(5200))
+		assert.Equal(t, -1, ac.nextValue(5201))
+	})
+}
+
+func TestNextAbsentValueArray(t *testing.T) {
+	t.Run("Java Port 1", func(t *testing.T) {
+		// [Java 1]  https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java#L850
+		ac := newArrayContainer()
+		ac.iaddRange(64, 129)
+		assert.Equal(t, 0, ac.nextAbsentValue(0))
+		assert.Equal(t, 63, ac.nextAbsentValue(63))
+		assert.Equal(t, 129, ac.nextAbsentValue(64))
+		assert.Equal(t, 129, ac.nextAbsentValue(65))
+		assert.Equal(t, 129, ac.nextAbsentValue(128))
+		assert.Equal(t, 129, ac.nextAbsentValue(129))
 	})
 
-	t.Run("larger range", func(t *testing.T) {
+	t.Run("Java Port 2", func(t *testing.T) {
+		// [Example 2] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java#L861
 		ac := newArrayContainer()
-		ac.iaddRange(1, 10)
-		ac.iaddRange(12, 20)
-		ac.iaddRange(62, 80)
-		ac.iaddRange(125, 170)
-
-		assert.Equal(t, 62, ac.nextValue(20))
-		assert.Equal(t, 1, ac.nextValue(1))
-		assert.Equal(t, 6, ac.nextValue(6))
-		assert.Equal(t, 9, ac.nextValue(9))
-		assert.Equal(t, 12, ac.nextValue(10))
-		assert.Equal(t, 62, ac.nextValue(20))
-		assert.Equal(t, 62, ac.nextValue(43))
-		assert.Equal(t, 62, ac.nextValue(62))
-		assert.Equal(t, 125, ac.nextValue(80))
-		assert.Equal(t, 125, ac.nextValue(125))
+		ac.iaddRange(64, 129)
+		ac.iaddRange(200, 501)
+		ac.iaddRange(5000, 5201)
+		assert.Equal(t, 0, ac.nextAbsentValue(0))
+		assert.Equal(t, 63, ac.nextAbsentValue(63))
+		assert.Equal(t, 129, ac.nextAbsentValue(64))
+		assert.Equal(t, 129, ac.nextAbsentValue(65))
+		assert.Equal(t, 129, ac.nextAbsentValue(128))
+		assert.Equal(t, 129, ac.nextAbsentValue(129))
+		assert.Equal(t, 199, ac.nextAbsentValue(199))
+		assert.Equal(t, 501, ac.nextAbsentValue(200))
+		assert.Equal(t, 501, ac.nextAbsentValue(250))
+		assert.Equal(t, 2500, ac.nextAbsentValue(2500))
+		assert.Equal(t, 5201, ac.nextAbsentValue(5000))
+		assert.Equal(t, 5201, ac.nextAbsentValue(5200))
+	})
 
+	t.Run("Java Port 3", func(t *testing.T) {
+		// [Java  3]  https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java#L878
+		ac := newArrayContainer()
+		for i := 0; i < 1000; i++ {
+			assert.Equal(t, i, ac.nextAbsentValue(uint16(i)))
+		}
+	})
+}
+
+func TestPreviousValueArray(t *testing.T) {
+	t.Run("Java Port 1", func(t *testing.T) {
+		// [Example 1] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java#L721
+		ac := newArrayContainer()
+		ac.iaddRange(64, 129)
 		assert.Equal(t, -1, ac.previousValue(0))
-		assert.Equal(t, 1, ac.previousValue(1))
-		assert.Equal(t, 9, ac.previousValue(11))
-		assert.Equal(t, 19, ac.previousValue(22))
-		assert.Equal(t, 19, ac.previousValue(61))
-		assert.Equal(t, 62, ac.previousValue(62))
-		assert.Equal(t, 79, ac.previousValue(79))
-		assert.Equal(t, 79, ac.previousValue(80))
-		assert.Equal(t, 79, ac.previousValue(124))
-		assert.Equal(t, 125, ac.previousValue(125))
-
-		assert.Equal(t, -1, ac.nextAbsentValue(0))
-		assert.Equal(t, 10, ac.nextAbsentValue(1))
-		assert.Equal(t, 10, ac.nextAbsentValue(9))
-		assert.Equal(t, 10, ac.nextAbsentValue(10))
-		assert.Equal(t, 11, ac.nextAbsentValue(11))
-		assert.Equal(t, 20, ac.nextAbsentValue(12))
-		assert.Equal(t, 21, ac.nextAbsentValue(21))
-		assert.Equal(t, 61, ac.nextAbsentValue(61))
-		assert.Equal(t, 80, ac.nextAbsentValue(62))
-		assert.Equal(t, 80, ac.nextAbsentValue(80))
-		assert.Equal(t, 90, ac.nextAbsentValue(90))
-		assert.Equal(t, 170, ac.nextAbsentValue(125))
-
-		assert.Equal(t, -1, ac.previousAbsentValue(0))
-		assert.Equal(t, -1, ac.previousAbsentValue(1))
-		assert.Equal(t, -1, ac.previousAbsentValue(9))
-		assert.Equal(t, 10, ac.previousAbsentValue(10))
-		assert.Equal(t, 11, ac.previousAbsentValue(11))
-		assert.Equal(t, 11, ac.previousAbsentValue(12))
-		assert.Equal(t, 11, ac.previousAbsentValue(15))
-		assert.Equal(t, 20, ac.previousAbsentValue(20))
-		assert.Equal(t, 61, ac.previousAbsentValue(62))
-		assert.Equal(t, 90, ac.previousAbsentValue(90))
+		assert.Equal(t, -1, ac.previousValue(63))
+		assert.Equal(t, 64, ac.previousValue(64))
+		assert.Equal(t, 65, ac.previousValue(65))
+		assert.Equal(t, 128, ac.previousValue(128))
+		assert.Equal(t, 128, ac.previousValue(129))
+	})
+
+	t.Run("Java Port 2", func(t *testing.T) {
+		// [Example 2]   https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java#L733
+		ac := newArrayContainer()
+		ac.iaddRange(64, 129)
+		ac.iaddRange(200, 501)
+		ac.iaddRange(5000, 5201)
+		assert.Equal(t, -1, ac.previousValue(0))
+		assert.Equal(t, -1, ac.previousValue(63))
+		assert.Equal(t, 64, ac.previousValue(64))
+		assert.Equal(t, 65, ac.previousValue(65))
+		assert.Equal(t, 128, ac.previousValue(128))
+		assert.Equal(t, 128, ac.previousValue(129))
+		assert.Equal(t, 128, ac.previousValue(199))
+		assert.Equal(t, 200, ac.previousValue(200))
+		assert.Equal(t, 250, ac.previousValue(250))
+		assert.Equal(t, 500, ac.previousValue(2500))
+		assert.Equal(t, 5000, ac.previousValue(5000))
+		assert.Equal(t, 5200, ac.previousValue(5200))
+	})
+
+	t.Run("Java Port 3", func(t *testing.T) {
+		// [Example 3] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java#L751
+		ac := newArrayContainer()
+		ac.iaddRange(64, 129)
+		assert.Equal(t, -1, ac.previousValue(5))
+	})
+}
+
+func TestPreviousAbsentValueArray(t *testing.T) {
+	t.Run("Java Port 1", func(t *testing.T) {
+		// [Example 1] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java#L793
+		ac := newArrayContainer()
+		ac.iaddRange(64, 129)
+		assert.Equal(t, 0, ac.previousAbsentValue(0))
+		assert.Equal(t, 63, ac.previousAbsentValue(63))
+		assert.Equal(t, 63, ac.previousAbsentValue(64))
+		assert.Equal(t, 63, ac.previousAbsentValue(65))
+		assert.Equal(t, 63, ac.previousAbsentValue(128))
+		assert.Equal(t, 129, ac.previousAbsentValue(129))
+	})
+
+	t.Run("Java Port 2", func(t *testing.T) {
+		// [Example 2] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java#L804
+		ac := newArrayContainer()
+		ac.iaddRange(64, 129)
+		ac.iaddRange(200, 500)
+		ac.iaddRange(5000, 5201)
+		assert.Equal(t, 0, ac.previousAbsentValue(0))
+		assert.Equal(t, 63, ac.previousAbsentValue(63))
+		assert.Equal(t, 63, ac.previousAbsentValue(64))
+		assert.Equal(t, 63, ac.previousAbsentValue(65))
+		assert.Equal(t, 63, ac.previousAbsentValue(128))
+		assert.Equal(t, 129, ac.previousAbsentValue(129))
+		assert.Equal(t, 199, ac.previousAbsentValue(199))
+		assert.Equal(t, 199, ac.previousAbsentValue(200))
+		assert.Equal(t, 199, ac.previousAbsentValue(250))
+		assert.Equal(t, 2500, ac.previousAbsentValue(2500))
+		assert.Equal(t, 4999, ac.previousAbsentValue(5000))
+		assert.Equal(t, 4999, ac.previousAbsentValue(5200))
+	})
+
+	t.Run("Java Port 3", func(t *testing.T) {
+		// [Example 3] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java#L821
+		ac := newArrayContainer()
+		for i := 0; i < 1000; i++ {
+			assert.Equal(t, i, ac.previousAbsentValue(uint16(i)))
+		}
 	})
 }
 
diff --git a/bitmapcontainer.go b/bitmapcontainer.go
index d8cb04f6..4463d7ae 100644
--- a/bitmapcontainer.go
+++ b/bitmapcontainer.go
@@ -1,6 +1,7 @@
 package roaring
 
 import (
+	"errors"
 	"fmt"
 	"math/bits"
 	"unsafe"
@@ -57,6 +58,17 @@ func (bc *bitmapContainer) minimum() uint16 {
 	return MaxUint16
 }
 
+func (bc *bitmapContainer) safeMinimum() (uint16, error) {
+	if len(bc.bitmap) == 0 {
+		return 0, errors.New("Empty bitmap")
+	}
+	val := bc.minimum()
+	if val == MaxUint16 {
+		return 0, errors.New("Empty bitmap")
+	}
+	return val, nil
+}
+
 // i should be non-zero
 func clz(i uint64) int {
 	n := 1
@@ -95,6 +107,17 @@ func (bc *bitmapContainer) maximum() uint16 {
 	return uint16(0)
 }
 
+func (bc *bitmapContainer) safeMaximum() (uint16, error) {
+	if len(bc.bitmap) == 0 {
+		return 0, errors.New("Empty bitmap")
+	}
+	val := bc.maximum()
+	if val == uint16(0) {
+		return 0, errors.New("Empty bitmap")
+	}
+	return val, nil
+}
+
 func (bc *bitmapContainer) iterate(cb func(x uint16) bool) bool {
 	iterator := bitmapContainerShortIterator{bc, bc.NextSetBit(0)}
 
diff --git a/bitmapcontainer_test.go b/bitmapcontainer_test.go
index 59e86194..bbb6dd1f 100644
--- a/bitmapcontainer_test.go
+++ b/bitmapcontainer_test.go
@@ -329,14 +329,6 @@ func TestBitmapContainerIAndNot(t *testing.T) {
 	require.Equal(t, 3, bc.getCardinality())
 }
 
-func TestPreviousNext(t *testing.T) {
-	clean := newBitmapContainer()
-	clean.iadd(1)
-	clean.contains(1)
-	clean.iadd(3)
-	clean.contains(3)
-}
-
 func TestPreviousNexts(t *testing.T) {
 	bc := newBitmapContainer()
 	bc.iadd(10)
@@ -348,57 +340,76 @@ func TestPreviousNexts(t *testing.T) {
 	// Another 64 division mod boundary
 	bc.iadd(129)
 
-	assert.Equal(t, 10, bc.nextValue(uint16(0)))
-	assert.Equal(t, 10, bc.nextValue(uint16(5)))
-	assert.Equal(t, 10, bc.nextValue(uint16(10)))
-	assert.Equal(t, 12, bc.nextValue(uint16(11)))
-	assert.Equal(t, 12, bc.nextValue(uint16(12)))
-	assert.Equal(t, 13, bc.nextValue(uint16(13)))
-	assert.Equal(t, 50, bc.nextValue(uint16(14)))
-	assert.Equal(t, 55, bc.nextValue(uint16(55)))
-	assert.Equal(t, 100, bc.nextValue(uint16(61)))
-	assert.Equal(t, 100, bc.nextValue(uint16(100)))
-	assert.Equal(t, 129, bc.nextValue(uint16(101)))
-	assert.Equal(t, 129, bc.nextValue(uint16(129)))
-	assert.Equal(t, -1, bc.nextValue(uint16(130)))
-
-	assert.Equal(t, -1, bc.previousValue(uint16(0)))
-	assert.Equal(t, -1, bc.previousValue(uint16(1)))
-	assert.Equal(t, -1, bc.previousValue(uint16(2)))
-	assert.Equal(t, -1, bc.previousValue(uint16(5)))
-	assert.Equal(t, 10, bc.previousValue(uint16(10)))
-	assert.Equal(t, 10, bc.previousValue(uint16(11)))
-	assert.Equal(t, 12, bc.previousValue(uint16(12)))
-	assert.Equal(t, 13, bc.previousValue(uint16(13)))
-	assert.Equal(t, 13, bc.previousValue(uint16(14)))
-	assert.Equal(t, 55, bc.previousValue(uint16(55)))
-	assert.Equal(t, 59, bc.previousValue(uint16(61)))
-	assert.Equal(t, 100, bc.previousValue(uint16(101)))
-
-	assert.Equal(t, 0, bc.nextAbsentValue(uint16(0)))
-	assert.Equal(t, 5, bc.nextAbsentValue(uint16(5)))
-	assert.Equal(t, 11, bc.nextAbsentValue(uint16(11)))
-	assert.Equal(t, 14, bc.nextAbsentValue(uint16(12)))
-	assert.Equal(t, 14, bc.nextAbsentValue(uint16(13)))
-	assert.Equal(t, 14, bc.nextAbsentValue(uint16(14)))
-	assert.Equal(t, 49, bc.nextAbsentValue(uint16(49)))
-	assert.Equal(t, 60, bc.nextAbsentValue(uint16(50)))
-	assert.Equal(t, 60, bc.nextAbsentValue(uint16(60)))
-	assert.Equal(t, 101, bc.nextAbsentValue(uint16(100)))
-	assert.Equal(t, 101, bc.nextAbsentValue(uint16(101)))
-	assert.Equal(t, 130, bc.nextAbsentValue(uint16(129)))
-
-	assert.Equal(t, 0, bc.previousAbsentValue(uint16(0)))
-	assert.Equal(t, 1, bc.previousAbsentValue(uint16(1)))
-	assert.Equal(t, 2, bc.previousAbsentValue(uint16(2)))
-	assert.Equal(t, 5, bc.previousAbsentValue(uint16(5)))
-	assert.Equal(t, 9, bc.previousAbsentValue(uint16(10)))
-	assert.Equal(t, 11, bc.previousAbsentValue(uint16(11)))
-	assert.Equal(t, 11, bc.previousAbsentValue(uint16(12)))
-	assert.Equal(t, 11, bc.previousAbsentValue(uint16(13)))
-	assert.Equal(t, 49, bc.previousAbsentValue(uint16(50)))
-	assert.Equal(t, 49, bc.previousAbsentValue(uint16(51)))
-	assert.Equal(t, 99, bc.previousAbsentValue(uint16(100)))
+	t.Run("Next value", func(t *testing.T) {
+		assert.Equal(t, 10, bc.nextValue(uint16(0)))
+		assert.Equal(t, 10, bc.nextValue(uint16(5)))
+		assert.Equal(t, 10, bc.nextValue(uint16(10)))
+		assert.Equal(t, 12, bc.nextValue(uint16(11)))
+		assert.Equal(t, 12, bc.nextValue(uint16(12)))
+		assert.Equal(t, 13, bc.nextValue(uint16(13)))
+		assert.Equal(t, 50, bc.nextValue(uint16(14)))
+		assert.Equal(t, 55, bc.nextValue(uint16(55)))
+		assert.Equal(t, 100, bc.nextValue(uint16(61)))
+		assert.Equal(t, 100, bc.nextValue(uint16(100)))
+		assert.Equal(t, 129, bc.nextValue(uint16(101)))
+		assert.Equal(t, 129, bc.nextValue(uint16(129)))
+		assert.Equal(t, -1, bc.nextValue(uint16(130)))
+	})
+
+	t.Run("Previous value", func(t *testing.T) {
+		assert.Equal(t, -1, bc.previousValue(uint16(0)))
+		assert.Equal(t, -1, bc.previousValue(uint16(1)))
+		assert.Equal(t, -1, bc.previousValue(uint16(2)))
+		assert.Equal(t, -1, bc.previousValue(uint16(5)))
+		assert.Equal(t, 10, bc.previousValue(uint16(10)))
+		assert.Equal(t, 10, bc.previousValue(uint16(11)))
+		assert.Equal(t, 12, bc.previousValue(uint16(12)))
+		assert.Equal(t, 13, bc.previousValue(uint16(13)))
+		assert.Equal(t, 13, bc.previousValue(uint16(14)))
+		assert.Equal(t, 55, bc.previousValue(uint16(55)))
+		assert.Equal(t, 59, bc.previousValue(uint16(61)))
+		assert.Equal(t, 100, bc.previousValue(uint16(101)))
+	})
+
+	t.Run("Next Absent value", func(t *testing.T) {
+		assert.Equal(t, 0, bc.nextAbsentValue(uint16(0)))
+		assert.Equal(t, 5, bc.nextAbsentValue(uint16(5)))
+		assert.Equal(t, 11, bc.nextAbsentValue(uint16(11)))
+		assert.Equal(t, 14, bc.nextAbsentValue(uint16(12)))
+		assert.Equal(t, 14, bc.nextAbsentValue(uint16(13)))
+		assert.Equal(t, 14, bc.nextAbsentValue(uint16(14)))
+		assert.Equal(t, 49, bc.nextAbsentValue(uint16(49)))
+		assert.Equal(t, 60, bc.nextAbsentValue(uint16(50)))
+		assert.Equal(t, 60, bc.nextAbsentValue(uint16(60)))
+		assert.Equal(t, 101, bc.nextAbsentValue(uint16(100)))
+		assert.Equal(t, 101, bc.nextAbsentValue(uint16(101)))
+		assert.Equal(t, 130, bc.nextAbsentValue(uint16(129)))
+	})
+
+	t.Run("Previous Absent value", func(t *testing.T) {
+		assert.Equal(t, 0, bc.previousAbsentValue(uint16(0)))
+		assert.Equal(t, 1, bc.previousAbsentValue(uint16(1)))
+		assert.Equal(t, 2, bc.previousAbsentValue(uint16(2)))
+		assert.Equal(t, 5, bc.previousAbsentValue(uint16(5)))
+		assert.Equal(t, 9, bc.previousAbsentValue(uint16(10)))
+		assert.Equal(t, 11, bc.previousAbsentValue(uint16(11)))
+		assert.Equal(t, 11, bc.previousAbsentValue(uint16(12)))
+		assert.Equal(t, 11, bc.previousAbsentValue(uint16(13)))
+		assert.Equal(t, 49, bc.previousAbsentValue(uint16(50)))
+		assert.Equal(t, 49, bc.previousAbsentValue(uint16(51)))
+		assert.Equal(t, 99, bc.previousAbsentValue(uint16(100)))
+		assert.Equal(t, 128, bc.previousAbsentValue(uint16(129)))
+		assert.Equal(t, 130, bc.previousAbsentValue(uint16(130)))
+	})
+}
+
+func TestNextAbsent(t *testing.T) {
+	bc := newBitmapContainer()
+	for i := 0; i < 1<<16; i++ {
+		bc.iadd(uint16(i))
+	}
+	v := bc.nextAbsentValue((1 << 16) - 1)
+	assert.Equal(t, v, 65536)
 }
 
 func TestBitMapContainerValidate(t *testing.T) {
diff --git a/roaring.go b/roaring.go
index 9508711a..769bfea5 100644
--- a/roaring.go
+++ b/roaring.go
@@ -1878,6 +1878,131 @@ func (rb *Bitmap) CloneCopyOnWriteContainers() {
 	rb.highlowcontainer.cloneCopyOnWriteContainers()
 }
 
+func (rb *Bitmap) NextValue(target int) int {
+	originalKey := highbits(uint32(target))
+	query := lowbits(uint32(target))
+	nextValue := -1
+	containerIndex := rb.highlowcontainer.advanceUntil(originalKey, -1)
+	for containerIndex < rb.highlowcontainer.size() && nextValue == -1 {
+		containerKey := rb.highlowcontainer.getKeyAtIndex(containerIndex)
+		container := rb.highlowcontainer.getContainer(containerKey)
+		// if containerKey > orginalKey then we are past the container which mapped to the orignal key
+		// in that case we can just return the minimum from that container
+		var responseBit int
+		if containerKey > originalKey {
+			bit, err := container.safeMinimum()
+			if err == nil {
+				responseBit = -1
+			}
+			responseBit = int(bit)
+		} else {
+			responseBit = container.nextValue(query)
+		}
+
+		if responseBit == -1 {
+			nextValue = -1
+		} else {
+			nextValue = int(combineLoHi32(uint32(responseBit), uint32(containerKey)))
+		}
+		containerIndex++
+	}
+
+	return nextValue
+}
+
+func (rb *Bitmap) PreviousValue(target int) int {
+	if rb.IsEmpty() {
+		return -1
+	}
+
+	originalKey := highbits(uint32(target))
+	query := lowbits(uint32(target))
+	prevValue := -1
+	containerIndex := rb.highlowcontainer.advanceUntil(originalKey, -1)
+
+	if containerIndex == rb.highlowcontainer.size() {
+		return int(rb.Maximum())
+	}
+
+	if rb.highlowcontainer.getKeyAtIndex(containerIndex) > originalKey {
+		return -1
+	}
+
+	for containerIndex != -1 && prevValue == -1 {
+		containerKey := rb.highlowcontainer.getKeyAtIndex(containerIndex)
+		container := rb.highlowcontainer.getContainer(containerKey)
+		// if containerKey > orginalKey then we are past the container which mapped to the orignal key
+		// in that case we can just return the minimum from that container
+		var responseBit int
+		if containerKey < originalKey {
+			bit, err := container.safeMaximum()
+
+			if err == nil {
+				responseBit = -1
+			}
+			responseBit = int(bit)
+		} else {
+			responseBit = container.previousValue(query)
+		}
+
+		if responseBit == -1 {
+			prevValue = -1
+		} else {
+			prevValue = int(combineLoHi32(uint32(responseBit), uint32(containerKey)))
+		}
+		containerIndex--
+	}
+
+	return prevValue
+}
+
+func (rb *Bitmap) NextAbsentValue(target int) int {
+	originalKey := highbits(uint32(target))
+	query := lowbits(uint32(target))
+	nextValue := -1
+
+	containerIndex := rb.highlowcontainer.advanceUntil(originalKey, -1)
+	if containerIndex == rb.highlowcontainer.size() {
+		// if we are here it means no container found, just return the target
+		return target
+	}
+
+	containerKey := rb.highlowcontainer.getKeyAtIndex(containerIndex)
+
+	keyspace := uint32(containerKey) << 16
+	if target < int(keyspace) {
+		// target is less than the start of the keyspace start
+		// that means target cannot be in the keyspace
+		return target
+	}
+
+	container := rb.highlowcontainer.getContainer(containerKey)
+	nextValue = container.nextAbsentValue(query)
+	for {
+		if nextValue != (1 << 16) {
+			return int(combineLoHi32(uint32(nextValue), keyspace))
+		}
+
+		if containerIndex == rb.highlowcontainer.size()-1 {
+			val, err := container.safeMaximum()
+			if err == nil {
+				return -1
+			}
+			return int(val) + 1
+		}
+		containerIndex++
+		nextContainerKey := rb.highlowcontainer.getKeyAtIndex(containerIndex)
+		if containerKey < nextContainerKey {
+			// There is a gap between keys
+			// Just increment the current key and shift to get HoB
+			return int(containerKey+1) << 16
+		}
+		containerKey = nextContainerKey
+		container = rb.highlowcontainer.getContainer(containerKey)
+		nextValue = container.nextAbsentValue(0)
+	}
+}
+
 // FlipInt calls Flip after casting the parameters (convenience method)
 func FlipInt(bm *Bitmap, rangeStart, rangeEnd int) *Bitmap {
 	return Flip(bm, uint64(rangeStart), uint64(rangeEnd))
diff --git a/roaring_test.go b/roaring_test.go
index 7124dfd6..4e89b06d 100644
--- a/roaring_test.go
+++ b/roaring_test.go
@@ -2773,6 +2773,155 @@ func TestBitMapValidationFromDeserialization(t *testing.T) {
 	}
 }
 
+func TestNextAndPreviousValue(t *testing.T) {
+	t.Run("Java Regression1 ", func(t *testing.T) {
+		// [Java1] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3645
+		bmp := New()
+		bmp.AddRange(64, 129)
+		assert.Equal(t, 64, bmp.NextValue(64))
+		assert.Equal(t, 64, bmp.NextValue(0))
+		assert.Equal(t, 64, bmp.NextValue(64))
+		assert.Equal(t, 65, bmp.NextValue(65))
+		assert.Equal(t, 128, bmp.NextValue(128))
+		assert.Equal(t, -1, bmp.NextValue(129))
+
+		assert.Equal(t, -1, bmp.PreviousValue(0))
+		assert.Equal(t, -1, bmp.PreviousValue(63))
+		assert.Equal(t, 64, bmp.PreviousValue(64))
+		assert.Equal(t, 65, bmp.PreviousValue(65))
+		assert.Equal(t, 128, bmp.PreviousValue(128))
+		assert.Equal(t, 128, bmp.PreviousValue(129))
+
+		assert.Equal(t, 0, bmp.NextAbsentValue(0))
+		assert.Equal(t, 63, bmp.NextAbsentValue(63))
+		assert.Equal(t, 129, bmp.NextAbsentValue(64))
+		assert.Equal(t, 129, bmp.NextAbsentValue(65))
+		assert.Equal(t, 129, bmp.NextAbsentValue(128))
+		assert.Equal(t, 129, bmp.NextAbsentValue(129))
+	})
+	t.Run("Java Regression2", func(t *testing.T) {
+		// [Java2] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3655
+
+		bmp := New()
+		bmp.AddRange(64, 129)
+		bmp.AddRange(256, 256+64+1)
+		assert.Equal(t, 64, bmp.NextValue(0))
+		assert.Equal(t, 64, bmp.NextValue(64))
+		assert.Equal(t, 65, bmp.NextValue(65))
+		assert.Equal(t, 128, bmp.NextValue(128))
+		assert.Equal(t, 256, bmp.NextValue(129))
+		assert.Equal(t, -1, bmp.NextValue(512))
+
+		assert.Equal(t, -1, bmp.PreviousValue(0))
+		assert.Equal(t, -1, bmp.PreviousValue(63))
+		assert.Equal(t, 64, bmp.PreviousValue(64))
+		assert.Equal(t, 65, bmp.PreviousValue(65))
+		assert.Equal(t, 128, bmp.PreviousValue(128))
+		assert.Equal(t, 128, bmp.PreviousValue(129))
+		assert.Equal(t, 128, bmp.PreviousValue(199))
+		assert.Equal(t, 128, bmp.PreviousValue(200))
+		assert.Equal(t, 128, bmp.PreviousValue(250))
+		assert.Equal(t, 256, bmp.PreviousValue(256))
+		assert.Equal(t, 320, bmp.PreviousValue(2500))
+
+		assert.Equal(t, 0, bmp.NextAbsentValue(0))
+		assert.Equal(t, 63, bmp.NextAbsentValue(63))
+		assert.Equal(t, 129, bmp.NextAbsentValue(64))
+		assert.Equal(t, 129, bmp.NextAbsentValue(65))
+		assert.Equal(t, 129, bmp.NextAbsentValue(128))
+		assert.Equal(t, 129, bmp.NextAbsentValue(129))
+		assert.Equal(t, 199, bmp.NextAbsentValue(199))
+		assert.Equal(t, 200, bmp.NextAbsentValue(200))
+		assert.Equal(t, 250, bmp.NextAbsentValue(250))
+		assert.Equal(t, 321, bmp.NextAbsentValue(256))
+		assert.Equal(t, 321, bmp.NextAbsentValue(320))
+	})
+
+	t.Run("Java Regression3", func(t *testing.T) {
+		// [Java3] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3666
+
+		bmp := New()
+		bmp.AddRange(64, 129)
+		bmp.AddRange(200, 200+300+1)
+		bmp.AddRange(5000, 5000+200+1)
+		assert.Equal(t, 64, bmp.NextValue(0))
+		assert.Equal(t, 64, bmp.NextValue(63))
+		assert.Equal(t, 64, bmp.NextValue(64))
+		assert.Equal(t, 65, bmp.NextValue(65))
+		assert.Equal(t, 128, bmp.NextValue(128))
+		assert.Equal(t, 200, bmp.NextValue(129))
+		assert.Equal(t, 200, bmp.NextValue(199))
+		assert.Equal(t, 200, bmp.NextValue(200))
+		assert.Equal(t, 250, bmp.NextValue(250))
+		assert.Equal(t, 5000, bmp.NextValue(2500))
+		assert.Equal(t, 5000, bmp.NextValue(5000))
+		assert.Equal(t, 5200, bmp.NextValue(5200))
+		assert.Equal(t, -1, bmp.NextValue(5201))
+
+		assert.Equal(t, -1, bmp.PreviousValue(0))
+		assert.Equal(t, -1, bmp.PreviousValue(63))
+		assert.Equal(t, 64, bmp.PreviousValue(64))
+		assert.Equal(t, 65, bmp.PreviousValue(65))
+		assert.Equal(t, 128, bmp.PreviousValue(128))
+		assert.Equal(t, 128, bmp.PreviousValue(129))
+		assert.Equal(t, 128, bmp.PreviousValue(199))
+		assert.Equal(t, 200, bmp.PreviousValue(200))
+		assert.Equal(t, 250, bmp.PreviousValue(250))
+		assert.Equal(t, 500, bmp.PreviousValue(2500))
+		assert.Equal(t, 5000, bmp.PreviousValue(5000))
+		assert.Equal(t, 5200, bmp.PreviousValue(5200))
+		assert.Equal(t, 5200, bmp.PreviousValue(5201))
+
+		assert.Equal(t, 0, bmp.NextAbsentValue(0))
+		assert.Equal(t, 63, bmp.NextAbsentValue(63))
+		assert.Equal(t, 129, bmp.NextAbsentValue(64))
+		assert.Equal(t, 129, bmp.NextAbsentValue(65))
+		assert.Equal(t, 129, bmp.NextAbsentValue(128))
+		assert.Equal(t, 129, bmp.NextAbsentValue(129))
+		assert.Equal(t, 199, bmp.NextAbsentValue(199))
+		assert.Equal(t, 501, bmp.NextAbsentValue(200))
+		assert.Equal(t, 501, bmp.NextAbsentValue(250))
+		assert.Equal(t, 2500, bmp.NextAbsentValue(2500))
+		assert.Equal(t, 5201, bmp.NextAbsentValue(5000))
+		assert.Equal(t, 5201, bmp.NextAbsentValue(5200))
+		assert.Equal(t, 5201, bmp.NextAbsentValue(5201))
+	})
+
+	t.Run("skip odd ", func(t *testing.T) {
+		bmp := New()
+		for i := 0; i < 2000; i++ {
+			bmp.Add(uint32(i * 2))
+		}
+		for i := 0; i < 2000; i++ {
+			assert.Equal(t, i*2, bmp.NextValue(i*2))
+			assert.Equal(t, i*2, bmp.PreviousValue(i*2))
+			assert.Equal(t, i*2+1, bmp.NextAbsentValue(i*2+1))
+		}
+	})
+
+	t.Run("skipping with ranges", func(t *testing.T) {
+		bmp := New()
+		intervalEnd := 512
+		rangeStart := intervalEnd * 2
+		rangeEnd := 2048
+		for i := 0; i < intervalEnd; i++ {
+			bmp.Add(uint32(i * 2))
+		}
+		bmp.AddRange(uint64(rangeStart), uint64(rangeEnd))
+
+		for i := 0; i < intervalEnd; i++ {
+			assert.Equal(t, i*2, bmp.NextValue(i*2))
+			assert.Equal(t, i*2, bmp.PreviousValue(i*2))
+			assert.Equal(t, i*2+1, bmp.NextAbsentValue(i*2))
+		}
+		for i := rangeStart; i < rangeEnd; i++ {
+			assert.Equal(t, i, bmp.NextValue(i))
+			assert.Equal(t, i, bmp.PreviousValue(i))
+			assert.Equal(t, rangeEnd, bmp.NextAbsentValue(rangeEnd))
+		}
+	})
+}
+
 func BenchmarkFromDense(b *testing.B) {
 	testDense(func(name string, rb *Bitmap) {
 		dense := make([]uint64, rb.DenseSize())
diff --git a/roaringarray.go b/roaringarray.go
index bd14bd1c..712e8f18 100644
--- a/roaringarray.go
+++ b/roaringarray.go
@@ -73,6 +73,8 @@ type container interface {
 	String() string
 	containerType() contype
 
+	safeMinimum() (uint16, error)
+	safeMaximum() (uint16, error)
 	nextValue(x uint16) int
 	previousValue(x uint16) int
 	nextAbsentValue(x uint16) int
@@ -298,6 +300,8 @@ func (ra *roaringArray) cloneCopyOnWriteContainers() {
 //	return (ra.binarySearch(0, int64(len(ra.keys)), x) >= 0)
 //}
 
+// getContainer returns the container with key `x`
+// if no such container exists `nil` is returned
 func (ra *roaringArray) getContainer(x uint16) container {
 	i := ra.binarySearch(0, int64(len(ra.keys)), x)
 	if i < 0 {
@@ -345,7 +349,10 @@ func (ra *roaringArray) getWritableContainerAtIndex(i int) container {
 	return ra.containers[i]
 }
 
+// getIndex returns the index of the container with key `x`
+// if no such container exists a negative value is returned
 func (ra *roaringArray) getIndex(x uint16) int {
+	// Todo : test
 	// before the binary search, we optimize for frequent cases
 	size := len(ra.keys)
 	if (size == 0) || (ra.keys[size-1] == x) {
@@ -405,7 +412,10 @@ func (ra *roaringArray) size() int {
 	return len(ra.keys)
 }
 
+// binarySearch returns the index of the key.
+// negative value returned if not found
 func (ra *roaringArray) binarySearch(begin, end int64, ikey uint16) int {
+	// TODO: add unit tests
 	low := begin
 	high := end - 1
 	for low+16 <= high {
@@ -698,6 +708,15 @@ func (ra *roaringArray) hasRunCompression() bool {
 	return false
 }
 
+/**
+ * Find the smallest integer index larger than pos such that array[index].key&gt;=x. If none can
+ * be found, return size. Based on code by O. Kaser.
+ *
+ * @param x minimal value
+ * @param pos index to exceed
+ * @return the smallest index greater than pos such that array[index].key is at least as large as
+ *         min, or size if it is not possible.
+ */
 func (ra *roaringArray) advanceUntil(min uint16, pos int) int {
 	lower := pos + 1
 
diff --git a/runcontainer.go b/runcontainer.go
index 87172f9e..645fe737 100644
--- a/runcontainer.go
+++ b/runcontainer.go
@@ -1798,10 +1798,25 @@ func (rc *runContainer16) minimum() uint16 {
 	return rc.iv[0].start // assume not empty
 }
 
+func (rc *runContainer16) safeMinimum() (uint16, error) {
+	if len(rc.iv) == 0 {
+		return 0, errors.New("Empty runs")
+	}
+
+	return rc.minimum(), nil
+}
+
 func (rc *runContainer16) maximum() uint16 {
 	return rc.iv[len(rc.iv)-1].last() // assume not empty
 }
 
+func (rc *runContainer16) safeMaximum() (uint16, error) {
+	if len(rc.iv) == 0 {
+		return 0, errors.New("Empty runs")
+	}
+	return rc.maximum(), nil // assume not empty
+}
+
 func (rc *runContainer16) isFull() bool {
 	return (len(rc.iv) == 1) && ((rc.iv[0].start == 0) && (rc.iv[0].last() == MaxUint16))
 }
@@ -2640,15 +2655,24 @@ func (rc *runContainer16) addOffset(x uint16) (container, container) {
 // If the target is in the interior or a run then `target` will be returned
 // Ex: If our run structure resmembles [[a,c], [d,f]] with a <= target <= c then `target` will be returned.
 // Ex: If c < target < d then d is returned.
-// if the target is out of bounds a -1 is returned
+// Ex: If target < a then a is returned
+// if the target > max, this is out of bounds and -1 is returned
 func (rc *runContainer16) nextValue(target uint16) int {
+	if len(rc.iv) == 0 {
+		return -1
+	}
+
 	whichIndex, alreadyPresent, _ := rc.search(int(target))
 
 	if alreadyPresent {
 		return int(target)
 	}
 
-	if whichIndex == -1 || whichIndex == len(rc.iv)-1 {
+	if whichIndex == -1 {
+		return int(rc.iv[0].start)
+	}
+
+	if whichIndex == len(rc.iv)-1 {
 		return -1
 	}
 
@@ -2666,29 +2690,18 @@ func (rc *runContainer16) nextValue(target uint16) int {
 
 // nextAbsentValue returns the next absent value.
 // By construction the next absent value will be located between gaps in runs
-// Ex: if our runs resemble [[a,b],[c,d]] then b+1 will not be equal to c, b+1 will be returned
-// if the target is out of bounds a -1 is returned
+//
+// Ex: if our runs resemble [[a,b],[c,d]] and a <= target <= b  then b+1 will not be equal to c, b+1 will be returned
+// Ex: if target < a then target is returned
+// Ex: if target > d then target is returned
 func (rc *runContainer16) nextAbsentValue(target uint16) int {
 	whichIndex, alreadyPresent, _ := rc.search(int(target))
-	lastIndex := len(rc.iv) - 1
 
 	if !alreadyPresent {
-		if whichIndex == -1 || whichIndex == lastIndex {
-			// TODO ask about the case whichIndex == len(rc.iv)-1
-			// should we return rc.iv[whichIndex].last() + 1
-			return -1
-		}
-
 		return int(target)
 	}
 
-	if whichIndex != lastIndex {
-		// if whichIndex is not the last index, then there is another run with larger start
-		// rc.iv[whichIndex].last() + 1 cannot equal rc.iv[whichIndex +1].start
-		// by invariant
-		return int(rc.iv[whichIndex].last()) + 1
-	}
-	return -1
+	return int(rc.iv[whichIndex].last()) + 1
 }
 
 // previousValue will return the previous present value
@@ -2697,14 +2710,19 @@ func (rc *runContainer16) nextAbsentValue(target uint16) int {
 // Example:
 // If our run structure resmembles [[a,c], [d,f]] with a <= target  <= c then target will be returned.
 // If c < target < d then c is returned.
-// if the target is out of bounds -1 is returned
+// if target > f then f is returned
+// if the target is less than a, this is out of bounds and -1 is returned
 func (rc *runContainer16) previousValue(target uint16) int {
 	whichIndex, alreadyPresent, _ := rc.search(int(target))
 
+	if len(rc.iv) == 0 {
+		return int(target)
+	}
+
 	if alreadyPresent {
 		return int(target)
 	}
-	if whichIndex == -1 || whichIndex == len(rc.iv)-1 {
+	if whichIndex == -1 {
 		return -1
 	}
 
@@ -2716,28 +2734,16 @@ func (rc *runContainer16) previousValue(target uint16) int {
 //
 // Example:
 // If our run structure resmembles [[x,z], [a,c], [d,f]] with a <= target  <= c then a-1 will be returned.
-// if the target is out of bounds a -1 is returned
+// if the target < x then target is returned
+// if target > f then target is returned
 func (rc *runContainer16) previousAbsentValue(target uint16) int {
 	whichIndex, alreadyPresent, _ := rc.search(int(target))
-	lastIndex := len(rc.iv) - 1
 
 	if !alreadyPresent {
-		if whichIndex == -1 || whichIndex == lastIndex {
-			// TODO ask about the case whichIndex == len(rc.iv)-1
-			// should we return rc.iv[whichIndex].last() + 1
-			return -1
-		}
-
 		return int(target)
 	}
 
-	if whichIndex != 0 {
-		// if whichIndex is not the last index, then there is another run with larger start
-		// rc.iv[whichIndex].last() + 1 cannot equal rc.iv[whichIndex +1].start
-		// by invariant
-		return int(rc.iv[whichIndex].start) - 1
-	}
-	return -1
+	return int(rc.iv[whichIndex].start) - 1
 }
 
 // isNonContiguousDisjoint returns an error if the intervals overlap e.g have non-empty intersection
diff --git a/runcontainer_test.go b/runcontainer_test.go
index d870d81e..296c3d6c 100644
--- a/runcontainer_test.go
+++ b/runcontainer_test.go
@@ -2306,64 +2306,178 @@ func TestAllContainerMethodsAllContainerTypesWithData067(t *testing.T) {
 	})
 }
 
-func TestNextPreviousValue(t *testing.T) {
-	runContainer := newRunContainer16()
-	runContainer.iaddRange(2, 10)
-	runContainer.iaddRange(20, 30)
-	runContainer.iaddRange(31, 40)
-	runContainer.iaddRange(60, 70)
-
-	assert.Equal(t, 2, runContainer.nextValue(2))
-	assert.Equal(t, 5, runContainer.nextValue(5))
-	assert.Equal(t, 20, runContainer.nextValue(10))
-	assert.Equal(t, 20, runContainer.nextValue(15))
-	assert.Equal(t, 20, runContainer.nextValue(20))
-	assert.Equal(t, 21, runContainer.nextValue(21))
-	assert.Equal(t, 29, runContainer.nextValue(29))
-	assert.Equal(t, 31, runContainer.nextValue(30))
-	assert.Equal(t, 60, runContainer.nextValue(40))
-	assert.Equal(t, 60, runContainer.nextValue(45))
-	assert.Equal(t, -1, runContainer.nextValue(80))
-
-	assert.Equal(t, 2, runContainer.previousValue(2))
-	assert.Equal(t, 5, runContainer.previousValue(5))
-	assert.Equal(t, 9, runContainer.previousValue(10))
-	assert.Equal(t, 9, runContainer.previousValue(15))
-	assert.Equal(t, 20, runContainer.previousValue(20))
-	assert.Equal(t, 21, runContainer.previousValue(21))
-	assert.Equal(t, 29, runContainer.previousValue(29))
-	assert.Equal(t, 29, runContainer.previousValue(30))
-	assert.Equal(t, 39, runContainer.previousValue(40))
-	assert.Equal(t, 39, runContainer.previousValue(45))
-	assert.Equal(t, -1, runContainer.previousValue(80))
-
-	assert.Equal(t, -1, runContainer.nextAbsentValue(0))
-	assert.Equal(t, -1, runContainer.nextAbsentValue(1))
-	assert.Equal(t, 10, runContainer.nextAbsentValue(5))
-	assert.Equal(t, 10, runContainer.nextAbsentValue(10))
-	assert.Equal(t, 15, runContainer.nextAbsentValue(15))
-	assert.Equal(t, 30, runContainer.nextAbsentValue(20))
-	assert.Equal(t, 30, runContainer.nextAbsentValue(21))
-	assert.Equal(t, 30, runContainer.nextAbsentValue(29))
-	assert.Equal(t, 30, runContainer.nextAbsentValue(30))
-	assert.Equal(t, 40, runContainer.nextAbsentValue(31))
-	assert.Equal(t, 40, runContainer.nextAbsentValue(40))
-	assert.Equal(t, 45, runContainer.nextAbsentValue(45))
-	assert.Equal(t, -1, runContainer.nextAbsentValue(80))
-
-	assert.Equal(t, -1, runContainer.previousAbsentValue(0))
-	assert.Equal(t, -1, runContainer.previousAbsentValue(1))
-	assert.Equal(t, -1, runContainer.previousAbsentValue(5))
-	assert.Equal(t, 10, runContainer.previousAbsentValue(10))
-	assert.Equal(t, 15, runContainer.previousAbsentValue(15))
-	assert.Equal(t, 19, runContainer.previousAbsentValue(20))
-	assert.Equal(t, 19, runContainer.previousAbsentValue(21))
-	assert.Equal(t, 19, runContainer.previousAbsentValue(29))
-	assert.Equal(t, 30, runContainer.previousAbsentValue(30))
-	assert.Equal(t, 30, runContainer.previousAbsentValue(31))
-	assert.Equal(t, 40, runContainer.previousAbsentValue(40))
-	assert.Equal(t, 45, runContainer.previousAbsentValue(45))
-	assert.Equal(t, -1, runContainer.previousAbsentValue(80))
+func TestNextValueRun(t *testing.T) {
+	t.Run("Java Regression1", func(t *testing.T) {
+		// [Java1] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3645
+		runContainer := newRunContainer16()
+		runContainer.iaddRange(64, 129)
+		assert.Equal(t, 64, runContainer.nextValue(0))
+		assert.Equal(t, 64, runContainer.nextValue(64))
+		assert.Equal(t, 65, runContainer.nextValue(65))
+		assert.Equal(t, 128, runContainer.nextValue(128))
+		assert.Equal(t, -1, runContainer.nextValue(129))
+	})
+
+	t.Run("Java Regression2", func(t *testing.T) {
+		// [Java2] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3655
+
+		runContainer := newRunContainer16()
+		runContainer.iaddRange(64, 129)
+		runContainer.iaddRange(256, 256+64+1)
+		assert.Equal(t, 64, runContainer.nextValue(0))
+		assert.Equal(t, 64, runContainer.nextValue(64))
+		assert.Equal(t, 65, runContainer.nextValue(65))
+		assert.Equal(t, 128, runContainer.nextValue(128))
+		assert.Equal(t, 256, runContainer.nextValue(129))
+		assert.Equal(t, -1, runContainer.nextValue(512))
+	})
+
+	t.Run("Java Regression3", func(t *testing.T) {
+		// [Java3] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3666
+
+		runContainer := newRunContainer16()
+		runContainer.iaddRange(64, 129)
+		runContainer.iaddRange(256, 200+300+1)
+		runContainer.iaddRange(200, 200+300+1)
+		runContainer.iaddRange(5000, 5000+200+1)
+		assert.Equal(t, 64, runContainer.nextValue(0))
+		assert.Equal(t, 64, runContainer.nextValue(64))
+		assert.Equal(t, 64, runContainer.nextValue(64))
+		assert.Equal(t, 65, runContainer.nextValue(65))
+		assert.Equal(t, 128, runContainer.nextValue(128))
+		assert.Equal(t, 200, runContainer.nextValue(129))
+		assert.Equal(t, 200, runContainer.nextValue(199))
+		assert.Equal(t, 200, runContainer.nextValue(200))
+		assert.Equal(t, 250, runContainer.nextValue(250))
+		assert.Equal(t, 5000, runContainer.nextValue(2500))
+		assert.Equal(t, 5000, runContainer.nextValue(5000))
+		assert.Equal(t, 5200, runContainer.nextValue(5200))
+		assert.Equal(t, -1, runContainer.nextValue(5201))
+	})
+}
+
+func TestPreviousValueRun(t *testing.T) {
+	t.Run("Java Regression1", func(t *testing.T) {
+		// [Java 1] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3684
+		runContainer := newRunContainer16()
+		runContainer.iaddRange(64, 129)
+		assert.Equal(t, -1, runContainer.previousValue(0))
+		assert.Equal(t, -1, runContainer.previousValue(63))
+		assert.Equal(t, 64, runContainer.previousValue(64))
+		assert.Equal(t, 65, runContainer.previousValue(65))
+		assert.Equal(t, 128, runContainer.previousValue(128))
+		assert.Equal(t, 128, runContainer.previousValue(129))
+	})
+
+	t.Run("Java Regression2", func(t *testing.T) {
+		// [Java 2]  https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3695
+		runContainer := newRunContainer16()
+		runContainer.iaddRange(64, 129)
+		runContainer.iaddRange(200, 200+300+1)
+		runContainer.iaddRange(5000, 5000+200+1)
+		assert.Equal(t, -1, runContainer.previousValue(0))
+		assert.Equal(t, -1, runContainer.previousValue(63))
+		assert.Equal(t, 64, runContainer.previousValue(64))
+		assert.Equal(t, 65, runContainer.previousValue(65))
+		assert.Equal(t, 128, runContainer.previousValue(128))
+		assert.Equal(t, 128, runContainer.previousValue(129))
+		assert.Equal(t, 128, runContainer.previousValue(199))
+		assert.Equal(t, 200, runContainer.previousValue(200))
+		assert.Equal(t, 250, runContainer.previousValue(250))
+		assert.Equal(t, 500, runContainer.previousValue(2500))
+		assert.Equal(t, 5000, runContainer.previousValue(5000))
+		assert.Equal(t, 5200, runContainer.previousValue(5200))
+		// TODO Question
+		assert.Equal(t, 5200, runContainer.previousValue(5201))
+	})
+}
+
+func TestNextAbsentValueRun(t *testing.T) {
+	t.Run("Java Regression1", func(t *testing.T) {
+		// [Java 1] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3760
+		runContainer := newRunContainer16()
+		runContainer.iaddRange(64, 129)
+		assert.Equal(t, 0, runContainer.nextAbsentValue(0))
+		assert.Equal(t, 63, runContainer.nextAbsentValue(63))
+		assert.Equal(t, 129, runContainer.nextAbsentValue(64))
+		assert.Equal(t, 129, runContainer.nextAbsentValue(65))
+		assert.Equal(t, 129, runContainer.nextAbsentValue(128))
+		assert.Equal(t, 129, runContainer.nextAbsentValue(129))
+	})
+
+	t.Run("Java Regression2", func(t *testing.T) {
+		// [Java 2] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3815
+		runContainer := newRunContainer16()
+		runContainer.iaddRange(64, 129)
+		runContainer.iaddRange(200, 501)
+		runContainer.iaddRange(5000, 5201)
+
+		assert.Equal(t, 0, runContainer.nextAbsentValue(0))
+		assert.Equal(t, 63, runContainer.nextAbsentValue(63))
+		assert.Equal(t, 129, runContainer.nextAbsentValue(64))
+		assert.Equal(t, 129, runContainer.nextAbsentValue(65))
+		assert.Equal(t, 129, runContainer.nextAbsentValue(128))
+		assert.Equal(t, 129, runContainer.nextAbsentValue(129))
+		assert.Equal(t, 199, runContainer.nextAbsentValue(199))
+		assert.Equal(t, 501, runContainer.nextAbsentValue(200))
+		assert.Equal(t, 501, runContainer.nextAbsentValue(250))
+		assert.Equal(t, 2500, runContainer.nextAbsentValue(2500))
+		assert.Equal(t, 5201, runContainer.nextAbsentValue(5000))
+		assert.Equal(t, 5201, runContainer.nextAbsentValue(5200))
+	})
+
+	t.Run("Java Regression3", func(t *testing.T) {
+		// [Java 3] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3832
+		runContainer := newRunContainer16()
+		for i := 0; i < 1000; i++ {
+			assert.Equal(t, i, runContainer.nextAbsentValue(uint16(i)))
+		}
+	})
+}
+
+func TestPreviousAbsentValueRun(t *testing.T) {
+	t.Run("Java Regression 1", func(t *testing.T) {
+		// [Java 1] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3732
+		runContainer := newRunContainer16()
+		runContainer.iaddRange(64, 129)
+
+		assert.Equal(t, 0, runContainer.previousAbsentValue(0))
+		assert.Equal(t, 63, runContainer.previousAbsentValue(63))
+		assert.Equal(t, 63, runContainer.previousAbsentValue(64))
+		assert.Equal(t, 63, runContainer.previousAbsentValue(65))
+		assert.Equal(t, 63, runContainer.previousAbsentValue(128))
+		assert.Equal(t, 129, runContainer.previousAbsentValue(129))
+	})
+
+	t.Run("Java Regression2", func(t *testing.T) {
+		// [Java 2] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3743
+
+		runContainer := newRunContainer16()
+		runContainer.iaddRange(64, 129)
+		runContainer.iaddRange(200, 501)
+		runContainer.iaddRange(5000, 5201)
+
+		assert.Equal(t, 0, runContainer.previousAbsentValue(0))
+		assert.Equal(t, 63, runContainer.previousAbsentValue(63))
+		assert.Equal(t, 63, runContainer.previousAbsentValue(64))
+		assert.Equal(t, 63, runContainer.previousAbsentValue(65))
+		assert.Equal(t, 63, runContainer.previousAbsentValue(128))
+		assert.Equal(t, 129, runContainer.previousAbsentValue(129))
+		assert.Equal(t, 199, runContainer.previousAbsentValue(199))
+		assert.Equal(t, 199, runContainer.previousAbsentValue(200))
+		assert.Equal(t, 199, runContainer.previousAbsentValue(250))
+		assert.Equal(t, 2500, runContainer.previousAbsentValue(2500))
+		assert.Equal(t, 4999, runContainer.previousAbsentValue(5000))
+		assert.Equal(t, 4999, runContainer.previousAbsentValue(5200))
+	})
+
+	t.Run("Java Regression3", func(t *testing.T) {
+		// [Java 3] https://github.com/RoaringBitmap/RoaringBitmap/blob/5235aa62c32fa3bf7fae40a562e3edc75f61be4e/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java#L3760
+		runContainer := newRunContainer16()
+		for i := 0; i < 1000; i++ {
+			assert.Equal(t, i, runContainer.previousAbsentValue(uint16(i)))
+		}
+	})
 }
 
 func TestRuntimeIteratorPeekNext(t *testing.T) {
diff --git a/setutil.go b/setutil.go
index 7dbd37de..29ba4c3a 100644
--- a/setutil.go
+++ b/setutil.go
@@ -546,16 +546,6 @@ func binarySearch(array []uint16, ikey uint16) int {
 	return -(low + 1)
 }
 
-func closestByIndex(array []uint16, smallerIdx int, largerIdx int, target uint16) int {
-	smallerVal := array[smallerIdx]
-	largerVal := array[largerIdx]
-
-	if (int(largerVal) - int(target)) >= (int(target) - int(smallerVal)) {
-		return smallerIdx
-	}
-	return largerIdx
-}
-
 // searchResult provides information about a search request.
 // The values will depend on the context of the search
 type searchResult struct {
@@ -600,7 +590,7 @@ func binarySearchUntilWithBounds(array []uint16, target uint16, lowIndex int, ma
 	}
 
 	if target > array[maxIndex] {
-		return searchResult{0, closestIndex, false}
+		return searchResult{0, len(array), false}
 	}
 
 	for lowIndex <= highIndex {
@@ -654,7 +644,7 @@ func binarySearchPastWithBounds(array []uint16, target uint16, lowIndex int, max
 	}
 
 	if target > array[maxIndex] {
-		return searchResult{0, closestIndex, false}
+		return searchResult{0, len(array), false}
 	}
 
 	for lowIndex <= highIndex {
diff --git a/setutil_test.go b/setutil_test.go
index 0e5c7a73..1d60e094 100644
--- a/setutil_test.go
+++ b/setutil_test.go
@@ -182,7 +182,7 @@ func TestBinarySearchUntil(t *testing.T) {
 		{
 			"out of bounds at the end",
 			[]uint16{0, 1, 2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},
-			100, 0, false, -1,
+			100, 0, false, 15,
 		},
 		{
 			"missing alternating",
@@ -217,7 +217,7 @@ func TestBinarySearchPastWithBounds(t *testing.T) {
 		{
 			"has match but not in range",
 			[]uint16{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 16, 17},
-			9, 0, false, -1, 0, 4,
+			9, 0, false, 15, 0, 4,
 		},
 		{
 			"matches",
@@ -232,7 +232,7 @@ func TestBinarySearchPastWithBounds(t *testing.T) {
 		{
 			"has match but not in range",
 			[]uint16{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 16, 17},
-			9, 0, false, -1, 0, 4,
+			9, 0, false, 15, 0, 4,
 		},
 		{
 			"missing 12 with gap",
@@ -247,7 +247,7 @@ func TestBinarySearchPastWithBounds(t *testing.T) {
 		{
 			"missing 10 out of range",
 			[]uint16{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12},
-			10, 0, false, -1, 0, 5,
+			10, 0, false, 12, 0, 5,
 		},
 	}
 
diff --git a/util.go b/util.go
index 48b9d5a1..f58a86b2 100644
--- a/util.go
+++ b/util.go
@@ -52,6 +52,7 @@ func fill(arr []uint64, val uint64) {
 		arr[i] = val
 	}
 }
+
 func fillRange(arr []uint64, start, end int, val uint64) {
 	for i := start; i < end; i++ {
 		arr[i] = val
@@ -112,10 +113,19 @@ func fillArrayXOR(container []uint16, bitmap1, bitmap2 []uint64) {
 func highbits(x uint32) uint16 {
 	return uint16(x >> 16)
 }
+
 func lowbits(x uint32) uint16 {
 	return uint16(x & maxLowBit)
 }
 
+func combineLoHi16(lob uint16, hob uint16) uint32 {
+	return combineLoHi32(uint32(lob), uint32(hob))
+}
+
+func combineLoHi32(lob uint32, hob uint32) uint32 {
+	return uint32(lob) | (hob << 16)
+}
+
 const maxLowBit = 0xFFFF
 
 func flipBitmapRange(bitmap []uint64, start int, end int) {
@@ -146,7 +156,6 @@ func resetBitmapRange(bitmap []uint64, start int, end int) {
 		bitmap[i] = 0
 	}
 	bitmap[endword] &= ^(^uint64(0) >> (uint(-end) % 64))
-
 }
 
 func setBitmapRange(bitmap []uint64, start int, end int) {
@@ -242,7 +251,6 @@ func selectBitPosition(w uint64, j int) int {
 		}
 	}
 	return seen + int(counter)
-
 }
 
 func panicOn(err error) {
diff --git a/util_test.go b/util_test.go
new file mode 100644
index 00000000..3b6aa0a8
--- /dev/null
+++ b/util_test.go
@@ -0,0 +1,25 @@
+package roaring
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestLobHob(t *testing.T) {
+	for i := 0; i < 2049; i++ {
+		val := uint32(i)
+		lob := lowbits(uint32(val))
+		hob := highbits(uint32(val))
+		reconstructed := combineLoHi16(lob, hob)
+		assert.Equal(t, reconstructed, val)
+	}
+
+	for i := 0; i < 2049; i++ {
+		val := uint32(i)
+		lob := lowbits(uint32(val))
+		hob := highbits(uint32(val))
+		reconstructed := combineLoHi32(uint32(lob), uint32(hob))
+		assert.Equal(t, reconstructed, val)
+	}
+}