11cb0ef41Sopenharmony_ci// Copyright 2021 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci// "Schoolbook" division. This is loosely based on Go's implementation
61cb0ef41Sopenharmony_ci// found at https://golang.org/src/math/big/nat.go, licensed as follows:
71cb0ef41Sopenharmony_ci//
81cb0ef41Sopenharmony_ci// Copyright 2009 The Go Authors. All rights reserved.
91cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style
101cb0ef41Sopenharmony_ci// license that can be found in the LICENSE file [1].
111cb0ef41Sopenharmony_ci//
121cb0ef41Sopenharmony_ci// [1] https://golang.org/LICENSE
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci#include <limits>
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci#include "src/bigint/bigint-internal.h"
171cb0ef41Sopenharmony_ci#include "src/bigint/digit-arithmetic.h"
181cb0ef41Sopenharmony_ci#include "src/bigint/div-helpers.h"
191cb0ef41Sopenharmony_ci#include "src/bigint/util.h"
201cb0ef41Sopenharmony_ci#include "src/bigint/vector-arithmetic.h"
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_cinamespace v8 {
231cb0ef41Sopenharmony_cinamespace bigint {
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci// Computes Q(uotient) and remainder for A/b, such that
261cb0ef41Sopenharmony_ci// Q = (A - remainder) / b, with 0 <= remainder < b.
271cb0ef41Sopenharmony_ci// If Q.len == 0, only the remainder will be returned.
281cb0ef41Sopenharmony_ci// Q may be the same as A for an in-place division.
291cb0ef41Sopenharmony_civoid ProcessorImpl::DivideSingle(RWDigits Q, digit_t* remainder, Digits A,
301cb0ef41Sopenharmony_ci                                 digit_t b) {
311cb0ef41Sopenharmony_ci  DCHECK(b != 0);
321cb0ef41Sopenharmony_ci  DCHECK(A.len() > 0);
331cb0ef41Sopenharmony_ci  *remainder = 0;
341cb0ef41Sopenharmony_ci  int length = A.len();
351cb0ef41Sopenharmony_ci  if (Q.len() != 0) {
361cb0ef41Sopenharmony_ci    if (A[length - 1] >= b) {
371cb0ef41Sopenharmony_ci      DCHECK(Q.len() >= A.len());
381cb0ef41Sopenharmony_ci      for (int i = length - 1; i >= 0; i--) {
391cb0ef41Sopenharmony_ci        Q[i] = digit_div(*remainder, A[i], b, remainder);
401cb0ef41Sopenharmony_ci      }
411cb0ef41Sopenharmony_ci      for (int i = length; i < Q.len(); i++) Q[i] = 0;
421cb0ef41Sopenharmony_ci    } else {
431cb0ef41Sopenharmony_ci      DCHECK(Q.len() >= A.len() - 1);
441cb0ef41Sopenharmony_ci      *remainder = A[length - 1];
451cb0ef41Sopenharmony_ci      for (int i = length - 2; i >= 0; i--) {
461cb0ef41Sopenharmony_ci        Q[i] = digit_div(*remainder, A[i], b, remainder);
471cb0ef41Sopenharmony_ci      }
481cb0ef41Sopenharmony_ci      for (int i = length - 1; i < Q.len(); i++) Q[i] = 0;
491cb0ef41Sopenharmony_ci    }
501cb0ef41Sopenharmony_ci  } else {
511cb0ef41Sopenharmony_ci    for (int i = length - 1; i >= 0; i--) {
521cb0ef41Sopenharmony_ci      digit_div(*remainder, A[i], b, remainder);
531cb0ef41Sopenharmony_ci    }
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci}
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci// Z += X. Returns the "carry" (0 or 1) after adding all of X's digits.
581cb0ef41Sopenharmony_ciinline digit_t InplaceAdd(RWDigits Z, Digits X) {
591cb0ef41Sopenharmony_ci  return AddAndReturnCarry(Z, Z, X);
601cb0ef41Sopenharmony_ci}
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci// Z -= X. Returns the "borrow" (0 or 1) after subtracting all of X's digits.
631cb0ef41Sopenharmony_ciinline digit_t InplaceSub(RWDigits Z, Digits X) {
641cb0ef41Sopenharmony_ci  return SubtractAndReturnBorrow(Z, Z, X);
651cb0ef41Sopenharmony_ci}
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci// Returns whether (factor1 * factor2) > (high << kDigitBits) + low.
681cb0ef41Sopenharmony_cibool ProductGreaterThan(digit_t factor1, digit_t factor2, digit_t high,
691cb0ef41Sopenharmony_ci                        digit_t low) {
701cb0ef41Sopenharmony_ci  digit_t result_high;
711cb0ef41Sopenharmony_ci  digit_t result_low = digit_mul(factor1, factor2, &result_high);
721cb0ef41Sopenharmony_ci  return result_high > high || (result_high == high && result_low > low);
731cb0ef41Sopenharmony_ci}
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci#if DEBUG
761cb0ef41Sopenharmony_cibool QLengthOK(Digits Q, Digits A, Digits B) {
771cb0ef41Sopenharmony_ci  // If A's top B.len digits are greater than or equal to B, then the division
781cb0ef41Sopenharmony_ci  // result will be greater than A.len - B.len, otherwise it will be that
791cb0ef41Sopenharmony_ci  // difference. Intuitively: 100/10 has 2 digits, 100/11 has 1.
801cb0ef41Sopenharmony_ci  if (GreaterThanOrEqual(Digits(A, A.len() - B.len(), B.len()), B)) {
811cb0ef41Sopenharmony_ci    return Q.len() >= A.len() - B.len() + 1;
821cb0ef41Sopenharmony_ci  }
831cb0ef41Sopenharmony_ci  return Q.len() >= A.len() - B.len();
841cb0ef41Sopenharmony_ci}
851cb0ef41Sopenharmony_ci#endif
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci// Computes Q(uotient) and R(emainder) for A/B, such that
881cb0ef41Sopenharmony_ci// Q = (A - R) / B, with 0 <= R < B.
891cb0ef41Sopenharmony_ci// Both Q and R are optional: callers that are only interested in one of them
901cb0ef41Sopenharmony_ci// can pass the other with len == 0.
911cb0ef41Sopenharmony_ci// If Q is present, its length must be at least A.len - B.len + 1.
921cb0ef41Sopenharmony_ci// If R is present, its length must be at least B.len.
931cb0ef41Sopenharmony_ci// See Knuth, Volume 2, section 4.3.1, Algorithm D.
941cb0ef41Sopenharmony_civoid ProcessorImpl::DivideSchoolbook(RWDigits Q, RWDigits R, Digits A,
951cb0ef41Sopenharmony_ci                                     Digits B) {
961cb0ef41Sopenharmony_ci  DCHECK(B.len() >= 2);        // Use DivideSingle otherwise.
971cb0ef41Sopenharmony_ci  DCHECK(A.len() >= B.len());  // No-op otherwise.
981cb0ef41Sopenharmony_ci  DCHECK(Q.len() == 0 || QLengthOK(Q, A, B));
991cb0ef41Sopenharmony_ci  DCHECK(R.len() == 0 || R.len() >= B.len());
1001cb0ef41Sopenharmony_ci  // The unusual variable names inside this function are consistent with
1011cb0ef41Sopenharmony_ci  // Knuth's book, as well as with Go's implementation of this algorithm.
1021cb0ef41Sopenharmony_ci  // Maintaining this consistency is probably more useful than trying to
1031cb0ef41Sopenharmony_ci  // come up with more descriptive names for them.
1041cb0ef41Sopenharmony_ci  const int n = B.len();
1051cb0ef41Sopenharmony_ci  const int m = A.len() - n;
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci  // In each iteration, {qhatv} holds {divisor} * {current quotient digit}.
1081cb0ef41Sopenharmony_ci  // "v" is the book's name for {divisor}, "qhat" the current quotient digit.
1091cb0ef41Sopenharmony_ci  ScratchDigits qhatv(n + 1);
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  // D1.
1121cb0ef41Sopenharmony_ci  // Left-shift inputs so that the divisor's MSB is set. This is necessary
1131cb0ef41Sopenharmony_ci  // to prevent the digit-wise divisions (see digit_div call below) from
1141cb0ef41Sopenharmony_ci  // overflowing (they take a two digits wide input, and return a one digit
1151cb0ef41Sopenharmony_ci  // result).
1161cb0ef41Sopenharmony_ci  ShiftedDigits b_normalized(B);
1171cb0ef41Sopenharmony_ci  B = b_normalized;
1181cb0ef41Sopenharmony_ci  // U holds the (continuously updated) remaining part of the dividend, which
1191cb0ef41Sopenharmony_ci  // eventually becomes the remainder.
1201cb0ef41Sopenharmony_ci  ScratchDigits U(A.len() + 1);
1211cb0ef41Sopenharmony_ci  LeftShift(U, A, b_normalized.shift());
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  // D2.
1241cb0ef41Sopenharmony_ci  // Iterate over the dividend's digits (like the "grad school" algorithm).
1251cb0ef41Sopenharmony_ci  // {vn1} is the divisor's most significant digit.
1261cb0ef41Sopenharmony_ci  digit_t vn1 = B[n - 1];
1271cb0ef41Sopenharmony_ci  for (int j = m; j >= 0; j--) {
1281cb0ef41Sopenharmony_ci    // D3.
1291cb0ef41Sopenharmony_ci    // Estimate the current iteration's quotient digit (see Knuth for details).
1301cb0ef41Sopenharmony_ci    // {qhat} is the current quotient digit.
1311cb0ef41Sopenharmony_ci    digit_t qhat = std::numeric_limits<digit_t>::max();
1321cb0ef41Sopenharmony_ci    // {ujn} is the dividend's most significant remaining digit.
1331cb0ef41Sopenharmony_ci    digit_t ujn = U[j + n];
1341cb0ef41Sopenharmony_ci    if (ujn != vn1) {
1351cb0ef41Sopenharmony_ci      // {rhat} is the current iteration's remainder.
1361cb0ef41Sopenharmony_ci      digit_t rhat = 0;
1371cb0ef41Sopenharmony_ci      // Estimate the current quotient digit by dividing the most significant
1381cb0ef41Sopenharmony_ci      // digits of dividend and divisor. The result will not be too small,
1391cb0ef41Sopenharmony_ci      // but could be a bit too large.
1401cb0ef41Sopenharmony_ci      qhat = digit_div(ujn, U[j + n - 1], vn1, &rhat);
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci      // Decrement the quotient estimate as needed by looking at the next
1431cb0ef41Sopenharmony_ci      // digit, i.e. by testing whether
1441cb0ef41Sopenharmony_ci      // qhat * v_{n-2} > (rhat << kDigitBits) + u_{j+n-2}.
1451cb0ef41Sopenharmony_ci      digit_t vn2 = B[n - 2];
1461cb0ef41Sopenharmony_ci      digit_t ujn2 = U[j + n - 2];
1471cb0ef41Sopenharmony_ci      while (ProductGreaterThan(qhat, vn2, rhat, ujn2)) {
1481cb0ef41Sopenharmony_ci        qhat--;
1491cb0ef41Sopenharmony_ci        digit_t prev_rhat = rhat;
1501cb0ef41Sopenharmony_ci        rhat += vn1;
1511cb0ef41Sopenharmony_ci        // v[n-1] >= 0, so this tests for overflow.
1521cb0ef41Sopenharmony_ci        if (rhat < prev_rhat) break;
1531cb0ef41Sopenharmony_ci      }
1541cb0ef41Sopenharmony_ci    }
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci    // D4.
1571cb0ef41Sopenharmony_ci    // Multiply the divisor with the current quotient digit, and subtract
1581cb0ef41Sopenharmony_ci    // it from the dividend. If there was "borrow", then the quotient digit
1591cb0ef41Sopenharmony_ci    // was one too high, so we must correct it and undo one subtraction of
1601cb0ef41Sopenharmony_ci    // the (shifted) divisor.
1611cb0ef41Sopenharmony_ci    if (qhat == 0) {
1621cb0ef41Sopenharmony_ci      qhatv.Clear();
1631cb0ef41Sopenharmony_ci    } else {
1641cb0ef41Sopenharmony_ci      MultiplySingle(qhatv, B, qhat);
1651cb0ef41Sopenharmony_ci    }
1661cb0ef41Sopenharmony_ci    digit_t c = InplaceSub(U + j, qhatv);
1671cb0ef41Sopenharmony_ci    if (c != 0) {
1681cb0ef41Sopenharmony_ci      c = InplaceAdd(U + j, B);
1691cb0ef41Sopenharmony_ci      U[j + n] = U[j + n] + c;
1701cb0ef41Sopenharmony_ci      qhat--;
1711cb0ef41Sopenharmony_ci    }
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci    if (Q.len() != 0) {
1741cb0ef41Sopenharmony_ci      if (j >= Q.len()) {
1751cb0ef41Sopenharmony_ci        DCHECK(qhat == 0);
1761cb0ef41Sopenharmony_ci      } else {
1771cb0ef41Sopenharmony_ci        Q[j] = qhat;
1781cb0ef41Sopenharmony_ci      }
1791cb0ef41Sopenharmony_ci    }
1801cb0ef41Sopenharmony_ci  }
1811cb0ef41Sopenharmony_ci  if (R.len() != 0) {
1821cb0ef41Sopenharmony_ci    RightShift(R, U, b_normalized.shift());
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci  // If Q has extra storage, clear it.
1851cb0ef41Sopenharmony_ci  for (int i = m + 1; i < Q.len(); i++) Q[i] = 0;
1861cb0ef41Sopenharmony_ci}
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci}  // namespace bigint
1891cb0ef41Sopenharmony_ci}  // namespace v8
190