Issue #8986: erfc was raising OverflowError on Linux for arguments in

the (approximate) range (-27.3, 30.0), as a result of an escaped errno
value.
This commit is contained in:
Mark Dickinson 2010-06-13 10:50:29 +00:00
parent 8842c356aa
commit e979ec8fbf
5 changed files with 68 additions and 6 deletions

View File

@ -84,6 +84,25 @@ erf0041 erf 1e16 -> 1.0
erf0042 erf -1e150 -> -1.0 erf0042 erf -1e150 -> -1.0
erf0043 erf 1.7e308 -> 1.0 erf0043 erf 1.7e308 -> 1.0
-- Issue 8986: inputs x with exp(-x*x) near the underflow threshold
-- incorrectly signalled overflow on some platforms.
erf0100 erf 26.2 -> 1.0
erf0101 erf 26.4 -> 1.0
erf0102 erf 26.6 -> 1.0
erf0103 erf 26.8 -> 1.0
erf0104 erf 27.0 -> 1.0
erf0105 erf 27.2 -> 1.0
erf0106 erf 27.4 -> 1.0
erf0107 erf 27.6 -> 1.0
erf0110 erf -26.2 -> -1.0
erf0111 erf -26.4 -> -1.0
erf0112 erf -26.6 -> -1.0
erf0113 erf -26.8 -> -1.0
erf0114 erf -27.0 -> -1.0
erf0115 erf -27.2 -> -1.0
erf0116 erf -27.4 -> -1.0
erf0117 erf -27.6 -> -1.0
---------------------------------------- ----------------------------------------
-- erfc: complementary error function -- -- erfc: complementary error function --
@ -127,6 +146,25 @@ erfc0051 erfc 1e16 -> 0.0
erfc0052 erfc -1e150 -> 2.0 erfc0052 erfc -1e150 -> 2.0
erfc0053 erfc 1.7e308 -> 0.0 erfc0053 erfc 1.7e308 -> 0.0
-- Issue 8986: inputs x with exp(-x*x) near the underflow threshold
-- incorrectly signalled overflow on some platforms.
erfc0100 erfc 26.2 -> 1.6432507924389461e-300
erfc0101 erfc 26.4 -> 4.4017768588035426e-305
erfc0102 erfc 26.6 -> 1.0885125885442269e-309
erfc0103 erfc 26.8 -> 2.4849621571966629e-314
erfc0104 erfc 27.0 -> 5.2370464393526292e-319
erfc0105 erfc 27.2 -> 9.8813129168249309e-324
erfc0106 erfc 27.4 -> 0.0
erfc0107 erfc 27.6 -> 0.0
erfc0110 erfc -26.2 -> 2.0
erfc0111 erfc -26.4 -> 2.0
erfc0112 erfc -26.6 -> 2.0
erfc0113 erfc -26.8 -> 2.0
erfc0114 erfc -27.0 -> 2.0
erfc0115 erfc -27.2 -> 2.0
erfc0116 erfc -27.4 -> 2.0
erfc0117 erfc -27.6 -> 2.0
--------------------------------------------------------- ---------------------------------------------------------
-- lgamma: log of absolute value of the gamma function -- -- lgamma: log of absolute value of the gamma function --

View File

@ -996,6 +996,15 @@ class MathTests(unittest.TestCase):
accuracy_failure = acc_check(expected, got, accuracy_failure = acc_check(expected, got,
rel_err = 5e-15, rel_err = 5e-15,
abs_err = 5e-15) abs_err = 5e-15)
elif fn == 'erfc':
# erfc has less-than-ideal accuracy for large
# arguments (x ~ 25 or so), mainly due to the
# error involved in computing exp(-x*x).
#
# XXX Would be better to weaken this test only
# for large x, instead of for all x.
accuracy_failure = ulps_check(expected, got, 2000)
else: else:
accuracy_failure = ulps_check(expected, got, 20) accuracy_failure = ulps_check(expected, got, 20)
if accuracy_failure is None: if accuracy_failure is None:

View File

@ -151,6 +151,7 @@ Benjamin Collar
Jeffery Collins Jeffery Collins
Robert Collins Robert Collins
Paul Colomiets Paul Colomiets
Geremy Condra
Juan José Conti Juan José Conti
Matt Conway Matt Conway
David M. Cooke David M. Cooke

View File

@ -25,6 +25,10 @@ Core and Builtins
Library Library
------- -------
- Issue #8986: math.erfc was incorrectly raising OverflowError for
values between -27.3 and -30.0 on some platforms.
- Issue #8924: logging: Improved error handling for Unicode in exception text. - Issue #8924: logging: Improved error handling for Unicode in exception text.
- Issue #8948: cleanup functions and class / module setups and teardowns are - Issue #8948: cleanup functions and class / module setups and teardowns are

View File

@ -428,8 +428,8 @@ m_lgamma(double x)
static double static double
m_erf_series(double x) m_erf_series(double x)
{ {
double x2, acc, fk; double x2, acc, fk, result;
int i; int i, saved_errno;
x2 = x * x; x2 = x * x;
acc = 0.0; acc = 0.0;
@ -438,7 +438,12 @@ m_erf_series(double x)
acc = 2.0 + x2 * acc / fk; acc = 2.0 + x2 * acc / fk;
fk -= 1.0; fk -= 1.0;
} }
return acc * x * exp(-x2) / sqrtpi; /* Make sure the exp call doesn't affect errno;
see m_erfc_contfrac for more. */
saved_errno = errno;
result = acc * x * exp(-x2) / sqrtpi;
errno = saved_errno;
return result;
} }
/* /*
@ -453,8 +458,8 @@ m_erf_series(double x)
static double static double
m_erfc_contfrac(double x) m_erfc_contfrac(double x)
{ {
double x2, a, da, p, p_last, q, q_last, b; double x2, a, da, p, p_last, q, q_last, b, result;
int i; int i, saved_errno;
if (x >= ERFC_CONTFRAC_CUTOFF) if (x >= ERFC_CONTFRAC_CUTOFF)
return 0.0; return 0.0;
@ -472,7 +477,12 @@ m_erfc_contfrac(double x)
temp = p; p = b*p - a*p_last; p_last = temp; temp = p; p = b*p - a*p_last; p_last = temp;
temp = q; q = b*q - a*q_last; q_last = temp; temp = q; q = b*q - a*q_last; q_last = temp;
} }
return p / q * x * exp(-x2) / sqrtpi; /* Issue #8986: On some platforms, exp sets errno on underflow to zero;
save the current errno value so that we can restore it later. */
saved_errno = errno;
result = p / q * x * exp(-x2) / sqrtpi;
errno = saved_errno;
return result;
} }
/* Error function erf(x), for general x */ /* Error function erf(x), for general x */