goog.math.Long.prototype.div = function()

in asdoc/library/closure/goog/math/long.js [749:825]


goog.math.Long.prototype.div = function(other) {
  if (other.isZero()) {
    throw new Error('division by zero');
  }
  if (this.isNegative()) {
    if (this.equals(goog.math.Long.getMinValue())) {
      if (other.equals(goog.math.Long.getOne()) ||
          other.equals(goog.math.Long.getNegOne())) {
        return goog.math.Long.getMinValue();  // recall -MIN_VALUE == MIN_VALUE
      }
      if (other.equals(goog.math.Long.getMinValue())) {
        return goog.math.Long.getOne();
      }
      // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
      var halfThis = this.shiftRight(1);
      var approx = halfThis.div(other).shiftLeft(1);
      if (approx.equals(goog.math.Long.getZero())) {
        return other.isNegative() ? goog.math.Long.getOne() :
                                    goog.math.Long.getNegOne();
      }
      var rem = this.subtract(other.multiply(approx));
      var result = approx.add(rem.div(other));
      return result;
    }
    if (other.isNegative()) {
      return this.negate().div(other.negate());
    }
    return this.negate().div(other).negate();
  }
  if (this.isZero()) {
    return goog.math.Long.getZero();
  }
  if (other.isNegative()) {
    if (other.equals(goog.math.Long.getMinValue())) {
      return goog.math.Long.getZero();
    }
    return this.div(other.negate()).negate();
  }

  // Repeat the following until the remainder is less than other:  find a
  // floating-point that approximates remainder / other *from below*, add this
  // into the result, and subtract it from the remainder.  It is critical that
  // the approximate value is less than or equal to the real value so that the
  // remainder never becomes negative.
  var res = goog.math.Long.getZero();
  var rem = this;
  while (rem.greaterThanOrEqual(other)) {
    // Approximate the result of division. This may be a little greater or
    // smaller than the actual value.
    var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));

    // We will tweak the approximate result by changing it in the 48-th digit or
    // the smallest non-fractional digit, whichever is larger.
    var log2 = Math.ceil(Math.log(approx) / Math.LN2);
    var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);

    // Decrease the approximation until it is smaller than the remainder.  Note
    // that if it is too large, the product overflows and is negative.
    var approxRes = goog.math.Long.fromNumber(approx);
    var approxRem = approxRes.multiply(other);
    while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
      approx -= delta;
      approxRes = goog.math.Long.fromNumber(approx);
      approxRem = approxRes.multiply(other);
    }

    // We know the answer can't be zero... and actually, zero would cause
    // infinite recursion since we would make no progress.
    if (approxRes.isZero()) {
      approxRes = goog.math.Long.getOne();
    }

    res = res.add(approxRes);
    rem = rem.subtract(approxRem);
  }
  return res;
};