@@ -4212,6 +4212,18 @@ mpd_qfma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c,
42124212 * status |= workstatus ;
42134213}
42144214
4215+ /*
4216+ * Schedule the optimal precision increase for the Newton iteration.
4217+ * v := input operand
4218+ * z_0 := initial approximation
4219+ * initprec := natural number such that abs(log(v) - z_0) < 10**-initprec
4220+ * maxprec := target precision
4221+ *
4222+ * For convenience the output klist contains the elements in reverse order:
4223+ * klist := [k_n-1, ..., k_0], where
4224+ * 1) k_0 <= initprec and
4225+ * 2) abs(log(v) - result) < 10**(-2*k_n-1 + 1) <= 10**-maxprec.
4226+ */
42154227static inline int
42164228ln_schedule_prec (mpd_ssize_t klist [MPD_MAX_PREC_LOG2 ], mpd_ssize_t maxprec ,
42174229 mpd_ssize_t initprec )
@@ -4231,6 +4243,7 @@ ln_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], mpd_ssize_t maxprec,
42314243 return i - 1 ;
42324244}
42334245
4246+ /* The constants have been verified with both decimal.py and mpfr. */
42344247#ifdef CONFIG_64
42354248#if MPD_RDIGITS != 19
42364249 #error "mpdecimal.c: MPD_RDIGITS must be 19."
@@ -4285,7 +4298,7 @@ static const mpd_t _mpd_ln10 = {
42854298 (mpd_uint_t * )mpd_ln10_data
42864299};
42874300
4288- /* Set 'result' to ln(10), with 'prec' digits, using ROUND_HALF_EVEN. */
4301+ /* Set 'result' to ln(10). ulp error: abs(result - log(10)) < ulp(log(10)) */
42894302void
42904303mpd_qln10 (mpd_t * result , mpd_ssize_t prec , uint32_t * status )
42914304{
@@ -4320,7 +4333,7 @@ mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status)
43204333 mpd_maxcontext (& varcontext );
43214334 varcontext .round = MPD_ROUND_TRUNC ;
43224335
4323- i = ln_schedule_prec (klist , prec + 2 , result -> digits );
4336+ i = ln_schedule_prec (klist , prec + 2 , - result -> exp );
43244337 for (; i >= 0 ; i -- ) {
43254338 varcontext .prec = 2 * klist [i ]+ 3 ;
43264339 result -> flags ^= MPD_NEG ;
@@ -4339,7 +4352,18 @@ mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status)
43394352 mpd_qfinalize (result , & maxcontext , status );
43404353}
43414354
4342- /* Initial approximations for the ln() iteration */
4355+ /*
4356+ * Initial approximations for the ln() iteration. The values have the
4357+ * following properties (established with both decimal.py and mpfr):
4358+ *
4359+ * Index 0 - 400, logarithms of x in [1.00, 5.00]:
4360+ * abs(lnapprox[i] * 10**-3 - log((i+100)/100)) < 10**-2
4361+ * abs(lnapprox[i] * 10**-3 - log((i+1+100)/100)) < 10**-2
4362+ *
4363+ * Index 401 - 899, logarithms of x in (0.500, 0.999]:
4364+ * abs(-lnapprox[i] * 10**-3 - log((i+100)/1000)) < 10**-2
4365+ * abs(-lnapprox[i] * 10**-3 - log((i+1+100)/1000)) < 10**-2
4366+ */
43434367static const uint16_t lnapprox [900 ] = {
43444368 /* index 0 - 400: log((i+100)/100) * 1000 */
43454369 0 , 10 , 20 , 30 , 39 , 49 , 58 , 68 , 77 , 86 , 95 , 104 , 113 , 122 , 131 , 140 , 148 , 157 ,
@@ -4406,7 +4430,10 @@ static const uint16_t lnapprox[900] = {
44064430 18 , 17 , 16 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1
44074431};
44084432
4409- /* Internal ln() function that does not check for specials, zero or one. */
4433+ /*
4434+ * Internal ln() function that does not check for specials, zero or one.
4435+ * Relative error: abs(result - log(a)) < 0.1 * 10**-prec * abs(log(a))
4436+ */
44104437static void
44114438_mpd_qln (mpd_t * result , const mpd_t * a , const mpd_context_t * ctx ,
44124439 uint32_t * status )
@@ -4451,10 +4478,16 @@ _mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
44514478 mpd_setdigits (z );
44524479
44534480 if (x <= 400 ) {
4481+ /* Reduce the input operand to 1.00 <= v <= 5.00. Let y = x + 100,
4482+ * so 100 <= y <= 500. Since y contains the most significant digits
4483+ * of v, y/100 <= v < (y+1)/100 and abs(z - log(v)) < 10**-2. */
44544484 v .exp = - (a_digits - 1 );
44554485 t = a_exp + a_digits - 1 ;
44564486 }
44574487 else {
4488+ /* Reduce the input operand to 0.500 < v <= 0.999. Let y = x + 100,
4489+ * so 500 < y <= 999. Since y contains the most significant digits
4490+ * of v, y/1000 <= v < (y+1)/1000 and abs(z - log(v)) < 10**-2. */
44584491 v .exp = - a_digits ;
44594492 t = a_exp + a_digits ;
44604493 mpd_set_negative (z );
@@ -4465,37 +4498,46 @@ _mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
44654498 varcontext .round = MPD_ROUND_TRUNC ;
44664499
44674500 maxprec = ctx -> prec + 2 ;
4468- if (x <= 10 || x >= 805 ) {
4469- /* v is close to 1: Estimate the magnitude of the logarithm.
4470- * If v = 1 or ln(v) will underflow, skip the loop. Otherwise,
4471- * adjust the precision upwards in order to obtain a sufficient
4472- * number of significant digits.
4473- *
4474- * 1) x/(1+x) < ln(1+x) < x, for x > -1, x != 0
4501+ if (t == 0 && (x <= 15 || x >= 800 )) {
4502+ /* 0.900 <= v <= 1.15: Estimate the magnitude of the logarithm.
4503+ * If ln(v) will underflow, skip the loop. Otherwise, adjust the
4504+ * precision upwards in order to obtain a sufficient number of
4505+ * significant digits.
44754506 *
4476- * 2) (v-1)/v < ln(v) < v-1
4507+ * Case v > 1:
4508+ * abs((v-1)/10) < abs((v-1)/v) < abs(ln(v)) < abs(v-1)
4509+ * Case v < 1:
4510+ * abs(v-1) < abs(ln(v)) < abs((v-1)/v) < abs((v-1)*10)
44774511 */
4478- mpd_t * lower = & tmp ;
4479- mpd_t * upper = & vtmp ;
44804512 int cmp = _mpd_cmp (& v , & one );
44814513
4482- varcontext . round = MPD_ROUND_CEILING ;
4483- varcontext . prec = maxprec ;
4484- mpd_qsub ( upper , & v , & one , & varcontext , & varcontext . status );
4485- varcontext . round = MPD_ROUND_FLOOR ;
4486- mpd_qdiv ( lower , upper , & v , & varcontext , & varcontext . status ) ;
4487- varcontext . round = MPD_ROUND_TRUNC ;
4514+ /* Upper bound (assume v > 1): abs(v-1), unrounded */
4515+ _mpd_qsub ( & tmp , & v , & one , & maxcontext , & maxcontext . status ) ;
4516+ if ( maxcontext . status & MPD_Errors ) {
4517+ mpd_seterror ( result , MPD_Malloc_error , status ) ;
4518+ goto finish ;
4519+ }
44884520
44894521 if (cmp < 0 ) {
4490- _mpd_ptrswap (& upper , & lower );
4522+ /* v < 1: abs((v-1)*10) */
4523+ tmp .exp += 1 ;
44914524 }
4492- if (mpd_adjexp (upper ) < mpd_etiny (ctx )) {
4493- _settriple (z , (cmp < 0 ), 1 , mpd_etiny (ctx )- 1 );
4494- goto postloop ;
4525+ if (mpd_adjexp (& tmp ) < mpd_etiny (ctx )) {
4526+ /* The upper bound is less than etiny: Underflow to zero */
4527+ _settriple (result , (cmp < 0 ), 1 , mpd_etiny (ctx )- 1 );
4528+ goto finish ;
44954529 }
4496- /* XXX optimization: t == 0 && mpd_adjexp(lower) < 0 */
4497- if (mpd_adjexp (lower ) < 0 ) {
4498- maxprec = maxprec - mpd_adjexp (lower );
4530+ /* Lower bound: abs((v-1)/10) or abs(v-1) */
4531+ tmp .exp -= 1 ;
4532+ if (mpd_adjexp (& tmp ) < 0 ) {
4533+ /* Absolute error of the loop: abs(z - log(v)) < 10**-p. If
4534+ * p = ctx->prec+2-adjexp(lower), then the relative error of
4535+ * the result is (using 10**adjexp(x) <= abs(x)):
4536+ *
4537+ * abs(z - log(v)) / abs(log(v)) < 10**-p / abs(log(v))
4538+ * <= 10**(-ctx->prec-2)
4539+ */
4540+ maxprec = maxprec - mpd_adjexp (& tmp );
44994541 }
45004542 }
45014543
@@ -4523,14 +4565,37 @@ _mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
45234565 }
45244566 }
45254567
4526- postloop :
4527- mpd_qln10 (& v , maxprec + 2 , status );
4568+ /*
4569+ * Case t == 0:
4570+ * t * log(10) == 0, the result does not change and the analysis
4571+ * above applies. If v < 0.900 or v > 1.15, the relative error is
4572+ * less than 10**(-ctx.prec-1).
4573+ * Case t != 0:
4574+ * z := approx(log(v))
4575+ * y := approx(log(10))
4576+ * p := maxprec = ctx->prec + 2
4577+ * Absolute errors:
4578+ * 1) abs(z - log(v)) < 10**-p
4579+ * 2) abs(y - log(10)) < 10**-p
4580+ * The multiplication is exact, so:
4581+ * 3) abs(t*y - t*log(10)) < t*10**-p
4582+ * The sum is exact, so:
4583+ * 4) abs((z + t*y) - (log(v) + t*log(10))) < (abs(t) + 1) * 10**-p
4584+ * Bounds for log(v) and log(10):
4585+ * 5) -7/10 < log(v) < 17/10
4586+ * 6) 23/10 < log(10) < 24/10
4587+ * Using 4), 5), 6) and t != 0, the relative error is:
4588+ *
4589+ * 7) relerr < ((abs(t) + 1)*10**-p) / abs(log(v) + t*log(10))
4590+ * < 0.5 * 10**(-p + 1) = 0.5 * 10**(-ctx->prec-1)
4591+ */
4592+ mpd_qln10 (& v , maxprec + 1 , status );
45284593 mpd_qmul_ssize (& tmp , & v , t , & maxcontext , status );
4529- varcontext .prec = maxprec + 2 ;
4530- mpd_qadd (result , & tmp , z , & varcontext , status );
4594+ mpd_qadd (result , & tmp , z , & maxcontext , status );
45314595
45324596
45334597finish :
4598+ * status |= (MPD_Inexact |MPD_Rounded );
45344599 mpd_del (& v );
45354600 mpd_del (& vtmp );
45364601 mpd_del (& tmp );
0 commit comments