Let IntRange's And and Or handle negative values
diff --git a/lib/interval/interval.go b/lib/interval/interval.go
index 8390ee9..45f556c 100644
--- a/lib/interval/interval.go
+++ b/lib/interval/interval.go
@@ -42,13 +42,35 @@
 	one = big.NewInt(1)
 )
 
-func bigIntClone(i *big.Int) *big.Int {
+// bitMask returns ((1<<n) - 1), where n is the largest of n0 and n1.
+func bitMask(n0 int, n1 int) *big.Int {
+	n := n0
+	if n < n1 {
+		n = n1
+	}
+	if n > (1 << 30) {
+		panic("interval: input is too large")
+	}
+	z := big.NewInt(1)
+	z = z.Lsh(z, uint(n))
+	z = z.Sub(z, one)
+	return z
+}
+
+func bigIntNewSet(i *big.Int) *big.Int {
 	if i != nil {
 		return big.NewInt(0).Set(i)
 	}
 	return nil
 }
 
+func bigIntNewNot(i *big.Int) *big.Int {
+	if i != nil {
+		return big.NewInt(0).Not(i)
+	}
+	return nil
+}
+
 func bigIntMul(i *big.Int, j *big.Int) *big.Int { return big.NewInt(0).Mul(i, j) }
 func bigIntQuo(i *big.Int, j *big.Int) *big.Int { return big.NewInt(0).Quo(i, j) }
 
@@ -263,6 +285,35 @@
 	return x[0] != nil && x[1] != nil && x[0].Sign() == 0 && x[1].Sign() == 0
 }
 
+// split2Ways splits x into negative and non-negative sub-intervals. The
+// IntRange values returned may be empty, which means that x does not contain
+// any negative or non-negative elements.
+func (x IntRange) split2Ways() (neg IntRange, nonNeg IntRange) {
+	if x.Empty() {
+		return empty(), empty()
+	}
+	if x[0] != nil && x[0].Sign() >= 0 {
+		return empty(), x
+	}
+	if x[1] != nil && x[1].Sign() < 0 {
+		return x, empty()
+	}
+
+	neg[0] = x[0]
+	neg[1] = big.NewInt(-1)
+	if x[1] != nil && x[1].Cmp(neg[1]) < 0 {
+		neg[1] = x[1]
+	}
+
+	nonNeg[0] = big.NewInt(0)
+	if x[0] != nil && x[0].Cmp(nonNeg[0]) > 0 {
+		nonNeg[0] = x[0]
+	}
+	nonNeg[1] = x[1]
+
+	return neg, nonNeg
+}
+
 // split splits x into negative, zero and positive sub-intervals. The IntRange
 // values returned may be empty, which means that x does not contain any
 // negative or positive elements.
