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