@@ -858,12 +858,15 @@ math_lcm_impl(PyObject *module, PyObject * const *args,
858858 * true (1), but may return false (0) without setting up an exception.
859859 */
860860static int
861- is_error (double x )
861+ is_error (double x , int raise_edom )
862862{
863863 int result = 1 ; /* presumption of guilt */
864864 assert (errno ); /* non-zero errno is a precondition for calling */
865- if (errno == EDOM )
866- PyErr_SetString (PyExc_ValueError , "math domain error" );
865+ if (errno == EDOM ) {
866+ if (raise_edom ) {
867+ PyErr_SetString (PyExc_ValueError , "math domain error" );
868+ }
869+ }
867870
868871 else if (errno == ERANGE ) {
869872 /* ANSI C generally requires libm functions to set ERANGE
@@ -928,50 +931,69 @@ is_error(double x)
928931*/
929932
930933static PyObject *
931- math_1 (PyObject * arg , double (* func ) (double ), int can_overflow )
934+ math_1 (PyObject * arg , double (* func ) (double ), int can_overflow ,
935+ const char * err_msg )
932936{
933937 double x , r ;
934938 x = PyFloat_AsDouble (arg );
935939 if (x == -1.0 && PyErr_Occurred ())
936940 return NULL ;
937941 errno = 0 ;
938942 r = (* func )(x );
939- if (isnan (r ) && !isnan (x )) {
940- PyErr_SetString (PyExc_ValueError ,
941- "math domain error" ); /* invalid arg */
942- return NULL ;
943- }
943+ if (isnan (r ) && !isnan (x ))
944+ goto domain_err ; /* domain error */
944945 if (isinf (r ) && isfinite (x )) {
945946 if (can_overflow )
946947 PyErr_SetString (PyExc_OverflowError ,
947948 "math range error" ); /* overflow */
948949 else
949- PyErr_SetString (PyExc_ValueError ,
950- "math domain error" ); /* singularity */
950+ goto domain_err ; /* singularity */
951951 return NULL ;
952952 }
953- if (isfinite (r ) && errno && is_error (r ))
953+ if (isfinite (r ) && errno && is_error (r , 1 ))
954954 /* this branch unnecessary on most platforms */
955955 return NULL ;
956956
957957 return PyFloat_FromDouble (r );
958+
959+ domain_err :
960+ if (err_msg ) {
961+ char * buf = PyOS_double_to_string (x , 'r' , 0 , Py_DTSF_ADD_DOT_0 , NULL );
962+ if (buf ) {
963+ PyErr_Format (PyExc_ValueError , err_msg , buf );
964+ PyMem_Free (buf );
965+ }
966+ }
967+ else {
968+ PyErr_SetString (PyExc_ValueError , "math domain error" );
969+ }
970+ return NULL ;
958971}
959972
960973/* variant of math_1, to be used when the function being wrapped is known to
961974 set errno properly (that is, errno = EDOM for invalid or divide-by-zero,
962975 errno = ERANGE for overflow). */
963976
964977static PyObject *
965- math_1a (PyObject * arg , double (* func ) (double ))
978+ math_1a (PyObject * arg , double (* func ) (double ), const char * err_msg )
966979{
967980 double x , r ;
968981 x = PyFloat_AsDouble (arg );
969982 if (x == -1.0 && PyErr_Occurred ())
970983 return NULL ;
971984 errno = 0 ;
972985 r = (* func )(x );
973- if (errno && is_error (r ))
986+ if (errno && is_error (r , err_msg ? 0 : 1 )) {
987+ if (err_msg && errno == EDOM ) {
988+ assert (!PyErr_Occurred ()); /* exception is not set by is_error() */
989+ char * buf = PyOS_double_to_string (x , 'r' , 0 , Py_DTSF_ADD_DOT_0 , NULL );
990+ if (buf ) {
991+ PyErr_Format (PyExc_ValueError , err_msg , buf );
992+ PyMem_Free (buf );
993+ }
994+ }
974995 return NULL ;
996+ }
975997 return PyFloat_FromDouble (r );
976998}
977999
@@ -1031,21 +1053,33 @@ math_2(PyObject *const *args, Py_ssize_t nargs,
10311053 else
10321054 errno = 0 ;
10331055 }
1034- if (errno && is_error (r ))
1056+ if (errno && is_error (r , 1 ))
10351057 return NULL ;
10361058 else
10371059 return PyFloat_FromDouble (r );
10381060}
10391061
10401062#define FUNC1 (funcname , func , can_overflow , docstring ) \
10411063 static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
1042- return math_1(args, func, can_overflow); \
1064+ return math_1(args, func, can_overflow, NULL); \
1065+ }\
1066+ PyDoc_STRVAR(math_##funcname##_doc, docstring);
1067+
1068+ #define FUNC1D (funcname , func , can_overflow , docstring , err_msg ) \
1069+ static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
1070+ return math_1(args, func, can_overflow, err_msg); \
10431071 }\
10441072 PyDoc_STRVAR(math_##funcname##_doc, docstring);
10451073
10461074#define FUNC1A (funcname , func , docstring ) \
10471075 static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
1048- return math_1a(args, func); \
1076+ return math_1a(args, func, NULL); \
1077+ }\
1078+ PyDoc_STRVAR(math_##funcname##_doc, docstring);
1079+
1080+ #define FUNC1AD (funcname , func , docstring , err_msg ) \
1081+ static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
1082+ return math_1a(args, func, err_msg); \
10491083 }\
10501084 PyDoc_STRVAR(math_##funcname##_doc, docstring);
10511085
@@ -1077,9 +1111,10 @@ FUNC2(atan2, atan2,
10771111 "atan2($module, y, x, /)\n--\n\n"
10781112 "Return the arc tangent (measured in radians) of y/x.\n\n"
10791113 "Unlike atan(y/x), the signs of both x and y are considered." )
1080- FUNC1 (atanh , atanh , 0 ,
1114+ FUNC1D (atanh , atanh , 0 ,
10811115 "atanh($module, x, /)\n--\n\n"
1082- "Return the inverse hyperbolic tangent of x." )
1116+ "Return the inverse hyperbolic tangent of x." ,
1117+ "expected a number between -1 and 1, got %s" )
10831118FUNC1 (cbrt , cbrt , 0 ,
10841119 "cbrt($module, x, /)\n--\n\n"
10851120 "Return the cube root of x." )
@@ -1190,9 +1225,10 @@ math_floor(PyObject *module, PyObject *number)
11901225 return PyLong_FromDouble (floor (x ));
11911226}
11921227
1193- FUNC1A (gamma , m_tgamma ,
1228+ FUNC1AD (gamma , m_tgamma ,
11941229 "gamma($module, x, /)\n--\n\n"
1195- "Gamma function at x." )
1230+ "Gamma function at x." ,
1231+ "expected a float or nonnegative integer, got %s" )
11961232FUNC1A (lgamma , m_lgamma ,
11971233 "lgamma($module, x, /)\n--\n\n"
11981234 "Natural logarithm of absolute value of Gamma function at x." )
@@ -1212,9 +1248,10 @@ FUNC1(sin, sin, 0,
12121248FUNC1 (sinh , sinh , 1 ,
12131249 "sinh($module, x, /)\n--\n\n"
12141250 "Return the hyperbolic sine of x." )
1215- FUNC1 (sqrt , sqrt , 0 ,
1251+ FUNC1D (sqrt , sqrt , 0 ,
12161252 "sqrt($module, x, /)\n--\n\n"
1217- "Return the square root of x." )
1253+ "Return the square root of x." ,
1254+ "expected a nonnegative input, got %s" )
12181255FUNC1 (tan , tan , 0 ,
12191256 "tan($module, x, /)\n--\n\n"
12201257 "Return the tangent of x (measured in radians)." )
@@ -2141,7 +2178,7 @@ math_ldexp_impl(PyObject *module, double x, PyObject *i)
21412178 errno = ERANGE ;
21422179 }
21432180
2144- if (errno && is_error (r ))
2181+ if (errno && is_error (r , 1 ))
21452182 return NULL ;
21462183 return PyFloat_FromDouble (r );
21472184}
@@ -2195,8 +2232,8 @@ loghelper(PyObject* arg, double (*func)(double))
21952232
21962233 /* Negative or zero inputs give a ValueError. */
21972234 if (!_PyLong_IsPositive ((PyLongObject * )arg )) {
2198- PyErr_SetString (PyExc_ValueError ,
2199- "math domain error" );
2235+ PyErr_Format (PyExc_ValueError ,
2236+ "expected a positive input, got %S" , arg );
22002237 return NULL ;
22012238 }
22022239
@@ -2220,7 +2257,7 @@ loghelper(PyObject* arg, double (*func)(double))
22202257 }
22212258
22222259 /* Else let libm handle it by itself. */
2223- return math_1 (arg , func , 0 );
2260+ return math_1 (arg , func , 0 , "expected a positive input, got %s" );
22242261}
22252262
22262263
@@ -2369,7 +2406,7 @@ math_fmod_impl(PyObject *module, double x, double y)
23692406 else
23702407 errno = 0 ;
23712408 }
2372- if (errno && is_error (r ))
2409+ if (errno && is_error (r , 1 ))
23732410 return NULL ;
23742411 else
23752412 return PyFloat_FromDouble (r );
@@ -3010,7 +3047,7 @@ math_pow_impl(PyObject *module, double x, double y)
30103047 }
30113048 }
30123049
3013- if (errno && is_error (r ))
3050+ if (errno && is_error (r , 1 ))
30143051 return NULL ;
30153052 else
30163053 return PyFloat_FromDouble (r );
0 commit comments