1// Copyright 2018 The Wuffs Authors. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// ---------------- 16 17// Package interval provides interval arithmetic on big integers. Big means 18// arbitrary-precision, as per the standard math/big package. 19// 20// For example, if x is in the interval [3, 6] and y is in the interval [10, 21// 15] then x+y is in the interval [13, 21]. 22// 23// Such intervals may have infinite bounds. For example, if x is in the 24// interval [3, +∞) and y is in the interval [-4, -2], then x*y is in the 25// interval (-∞, -6]. 26// 27// As a motivating example, if a compiler knows that the integer-typed 28// variables i and j are in the intervals [0, 255] and [0, 3], and that the 29// array a has 1024 elements, then it can prove that the array-index expression 30// a[4*i + j] is memory-safe without needing an at-runtime bounds check. 31// 32// This package depends only on the standard math/big package. 33package interval 34 35import ( 36 "math/big" 37) 38 39var ( 40 one = big.NewInt(1) 41) 42 43func bigIntMul(i *big.Int, j *big.Int) *big.Int { return big.NewInt(0).Mul(i, j) } 44func bigIntQuo(i *big.Int, j *big.Int) *big.Int { return big.NewInt(0).Quo(i, j) } 45 46func bigIntLsh(i *big.Int, j *big.Int) *big.Int { 47 if j.IsUint64() { 48 if u := j.Uint64(); u <= 0xFFFFFFFF { 49 return big.NewInt(0).Lsh(i, uint(u)) 50 } 51 } 52 53 // Fallback code path, copy-pasted to interval_test.go. 54 k := big.NewInt(2) 55 k.Exp(k, j, nil) 56 k.Mul(i, k) 57 return k 58} 59 60func bigIntRsh(i *big.Int, j *big.Int) *big.Int { 61 if j.IsUint64() { 62 if u := j.Uint64(); u <= 0xFFFFFFFF { 63 return big.NewInt(0).Rsh(i, uint(u)) 64 } 65 } 66 67 // Fallback code path, copy-pasted to interval_test.go. 68 k := big.NewInt(2) 69 k.Exp(k, j, nil) 70 k.Div(i, k) // This is explicitly Div, not Quo. 71 return k 72} 73 74// biggerInt is either a non-nil *big.Int or ±∞. 75type biggerInt struct { 76 // extra being less than or greater than 0 means that the biggerInt is -∞ 77 // or +∞ respectively. extra being zero means that the biggerInt is i, 78 // which should be a non-nil pointer. 79 extra int32 80 i *big.Int 81} 82 83type biggerIntPair [2]biggerInt 84 85// newBiggerIntPair returns a pair of biggerInt values, the first being +∞ 86// and the second being -∞. 87func newBiggerIntPair() biggerIntPair { return biggerIntPair{{extra: +1}, {extra: -1}} } 88 89// lowerMin sets x[0] to min(x[0], y). 90func (x *biggerIntPair) lowerMin(y biggerInt) { 91 if x[0].extra > 0 || y.extra < 0 || 92 (x[0].extra == 0 && y.extra == 0 && x[0].i.Cmp(y.i) > 0) { 93 x[0] = y 94 } 95} 96 97// raiseMax sets x[1] to max(x[1], y). 98func (x *biggerIntPair) raiseMax(y biggerInt) { 99 if x[1].extra < 0 || y.extra > 0 || 100 (x[1].extra == 0 && y.extra == 0 && x[1].i.Cmp(y.i) < 0) { 101 x[1] = y 102 } 103} 104 105func (x *biggerIntPair) toIntRange() IntRange { 106 if x[0].extra > 0 || x[1].extra < 0 { 107 return empty() 108 } 109 return IntRange{x[0].i, x[1].i} 110} 111 112func (x *biggerIntPair) fromIntRange(y IntRange) { 113 if y[0] != nil { 114 x[0] = biggerInt{i: big.NewInt(0).Set(y[0])} 115 } else { 116 x[0] = biggerInt{extra: -1} 117 } 118 if y[1] != nil { 119 x[1] = biggerInt{i: big.NewInt(0).Set(y[1])} 120 } else { 121 x[1] = biggerInt{extra: +1} 122 } 123} 124 125// IntRange is an integer interval. The array elements are the minimum and 126// maximum values, inclusive (if non-nil) on both ends. A nil element means 127// unbounded: negative or positive infinity. 128// 129// The zero value (zero in the Go sense, not in the integer sense) is a valid, 130// infinitely sized interval, unbounded at both ends. 131// 132// A subtle point is that an interval's minimum or maximum can be infinite, but 133// if an integer value i is known to be within such an interval, i's possible 134// values are arbitrarily large but not infinite. Specifically, 0*i is 135// unambiguously always equal to 0. 136// 137// It is also valid for the first element to be greater than the second 138// element. This represents an empty interval. There is more than one 139// representation of an empty interval. 140// 141// "Int" abbreviates "Integer" (the same as for big.Int), not "Interval". 142// Similarly, we use "Range" instead of "Interval" to avoid unnecessary 143// confusion, even though this type is indeed an integer interval. 144type IntRange [2]*big.Int 145 146// String returns a string representation of x. 147func (x IntRange) String() string { 148 if x.Empty() { 149 return "<empty>" 150 } 151 buf := []byte(nil) 152 if x[0] == nil { 153 buf = append(buf, "(-∞, "...) 154 } else { 155 buf = append(buf, '[') 156 buf = x[0].Append(buf, 10) 157 buf = append(buf, ".."...) 158 } 159 if x[1] == nil { 160 buf = append(buf, "+∞)"...) 161 } else { 162 buf = x[1].Append(buf, 10) 163 buf = append(buf, ']') 164 } 165 return string(buf) 166} 167 168// empty returns an empty IntRange: one that contains no elements. 169func empty() IntRange { 170 return IntRange{big.NewInt(+1), big.NewInt(-1)} 171} 172 173// ContainsNegative returns whether x contains at least one negative value. 174func (x IntRange) ContainsNegative() bool { 175 if x[0] == nil { 176 return true 177 } 178 if x[0].Sign() >= 0 { 179 return false 180 } 181 return x[1] == nil || x[0].Cmp(x[1]) <= 0 182} 183 184// ContainsPositive returns whether x contains at least one positive value. 185func (x IntRange) ContainsPositive() bool { 186 if x[1] == nil { 187 return true 188 } 189 if x[1].Sign() <= 0 { 190 return false 191 } 192 return x[0] == nil || x[0].Cmp(x[1]) <= 0 193} 194 195// ContainsZero returns whether x contains zero. 196func (x IntRange) ContainsZero() bool { 197 return (x[0] == nil || x[0].Sign() <= 0) && 198 (x[1] == nil || x[1].Sign() >= 0) 199} 200 201// ContainsInt returns whether x contains i. 202func (x IntRange) ContainsInt(i *big.Int) bool { 203 return (x[0] == nil || x[0].Cmp(i) <= 0) && 204 (x[1] == nil || x[1].Cmp(i) >= 0) 205} 206 207// ContainsIntRange returns whether x contains every element of y. 208// 209// It returns true if y is empty. 210func (x IntRange) ContainsIntRange(y IntRange) bool { 211 if y.Empty() { 212 return true 213 } 214 if (x[0] != nil) && (y[0] == nil || x[0].Cmp(y[0]) > 0) { 215 return false 216 } 217 if (x[1] != nil) && (y[1] == nil || x[1].Cmp(y[1]) < 0) { 218 return false 219 } 220 return true 221} 222 223// Eq returns whether x equals y. 224func (x IntRange) Eq(y IntRange) bool { 225 if xe, ye := x.Empty(), y.Empty(); xe || ye { 226 return xe == ye 227 } 228 if x0, y0 := x[0] != nil, y[0] != nil; x0 != y0 { 229 return false 230 } else if x0 && x[0].Cmp(y[0]) != 0 { 231 return false 232 } 233 if x1, y1 := x[1] != nil, y[1] != nil; x1 != y1 { 234 return false 235 } else if x1 && x[1].Cmp(y[1]) != 0 { 236 return false 237 } 238 return true 239} 240 241// Empty returns whether x is empty. 242func (x IntRange) Empty() bool { 243 return x[0] != nil && x[1] != nil && x[0].Cmp(x[1]) > 0 244} 245 246// justZero returns whether x is the [0, 0] interval, containing exactly one 247// element: the integer zero. 248func (x IntRange) justZero() bool { 249 return x[0] != nil && x[1] != nil && x[0].Sign() == 0 && x[1].Sign() == 0 250} 251 252// split splits x into negative, zero and positive sub-intervals. The IntRange 253// values returned may be empty, which means that x does not contain any 254// negative or positive elements. 255func (x IntRange) split() (neg IntRange, pos IntRange, negEmpty bool, hasZero bool, posEmpty bool) { 256 if x[0] != nil && x[0].Sign() > 0 { 257 return empty(), x, true, false, x.Empty() 258 } 259 if x[1] != nil && x[1].Sign() < 0 { 260 return x, empty(), x.Empty(), false, true 261 } 262 263 neg[0] = x[0] 264 neg[1] = big.NewInt(-1) 265 if x[1] != nil && x[1].Cmp(neg[1]) < 0 { 266 neg[1] = x[1] 267 } 268 269 pos[0] = big.NewInt(+1) 270 if x[0] != nil && x[0].Cmp(pos[0]) > 0 { 271 pos[0] = x[0] 272 } 273 pos[1] = x[1] 274 275 return neg, pos, neg.Empty(), x.ContainsZero(), pos.Empty() 276} 277 278// Add returns z = x + y. 279func (x IntRange) Add(y IntRange) (z IntRange) { 280 if x.Empty() || y.Empty() { 281 return empty() 282 } 283 if x[0] != nil && y[0] != nil { 284 z[0] = big.NewInt(0).Add(x[0], y[0]) 285 } 286 if x[1] != nil && y[1] != nil { 287 z[1] = big.NewInt(0).Add(x[1], y[1]) 288 } 289 return z 290} 291 292// Sub returns z = x - y. 293func (x IntRange) Sub(y IntRange) (z IntRange) { 294 if x.Empty() || y.Empty() { 295 return empty() 296 } 297 if x[0] != nil && y[1] != nil && (x[1] != nil || y[0] != nil) { 298 z[0] = big.NewInt(0).Sub(x[0], y[1]) 299 } 300 if x[1] != nil && y[0] != nil && (x[0] != nil || y[1] != nil) { 301 z[1] = big.NewInt(0).Sub(x[1], y[0]) 302 } 303 return z 304} 305 306// Mul returns z = x * y. 307func (x IntRange) Mul(y IntRange) (z IntRange) { 308 return x.mulLsh(y, false) 309} 310 311// Lsh returns z = x << y. 312// 313// ok is false (and z will be IntRange{nil, nil}) if x is non-empty and y 314// contains at least one negative value, as it's invalid to shift by a negative 315// number. Otherwise, ok is true. 316func (x IntRange) Lsh(y IntRange) (z IntRange, ok bool) { 317 if !x.Empty() && y.ContainsNegative() { 318 return IntRange{}, false 319 } 320 return x.mulLsh(y, true), true 321} 322 323func (x IntRange) mulLsh(y IntRange, shift bool) (z IntRange) { 324 if x.Empty() || y.Empty() { 325 return empty() 326 } 327 if x.justZero() || (!shift && y.justZero()) { 328 return IntRange{big.NewInt(0), big.NewInt(0)} 329 } 330 331 combine := bigIntMul 332 if shift { 333 combine = bigIntLsh 334 } 335 336 ret := newBiggerIntPair() 337 338 // Split x and y into negative, zero and positive parts. 339 negX, posX, negXEmpty, zeroX, posXEmpty := x.split() 340 negY, posY, negYEmpty, zeroY, posYEmpty := y.split() 341 342 if zeroY && shift { 343 ret.fromIntRange(x) 344 } else if (zeroY && !shift) || zeroX { 345 ret[0] = biggerInt{i: big.NewInt(0)} 346 ret[1] = biggerInt{i: big.NewInt(0)} 347 } 348 349 if !negXEmpty { 350 if !negYEmpty { 351 // x is negative and y is negative, so x op y is positive. 352 // 353 // If op is << instead of * then we have previously checked that y 354 // is non-negative, so this should be unreachable. 355 ret.lowerMin(biggerInt{i: combine(negX[1], negY[1])}) 356 if negX[0] == nil || negY[0] == nil { 357 ret.raiseMax(biggerInt{extra: +1}) 358 } else { 359 ret.raiseMax(biggerInt{i: combine(negX[0], negY[0])}) 360 } 361 } 362 363 if !posYEmpty { 364 // x is negative and y is positive, so x op y is negative. 365 if negX[0] == nil || posY[1] == nil { 366 ret.lowerMin(biggerInt{extra: -1}) 367 } else { 368 ret.lowerMin(biggerInt{i: combine(negX[0], posY[1])}) 369 } 370 ret.raiseMax(biggerInt{i: combine(negX[1], posY[0])}) 371 } 372 } 373 374 if !posXEmpty { 375 if !negYEmpty { 376 // x is positive and y is negative, so x op y is negative. 377 // 378 // If op is << instead of * then we have previously checked that y 379 // is non-negative, so this should be unreachable. 380 if posX[1] == nil || negY[0] == nil { 381 ret.lowerMin(biggerInt{extra: -1}) 382 } else { 383 ret.lowerMin(biggerInt{i: combine(posX[1], negY[0])}) 384 } 385 ret.raiseMax(biggerInt{i: combine(posX[0], negY[1])}) 386 } 387 388 if !posYEmpty { 389 // x is positive and y is positive, so x op y is positive. 390 ret.lowerMin(biggerInt{i: combine(posX[0], posY[0])}) 391 if posX[1] == nil || posY[1] == nil { 392 ret.raiseMax(biggerInt{extra: +1}) 393 } else { 394 ret.raiseMax(biggerInt{i: combine(posX[1], posY[1])}) 395 } 396 } 397 } 398 399 return ret.toIntRange() 400} 401 402// Quo returns z = x / y. Like the big.Int.Quo method (and unlike the 403// big.Int.Div method), it truncates towards zero. 404// 405// ok is false (and z will be IntRange{nil, nil}) if x is non-empty and y 406// contains zero, as it's invalid to divide by zero. Otherwise, ok is true. 407func (x IntRange) Quo(y IntRange) (z IntRange, ok bool) { 408 if x.Empty() || y.Empty() { 409 return empty(), true 410 } 411 if y.ContainsZero() { 412 return IntRange{}, false 413 } 414 if x.justZero() { 415 return IntRange{big.NewInt(0), big.NewInt(0)}, true 416 } 417 418 ret := newBiggerIntPair() 419 420 // Split x and y into negative, zero and positive parts. 421 negX, posX, negXEmpty, zeroX, posXEmpty := x.split() 422 negY, posY, negYEmpty, _, posYEmpty := y.split() 423 424 if zeroX { 425 ret[0] = biggerInt{i: big.NewInt(0)} 426 ret[1] = biggerInt{i: big.NewInt(0)} 427 } 428 429 if !negXEmpty { 430 if !negYEmpty { 431 // x is negative and y is negative, so x / y is non-negative. 432 if negX[0] == nil { 433 ret.raiseMax(biggerInt{extra: +1}) 434 } else { 435 ret.raiseMax(biggerInt{i: bigIntQuo(negX[0], negY[1])}) 436 } 437 if negY[0] == nil { 438 ret.lowerMin(biggerInt{i: big.NewInt(0)}) 439 } else { 440 ret.lowerMin(biggerInt{i: bigIntQuo(negX[1], negY[0])}) 441 } 442 } 443 444 if !posYEmpty { 445 // x is negative and y is positive, so x / y is non-positive. 446 if negX[0] == nil { 447 ret.lowerMin(biggerInt{extra: -1}) 448 } else { 449 ret.lowerMin(biggerInt{i: bigIntQuo(negX[0], posY[0])}) 450 } 451 if posY[1] == nil { 452 ret.raiseMax(biggerInt{i: big.NewInt(0)}) 453 } else { 454 ret.raiseMax(biggerInt{i: bigIntQuo(negX[1], posY[1])}) 455 } 456 } 457 } 458 459 if !posXEmpty { 460 if !negYEmpty { 461 // x is positive and y is negative, so x / y is non-positive. 462 if posX[1] == nil { 463 ret.lowerMin(biggerInt{extra: -1}) 464 } else { 465 ret.lowerMin(biggerInt{i: bigIntQuo(posX[1], negY[1])}) 466 } 467 if negY[0] == nil { 468 ret.raiseMax(biggerInt{i: big.NewInt(0)}) 469 } else { 470 ret.raiseMax(biggerInt{i: bigIntQuo(posX[0], negY[0])}) 471 } 472 } 473 474 if !posYEmpty { 475 // x is positive and y is positive, so x / y is non-negative. 476 if posX[1] == nil { 477 ret.raiseMax(biggerInt{extra: +1}) 478 } else { 479 ret.raiseMax(biggerInt{i: bigIntQuo(posX[1], posY[0])}) 480 } 481 if posY[1] == nil { 482 ret.lowerMin(biggerInt{i: big.NewInt(0)}) 483 } else { 484 ret.lowerMin(biggerInt{i: bigIntQuo(posX[0], posY[1])}) 485 } 486 } 487 } 488 489 return ret.toIntRange(), true 490} 491 492// Rsh returns z = x >> y. 493// 494// ok is false (and z will be IntRange{nil, nil}) if x is non-empty and y 495// contains at least one negative value, as it's invalid to shift by a negative 496// number. Otherwise, ok is true. 497func (x IntRange) Rsh(y IntRange) (z IntRange, ok bool) { 498 if x.Empty() || y.Empty() { 499 return empty(), true 500 } 501 if y.ContainsNegative() { 502 return IntRange{}, false 503 } 504 if x.justZero() { 505 return IntRange{big.NewInt(0), big.NewInt(0)}, true 506 } 507 508 ret := newBiggerIntPair() 509 510 // Split x and y into negative and zero-or-positive parts. 511 negX, posX, negXEmpty, zeroX, posXEmpty := x.split() 512 513 if zeroX { 514 ret[0] = biggerInt{i: big.NewInt(0)} 515 ret[1] = biggerInt{i: big.NewInt(0)} 516 } 517 518 if !negXEmpty { 519 // x is negative and y is positive, so x >> y is non-positive. 520 if negX[0] == nil { 521 ret.lowerMin(biggerInt{extra: -1}) 522 } else { 523 ret.lowerMin(biggerInt{i: bigIntRsh(negX[0], y[0])}) 524 } 525 if y[1] == nil { 526 ret.raiseMax(biggerInt{i: big.NewInt(-1)}) 527 } else { 528 ret.raiseMax(biggerInt{i: bigIntRsh(negX[1], y[1])}) 529 } 530 } 531 532 if !posXEmpty { 533 // x is positive and y is positive, so x >> y is non-negative. 534 if y[1] == nil { 535 ret.lowerMin(biggerInt{i: big.NewInt(0)}) 536 } else { 537 ret.lowerMin(biggerInt{i: bigIntRsh(posX[0], y[1])}) 538 } 539 if posX[1] == nil { 540 ret.raiseMax(biggerInt{extra: +1}) 541 } else { 542 ret.raiseMax(biggerInt{i: bigIntRsh(posX[1], y[0])}) 543 } 544 } 545 546 return ret.toIntRange(), true 547} 548 549// And returns z = x & y. 550// 551// ok is false (and z will be IntRange{nil, nil}) if x or y contains at least 552// one negative value. Otherwise, ok is true. 553// 554// TODO: implement bit-wise operations (with tight bounds) on negative 555// integers. In that case, we could drop the "ok" return value. 556func (x IntRange) And(y IntRange) (z IntRange, ok bool) { 557 if x.Empty() || y.Empty() { 558 return empty(), true 559 } 560 if x.ContainsNegative() || y.ContainsNegative() { 561 return IntRange{}, false 562 } 563 564 zMax := (*big.Int)(nil) 565 if x[1] != nil { 566 if y[1] != nil { 567 zMax = x.andMax(y) 568 } else { 569 return IntRange{big.NewInt(0), x[1]}, true 570 } 571 } else { 572 if y[1] != nil { 573 return IntRange{big.NewInt(0), y[1]}, true 574 } else { 575 return IntRange{big.NewInt(0), nil}, true 576 } 577 } 578 579 // andMin(x, y) is ~orMax(~x, ~y). 580 notX := IntRange{ 581 big.NewInt(0).Not(x[1]), 582 big.NewInt(0).Not(x[0]), 583 } 584 notY := IntRange{ 585 big.NewInt(0).Not(y[1]), 586 big.NewInt(0).Not(y[0]), 587 } 588 zMin := notX.orMax(notY) 589 zMin.Not(zMin) 590 591 return IntRange{zMin, zMax}, true 592} 593 594// Or returns z = x | y. 595// 596// ok is false (and z will be IntRange{nil, nil}) if x or y contains at least 597// one negative value. Otherwise, ok is true. 598// 599// TODO: implement bit-wise operations (with tight bounds) on negative 600// integers. In that case, we could drop the "ok" return value. 601func (x IntRange) Or(y IntRange) (z IntRange, ok bool) { 602 if x.Empty() || y.Empty() { 603 return empty(), true 604 } 605 if x.ContainsNegative() || y.ContainsNegative() { 606 return IntRange{}, false 607 } 608 609 zMax := (*big.Int)(nil) 610 if x[1] != nil && y[1] != nil { 611 zMax = x.orMax(y) 612 } else { 613 // Keep zMax as nil, which means that (x | y) can be arbitrarily large. 614 // 615 // If the integers xx and yy are in the intervals x and y, then (xx | 616 // yy) is at least yy, since a bit-wise or can only turn bits on, and 617 // yy is at least y's lower bound, y[0]. 618 // 619 // Therefore, (z[0] >= x[0]) && (z[0] >= y[0]) is a necessary bound. 620 // The smaller of those is also a sufficient bound if that smaller 621 // value is contained in the other interval. For example, if both xx 622 // and yy can be x[0], then (x[0] | x[0]) is simply x[0]. 623 if x.ContainsInt(y[0]) { 624 return IntRange{y[0], nil}, true 625 } 626 if y.ContainsInt(x[0]) { 627 return IntRange{x[0], nil}, true 628 } 629 if x[1] == nil && y[1] == nil { 630 panic("unreachable") 631 } 632 633 // The two intervals are non-empty but don't overlap. Furthermore, 634 // exactly one of the two intervals have an infinite upper bound. 635 // Without loss of generality, assume that that interval is y. 636 // 637 // Therefore, (x[0] <= x[1]) && (x[1] < y[0]) && (y[1] == nil). 638 if x[1] == nil { 639 x, y = y, x 640 } 641 if x[1].Cmp(y[0]) >= 0 { 642 panic("unreachable") 643 } 644 645 // We've already calculated zMax: it is infinite. To calculate zMin, 646 // also known as z[0], replace the infinite upper bound y[1] with a 647 // finite value equal to right-filling all of y[0]'s bits. 648 y[1] = big.NewInt(0).Set(y[0]) 649 bitFillRight(y[1]) 650 } 651 652 // orMin(x, y) is ~andMax(~x, ~y). 653 notX := IntRange{ 654 big.NewInt(0).Not(x[1]), 655 big.NewInt(0).Not(x[0]), 656 } 657 notY := IntRange{ 658 big.NewInt(0).Not(y[1]), 659 big.NewInt(0).Not(y[0]), 660 } 661 zMin := notX.andMax(notY) 662 zMin.Not(zMin) 663 664 return IntRange{zMin, zMax}, true 665} 666 667// The andMax and orMax algorithms are tricky. 668// 669// First, some notation. Let x and y be intervals, and in math notation, denote 670// those intervals' bounds as [xMin, xMax] and [yMin, yMax]. In Go terms, x is 671// an IntRange, xMin is x[0], xMax is x[1], and likewise for y. In the 672// algorithm discussion below, we'll use square brackets only for denoting 673// intervals, not array indices, and so we'll say xMin instead of x[0]. 674// 675// xMin, xMax, yMin and yMax are all assumed to be finite (i.e. a non-nil 676// *big.Int) and non-negative. The caller is responsible for enforcing this. 677// 678// For a given range r, define maximal(r) to be the integers in r for which you 679// cannot flip any bits from 0 to 1 and have the result still be in r. Clearly 680// rMax is in maximal(r), but there are other elements as well -- for each bit 681// that is set in rMax, if you unset that bit, and set all bits to its right, 682// the result is also in maximal(r) as long as it is >= rMin (which is true iff 683// the bit is in bitFillRight(rMax & ~rMin). 684// 685// Clearly x.andMax(y) == maximal(x).andMax(maximal(y)) and x.orMax(y) == 686// maximal(x).orMax(maximal(y)) -- that is, we only need to consider the 687// maximal elements in each range. 688// 689// For orMax, the max is achieved by starting with xMax | yMax, and then 690// realizing that we can get a larger result by choosing the leftmost bit in 691// xMax & yMax (which we effectively have twice), flipping it to zero in either 692// of the inputs, and replacing all bits to its right with 1s. However, that 693// might end up with the input being below the minimum in its range, so instead 694// of considering all bits in xMax & yMax, we have to restrict to those that 695// are also set in either bitFillRight(xMax & ~xMin) or bitFillRight(yMax & 696// ~yMin). 697// 698// For andMax, we can again only consider the maximal elements. Here, we have 699// either yMax and the best maximal element from x, or xMax and the best 700// maximal element from y. For symmetry assume it's the former (though we must 701// actually check both). 702// 703// We take yMax, and then the maximal element from x that is chosen by flipping 704// the leftmost bit in xMax that will result in a number that is >= xMin and is 705// not also set in yMax. That is, the leftmost bit in bitFillRight(xMax & 706// ~xMin) & xMax & ~yMax. 707 708// andMax returns an exact solution for the maximum possible (xx & yy), for all 709// possible xx in x and yy in y. 710// 711// Algorithm: 712// // If the two intervals overlap, the result is the minimum of the two 713// // intervals' maxima. 714// // 715// // This overlaps code path is just an optimization. 716// if overlaps(x, y) { 717// return min(xMax, yMax) 718// } 719// xFlip = bitFillRight(bitFillRight(xMax & ~xMin) & xMax & ~yMax) 720// xResult = yMax & ((xMax & ~xFlip) | (xFlip >> 1)) 721// yFlip = bitFillRight(bitFillRight(yMax & ~yMin) & yMax & ~xMax) 722// yResult = xMax & ((yMax & ~yFlip) | (yFlip >> 1)) 723// return max(xResult, yResult) 724// 725// If xMin and yMin are both zero, the overlaps branch is taken. 726// 727// TODO: can this algorithm be simplified?? 728func (x IntRange) andMax(y IntRange) *big.Int { 729 // Check for overlap. 730 if (y[1].Cmp(x[0]) >= 0) && (x[1].Cmp(y[0]) >= 0) { 731 min := x[1] 732 if x[1].Cmp(y[1]) > 0 { 733 min = y[1] 734 } 735 return min 736 } 737 738 // Otherwise, x and y don't overlap. Four examples: 739 // - Example #0: x is [1, 3] and y is [ 4, 9], andMax is 3. 740 // - Example #1: x is [3, 4] and y is [ 5, 6], andMax is 4. 741 // - Example #2: x is [4, 5] and y is [ 6, 7], andMax is 5. 742 // - Example #3: x is [7, 7] and y is [12, 14], andMax is 6. 743 744 i := big.NewInt(0) 745 j := big.NewInt(0) 746 k := big.NewInt(0) 747 748 // Calculate xFlip and xResult. 749 { 750 // j = bitFillRight(xMax & ~xMin) 751 // 752 // For example #0, j = bfr(3 & ~1) = bfr(2) = 3. 753 // For example #1, j = bfr(4 & ~3) = bfr(4) = 7. 754 // For example #2, j = bfr(5 & ~4) = bfr(1) = 1. 755 // For example #3, j = bfr(7 & ~7) = bfr(0) = 0. 756 j.AndNot(x[1], x[0]) 757 bitFillRight(j) 758 759 // j = xFlip = bitFillRight(j & xMax & ~yMax) 760 // 761 // For example #0, j = bfr(3 & 3 & ~ 9) = bfr(2) = 3. 762 // For example #1, j = bfr(7 & 4 & ~ 6) = bfr(0) = 0. 763 // For example #2, j = bfr(1 & 5 & ~ 7) = bfr(0) = 0. 764 // For example #3, j = bfr(0 & 7 & ~15) = bfr(0) = 0. 765 j.And(j, x[1]) 766 j.AndNot(j, y[1]) 767 bitFillRight(j) 768 769 // i = xMax & ~xFlip 770 // 771 // For example #0, i = 3 & ~3 = 0. 772 // For example #1, i = 4 & ~0 = 4. 773 // For example #2, i = 5 & ~0 = 5. 774 // For example #3, i = 7 & ~0 = 7. 775 i.AndNot(x[1], j) 776 777 // j = xResult = yMax & (i | (xFlip >> 1)) 778 // 779 // For example #0, j = 9 & (0 | (3 >> 1)) = 1. 780 // For example #1, j = 6 & (4 | (0 >> 1)) = 4. 781 // For example #2, j = 7 & (5 | (0 >> 1)) = 5. 782 // For example #3, j = 14 & (7 | (0 >> 1)) = 6. 783 j.Rsh(j, 1) 784 j.Or(j, i) 785 j.And(j, y[1]) 786 } 787 788 // Calculate yFlip and yResult. 789 { 790 // k = bitFillRight(yMax & ~yMin) 791 // 792 // For example #0, k = bfr( 9 & ~ 4) = bfr(9) = 15. 793 // For example #1, k = bfr( 6 & ~ 5) = bfr(2) = 3. 794 // For example #2, k = bfr( 7 & ~ 6) = bfr(1) = 1. 795 // For example #3, k = bfr(14 & ~12) = bfr(2) = 3. 796 k.AndNot(y[1], y[0]) 797 bitFillRight(k) 798 799 // k = yFlip = bitFillRight(k & yMax & ~xMax) 800 // 801 // For example #0, k = bfr(15 & 9 & ~3) = bfr(8) = 15. 802 // For example #1, k = bfr( 3 & 6 & ~4) = bfr(2) = 3. 803 // For example #2, k = bfr( 1 & 14 & ~5) = bfr(0) = 0. 804 // For example #3, k = bfr( 3 & 7 & ~7) = bfr(0) = 0. 805 k.And(k, y[1]) 806 k.AndNot(k, x[1]) 807 bitFillRight(k) 808 809 // i = yMax & ~yFlip 810 // 811 // For example #0, i = 9 & ~15 = 0. 812 // For example #1, i = 6 & ~ 3 = 4. 813 // For example #2, i = 7 & ~ 0 = 7. 814 // For example #3, i = 14 & ~ 0 = 14. 815 i.AndNot(y[1], k) 816 817 // k = yResult = xMax & (i | (yFlip >> 1)) 818 // 819 // For example #0, k = 3 & ( 0 | (15 >> 1)) = 3. 820 // For example #1, k = 4 & ( 4 | ( 3 >> 1)) = 4. 821 // For example #2, k = 5 & ( 7 | ( 0 >> 1)) = 5. 822 // For example #3, k = 7 & (14 | ( 0 >> 1)) = 6. 823 k.Rsh(k, 1) 824 k.Or(k, i) 825 k.And(k, x[1]) 826 } 827 828 // return max(xResult, yResult) 829 // 830 // For example #0, return max(1, 3). 831 // For example #1, return max(4, 4). 832 // For example #2, return max(5, 5). 833 // For example #3, return max(6, 6). 834 if j.Cmp(k) < 0 { 835 return k 836 } 837 return j 838} 839 840// orMax returns an exact solution for the maximum possible (xx | yy), for all 841// possible xx in x and yy in y. 842// 843// Algorithm: 844// droppable = bitFillRight((xMax & ~xMin) | (yMax & ~yMin)) 845// available = xMax & yMax & droppable 846// return xMax | yMax | (bitFillRight(available) >> 1) 847// 848// If xMin and yMin are both zero, this simplifies to: 849// available = xMax & yMax 850// return xMax | yMax | (bitFillRight(available) >> 1) 851func (x IntRange) orMax(y IntRange) *big.Int { 852 if x[0].Sign() == 0 && y[0].Sign() == 0 { 853 i := big.NewInt(0) 854 i.And(x[1], y[1]) 855 bitFillRight(i) 856 i.Rsh(i, 1) 857 i.Or(i, x[1]) 858 i.Or(i, y[1]) 859 return i 860 } 861 862 // Four examples: 863 // - Example #0: x is [1, 3] and y is [ 4, 9], orMax is 11. 864 // - Example #1: x is [3, 4] and y is [ 5, 6], orMax is 7. 865 // - Example #2: x is [4, 5] and y is [ 6, 7], orMax is 7. 866 // - Example #3: x is [7, 7] and y is [12, 14], orMax is 15. 867 868 i := big.NewInt(0) 869 j := big.NewInt(0) 870 871 // j = droppable = bitFillRight((xMax & ~xMin) | (yMax & ~yMin)) 872 // 873 // For example #0, j = bfr((3 & ~1) | ( 9 & ~ 4)) = bfr(2 | 9) = 15. 874 // For example #1, j = bfr((4 & ~3) | ( 6 & ~ 5)) = bfr(4 | 2) = 7. 875 // For example #2, j = bfr((5 & ~4) | ( 7 & ~ 6)) = bfr(1 | 1) = 1. 876 // For example #3, j = bfr((7 & ~7) | (14 & ~12)) = bfr(0 | 2) = 3. 877 i.AndNot(x[1], x[0]) 878 j.AndNot(y[1], y[0]) 879 j.Or(j, i) 880 bitFillRight(j) 881 882 // j = available = xMax & yMax & j 883 // 884 // For example #0, j = 3 & 9 & 15 = 1. 885 // For example #1, j = 4 & 6 & 7 = 4. 886 // For example #2, j = 5 & 7 & 1 = 1. 887 // For example #3, j = 7 & 14 & 3 = 2. 888 j.And(j, x[1]) 889 j.And(j, y[1]) 890 891 // j = bitFillRight(j) >> 1 892 // 893 // For example #0, j = bfr(1) >> 1 = 0. 894 // For example #1, j = bfr(4) >> 1 = 3. 895 // For example #2, j = bfr(1) >> 1 = 0. 896 // For example #3, j = bfr(2) >> 1 = 1. 897 bitFillRight(j) 898 j.Rsh(j, 1) 899 900 // return xMax | yMax | j 901 // 902 // For example #0, return 3 | 9 | 0 = 11. 903 // For example #1, return 4 | 6 | 3 = 7. 904 // For example #2, return 5 | 7 | 0 = 7. 905 // For example #3, return 7 | 14 | 1 = 15. 906 j.Or(j, x[1]) 907 j.Or(j, y[1]) 908 return j 909} 910 911// bitFillRight modifies i to round up to the next power of 2 minus 1: 912// - If i is +0 then bitFillRight(i) sets i to 0. 913// - If i is +1 then bitFillRight(i) sets i to 1. 914// - If i is +2 then bitFillRight(i) sets i to 3. 915// - If i is +3 then bitFillRight(i) sets i to 3. 916// - If i is +4 then bitFillRight(i) sets i to 7. 917// - If i is +5 then bitFillRight(i) sets i to 7. 918// - If i is +6 then bitFillRight(i) sets i to 7. 919// - If i is +7 then bitFillRight(i) sets i to 7. 920// - If i is +8 then bitFillRight(i) sets i to 15. 921// - If i is +9 then bitFillRight(i) sets i to 15. 922// - Etc. 923func bitFillRight(i *big.Int) { 924 if s := i.Sign(); s < 0 { 925 panic("TODO: implement bit-wise operations on negative integers") 926 } else if s == 0 { 927 return 928 } 929 n := i.BitLen() 930 if n > 0xFFFF { 931 panic("interval: input is too large") 932 } 933 i.SetInt64(1) 934 i.Lsh(i, uint(n)) 935 i.Sub(i, one) 936} 937