@@ -921,33 +921,40 @@ 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
+
949
+ domain_err :
950
+ PyObject * a = PyFloat_FromDouble (x );
951
+
952
+ if (a ) {
953
+ PyErr_Format (PyExc_ValueError ,
954
+ err_msg ? err_msg : "math domain error" , a );
955
+ Py_DECREF (a );
956
+ }
957
+ return NULL ;
951
958
}
952
959
953
960
/* variant of math_1, to be used when the function being wrapped is known to
@@ -1032,7 +1039,13 @@ math_2(PyObject *const *args, Py_ssize_t nargs,
1032
1039
1033
1040
#define FUNC1 (funcname , func , can_overflow , docstring ) \
1034
1041
static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
1035
- return math_1(args, func, can_overflow); \
1042
+ return math_1(args, func, can_overflow, NULL); \
1043
+ }\
1044
+ PyDoc_STRVAR(math_##funcname##_doc, docstring);
1045
+
1046
+ #define FUNC1D (funcname , func , can_overflow , docstring , err_msg ) \
1047
+ static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
1048
+ return math_1(args, func, can_overflow, err_msg); \
1036
1049
}\
1037
1050
PyDoc_STRVAR(math_##funcname##_doc, docstring);
1038
1051
@@ -1070,9 +1083,10 @@ FUNC2(atan2, atan2,
1070
1083
"atan2($module, y, x, /)\n--\n\n"
1071
1084
"Return the arc tangent (measured in radians) of y/x.\n\n"
1072
1085
"Unlike atan(y/x), the signs of both x and y are considered." )
1073
- FUNC1 (atanh , atanh , 0 ,
1086
+ FUNC1D (atanh , atanh , 0 ,
1074
1087
"atanh($module, x, /)\n--\n\n"
1075
- "Return the inverse hyperbolic tangent of x." )
1088
+ "Return the inverse hyperbolic tangent of x." ,
1089
+ "expected a number between -1 and 1, got %R" )
1076
1090
FUNC1 (cbrt , cbrt , 0 ,
1077
1091
"cbrt($module, x, /)\n--\n\n"
1078
1092
"Return the cube root of x." )
@@ -1205,9 +1219,10 @@ FUNC1(sin, sin, 0,
1205
1219
FUNC1 (sinh , sinh , 1 ,
1206
1220
"sinh($module, x, /)\n--\n\n"
1207
1221
"Return the hyperbolic sine of x." )
1208
- FUNC1 (sqrt , sqrt , 0 ,
1222
+ FUNC1D (sqrt , sqrt , 0 ,
1209
1223
"sqrt($module, x, /)\n--\n\n"
1210
- "Return the square root of x." )
1224
+ "Return the square root of x." ,
1225
+ "expected a nonnegative input, got %R" )
1211
1226
FUNC1 (tan , tan , 0 ,
1212
1227
"tan($module, x, /)\n--\n\n"
1213
1228
"Return the tangent of x (measured in radians)." )
@@ -2180,7 +2195,7 @@ math_modf_impl(PyObject *module, double x)
2180
2195
in that int is larger than PY_SSIZE_T_MAX. */
2181
2196
2182
2197
static PyObject *
2183
- loghelper (PyObject * arg , double (* func )(double ))
2198
+ loghelper (PyObject * arg , double (* func )(double ), const char * err_msg )
2184
2199
{
2185
2200
/* If it is int, do it ourselves. */
2186
2201
if (PyLong_Check (arg )) {
@@ -2189,8 +2204,7 @@ loghelper(PyObject* arg, double (*func)(double))
2189
2204
2190
2205
/* Negative or zero inputs give a ValueError. */
2191
2206
if (!_PyLong_IsPositive ((PyLongObject * )arg )) {
2192
- PyErr_SetString (PyExc_ValueError ,
2193
- "math domain error" );
2207
+ PyErr_Format (PyExc_ValueError , err_msg , arg );
2194
2208
return NULL ;
2195
2209
}
2196
2210
@@ -2214,7 +2228,7 @@ loghelper(PyObject* arg, double (*func)(double))
2214
2228
}
2215
2229
2216
2230
/* Else let libm handle it by itself. */
2217
- return math_1 (arg , func , 0 );
2231
+ return math_1 (arg , func , 0 , err_msg );
2218
2232
}
2219
2233
2220
2234
@@ -2229,11 +2243,11 @@ math_log(PyObject *module, PyObject * const *args, Py_ssize_t nargs)
2229
2243
if (!_PyArg_CheckPositional ("log" , nargs , 1 , 2 ))
2230
2244
return NULL ;
2231
2245
2232
- num = loghelper (args [0 ], m_log );
2246
+ num = loghelper (args [0 ], m_log , "expected a positive input, got %R" );
2233
2247
if (num == NULL || nargs == 1 )
2234
2248
return num ;
2235
2249
2236
- den = loghelper (args [1 ], m_log );
2250
+ den = loghelper (args [1 ], m_log , "expected a positive input, got %R" );
2237
2251
if (den == NULL ) {
2238
2252
Py_DECREF (num );
2239
2253
return NULL ;
@@ -2263,7 +2277,7 @@ static PyObject *
2263
2277
math_log2 (PyObject * module , PyObject * x )
2264
2278
/*[clinic end generated code: output=5425899a4d5d6acb input=08321262bae4f39b]*/
2265
2279
{
2266
- return loghelper (x , m_log2 );
2280
+ return loghelper (x , m_log2 , "expected a positive input, got %R" );
2267
2281
}
2268
2282
2269
2283
@@ -2280,7 +2294,7 @@ static PyObject *
2280
2294
math_log10 (PyObject * module , PyObject * x )
2281
2295
/*[clinic end generated code: output=be72a64617df9c6f input=b2469d02c6469e53]*/
2282
2296
{
2283
- return loghelper (x , m_log10 );
2297
+ return loghelper (x , m_log10 , "expected a positive input, got %R" );
2284
2298
}
2285
2299
2286
2300
0 commit comments