Python: why do functions in a math module accept decimal objects as arguments?

Bizzarely, every function in the Python math module seems to work fine with decimal objects. For example: frexp, exp, cos.

When I type print(math.frexp(decimal.Decimal('2341.12412'))) , Python prints the correct answer, which is (0.57156... , 12) , and does not throw any exceptions.

I would suggest that the math module be written in low-level C, relying as much as possible on hardware math operations to increase efficiency. So ... why will it work for Decimal objects?

Did they put type checking in mathematical functions and switch to another implementation if the argument is decimal? I have not seen anything like this in the docs. It may also be that Decimal is automatically converted to a float, but that also makes no sense.

Yes, I am confused.

+8
python decimal math
source share
1 answer

Looking good at math module.c , I got the following:

 static PyObject * math_frexp(PyObject *self, PyObject *arg) { int i; double x = PyFloat_AsDouble(arg); if (x == -1.0 && PyErr_Occurred()) return NULL; /* deal with special cases directly, to sidestep platform differences */ if (Py_IS_NAN(x) || Py_IS_INFINITY(x) || !x) { i = 0; } else { PyFPE_START_PROTECT("in math_frexp", return 0); x = frexp(x, &i); PyFPE_END_PROTECT(x); } return Py_BuildValue("(di)", x, i); } 

If you look at the code, it really uses float ( PyFloat_AsDouble )

Same for exp ,

 static PyObject * math_factorial(PyObject *self, PyObject *arg) { long x; PyObject *result, *odd_part, *two_valuation; if (PyFloat_Check(arg)) { PyObject *lx; double dx = PyFloat_AS_DOUBLE((PyFloatObject *)arg); if (!(Py_IS_FINITE(dx) && dx == floor(dx))) { PyErr_SetString(PyExc_ValueError, "factorial() only accepts integral values"); return NULL; } lx = PyLong_FromDouble(dx); if (lx == NULL) return NULL; x = PyLong_AsLong(lx); Py_DECREF(lx); ......................................................... 
+7
source share

All Articles