Home >Backend Development >Python Tutorial >What is the implementation principle of complex numbers in the Python virtual machine?
The implementation of the complex data structure in cpython is as follows:
typedef struct { double real; double imag; } Py_complex; #define PyObject_HEAD PyObject ob_base; typedef struct { PyObject_HEAD Py_complex cval; } PyComplexObject; typedef struct _object { _PyObject_HEAD_EXTRA Py_ssize_t ob_refcnt; struct _typeobject *ob_type; } PyObject;
The above data structure diagram As follows:
Complex data should be relatively simple in the entire cpython virtual machine. In addition to a PyObject header, there are real and imaginary parts.
ob_refcnt represents the number of reference counts of the object. This is very useful for garbage collection. Later we will analyze the garbage collection part of the virtual machine in depth.
ob_type, indicates the data type of this object. In python, sometimes it is necessary to judge the data type of the data. For example, the two keywords of isinstance and type will be used. field.
real represents the real part of a complex number.
imag, represents the imaginary part of a complex number.
The following is the implementation of complex number addition in cpython. Some useless code has been deleted for simplicity.
static PyObject * complex_add(PyObject *v, PyObject *w) { Py_complex result; Py_complex a, b; TO_COMPLEX(v, a); // TO_COMPLEX 这个宏的作用就是将一个 PyComplexObject 中的 Py_complex 对象存储到 a 当中 TO_COMPLEX(w, b); result = _Py_c_sum(a, b); // 这个函数的具体实现在下方 return PyComplex_FromCComplex(result); // 这个函数的具体实现在下方 } // 真正实现复数加法的函数 Py_complex _Py_c_sum(Py_complex a, Py_complex b) { Py_complex r; r.real = a.real + b.real; r.imag = a.imag + b.imag; return r; } PyObject * PyComplex_FromCComplex(Py_complex cval) { PyComplexObject *op; /* Inline PyObject_New */ // 申请内存空间 op = (PyComplexObject *) PyObject_MALLOC(sizeof(PyComplexObject)); if (op == NULL) return PyErr_NoMemory(); // 将这个对象的引用计数设置成 1 (void)PyObject_INIT(op, &PyComplex_Type); // 将复数结构体保存下来 op->cval = cval; return (PyObject *) op; }
The overall process of the above code is relatively simple:
First extract the real plural part from PyComplexObject.
Add the two extracted complex numbers.
Create a PyComplexObject object based on the result obtained, and return this object.
The complex number inversion operation is just to invert the real part and the imaginary part. This operation is also relatively simple.
static PyObject * complex_neg(PyComplexObject *v) { Py_complex neg; neg.real = -v->cval.real; neg.imag = -v->cval.imag; return PyComplex_FromCComplex(neg); } PyObject * PyComplex_FromCComplex(Py_complex cval) { PyComplexObject *op; /* Inline PyObject_New */ op = (PyComplexObject *) PyObject_MALLOC(sizeof(PyComplexObject)); if (op == NULL) return PyErr_NoMemory(); (void)PyObject_INIT(op, &PyComplex_Type); op->cval = cval; return (PyObject *) op; }
We will now introduce an interesting method, which is the repr function of the complex type. This function has the same effect as the __repr__ function of the class. Let’s take a look at the output of complex numbers. What is it:
>>> data = complex(0, 1) >>> data 1j >>> data = complex(1, 1) >>> data (1+1j) >>> print(data) (1+1j)
The C function corresponding to the plural repr is as follows:
static PyObject * complex_repr(PyComplexObject *v) { int precision = 0; char format_code = 'r'; PyObject *result = NULL; /* If these are non-NULL, they'll need to be freed. */ char *pre = NULL; char *im = NULL; /* These do not need to be freed. re is either an alias for pre or a pointer to a constant. lead and tail are pointers to constants. */ char *re = NULL; char *lead = ""; char *tail = ""; // 对应实部等于 0 虚部大于 0 的情况 if (v->cval.real == 0. && copysign(1.0, v->cval.real)==1.0) { /* Real part is +0: just output the imaginary part and do not include parens. */ re = ""; im = PyOS_double_to_string(v->cval.imag, format_code, precision, 0, NULL); if (!im) { PyErr_NoMemory(); goto done; } } else { /* Format imaginary part with sign, real part without. Include parens in the result. */ // 将实部浮点数变成字符串 pre = PyOS_double_to_string(v->cval.real, format_code, precision, 0, NULL); if (!pre) { PyErr_NoMemory(); goto done; } re = pre; // 将虚部浮点数变成字符串 im = PyOS_double_to_string(v->cval.imag, format_code, precision, Py_DTSF_SIGN, NULL); if (!im) { PyErr_NoMemory(); goto done; } // 用什么括号包围起来 lead = "("; tail = ")"; } result = PyUnicode_FromFormat("%s%s%sj%s", lead, re, im, tail); done: PyMem_Free(im); PyMem_Free(pre); return result; }
We now modify the source program to change the two parentheses of () above into [], and execute it after compilation The result is as follows:
#You can see that the brackets have changed to [].
The above is the detailed content of What is the implementation principle of complex numbers in the Python virtual machine?. For more information, please follow other related articles on the PHP Chinese website!