@@ -293,14 +344,14 @@
 func (x IntRange) Unite(y IntRange) (z IntRange) {
 	if x.Empty() {
 		return IntRange{
-			bigIntClone(y[0]),
-			bigIntClone(y[1]),
+			bigIntNewSet(y[0]),
+			bigIntNewSet(y[1]),
 		}
 	}
 	if y.Empty() {
 		return IntRange{
-			bigIntClone(x[0]),
-			bigIntClone(x[1]),
+			bigIntNewSet(x[0]),
+			bigIntNewSet(x[1]),
 		}
 	}
 
@@ -330,9 +381,9 @@
 	}
 
 	if x[0] == nil {
-		z[0] = bigIntClone(y[0])
+		z[0] = bigIntNewSet(y[0])
 	} else if y[0] == nil {
-		z[0] = bigIntClone(x[0])
+		z[0] = bigIntNewSet(x[0])
 	} else if x[0].Cmp(y[0]) < 0 {
 		z[0] = big.NewInt(0).Set(y[0])
 	} else {
@@ -340,9 +391,9 @@
 	}
 
 	if x[1] == nil {
-		z[1] = bigIntClone(y[1])
+		z[1] = bigIntNewSet(y[1])
 	} else if y[1] == nil {
-		z[1] = bigIntClone(x[1])
+		z[1] = bigIntNewSet(x[1])
 	} else if x[1].Cmp(y[1]) < 0 {
 		z[1] = big.NewInt(0).Set(x[1])
 	} else {
@@ -627,15 +678,54 @@
 //
 // ok is false (and z will be IntRange{nil, nil}) if x or y contains at least
 // one negative value. Otherwise, ok is true.
-//
-// TODO: implement bit-wise operations (with tight bounds) on negative
-// integers. In that case, we could drop the "ok" return value.
 func (x IntRange) And(y IntRange) (z IntRange, ok bool) {
 	if x.Empty() || y.Empty() {
 		return empty(), true
 	}
-	if x.ContainsNegative() || y.ContainsNegative() {
-		return IntRange{}, false
+	if !x.ContainsNegative() && !y.ContainsNegative() {
+		return andBothNonNeg(x, y), true
+	}
+
+	xNeg, xNon := x.split2Ways()
+	yNeg, yNon := y.split2Ways()
+	hasXNeg := !xNeg.Empty()
+	hasXNon := !xNon.Empty()
+	hasYNeg := !yNeg.Empty()
+	hasYNon := !yNon.Empty()
+
+	z = empty()
+	if hasXNeg {
+		if hasYNeg {
+			w := orBothNonNeg(IntRange{
+				bigIntNewNot(xNeg[1]),
+				bigIntNewNot(xNeg[0]),
+			}, IntRange{
+				bigIntNewNot(yNeg[1]),
+				bigIntNewNot(yNeg[0]),
+			})
+			z = z.Unite(IntRange{
+				bigIntNewNot(w[1]),
+				bigIntNewNot(w[0]),
+			})
+		}
+		if hasYNon {
+			z = z.Unite(andOneNegOneNonNeg(xNeg, yNon))
+		}
+	}
+	if hasXNon {
+		if hasYNeg {
+			z = z.Unite(andOneNegOneNonNeg(yNeg, xNon))
+		}
+		if hasYNon {
+			z = z.Unite(andBothNonNeg(xNon, yNon))
+		}
+	}
+	return z, true
+}
+
+func andBothNonNeg(x IntRange, y IntRange) (z IntRange) {
+	if x.Empty() || x.ContainsNegative() || y.Empty() || y.ContainsNegative() {
+		panic("pre-condition failure")
 	}
 
 	zMax := (*big.Int)(nil)
@@ -643,13 +733,13 @@
 		if y[1] != nil {
 			zMax = x.andMax(y)
 		} else {
-			return IntRange{big.NewInt(0), big.NewInt(0).Set(x[1])}, true
+			return IntRange{big.NewInt(0), big.NewInt(0).Set(x[1])}
 		}
 	} else {
 		if y[1] != nil {
-			return IntRange{big.NewInt(0), big.NewInt(0).Set(y[1])}, true
+			return IntRange{big.NewInt(0), big.NewInt(0).Set(y[1])}
 		} else {
-			return IntRange{big.NewInt(0), nil}, true
+			return IntRange{big.NewInt(0), nil}
 		}
 	}
 
@@ -665,22 +755,86 @@
 	zMin := notX.orMax(notY)
 	zMin.Not(zMin)
 
-	return IntRange{zMin, zMax}, true
+	return IntRange{zMin, zMax}
+}
+
+func andOneNegOneNonNeg(neg IntRange, non IntRange) (z IntRange) {
+	if neg.Empty() || neg.ContainsZero() || neg.ContainsPositive() || non.Empty() || non.ContainsNegative() {
+		panic("pre-condition failure")
+	}
+
+	if neg[0] == nil {
+		return IntRange{big.NewInt(0), bigIntNewSet(non[1])}
+	} else if non[1] == nil {
+		mask := bitMask(neg[0].BitLen(), non[0].BitLen())
+		biasedNeg := IntRange{
+			big.NewInt(0).And(mask, neg[0]),
+			big.NewInt(0).And(mask, neg[1]),
+		}
+		w := andBothNonNeg(biasedNeg, IntRange{non[0], mask})
+		return IntRange{w[0], nil}
+	} else {
+		mask := bitMask(neg[0].BitLen(), non[1].BitLen())
+		biasedNeg := IntRange{
+			big.NewInt(0).And(mask, neg[0]),
+			big.NewInt(0).And(mask, neg[1]),
+		}
+		return andBothNonNeg(biasedNeg, non)
+	}
 }
 
 // Or returns z = x | y.
 //
 // ok is false (and z will be IntRange{nil, nil}) if x or y contains at least
 // one negative value. Otherwise, ok is true.
-//
-// TODO: implement bit-wise operations (with tight bounds) on negative
-// integers. In that case, we could drop the "ok" return value.
 func (x IntRange) Or(y IntRange) (z IntRange, ok bool) {
 	if x.Empty() || y.Empty() {
 		return empty(), true
 	}
-	if x.ContainsNegative() || y.ContainsNegative() {
-		return IntRange{}, false
+	if !x.ContainsNegative() && !y.ContainsNegative() {
+		return orBothNonNeg(x, y), true
+	}
+
+	xNeg, xNon := x.split2Ways()
+	yNeg, yNon := y.split2Ways()
+	hasXNeg := !xNeg.Empty()
+	hasXNon := !xNon.Empty()
+	hasYNeg := !yNeg.Empty()
+	hasYNon := !yNon.Empty()
+
+	z = empty()
+	if hasXNeg {
+		if hasYNeg {
+			w := andBothNonNeg(IntRange{
+				bigIntNewNot(xNeg[1]),
+				bigIntNewNot(xNeg[0]),
+			}, IntRange{
+				bigIntNewNot(yNeg[1]),
+				bigIntNewNot(yNeg[0]),
+			})
+			z = z.Unite(IntRange{
+				bigIntNewNot(w[1]),
+				bigIntNewNot(w[0]),
+			})
+		}
+		if hasYNon {
+			z = z.Unite(orOneNegOneNonNeg(xNeg, yNon))
+		}
+	}
+	if hasXNon {
+		if hasYNeg {
+			z = z.Unite(orOneNegOneNonNeg(yNeg, xNon))
+		}
+		if hasYNon {
+			z = z.Unite(orBothNonNeg(xNon, yNon))
+		}
+	}
+	return z, true
+}
+
+func orBothNonNeg(x IntRange, y IntRange) (z IntRange) {
+	if x.Empty() || x.ContainsNegative() || y.Empty() || y.ContainsNegative() {
+		panic("pre-condition failure")
 	}
 
 	zMax := (*big.Int)(nil)
@@ -698,10 +852,10 @@
 		// value is contained in the other interval. For example, if both xx
 		// and yy can be x[0], then (x[0] | x[0]) is simply x[0].
 		if x.ContainsInt(y[0]) {
-			return IntRange{big.NewInt(0).Set(y[0]), nil}, true
+			return IntRange{big.NewInt(0).Set(y[0]), nil}
 		}
 		if y.ContainsInt(x[0]) {
-			return IntRange{big.NewInt(0).Set(x[0]), nil}, true
+			return IntRange{big.NewInt(0).Set(x[0]), nil}
 		}
 		if x[1] == nil && y[1] == nil {
 			panic("unreachable")
@@ -738,7 +892,21 @@
 	zMin := notX.andMax(notY)
 	zMin.Not(zMin)
 
-	return IntRange{zMin, zMax}, true
+	return IntRange{zMin, zMax}
+}
+
+func orOneNegOneNonNeg(neg IntRange, non IntRange) (z IntRange) {
+	w := andOneNegOneNonNeg(IntRange{
+		bigIntNewNot(non[1]),
+		bigIntNewNot(non[0]),
+	}, IntRange{
+		bigIntNewNot(neg[1]),
+		bigIntNewNot(neg[0]),
+	})
+	return IntRange{
+		bigIntNewNot(w[1]),
+		bigIntNewNot(w[0]),
+	}
 }
 
 // The andMax and orMax algorithms are tricky.
@@ -999,7 +1167,7 @@
 //  - Etc.
 func bitFillRight(i *big.Int) {
 	if s := i.Sign(); s < 0 {
-		panic("TODO: implement bit-wise operations on negative integers")
+		panic("pre-condition failure")
 	} else if s == 0 {
 		return
 	}
diff --git a/lib/interval/interval_test.go b/lib/interval/interval_test.go
index 874a5a5..cbf1f77 100644
--- a/lib/interval/interval_test.go
+++ b/lib/interval/interval_test.go
@@ -24,6 +24,36 @@
 	"testing"
 )
 
+var fromNeg7ToPos7 = []*big.Int{
+	big.NewInt(-7),
+	big.NewInt(-6),
+	big.NewInt(-5),
+	big.NewInt(-4),
+	big.NewInt(-3),
+	big.NewInt(-2),
+	big.NewInt(-1),
+	big.NewInt(+0),
+	big.NewInt(+1),
+	big.NewInt(+2),
+	big.NewInt(+3),
+	big.NewInt(+4),
+	big.NewInt(+5),
+	big.NewInt(+6),
+	big.NewInt(+7),
+	nil,
+}
+
+var fromNeg3ToPos3 = []*big.Int{
+	big.NewInt(-3),
+	big.NewInt(-2),
+	big.NewInt(-1),
+	big.NewInt(+0),
+	big.NewInt(+1),
+	big.NewInt(+2),
+	big.NewInt(+3),
+	nil,
+}
+
 // TestMotivatingExample tests the "motivating example" given in the package
 // doc comment.
 func TestMotivatingExample(tt *testing.T) {
@@ -311,33 +341,13 @@
 }
 
 func TestBruteForceAgreesSystematically(tt *testing.T) {
-	ints := []*big.Int{
-		big.NewInt(-7),
-		big.NewInt(-6),
-		big.NewInt(-5),
-		big.NewInt(-4),
-		big.NewInt(-3),
-		big.NewInt(-2),
-		big.NewInt(-1),
-		big.NewInt(+0),
-		big.NewInt(+1),
-		big.NewInt(+2),
-		big.NewInt(+3),
-		big.NewInt(+4),
-		big.NewInt(+5),
-		big.NewInt(+6),
-		big.NewInt(+7),
-		nil,
-	}
-
 	for _, opKey := range intOperatorsKeys {
-
-		for _, x0 := range ints {
-			for _, x1 := range ints {
+		for _, x0 := range fromNeg7ToPos7 {
+			for _, x1 := range fromNeg7ToPos7 {
 				x := IntRange{x0, x1}
 
-				for _, y0 := range ints {
-					for _, y1 := range ints {
+				for _, y0 := range fromNeg7ToPos7 {
+					for _, y1 := range fromNeg7ToPos7 {
 						y := IntRange{y0, y1}
 
 						if err := testBruteForceAgrees(x, y, opKey); err != nil {
@@ -422,7 +432,7 @@
 
 	got, gotOK := intOperators[opKey](x, y)
 	if !got.Eq(want) || gotOK != wantOK {
-		return fmt.Errorf("package code: got %v, %t, want %v, %t", got, gotOK, want, wantOK)
+		return fmt.Errorf("got %v, %t, want %v, %t", got, gotOK, want, wantOK)
 	}
 	return nil
 }
@@ -755,46 +765,46 @@
 
 func TestOpAnd(tt *testing.T) {
 	testOp(tt,
-		"[   3,    3]   &  [  -5,   -5]  ==  invalid",
+		"[   3,    3]   &  [  -5,   -5]  ==  [   3,    3]",
 		"[   3,    3]   &  [   0,    0]  ==  [   0,    0]",
-		"[   0,    0]   &  [  -7,    7]  ==  invalid",
+		"[   0,    0]   &  [  -7,    7]  ==  [   0,    0]",
 		"[   0,    2]   &  [   0,    5]  ==  [   0,    2]",
 		"[   3,    6]   &  [  10,   15]  ==  [   0,    6]",
-		"[   3,   +∞)   &  [  -4,   -2]  ==  invalid",
+		"[   3,   +∞)   &  [  -4,   -2]  ==  [   0,   +∞)",
 		"[   3,   +∞)   &  [  10,   15]  ==  [   0,   15]",
-		"[   3,   +∞)   &  (  -∞,   15]  ==  invalid",
-		"[   3,    6]   &  (  -∞,   15]  ==  invalid",
-		"[   3,    6]   &  (  -∞,   +∞)  ==  invalid",
-		"(  -∞,   +∞)   &  (  -∞,   +∞)  ==  invalid",
-		"(  -∞,   +∞)   &  [   1,    2]  ==  invalid",
-		"(  -∞,   +∞)   &  [   0,    0]  ==  invalid",
+		"[   3,   +∞)   &  (  -∞,   15]  ==  [   0,   +∞)",
+		"[   3,    6]   &  (  -∞,   15]  ==  [   0,    6]",
+		"[   3,    6]   &  (  -∞,   +∞)  ==  [   0,    6]",
+		"(  -∞,   +∞)   &  (  -∞,   +∞)  ==  (  -∞,   +∞)",
+		"(  -∞,   +∞)   &  [   1,    2]  ==  [   0,    2]",
+		"(  -∞,   +∞)   &  [   0,    0]  ==  [   0,    0]",
 		"[   3,    6]   &  [...empty..]  ==  [...empty..]",
 		"[...empty..]   &  [  10,   15]  ==  [...empty..]",
 		"[...empty..]   &  [...empty..]  ==  [...empty..]",
 		"(  -∞,   +∞)   &  [...empty..]  ==  [...empty..]",
 
-		"[   1,    4]   &  [ -11,  -10]  ==  invalid",
+		"[   1,    4]   &  [ -11,  -10]  ==  [   0,    4]",
 
-		"[   1,    4]   &  [  -6,    2]  ==  invalid",
+		"[   1,    4]   &  [  -6,    2]  ==  [   0,    4]",
 
-		"[  -3,   -1]   &  [   0,    3]  ==  invalid",
-		"[  -1,    4]   &  [   0,    3]  ==  invalid",
+		"[  -3,   -1]   &  [   0,    3]  ==  [   0,    3]",
+		"[  -1,    4]   &  [   0,    3]  ==  [   0,    3]",
 		"[   0,    4]   &  [   0,    3]  ==  [   0,    3]",
 		"[   1,    4]   &  [   0,    3]  ==  [   0,    3]",
 
-		"[  -3,   -1]   &  [   2,    3]  ==  invalid",
-		"[  -1,    4]   &  [   2,    3]  ==  invalid",
+		"[  -3,   -1]   &  [   2,    3]  ==  [   0,    3]",
+		"[  -1,    4]   &  [   2,    3]  ==  [   0,    3]",
 		"[   0,    4]   &  [   2,    3]  ==  [   0,    3]",
 		"[   1,    4]   &  [   2,    3]  ==  [   0,    3]",
 
-		"[  -9,   +∞)   &  [   2,   +∞)  ==  invalid",
-		"[  -1,   +∞)   &  [   2,   +∞)  ==  invalid",
+		"[  -9,   +∞)   &  [   2,   +∞)  ==  [   0,   +∞)",
+		"[  -1,   +∞)   &  [   2,   +∞)  ==  [   0,   +∞)",
 		"[   0,   +∞)   &  [   2,   +∞)  ==  [   0,   +∞)",
 		"[   1,   +∞)   &  [   2,   +∞)  ==  [   0,   +∞)",
 		"[   7,   +∞)   &  [   2,   +∞)  ==  [   0,   +∞)",
-		"[  -1,    1]   &  (  -∞,   +∞)  ==  invalid",
-		"[   0,    0]   &  (  -∞,   +∞)  ==  invalid",
-		"[   1,    1]   &  (  -∞,   +∞)  ==  invalid",
+		"[  -1,    1]   &  (  -∞,   +∞)  ==  (  -∞,   +∞)",
+		"[   0,    0]   &  (  -∞,   +∞)  ==  [   0,    0]",
+		"[   1,    1]   &  (  -∞,   +∞)  ==  [   0,    1]",
 
 		"[   1,    3]   &  [   4,    9]  ==  [   0,    3]",
 		"[   3,    4]   &  [   5,    6]  ==  [   1,    4]",
@@ -816,51 +826,54 @@
 		"[   5,    9]   &  [   9,   +∞)  ==  [   0,    9]",
 		"[   5,    6]   &  [  12,   +∞)  ==  [   0,    6]",
 		"[   5,    9]   &  [  12,   +∞)  ==  [   0,    9]",
+
+		"(  -∞,   -3]   &  [  -3,   -2]  ==  (  -∞,   -3]",
+		"[   2,   +∞)   &  [   1,    2]  ==  [   0,    2]",
 	)
 }
 
 func TestOpOr(tt *testing.T) {
 	testOp(tt,
-		"[   3,    3]   |  [  -5,   -5]  ==  invalid",
+		"[   3,    3]   |  [  -5,   -5]  ==  [  -5,   -5]",
 		"[   3,    3]   |  [   0,    0]  ==  [   3,    3]",
-		"[   0,    0]   |  [  -7,    7]  ==  invalid",
+		"[   0,    0]   |  [  -7,    7]  ==  [  -7,    7]",
 		"[   0,    2]   |  [   0,    5]  ==  [   0,    7]",
 		"[   3,    6]   |  [  10,   15]  ==  [  11,   15]",
-		"[   3,   +∞)   |  [  -4,   -2]  ==  invalid",
+		"[   3,   +∞)   |  [  -4,   -2]  ==  [  -4,   -1]",
 		"[   3,   +∞)   |  [  10,   15]  ==  [  10,   +∞)",
-		"[   3,   +∞)   |  (  -∞,   15]  ==  invalid",
-		"[   3,    6]   |  (  -∞,   15]  ==  invalid",
-		"[   3,    6]   |  (  -∞,   +∞)  ==  invalid",
-		"(  -∞,   +∞)   |  (  -∞,   +∞)  ==  invalid",
-		"(  -∞,   +∞)   |  [   1,    2]  ==  invalid",
-		"(  -∞,   +∞)   |  [   0,    0]  ==  invalid",
+		"[   3,   +∞)   |  (  -∞,   15]  ==  (  -∞,   +∞)",
+		"[   3,    6]   |  (  -∞,   15]  ==  (  -∞,   15]",
+		"[   3,    6]   |  (  -∞,   +∞)  ==  (  -∞,   +∞)",
+		"(  -∞,   +∞)   |  (  -∞,   +∞)  ==  (  -∞,   +∞)",
+		"(  -∞,   +∞)   |  [   1,    2]  ==  (  -∞,   +∞)",
+		"(  -∞,   +∞)   |  [   0,    0]  ==  (  -∞,   +∞)",
 		"[   3,    6]   |  [...empty..]  ==  [...empty..]",
 		"[...empty..]   |  [  10,   15]  ==  [...empty..]",
 		"[...empty..]   |  [...empty..]  ==  [...empty..]",
 		"(  -∞,   +∞)   |  [...empty..]  ==  [...empty..]",
 
-		"[   1,    4]   |  [ -11,  -10]  ==  invalid",
+		"[   1,    4]   |  [ -11,  -10]  ==  [ -11,   -9]",
 
-		"[   1,    4]   |  [  -6,    2]  ==  invalid",
+		"[   1,    4]   |  [  -6,    2]  ==  [  -6,    6]",
 
-		"[  -3,   -1]   |  [   0,    3]  ==  invalid",
-		"[  -1,    4]   |  [   0,    3]  ==  invalid",
+		"[  -3,   -1]   |  [   0,    3]  ==  [  -3,   -1]",
+		"[  -1,    4]   |  [   0,    3]  ==  [  -1,    7]",
 		"[   0,    4]   |  [   0,    3]  ==  [   0,    7]",
 		"[   1,    4]   |  [   0,    3]  ==  [   1,    7]",
 
-		"[  -3,   -1]   |  [   2,    3]  ==  invalid",
-		"[  -1,    4]   |  [   2,    3]  ==  invalid",
+		"[  -3,   -1]   |  [   2,    3]  ==  [  -2,   -1]",
+		"[  -1,    4]   |  [   2,    3]  ==  [  -1,    7]",
 		"[   0,    4]   |  [   2,    3]  ==  [   2,    7]",
 		"[   1,    4]   |  [   2,    3]  ==  [   2,    7]",
 
-		"[  -9,   +∞)   |  [   2,   +∞)  ==  invalid",
-		"[  -1,   +∞)   |  [   2,   +∞)  ==  invalid",
+		"[  -9,   +∞)   |  [   2,   +∞)  ==  [  -9,   +∞)",
+		"[  -1,   +∞)   |  [   2,   +∞)  ==  [  -1,   +∞)",
 		"[   0,   +∞)   |  [   2,   +∞)  ==  [   2,   +∞)",
 		"[   1,   +∞)   |  [   2,   +∞)  ==  [   2,   +∞)",
 		"[   7,   +∞)   |  [   2,   +∞)  ==  [   7,   +∞)",
-		"[  -1,    1]   |  (  -∞,   +∞)  ==  invalid",
-		"[   0,    0]   |  (  -∞,   +∞)  ==  invalid",
-		"[   1,    1]   |  (  -∞,   +∞)  ==  invalid",
+		"[  -1,    1]   |  (  -∞,   +∞)  ==  (  -∞,   +∞)",
+		"[   0,    0]   |  (  -∞,   +∞)  ==  (  -∞,   +∞)",
+		"[   1,    1]   |  (  -∞,   +∞)  ==  (  -∞,   +∞)",
 
 		"[   1,    3]   |  [   4,    9]  ==  [   5,   11]",
 		"[   3,    4]   |  [   5,    6]  ==  [   5,    7]",
@@ -882,5 +895,82 @@
 		"[   5,    9]   |  [   9,   +∞)  ==  [   9,   +∞)",
 		"[   5,    6]   |  [  12,   +∞)  ==  [  13,   +∞)",
 		"[   5,    9]   |  [  12,   +∞)  ==  [  12,   +∞)",
+
+		"(  -∞,   -3]   |  [  -3,   -2]  ==  [  -3,   -1]",
+		"[   2,   +∞)   |  [   1,    2]  ==  [   2,   +∞)",
 	)
 }
+
+func TestOpAndWithMinusOne(tt *testing.T) {
+	minusOne := IntRange{big.NewInt(-1), big.NewInt(-1)}
+	for _, x0 := range fromNeg3ToPos3 {
+		for _, x1 := range fromNeg3ToPos3 {
+			x := IntRange{x0, x1}
+			want := x
+
+			if got, _ := x.And(minusOne); !got.Eq(want) {
+				tt.Fatalf("%v & -1: got %v, want %v", x, got, want)
+			}
+			if got, _ := minusOne.And(x); !got.Eq(want) {
+				tt.Fatalf("-1 & %v: got %v, want %v", x, got, want)
+			}
+		}
+	}
+}
+
+func TestOpAndWithZero(tt *testing.T) {
+	zero := IntRange{big.NewInt(+0), big.NewInt(+0)}
+	for _, x0 := range fromNeg3ToPos3 {
+		for _, x1 := range fromNeg3ToPos3 {
+			x := IntRange{x0, x1}
+			want := zero
+			if x.Empty() {
+				want = empty()
+			}
+
+			if got, _ := x.And(zero); !got.Eq(want) {
+				tt.Fatalf("%v & +0: got %v, want %v", x, got, want)
+			}
+			if got, _ := zero.And(x); !got.Eq(want) {
+				tt.Fatalf("+0 & %v: got %v, want %v", x, got, want)
+			}
+		}
+	}
+}
+
+func TestOpOrWithMinusOne(tt *testing.T) {
+	minusOne := IntRange{big.NewInt(-1), big.NewInt(-1)}
+	for _, x0 := range fromNeg3ToPos3 {
+		for _, x1 := range fromNeg3ToPos3 {
+			x := IntRange{x0, x1}
+			want := minusOne
+			if x.Empty() {
+				want = empty()
+			}
+
+			if got, _ := x.Or(minusOne); !got.Eq(want) {
+				tt.Fatalf("%v | -1: got %v, want %v", x, got, want)
+			}
+			if got, _ := minusOne.Or(x); !got.Eq(want) {
+				tt.Fatalf("-1 | %v: got %v, want %v", x, got, want)
+			}
+		}
+	}
+}
+
+func TestOpOrWithZero(tt *testing.T) {
+	zero := IntRange{big.NewInt(+0), big.NewInt(+0)}
+	for _, x0 := range fromNeg3ToPos3 {
+		for _, x1 := range fromNeg3ToPos3 {
+			x := IntRange{x0, x1}
+			want := x
+
+			if got, _ := x.Or(zero); !got.Eq(want) {
+				tt.Fatalf("%v | +0: got %v, want %v", x, got, want)
+			}
+			if got, _ := zero.Or(x); !got.Eq(want) {
+				tt.Fatalf("+0 | %v: got %v, want %v", x, got, want)
+			}
+		}
+	}
+}
diff --git a/lib/interval/radial_test.go b/lib/interval/radial_test.go
index 102280d..e69acfb 100644
--- a/lib/interval/radial_test.go
+++ b/lib/interval/radial_test.go
@@ -83,7 +83,8 @@
 const (
 	radialNaN = -1 << 31
 
-	// Note that radialInput.Or requires that (riRadius + 1) is a power of 2.
+	// Note that radialInput.And and radialInput.Or require that (riRadius + 1)
+	// is a power of 2.
 	riRadius = 15
 	roRadius = 16 << 16
 
@@ -343,36 +344,56 @@
 	if x == radialNaN || y == radialNaN {
 		return radialOutPair{radialNaN, radialNaN}
 	}
-	if x < 0 || y < 0 {
-		// TODO: handle negative numbers.
-		return radialOutPair{radialNaN, radialNaN}
-	}
 	ox := x.canonicalize()
 	oy := y.canonicalize()
 
-	if ox > +riRadius {
-		if oy > +riRadius {
+	// r is a power of 2, so that its binary representation contains one "1"
+	// digit, and that digit is not shared with any "small" value <= riRadius.
+	const r = riRadius + 1
+
+	if ox < -riRadius {
+		if oy < -riRadius {
+			return radialOutPair{roLargeNeg, -r}
+		} else if oy > +riRadius {
 			return radialOutPair{0, roLargePos}
+		} else if oy < 0 {
+			return radialOutPair{roLargeNeg, -r}
 		} else {
 			return radialOutPair{0, oy}
 		}
-	} else {
-		if oy > +riRadius {
-			return radialOutPair{0, ox}
+	} else if ox > +riRadius {
+		if oy < -riRadius {
+			return radialOutPair{0, roLargePos}
+		} else if oy > +riRadius {
+			return radialOutPair{0, roLargePos}
+		} else if oy < 0 {
+			return radialOutPair{+r, roLargePos}
 		} else {
-			return radialOutPair{ox & oy, ox & oy}
+			return radialOutPair{0, oy}
 		}
 	}
+
+	if oy < -riRadius {
+		if ox < 0 {
+			return radialOutPair{roLargeNeg, -r}
+		} else {
+			return radialOutPair{0, ox}
+		}
+	} else if oy > +riRadius {
+		if ox < 0 {
+			return radialOutPair{+r, roLargePos}
+		} else {
+			return radialOutPair{0, ox}
+		}
+	}
+
+	return radialOutPair{ox & oy, ox & oy}
 }
 
 func (x radialInput) Or(y radialInput) radialOutPair {
 	if x == radialNaN || y == radialNaN {
 		return radialOutPair{radialNaN, radialNaN}
 	}
-	if x < 0 || y < 0 {
-		// TODO: handle negative numbers.
-		return radialOutPair{radialNaN, radialNaN}
-	}
 	ox := x.canonicalize()
 	oy := y.canonicalize()
 
@@ -380,19 +401,43 @@
 	// digit, and that digit is not shared with any "small" value <= riRadius.
 	const r = riRadius + 1
 
-	if ox > +riRadius {
-		if oy > +riRadius {
-			return radialOutPair{r, roLargePos}
+	if ox < -riRadius {
+		if oy < -riRadius {
+			return radialOutPair{roLargeNeg, -1}
+		} else if oy > +riRadius {
+			return radialOutPair{roLargeNeg, -1}
+		} else if oy < 0 {
+			return radialOutPair{oy, -1}
 		} else {
-			return radialOutPair{oy | r, roLargePos}
+			return radialOutPair{roLargeNeg, oy | -r}
 		}
-	} else {
-		if oy > +riRadius {
-			return radialOutPair{ox | r, roLargePos}
+	} else if ox > +riRadius {
+		if oy < -riRadius {
+			return radialOutPair{roLargeNeg, -1}
+		} else if oy > +riRadius {
+			return radialOutPair{+r, roLargePos}
+		} else if oy < 0 {
+			return radialOutPair{oy, -1}
 		} else {
-			return radialOutPair{ox | oy, ox | oy}
+			return radialOutPair{oy | +r, roLargePos}
 		}
 	}
+
+	if oy < -riRadius {
+		if ox < 0 {
+			return radialOutPair{ox, -1}
+		} else {
+			return radialOutPair{roLargeNeg, ox | -r}
+		}
+	} else if oy > +riRadius {
+		if ox < 0 {
+			return radialOutPair{ox, -1}
+		} else {
+			return radialOutPair{ox | +r, roLargePos}
+		}
+	}
+
+	return radialOutPair{ox | oy, ox | oy}
 }
 
 var riOperators = map[string]func(radialInput, radialInput) radialOutPair{