@@ -921,33 +921,38 @@ is_error(double x)
921
921
*/
922
922
923
923
static PyObject *
924
- math_1 (PyObject * arg , double (* func ) (double ), int can_overflow )
924
+ math_1 (PyObject * arg , double (* func ) (double ), int can_overflow ,
925
+ const char * err_msg )
925
926
{
926
927
double x , r ;
927
928
x = PyFloat_AsDouble (arg );
928
929
if (x == -1.0 && PyErr_Occurred ())
929
930
return NULL ;
930
931
errno = 0 ;
931
932
r = (* func )(x );
932
- if (isnan (r ) && !isnan (x )) {
933
- PyErr_SetString (PyExc_ValueError ,
934
- "math domain error" ); /* invalid arg */
935
- return NULL ;
936
- }
933
+ if (isnan (r ) && !isnan (x ))
934
+ goto domain_err ; /* domain error */
937
935
if (isinf (r ) && isfinite (x )) {
938
936
if (can_overflow )
939
937
PyErr_SetString (PyExc_OverflowError ,
940
938
"math range error" ); /* overflow */
941
939
else
942
- PyErr_SetString (PyExc_ValueError ,
943
- "math domain error" ); /* singularity */
940
+ goto domain_err ; /* singularity */
944
941
return NULL ;
945
942
}
946
943
if (isfinite (r ) && errno && is_error (r ))
947
944
/* this branch unnecessary on most platforms */
948
945
return NULL ;
949
946
950
947
return PyFloat_FromDouble (r );
948
+ domain_err :
949
+ PyObject * a = PyFloat_FromDouble (x );
950
+ if (a ) {
951
+ PyErr_Format (PyExc_ValueError ,
952
+ err_msg ? err_msg : "math domain error" , a );
953
+ Py_DECREF (a );
954
+ }
955
+ return NULL ;
951
956
}
952
957
953
958
/* variant of math_1, to be used when the function being wrapped is known to
@@ -1032,7 +1037,13 @@ math_2(PyObject *const *args, Py_ssize_t nargs,
1032
1037
1033
1038
#define FUNC1 (funcname , func , can_overflow , docstring ) \
1034
1039
static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
1035
- return math_1(args, func, can_overflow); \
1040
+ return math_1(args, func, can_overflow, NULL); \
1041
+ }\
1042
+ PyDoc_STRVAR(math_##funcname##_doc, docstring);
1043
+
1044
+ #define FUNC1D (funcname , func , can_overflow , docstring , err_msg ) \
1045
+ static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
1046
+ return math_1(args, func, can_overflow, err_msg); \
1036
1047
}\
1037
1048
PyDoc_STRVAR(math_##funcname##_doc, docstring);
1038
1049
@@ -1070,9 +1081,10 @@ FUNC2(atan2, atan2,
1070
1081
"atan2($module, y, x, /)\n--\n\n"
1071
1082
"Return the arc tangent (measured in radians) of y/x.\n\n"
1072
1083
"Unlike atan(y/x), the signs of both x and y are considered." )
1073
- FUNC1 (atanh , atanh , 0 ,
1084
+ FUNC1D (atanh , atanh , 0 ,
1074
1085
"atanh($module, x, /)\n--\n\n"
1075
- "Return the inverse hyperbolic tangent of x." )
1086
+ "Return the inverse hyperbolic tangent of x." ,
1087
+ "expected a number between -1 and 1, got %R" )
1076
1088
FUNC1 (cbrt , cbrt , 0 ,
1077
1089
"cbrt($module, x, /)\n--\n\n"
1078
1090
"Return the cube root of x." )
@@ -1205,9 +1217,10 @@ FUNC1(sin, sin, 0,
1205
1217
FUNC1 (sinh , sinh , 1 ,
1206
1218
"sinh($module, x, /)\n--\n\n"
1207
1219
"Return the hyperbolic sine of x." )
1208
- FUNC1 (sqrt , sqrt , 0 ,
1220
+ FUNC1D (sqrt , sqrt , 0 ,
1209
1221
"sqrt($module, x, /)\n--\n\n"
1210
- "Return the square root of x." )
1222
+ "Return the square root of x." ,
1223
+ "expected a nonnegative input, got %R" )
1211
1224
FUNC1 (tan , tan , 0 ,
1212
1225
"tan($module, x, /)\n--\n\n"
1213
1226
"Return the tangent of x (measured in radians)." )
@@ -2180,7 +2193,7 @@ math_modf_impl(PyObject *module, double x)
2180
2193
in that int is larger than PY_SSIZE_T_MAX. */
2181
2194
2182
2195
static PyObject *
2183
- loghelper (PyObject * arg , double (* func )(double ))
2196
+ loghelper (PyObject * arg , double (* func )(double ), const char * err_msg )
2184
2197
{
2185
2198
/* If it is int, do it ourselves. */
2186
2199
if (PyLong_Check (arg )) {
@@ -2189,8 +2202,7 @@ loghelper(PyObject* arg, double (*func)(double))
2189
2202
2190
2203
/* Negative or zero inputs give a ValueError. */
2191
2204
if (!_PyLong_IsPositive ((PyLongObject * )arg )) {
2192
- PyErr_SetString (PyExc_ValueError ,
2193
- "math domain error" );
2205
+ PyErr_Format (PyExc_ValueError , err_msg , arg );
2194
2206
return NULL ;
2195
2207
}
2196
2208
@@ -2214,7 +2226,7 @@ loghelper(PyObject* arg, double (*func)(double))
2214
2226
}
2215
2227
2216
2228
/* Else let libm handle it by itself. */
2217
- return math_1 (arg , func , 0 );
2229
+ return math_1 (arg , func , 0 , err_msg );
2218
2230
}
2219
2231
2220
2232
@@ -2229,11 +2241,11 @@ math_log(PyObject *module, PyObject * const *args, Py_ssize_t nargs)
2229
2241
if (!_PyArg_CheckPositional ("log" , nargs , 1 , 2 ))
2230
2242
return NULL ;
2231
2243
2232
- num = loghelper (args [0 ], m_log );
2244
+ num = loghelper (args [0 ], m_log , "expected a positive input, got %R" );
2233
2245
if (num == NULL || nargs == 1 )
2234
2246
return num ;
2235
2247
2236
- den = loghelper (args [1 ], m_log );
2248
+ den = loghelper (args [1 ], m_log , "expected a positive input, got %R" );
2237
2249
if (den == NULL ) {
2238
2250
Py_DECREF (num );
2239
2251
return NULL ;
@@ -2263,7 +2275,7 @@ static PyObject *
2263
2275
math_log2 (PyObject * module , PyObject * x )
2264
2276
/*[clinic end generated code: output=5425899a4d5d6acb input=08321262bae4f39b]*/
2265
2277
{
2266
- return loghelper (x , m_log2 );
2278
+ return loghelper (x , m_log2 , "expected a positive input, got %R" );
2267
2279
}
2268
2280
2269
2281
@@ -2280,7 +2292,7 @@ static PyObject *
2280
2292
math_log10 (PyObject * module , PyObject * x )
2281
2293
/*[clinic end generated code: output=be72a64617df9c6f input=b2469d02c6469e53]*/
2282
2294
{
2283
- return loghelper (x , m_log10 );
2295
+ return loghelper (x , m_log10 , "expected a positive input, got %R" );
2284
2296
}
2285
2297
2286
2298
0 commit comments