+++ /dev/null
-/* mpn_tdiv_qr -- Divide the numerator (np,nn) by the denominator (dp,dn) and
- write the nn-dn+1 quotient limbs at qp and the dn remainder limbs at rp. If
- qxn is non-zero, generate that many fraction limbs and append them after the
- other quotient limbs, and update the remainder accordningly. The input
- operands are unaffected.
-
- Preconditions:
- 1. The most significant limb of of the divisor must be non-zero.
- 2. No argument overlap is permitted. (??? relax this ???)
- 3. nn >= dn, even if qxn is non-zero. (??? relax this ???)
-
- The time complexity of this is O(qn*qn+M(dn,qn)), where M(m,n) is the time
- complexity of multiplication.
-
-Copyright (C) 1997, 2000 Free Software Foundation, Inc.
-
-This file is part of the GNU MP Library.
-
-The GNU MP Library is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or (at your
-option) any later version.
-
-The GNU MP Library is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with the GNU MP Library; see the file COPYING.LIB. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-MA 02111-1307, USA. */
-
-#include "gmp.h"
-#include "gmp-impl.h"
-#include "longlong.h"
-
-#ifndef BZ_THRESHOLD
-#define BZ_THRESHOLD (7 * KARATSUBA_MUL_THRESHOLD)
-#endif
-
-/* Extract the middle limb from ((h,,l) << cnt) */
-#define SHL(h,l,cnt) \
- ((h << cnt) | ((l >> 1) >> ((~cnt) & (BITS_PER_MP_LIMB - 1))))
-
-void
-#if __STDC__
-mpn_tdiv_qr (mp_ptr qp, mp_ptr rp, mp_size_t qxn,
- mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
-#else
-mpn_tdiv_qr (qp, rp, qxn, np, nn, dp, dn)
- mp_ptr qp;
- mp_ptr rp;
- mp_size_t qxn;
- mp_srcptr np;
- mp_size_t nn;
- mp_srcptr dp;
- mp_size_t dn;
-#endif
-{
- /* FIXME:
- 1. qxn
- 2. pass allocated storage in additional parameter?
- */
- if (qxn != 0)
- abort ();
-
- switch (dn)
- {
- case 0:
- DIVIDE_BY_ZERO;
-
- case 1:
- {
- rp[0] = mpn_divmod_1 (qp, np, nn, dp[0]);
- return;
- }
-
- case 2:
- {
- int cnt;
- mp_ptr n2p, d2p;
- mp_limb_t qhl, cy;
- TMP_DECL (marker);
- TMP_MARK (marker);
- count_leading_zeros (cnt, dp[dn - 1]);
- if (cnt != 0)
- {
- d2p = (mp_ptr) TMP_ALLOC (dn * BYTES_PER_MP_LIMB);
- mpn_lshift (d2p, dp, dn, cnt);
- n2p = (mp_ptr) TMP_ALLOC ((nn + 1) * BYTES_PER_MP_LIMB);
- cy = mpn_lshift (n2p, np, nn, cnt);
- n2p[nn] = cy;
- qhl = mpn_divrem_2 (qp, 0L, n2p, nn + (cy != 0), d2p);
- if (cy == 0)
- qp[nn - 2] = qhl; /* always store nn-dn+1 quotient limbs */
- }
- else
- {
- d2p = (mp_ptr) dp;
- n2p = (mp_ptr) TMP_ALLOC (nn * BYTES_PER_MP_LIMB);
- MPN_COPY (n2p, np, nn);
- qhl = mpn_divrem_2 (qp, 0L, n2p, nn, d2p);
- qp[nn - 2] = qhl; /* always store nn-dn+1 quotient limbs */
- }
-
- if (cnt != 0)
- mpn_rshift (rp, n2p, dn, cnt);
- else
- MPN_COPY (rp, n2p, dn);
- TMP_FREE (marker);
- return;
- }
-
- default:
- {
- int adjust;
- TMP_DECL (marker);
- TMP_MARK (marker);
- adjust = np[nn - 1] >= dp[dn - 1]; /* conservative tests for quotient size */
- if (nn + adjust >= 2 * dn)
- {
- mp_ptr n2p, d2p;
- mp_limb_t cy;
- int cnt;
- count_leading_zeros (cnt, dp[dn - 1]);
-
- qp[nn - dn] = 0; /* zero high quotient limb */
- if (cnt != 0) /* normalize divisor if needed */
- {
- d2p = (mp_ptr) TMP_ALLOC (dn * BYTES_PER_MP_LIMB);
- mpn_lshift (d2p, dp, dn, cnt);
- n2p = (mp_ptr) TMP_ALLOC ((nn + 1) * BYTES_PER_MP_LIMB);
- cy = mpn_lshift (n2p, np, nn, cnt);
- n2p[nn] = cy;
- nn += adjust;
- }
- else
- {
- d2p = (mp_ptr) dp;
- n2p = (mp_ptr) TMP_ALLOC ((nn + 1) * BYTES_PER_MP_LIMB);
- MPN_COPY (n2p, np, nn);
- n2p[nn] = 0;
- nn += adjust;
- }
-
- if (dn == 2)
- mpn_divrem_2 (qp, 0L, n2p, nn, d2p);
- else if (dn < BZ_THRESHOLD)
- mpn_sb_divrem_mn (qp, n2p, nn, d2p, dn);
- else
- {
- /* Perform 2*dn / dn limb divisions as long as the limbs
- in np last. */
- mp_ptr q2p = qp + nn - 2 * dn;
- n2p += nn - 2 * dn;
- mpn_bz_divrem_n (q2p, n2p, d2p, dn);
- nn -= dn;
- while (nn >= 2 * dn)
- {
- mp_limb_t c;
- q2p -= dn; n2p -= dn;
- c = mpn_bz_divrem_n (q2p, n2p, d2p, dn);
- ASSERT_ALWAYS (c == 0);
- nn -= dn;
- }
-
- if (nn != dn)
- {
- n2p -= nn - dn;
- /* In theory, we could fall out to the cute code below
- since we now have exactly the situation that code
- is designed to handle. We botch this badly and call
- the basic mpn_sb_divrem_mn! */
- if (dn == 2)
- mpn_divrem_2 (qp, 0L, n2p, nn, d2p);
- else
- mpn_sb_divrem_mn (qp, n2p, nn, d2p, dn);
- }
- }
-
-
- if (cnt != 0)
- mpn_rshift (rp, n2p, dn, cnt);
- else
- MPN_COPY (rp, n2p, dn);
- TMP_FREE (marker);
- return;
- }
-
- /* When we come here, the numerator/partial remainder is less
- than twice the size of the denominator. */
-
- {
- /* Problem:
-
- Divide a numerator N with nn limbs by a denominator D with dn
- limbs forming a quotient of nn-dn+1 limbs. When qn is small
- compared to dn, conventional division algorithms perform poorly.
- We want an algorithm that has an expected running time that is
- dependent only on qn. It is assumed that the most significant
- limb of the numerator is smaller than the most significant limb
- of the denominator.
-
- Algorithm (very informally stated):
-
- 1) Divide the 2 x qn most significant limbs from the numerator
- by the qn most significant limbs from the denominator. Call
- the result qest. This is either the correct quotient, but
- might be 1 or 2 too large. Compute the remainder from the
- division. (This step is implemented by a mpn_divrem call.)
-
- 2) Is the most significant limb from the remainder < p, where p
- is the product of the most significant limb from the quotient
- and the next(d). (Next(d) denotes the next ignored limb from
- the denominator.) If it is, decrement qest, and adjust the
- remainder accordingly.
-
- 3) Is the remainder >= qest? If it is, qest is the desired
- quotient. The algorithm terminates.
-
- 4) Subtract qest x next(d) from the remainder. If there is
- borrow out, decrement qest, and adjust the remainder
- accordingly.
-
- 5) Skip one word from the denominator (i.e., let next(d) denote
- the next less significant limb. */
-
- mp_size_t qn;
- mp_ptr n2p, d2p;
- mp_ptr tp;
- mp_limb_t cy;
- mp_size_t in, rn;
- mp_limb_t quotient_too_large;
- int cnt;
-
- qn = nn - dn;
- qp[qn] = 0; /* zero high quotient limb */
- qn += adjust; /* qn cannot become bigger */
-
- if (qn == 0)
- {
- MPN_COPY (rp, np, dn);
- TMP_FREE (marker);
- return;
- }
-
- in = dn - qn; /* (at least partially) ignored # of limbs in ops */
- /* Normalize denominator by shifting it to the left such that its
- most significant bit is set. Then shift the numerator the same
- amount, to mathematically preserve quotient. */
- count_leading_zeros (cnt, dp[dn - 1]);
- if (cnt != 0)
- {
- d2p = (mp_ptr) TMP_ALLOC (qn * BYTES_PER_MP_LIMB);
-
- mpn_lshift (d2p, dp + in, qn, cnt);
- d2p[0] |= dp[in - 1] >> (BITS_PER_MP_LIMB - cnt);
-
- n2p = (mp_ptr) TMP_ALLOC ((2 * qn + 1) * BYTES_PER_MP_LIMB);
- cy = mpn_lshift (n2p, np + nn - 2 * qn, 2 * qn, cnt);
- if (adjust)
- {
- n2p[2 * qn] = cy;
- n2p++;
- }
- else
- {
- n2p[0] |= np[nn - 2 * qn - 1] >> (BITS_PER_MP_LIMB - cnt);
- }
- }
- else
- {
- d2p = (mp_ptr) dp + in;
-
- n2p = (mp_ptr) TMP_ALLOC ((2 * qn + 1) * BYTES_PER_MP_LIMB);
- MPN_COPY (n2p, np + nn - 2 * qn, 2 * qn);
- if (adjust)
- {
- n2p[2 * qn] = 0;
- n2p++;
- }
- }
-
- /* Get an approximate quotient using the extracted operands. */
- if (qn == 1)
- {
- mp_limb_t q0, r0;
- mp_limb_t gcc272bug_n1, gcc272bug_n0, gcc272bug_d0;
- /* Due to a gcc 2.7.2.3 reload pass bug, we have to use some
- temps here. This doesn't hurt code quality on any machines
- so we do it unconditionally. */
- gcc272bug_n1 = n2p[1];
- gcc272bug_n0 = n2p[0];
- gcc272bug_d0 = d2p[0];
- udiv_qrnnd (q0, r0, gcc272bug_n1, gcc272bug_n0, gcc272bug_d0);
- n2p[0] = r0;
- qp[0] = q0;
- }
- else if (qn == 2)
- mpn_divrem_2 (qp, 0L, n2p, 4L, d2p);
- else if (qn < BZ_THRESHOLD)
- mpn_sb_divrem_mn (qp, n2p, qn * 2, d2p, qn);
- else
- mpn_bz_divrem_n (qp, n2p, d2p, qn);
-
- rn = qn;
- /* Multiply the first ignored divisor limb by the most significant
- quotient limb. If that product is > the partial remainder's
- most significant limb, we know the quotient is too large. This
- test quickly catches most cases where the quotient is too large;
- it catches all cases where the quotient is 2 too large. */
- {
- mp_limb_t dl, x;
- mp_limb_t h, l;
-
- if (in - 2 < 0)
- dl = 0;
- else
- dl = dp[in - 2];
-
- x = SHL (dp[in - 1], dl, cnt);
- umul_ppmm (h, l, x, qp[qn - 1]);
-
- if (n2p[qn - 1] < h)
- {
- mp_limb_t cy;
-
- mpn_decr_u (qp, (mp_limb_t) 1);
- cy = mpn_add_n (n2p, n2p, d2p, qn);
- if (cy)
- {
- /* The partial remainder is safely large. */
- n2p[qn] = cy;
- ++rn;
- }
- }
- }
-
- quotient_too_large = 0;
- if (cnt != 0)
- {
- mp_limb_t cy1, cy2;
-
- /* Append partially used numerator limb to partial remainder. */
- cy1 = mpn_lshift (n2p, n2p, rn, BITS_PER_MP_LIMB - cnt);
- n2p[0] |= np[in - 1] & (~(mp_limb_t) 0 >> cnt);
-
- /* Update partial remainder with partially used divisor limb. */
- cy2 = mpn_submul_1 (n2p, qp, qn, dp[in - 1] & (~(mp_limb_t) 0 >> cnt));
- if (qn != rn)
- {
- if (n2p[qn] < cy2)
- abort ();
- n2p[qn] -= cy2;
- }
- else
- {
- n2p[qn] = cy1 - cy2;
-
- quotient_too_large = (cy1 < cy2);
- ++rn;
- }
- --in;
- }
- /* True: partial remainder now is neutral, i.e., it is not shifted up. */
-
- tp = (mp_ptr) TMP_ALLOC (dn * BYTES_PER_MP_LIMB);
-
- if (in < qn)
- {
- if (in == 0)
- {
- MPN_COPY (rp, n2p, rn);
- if (rn != dn)
- abort ();
- goto foo;
- }
- mpn_mul (tp, qp, qn, dp, in);
- }
- else
- mpn_mul (tp, dp, in, qp, qn);
-
- cy = mpn_sub (n2p, n2p, rn, tp + in, qn);
- MPN_COPY (rp + in, n2p, dn - in);
- quotient_too_large |= cy;
- cy = mpn_sub_n (rp, np, tp, in);
- cy = mpn_sub_1 (rp + in, rp + in, rn, cy);
- quotient_too_large |= cy;
- foo:
- if (quotient_too_large)
- {
- mpn_decr_u (qp, (mp_limb_t) 1);
- mpn_add_n (rp, rp, dp, dn);
- }
- }
- TMP_FREE (marker);
- return;
- }
- }
-}