version 1.1.1.1, 2000/09/09 14:12:24 |
version 1.1.1.2, 2003/08/25 16:06:20 |
|
|
RELEASE. |
RELEASE. |
|
|
|
|
Copyright (C) 1993, 1994, 1995, 1996, 1999, 2000 Free Software Foundation, |
Copyright 1993, 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software |
Inc. |
Foundation, Inc. |
|
|
This file is part of the GNU MP Library. |
This file is part of the GNU MP Library. |
|
|
Line 31 MA 02111-1307, USA. */ |
|
Line 31 MA 02111-1307, USA. */ |
|
#include "gmp-impl.h" |
#include "gmp-impl.h" |
#include "longlong.h" |
#include "longlong.h" |
|
|
|
|
|
/* The size where udiv_qrnnd_preinv should be used rather than udiv_qrnnd, |
|
meaning the quotient size where that should happen, the quotient size |
|
being how many udiv divisions will be done. |
|
|
|
The default is to use preinv always, CPUs where this doesn't suit have |
|
tuned thresholds. Note in particular that preinv should certainly be |
|
used if that's the only division available (USE_PREINV_ALWAYS). */ |
|
|
|
#ifndef DIVREM_2_THRESHOLD |
|
#define DIVREM_2_THRESHOLD 0 |
|
#endif |
|
|
|
|
/* Divide num (NP/NSIZE) by den (DP/2) and write |
/* Divide num (NP/NSIZE) by den (DP/2) and write |
the NSIZE-2 least significant quotient limbs at QP |
the NSIZE-2 least significant quotient limbs at QP |
and the 2 long remainder at NP. If QEXTRA_LIMBS is |
and the 2 long remainder at NP. If QEXTRA_LIMBS is |
Line 48 MA 02111-1307, USA. */ |
|
Line 62 MA 02111-1307, USA. */ |
|
3. NSIZE >= 2, even if QEXTRA_LIMBS is non-zero. */ |
3. NSIZE >= 2, even if QEXTRA_LIMBS is non-zero. */ |
|
|
mp_limb_t |
mp_limb_t |
#if __STDC__ |
|
mpn_divrem_2 (mp_ptr qp, mp_size_t qxn, |
mpn_divrem_2 (mp_ptr qp, mp_size_t qxn, |
mp_ptr np, mp_size_t nsize, |
mp_ptr np, mp_size_t nn, |
mp_srcptr dp) |
mp_srcptr dp) |
#else |
|
mpn_divrem_2 (qp, qxn, np, nsize, dp) |
|
mp_ptr qp; |
|
mp_size_t qxn; |
|
mp_ptr np; |
|
mp_size_t nsize; |
|
mp_srcptr dp; |
|
#endif |
|
{ |
{ |
mp_limb_t most_significant_q_limb = 0; |
mp_limb_t most_significant_q_limb = 0; |
mp_size_t i; |
mp_size_t i; |
mp_limb_t n1, n0, n2; |
mp_limb_t n1, n0, n2; |
mp_limb_t d1, d0; |
mp_limb_t d1, d0; |
mp_limb_t d1inv; |
mp_limb_t d1inv; |
int have_preinv; |
int use_preinv; |
|
|
np += nsize - 2; |
ASSERT (nn >= 2); |
|
ASSERT (qxn >= 0); |
|
ASSERT (dp[1] & GMP_NUMB_HIGHBIT); |
|
ASSERT (! MPN_OVERLAP_P (qp, nn-2+qxn, np, nn) || qp+2 >= np); |
|
ASSERT_MPN (np, nn); |
|
ASSERT_MPN (dp, 2); |
|
|
|
np += nn - 2; |
d1 = dp[1]; |
d1 = dp[1]; |
d0 = dp[0]; |
d0 = dp[0]; |
n1 = np[1]; |
n1 = np[1]; |
Line 76 mpn_divrem_2 (qp, qxn, np, nsize, dp) |
|
Line 88 mpn_divrem_2 (qp, qxn, np, nsize, dp) |
|
|
|
if (n1 >= d1 && (n1 > d1 || n0 >= d0)) |
if (n1 >= d1 && (n1 > d1 || n0 >= d0)) |
{ |
{ |
|
#if GMP_NAIL_BITS == 0 |
sub_ddmmss (n1, n0, n1, n0, d1, d0); |
sub_ddmmss (n1, n0, n1, n0, d1, d0); |
|
#else |
|
n0 = n0 - d0; |
|
n1 = n1 - d1 - (n0 >> GMP_LIMB_BITS - 1); |
|
n0 &= GMP_NUMB_MASK; |
|
#endif |
most_significant_q_limb = 1; |
most_significant_q_limb = 1; |
} |
} |
|
|
/* If multiplication is much faster than division, preinvert the most |
use_preinv = ABOVE_THRESHOLD (qxn + nn - 2, DIVREM_2_THRESHOLD); |
significant divisor limb before entering the loop. */ |
if (use_preinv) |
if (UDIV_TIME > 2 * UMUL_TIME + 6) |
invert_limb (d1inv, d1); |
{ |
|
have_preinv = 0; |
|
if ((UDIV_TIME - (2 * UMUL_TIME + 6)) * (nsize - 2) > UDIV_TIME) |
|
{ |
|
invert_limb (d1inv, d1); |
|
have_preinv = 1; |
|
} |
|
} |
|
|
|
for (i = qxn + nsize - 2 - 1; i >= 0; i--) |
for (i = qxn + nn - 2 - 1; i >= 0; i--) |
{ |
{ |
mp_limb_t q; |
mp_limb_t q; |
mp_limb_t r; |
mp_limb_t r; |
Line 104 mpn_divrem_2 (qp, qxn, np, nsize, dp) |
|
Line 114 mpn_divrem_2 (qp, qxn, np, nsize, dp) |
|
|
|
if (n1 == d1) |
if (n1 == d1) |
{ |
{ |
/* Q should be either 111..111 or 111..110. Need special treatment |
/* Q should be either 111..111 or 111..110. Need special handling |
of this rare case as normal division would give overflow. */ |
of this rare case as normal division would give overflow. */ |
q = ~(mp_limb_t) 0; |
q = GMP_NUMB_MASK; |
|
|
r = n0 + d1; |
r = (n0 + d1) & GMP_NUMB_MASK; |
if (r < d1) /* Carry in the addition? */ |
if (r < d1) /* Carry in the addition? */ |
{ |
{ |
|
#if GMP_NAIL_BITS == 0 |
add_ssaaaa (n1, n0, r - d0, np[0], 0, d0); |
add_ssaaaa (n1, n0, r - d0, np[0], 0, d0); |
|
#else |
|
n0 = np[0] + d0; |
|
n1 = (r - d0 + (n0 >> GMP_NUMB_BITS)) & GMP_NUMB_MASK; |
|
n0 &= GMP_NUMB_MASK; |
|
#endif |
qp[i] = q; |
qp[i] = q; |
continue; |
continue; |
} |
} |
n1 = d0 - (d0 != 0); |
n1 = d0 - (d0 != 0); |
n0 = -d0; |
n0 = -d0 & GMP_NUMB_MASK; |
} |
} |
else |
else |
{ |
{ |
if (UDIV_TIME > 2 * UMUL_TIME + 6 && have_preinv) |
if (use_preinv) |
udiv_qrnnd_preinv (q, r, n1, n0, d1, d1inv); |
udiv_qrnnd_preinv (q, r, n1, n0, d1, d1inv); |
else |
else |
udiv_qrnnd (q, r, n1, n0, d1); |
udiv_qrnnd (q, r, n1, n0 << GMP_NAIL_BITS, d1 << GMP_NAIL_BITS); |
umul_ppmm (n1, n0, d0, q); |
r >>= GMP_NAIL_BITS; |
|
umul_ppmm (n1, n0, d0, q << GMP_NAIL_BITS); |
|
n0 >>= GMP_NAIL_BITS; |
} |
} |
|
|
n2 = np[0]; |
n2 = np[0]; |
Line 135 mpn_divrem_2 (qp, qxn, np, nsize, dp) |
|
Line 153 mpn_divrem_2 (qp, qxn, np, nsize, dp) |
|
/* The estimated Q was too large. */ |
/* The estimated Q was too large. */ |
q--; |
q--; |
|
|
|
#if GMP_NAIL_BITS == 0 |
sub_ddmmss (n1, n0, n1, n0, 0, d0); |
sub_ddmmss (n1, n0, n1, n0, 0, d0); |
|
#else |
|
n0 = n0 - d0; |
|
n1 = n1 - (n0 >> GMP_LIMB_BITS - 1); |
|
n0 &= GMP_NUMB_MASK; |
|
#endif |
r += d1; |
r += d1; |
if (r >= d1) /* If not carry, test Q again. */ |
if (r >= d1) /* If not carry, test Q again. */ |
goto q_test; |
goto q_test; |
} |
} |
|
|
qp[i] = q; |
qp[i] = q; |
|
#if GMP_NAIL_BITS == 0 |
sub_ddmmss (n1, n0, r, n2, n1, n0); |
sub_ddmmss (n1, n0, r, n2, n1, n0); |
|
#else |
|
n0 = n2 - n0; |
|
n1 = r - n1 - (n0 >> GMP_LIMB_BITS - 1); |
|
n0 &= GMP_NUMB_MASK; |
|
#endif |
} |
} |
np[1] = n1; |
np[1] = n1; |
np[0] = n0; |
np[0] = n0; |