private void shiftRightDestructive(int wordShifts, int bitShiftsInWord,
      boolean roundUp) {
    if (wordShifts == 0 && bitShiftsInWord == 0) {
      return;
    }

    assert (wordShifts >= 0);
    assert (bitShiftsInWord >= 0);
    assert (bitShiftsInWord < 32);
    if (wordShifts >= 4) {
      zeroClear();
      return;
    }

    final int shiftRestore = 32 - bitShiftsInWord;

    // check this because "123 << 32" will be 123.
    final boolean noRestore = bitShiftsInWord == 0;
    final int roundCarryNoRestoreMask = 1 << 31;
    final int roundCarryMask = (1 << (bitShiftsInWord - 1));
    boolean roundCarry;
    int z0 = 0, z1 = 0, z2 = 0, z3 = 0;

    switch (wordShifts) {
    case 3:
      roundCarry = (noRestore ? (this.v[2] & roundCarryNoRestoreMask)
          : (this.v[3] & roundCarryMask)) != 0;
      z0 = this.v[3] >>> bitShiftsInWord;
      break;
    case 2:
      roundCarry = (noRestore ? (this.v[1] & roundCarryNoRestoreMask)
          : (this.v[2] & roundCarryMask)) != 0;
      z1 = this.v[3] >>> bitShiftsInWord;
      z0 = (noRestore ? 0 : this.v[3] << shiftRestore)
          | (this.v[2] >>> bitShiftsInWord);
      break;
    case 1:
      roundCarry = (noRestore ? (this.v[0] & roundCarryNoRestoreMask)
          : (this.v[1] & roundCarryMask)) != 0;
      z2 = this.v[3] >>> bitShiftsInWord;
      z1 = (noRestore ? 0 : this.v[3] << shiftRestore)
          | (this.v[2] >>> bitShiftsInWord);
      z0 = (noRestore ? 0 : this.v[2] << shiftRestore)
          | (this.v[1] >>> bitShiftsInWord);
      break;
    case 0:
      roundCarry = (noRestore ? 0 : (this.v[0] & roundCarryMask)) != 0;
      z3 = this.v[3] >>> bitShiftsInWord;
      z2 = (noRestore ? 0 : this.v[3] << shiftRestore)
          | (this.v[2] >>> bitShiftsInWord);
      z1 = (noRestore ? 0 : this.v[2] << shiftRestore)
          | (this.v[1] >>> bitShiftsInWord);
      z0 = (noRestore ? 0 : this.v[1] << shiftRestore)
          | (this.v[0] >>> bitShiftsInWord);
      break;
    default:
      assert (false);
      throw new RuntimeException();
    }

    update(z0, z1, z2, z3);

    // round up
    if (roundUp && roundCarry) {
      incrementDestructive();
    }
  }
This version returns the result as a new object, not modifying the give
objects.

@param bits
         the number of bits. must be positive
@return operation result as a new object
common/src/java/org/apache/hadoop/hive/common/type/UnsignedInt128.java