Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4d3e0a6

Browse files
author
Stefan Krah
committed
Improve Underflow handling in the correct-rounding loop. The case for
Underflow to zero hasn't changed: _mpd_qexp() internally uses MIN_EMIN, so the result would also underflow to zero for all emin > MIN_EMIN. In case digits are left, the informal argument is as follows: Underflow can occur only once in the last multiplication of the power stage (in the Horner stage Underflow provably cannot occur, and if Underflow occurred twice in the power stage, the result would underflow to zero on the second occasion). Since there is no double rounding during Underflow, the effective work precision is now 1 <= result->digits < prec. It can be shown by a somewhat tedious argument that abs(result - e**x) < ulp(result, result->digits). Therefore the correct rounding loop now uses ulp(result, result->digits) to generate the bounds for e**x in case of Underflow.
1 parent d3487be commit 4d3e0a6

1 file changed

Lines changed: 17 additions & 4 deletions

File tree

Modules/_decimal/libmpdec/mpdecimal.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4122,6 +4122,8 @@ mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
41224122
MPD_NEW_STATIC(ulp, 0,0,0,0);
41234123
MPD_NEW_STATIC(aa, 0,0,0,0);
41244124
mpd_ssize_t prec;
4125+
mpd_ssize_t ulpexp;
4126+
uint32_t workstatus;
41254127

41264128
if (result == a) {
41274129
if (!mpd_qcopy(&aa, a, status)) {
@@ -4135,19 +4137,30 @@ mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
41354137
prec = ctx->prec + 3;
41364138
while (1) {
41374139
workctx.prec = prec;
4138-
_mpd_qexp(result, a, &workctx, status);
4139-
_ssettriple(&ulp, MPD_POS, 1,
4140-
result->exp + result->digits-workctx.prec);
4140+
workstatus = 0;
4141+
4142+
_mpd_qexp(result, a, &workctx, &workstatus);
4143+
*status |= workstatus;
4144+
4145+
ulpexp = result->exp + result->digits - workctx.prec;
4146+
if (workstatus & MPD_Underflow) {
4147+
/* The effective work precision is result->digits. */
4148+
ulpexp = result->exp;
4149+
}
4150+
_ssettriple(&ulp, MPD_POS, 1, ulpexp);
41414151

41424152
/*
4143-
* At this point:
4153+
* At this point [1]:
41444154
* 1) abs(result - e**x) < 0.5 * 10**(-prec) * e**x
41454155
* 2) result - ulp < e**x < result + ulp
41464156
* 3) result - ulp < result < result + ulp
41474157
*
41484158
* If round(result-ulp)==round(result+ulp), then
41494159
* round(result)==round(e**x). Therefore the result
41504160
* is correctly rounded.
4161+
*
4162+
* [1] If abs(a) <= 9 * 10**(-prec-1), use the absolute
4163+
* error for a similar argument.
41514164
*/
41524165
workctx.prec = ctx->prec;
41534166
mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);

0 commit comments

Comments
 (0)