public static int[] divideMultiPrecision(int[] dividend, int[] divisor,
      int[] quotient) {
    final int dividendLength = arrayValidLength(dividend);
    final int divisorLength = arrayValidLength(divisor);
    Arrays.fill(quotient, 0);

    // Remainder := Dividend
    int[] remainder = new int[dividend.length + 1];
    System.arraycopy(dividend, 0, remainder, 0, dividend.length);
    remainder[remainder.length - 1] = 0;

    if (divisorLength == 0) {
      throwZeroDivisionException();
    }
    if (dividendLength < divisorLength) {
      return remainder;
    }
    if (divisorLength == 1) {
      int rem = divideMultiPrecision(remainder, divisor[0]);
      System.arraycopy(remainder, 0, quotient, 0, quotient.length);
      Arrays.fill(remainder, 0);
      remainder[0] = rem;
      return remainder;
    }

    // Knuth, "The Art of Computer Programming", 3rd edition, vol.II, Alg.D,
    // pg 272
    // D1. Normalize so high digit of D >= BASE/2 - that guarantee
    // that QH will not be too far from the correct digit later in D3
    int d1 = (int) (BASE / ((divisor[divisorLength - 1] & LONG_MASK) + 1L));
    if (d1 > 1) {

      // We are modifying divisor here, so make a local copy.
      int[] newDivisor = new int[divisorLength];
      System.arraycopy(divisor, 0, newDivisor, 0, divisorLength);
      multiplyMultiPrecision(newDivisor, d1);
      divisor = newDivisor;
      multiplyMultiPrecision(remainder, d1);
    }

    // only 32bits, but long to behave as unsigned
    long dHigh = (divisor[divisorLength - 1] & LONG_MASK);
    long dLow = (divisor[divisorLength - 2] & LONG_MASK);

    // D2 already done - iulRindex initialized before normalization of R.
    // D3-D7. Loop on iulRindex - obtaining digits one-by-one, as "in paper"
    for (int rIndex = remainder.length - 1; rIndex >= divisorLength; --rIndex) {

      // D3. Calculate Q hat - estimation of the next digit
      long accum = combineInts(remainder[rIndex - 1], remainder[rIndex]);
      int qhat;
      if (dHigh == (remainder[rIndex] & LONG_MASK)) {
        qhat = (int) (BASE - 1);
      } else {
        qhat = (int) divideUnsignedLong(accum, dHigh);
      }

      int rhat = (int) (accum - (qhat & LONG_MASK) * dHigh);
      while (compareUnsignedLong(dLow * (qhat & LONG_MASK),
          combineInts(remainder[rIndex - 2], rhat)) > 0) {
        qhat--;
        if ((rhat & LONG_MASK) >= -((int) dHigh)) {
          break;
        }
        rhat += dHigh;
      }

      // D4. Multiply and subtract: (some digits of) R -= D * QH
      long dwlMulAccum = 0;
      accum = BASE;
      int iulRwork = rIndex - divisorLength;
      for (int dIndex = 0; dIndex < divisorLength; dIndex++, iulRwork++) {
        dwlMulAccum += (qhat & LONG_MASK) * (divisor[dIndex] & LONG_MASK);
        accum += (remainder[iulRwork] & LONG_MASK)
            - (extractLowInt(dwlMulAccum) & LONG_MASK);
        dwlMulAccum = (extractHiInt(dwlMulAccum) & LONG_MASK);
        remainder[iulRwork] = extractLowInt(accum);
        accum = (extractHiInt(accum) & LONG_MASK) + BASE - 1;
      }
      accum += (remainder[iulRwork] & LONG_MASK) - dwlMulAccum;
      remainder[iulRwork] = extractLowInt(accum);
      quotient[rIndex - divisorLength] = qhat;

      // D5. Test remainder. Carry indicates result<0, therefore QH 1 too
      // large
      if (extractHiInt(accum) == 0) {

        // D6. Add back - probability is 2**(-31). R += D. Q[digit] -= 1
        quotient[rIndex - divisorLength] = qhat - 1;
        int carry = 0;
        int dIndex = 0;
        for (iulRwork = rIndex - divisorLength; dIndex < divisorLength; dIndex++, iulRwork++) {
          long accum2 = (divisor[dIndex] & LONG_MASK)
              + (remainder[iulRwork] & LONG_MASK) + (carry & LONG_MASK);
          carry = extractHiInt(accum2);
          remainder[iulRwork] = extractLowInt(accum2);
        }
        remainder[iulRwork] += carry;
      }
    }

    // D8. Unnormalize: Divide R to get result
    if (d1 > 1) {
      divideMultiPrecision(remainder, d1);
    }

    return remainder;
  }
Multi-precision divide. dividend and divisor not changed. Assumes that
there is enough room in quotient for results. Drawbacks of this
implementation: 1) Need one extra super-digit in R 2) As it modifies D
during work, then it restores it back (this is necessary because the caller
doesn't expect D to change) 3) Always get Q and R - if R is unnecessary,
can be slightly faster.

@param dividend
         dividend. in.
@param divisor
         divisor. in.
@param quotient
         quotient. out.
@return remainder
common/src/java/org/apache/hadoop/hive/common/type/SqlMathUtil.java