[Python-checkins] CVS: python/dist/src/Modules mathmodule.c,2.56,2.57

Tim Peters python-dev@python.org
Wed, 11 Oct 2000 23:10:28 -0700


Update of /cvsroot/python/python/dist/src/Modules
In directory slayer.i.sourceforge.net:/tmp/cvs-serv13972/python/dist/src/Modules

Modified Files:
	mathmodule.c 
Log Message:
Stop raising OverflowError on underflows reported by libm (errno==ERANGE and
libm result is 0).  Cautiously add a few libm exception test cases:
1. That exp(-huge) returns 0 without exception.
2. That exp(+huge) triggers OverflowError.
3. That sqrt(-1) raises ValueError specifically (apparently under glibc linked
   with -lieee, it was raising OverflowError due to an accident of the way
   mathmodule.c's CHECK() macro happened to deal with Infs and NaNs under gcc).


Index: mathmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/mathmodule.c,v
retrieving revision 2.56
retrieving revision 2.57
diff -C2 -r2.56 -r2.57
*** mathmodule.c	2000/09/16 03:54:24	2.56
--- mathmodule.c	2000/10/12 06:10:25	2.57
***************
*** 1,3 ****
- 
  /* Math module -- standard C math library functions, pi and e */
  
--- 1,2 ----
***************
*** 19,22 ****
--- 18,26 ----
  #endif
  
+ /* RED_FLAG 12-Oct-2000 Tim
+  * What CHECK does if errno != 0 and x is a NaN is a platform-dependent crap
+  * shoot.  Most (but not all!) platforms will end up setting errno to ERANGE
+  * then, but EDOM is probably better.
+  */
  #ifdef HUGE_VAL
  #define CHECK(x) if (errno != 0) ; \
***************
*** 27,41 ****
  #endif
  
! static PyObject *
! math_error(void)
  {
  	if (errno == EDOM)
  		PyErr_SetString(PyExc_ValueError, "math domain error");
! 	else if (errno == ERANGE)
! 		PyErr_SetString(PyExc_OverflowError, "math range error");
  	else
                  /* Unexpected math error */
  		PyErr_SetFromErrno(PyExc_ValueError);
! 	return NULL;
  }
  
--- 31,63 ----
  #endif
  
! /* Call is_error when errno != 0, and where x is the result libm
!  * returned.  is_error will usually set up an exception and return
!  * true (1), but may return false (0) without setting up an exception.
!  */
! static int
! is_error(double x)
  {
+ 	int result = 1;	/* presumption of guilt */
  	if (errno == EDOM)
  		PyErr_SetString(PyExc_ValueError, "math domain error");
! 	else if (errno == ERANGE) {
! 		/* ANSI C generally requires libm functions to set ERANGE
! 		 * on overflow, but also generally *allows* them to set
! 		 * ERANGE on underflow too.  There's no consistency about
! 		 * the latter across platforms.  Here we suppress the
! 		 * underflow errors (libm functions should return a zero
! 		 * on underflow, and +- HUGE_VAL on overflow, so testing
! 		 * the result for zero suffices to distinguish the cases).
! 		 */
! 		if (x)
! 			PyErr_SetString(PyExc_OverflowError, 
! 					"math range error");
! 		else
! 			result = 0;
! 	}
  	else
                  /* Unexpected math error */
  		PyErr_SetFromErrno(PyExc_ValueError);
! 	return result;
  }
  
***************
*** 51,56 ****
  	PyFPE_END_PROTECT(x)
  	CHECK(x);
! 	if (errno != 0)
! 		return math_error();
  	else
  		return PyFloat_FromDouble(x);
--- 73,78 ----
  	PyFPE_END_PROTECT(x)
  	CHECK(x);
! 	if (errno && is_error(x))
! 		return NULL;
  	else
  		return PyFloat_FromDouble(x);
***************
*** 68,73 ****
  	PyFPE_END_PROTECT(x)
  	CHECK(x);
! 	if (errno != 0)
! 		return math_error();
  	else
  		return PyFloat_FromDouble(x);
--- 90,95 ----
  	PyFPE_END_PROTECT(x)
  	CHECK(x);
! 	if (errno && is_error(x))
! 		return NULL;
  	else
  		return PyFloat_FromDouble(x);
***************
*** 144,150 ****
  	x = frexp(x, &i);
  	CHECK(x);
! 	if (errno != 0)
! 		return math_error();
! 	return Py_BuildValue("(di)", x, i);
  }
  
--- 166,173 ----
  	x = frexp(x, &i);
  	CHECK(x);
! 	if (errno && is_error(x))
! 		return NULL;
! 	else
! 		return Py_BuildValue("(di)", x, i);
  }
  
***************
*** 169,174 ****
  	PyFPE_END_PROTECT(x)
  	CHECK(x);
! 	if (errno != 0)
! 		return math_error();
  	else
  		return PyFloat_FromDouble(x);
--- 192,197 ----
  	PyFPE_END_PROTECT(x)
  	CHECK(x);
! 	if (errno && is_error(x))
! 		return NULL;
  	else
  		return PyFloat_FromDouble(x);
***************
*** 198,204 ****
  #endif
  	CHECK(x);
! 	if (errno != 0)
! 		return math_error();
! 	return Py_BuildValue("(dd)", x, y);
  }
  
--- 221,228 ----
  #endif
  	CHECK(x);
! 	if (errno && is_error(x))
! 		return NULL;
! 	else
! 		return Py_BuildValue("(dd)", x, y);
  }