YoushouldhavereceivedcopiesoftheGNUGeneralPublicLicenseandthe GNULesserGeneralPublicLicensealongwiththeGNUMPLibrary.Ifnot,
see https://www.gnu.org/licenses/. */
#ifdef STAT #undef STAT #define STAT(x) x #else #define STAT(x) #endif
#include <stdlib.h> /* for NULL */ #include"gmp-impl.h"
/* FIXME: The MU_DIV_QR_SKEW_THRESHOLD was not analysed properly. It gives a speedupaccordingtooldmeasurements,butdoesthedecisionmechanism reallymakesense?Itseemlikethequotientbetweendnandqnmightbe
what we really should be checking. */ #ifndef MU_DIV_QR_SKEW_THRESHOLD #define MU_DIV_QR_SKEW_THRESHOLD 100 #endif
/* Compute the inverse size. */
in = mpn_mu_div_qr_choose_in (qn, dn, 0);
ASSERT (in <= dn);
#if1 /* This alternative inverse computation method gets slightly more accurate results.FIXMEs:(1)Tempallocationneedsnotanalysed(2)itchfunction
not adapted (3) mpn_invertappr scratch needs not met. */
ip = scratch;
tp = scratch + in + 1;
/* compute an approximate inverse on (in+1) limbs */ if (dn == in)
{
MPN_COPY (tp + 1, dp, in);
tp[0] = 1;
mpn_invertappr (ip, tp, in + 1, tp + in + 1);
MPN_COPY_INCR (ip, ip + 1, in);
} else
{
cy = mpn_add_1 (tp, dp + dn - (in + 1), in + 1, 1); if (UNLIKELY (cy != 0))
MPN_ZERO (ip, in); else
{
mpn_invertappr (ip, tp, in + 1, tp + in + 1);
MPN_COPY_INCR (ip, ip + 1, in);
}
} #else /* This older inverse computation method gets slightly worse results than the
one above. */
ip = scratch;
tp = scratch + in;
/* Compute inverse of D to in+1 limbs, then round to 'in' limbs. Ideally the
inversion function should do this automatically. */ if (dn == in)
{
tp[in + 1] = 0;
MPN_COPY (tp + in + 2, dp, in);
mpn_invertappr (tp, tp + in + 1, in + 1, NULL);
} else
{
mpn_invertappr (tp, dp + dn - (in + 1), in + 1, NULL);
}
cy = mpn_sub_1 (tp, tp, in + 1, GMP_NUMB_HIGHBIT); if (UNLIKELY (cy != 0))
MPN_ZERO (tp + 1, in);
MPN_COPY (ip, tp + 1, in); #endif
/* if (qn == 0) */ /* The while below handles this case */ /* return qh; */ /* Degenerate use. Should we allow this? */
while (qn > 0)
{ if (qn < in)
{
ip += in - qn;
in = qn;
}
np -= in;
qp -= in;
/* Compute the next block of quotient limbs by multiplying the inverse I
by the upper part of the partial remainder R. */
mpn_mul_n (tp, rp + dn - in, ip, in); /* mulhi */
cy = mpn_add_n (qp, tp + in, rp + dn - in, in); /* I's msb implicit */
ASSERT_ALWAYS (cy == 0);
qn -= in;
/* Compute the product of the quotient block and the divisor D, to be subtractedfromthepartialremaindercombinedwithnewlimbsfromthe
dividend N. We only really need the low dn+1 limbs. */
/* Subtract the product from the partial remainder combined with new
limbs from the dividend N, generating a new partial remainder R. */ if (dn != in)
{
cy = mpn_sub_n (tp, np, tp, in); /* get next 'in' limbs from N */
cy = mpn_sub_nc (tp + in, rp, tp + in, dn - in, cy);
MPN_COPY (rp, tp, dn); /* FIXME: try to avoid this */
} else
{
cy = mpn_sub_n (rp, np, tp, in); /* get next 'in' limbs from N */
}
STAT (int i; int err = 0; staticint errarr[5]; staticint err_rec; staticint tot);
/* Check the remainder R and adjust the quotient as needed. */
r -= cy; while (r != 0)
{ /* We loop 0 times with about 69% probability, 1 time with about 31% probability,2timeswithabout0.6%probability,ifinverseis
computed as recommended. */
mpn_incr_u (qp, 1);
cy = mpn_sub_n (rp, rp, dp, dn);
r -= cy;
STAT (err++);
} if (mpn_cmp (rp, dp, dn) >= 0)
{ /* This is executed with about 76% probability. */
mpn_incr_u (qp, 1);
cy = mpn_sub_n (rp, rp, dp, dn);
STAT (err++);
}
STAT (
tot++;
errarr[err]++; if (err > err_rec)
err_rec = err; if (tot % 0x10000 == 0)
{ for (i = 0; i <= err_rec; i++)
printf (" %d(%.1f%%)", errarr[i], 100.0*errarr[i]/tot);
printf ("\n");
}
);
}
return qh;
}
/* In case k=0 (automatic choice), we distinguish 3 cases: (a)dn<qn:in=ceil(qn/ceil(qn/dn)) (b)dn/3<qn<=dn:in=ceil(qn/2) (c)qn<dn/3:in=qn Inallcaseswehavein<=dn.
*/ static mp_size_t
mpn_mu_div_qr_choose_in (mp_size_t qn, mp_size_t dn, int k)
{
mp_size_t in;
if (k == 0)
{
mp_size_t b; if (qn > dn)
{ /* Compute an inverse size that is a nice partition of the quotient. */
b = (qn - 1) / dn + 1; /* ceil(qn/dn), number of blocks */
in = (qn - 1) / b + 1; /* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
} elseif (3 * qn > dn)
{
in = (qn - 1) / 2 + 1; /* b = 2 */
} else
{
in = (qn - 1) / 1 + 1; /* b = 1 */
}
} else
{
mp_size_t xn;
xn = MIN (dn, qn);
in = (xn - 1) / k + 1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.