Was ist das Implementierungsprinzip komplexer Zahlen in der virtuellen Python-Maschine?

王林
Freigeben: 2023-05-13 10:40:21
nach vorne
1377 Leute haben es durchsucht

    复数数据结构

    在 cpython 当中对于复数的数据结构实现如下所示:

    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;
    Nach dem Login kopieren

    上面的数据结构图示如下:

    Was ist das Implementierungsprinzip komplexer Zahlen in der virtuellen Python-Maschine?

    复数的数据在整个 cpython 虚拟机当中来说应该算是比较简单的了,除了一个 PyObject 头部之外就是实部和虚部了。

    • ob_refcnt,表示对象的引用记数的个数,这个对于垃圾回收很有用处,后面我们分析虚拟机中垃圾回收部分在深入分析。

    • ob_type,表示这个对象的数据类型是什么,在 python 当中有时候需要对数据的数据类型进行判断比如 isinstance, type 这两个关键字就会使用到这个字段。

    • real,表示复数的实部。

    • imag,表示复数的虚部。

    复数的操作

    复数加法

    下面是 cpython 当中对于复数加法的实现,为了简洁删除了部分无用代码。

    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;
    }
    Nach dem Login kopieren

    上面代码的整体过程比较简单:

    • 首先先从 PyComplexObject 提取真正的复数部分。

    • 将提取到的两个复数进行相加操作。

    • 根据得到的结果在创建一个 PyComplexObject 对象,并且将这个对象返回。

    复数取反

    复数取反操作就是将实部和虚部取相反数就可以了,这个操作也比较简单。

    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;
    }
    Nach dem Login kopieren

    Repr 函数

    我们现在来介绍一下一个有趣的方法,就是复数类型的 repr 函数,这个和类的 __repr__ 函数是作用是一样的我们看一下复数的输出是什么:

    >>> data = complex(0, 1)
    >>> data
    1j
    >>> data = complex(1, 1)
    >>> data
    (1+1j)
    >>> print(data)
    (1+1j)
    Nach dem Login kopieren

    复数的 repr 对应的 C 函数如下所示:

    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;
    }
    Nach dem Login kopieren

    我们现在修改源程序将上面的 () 两个括号变成 [],编译之后执行的结果如下所示:

    Was ist das Implementierungsprinzip komplexer Zahlen in der virtuellen Python-Maschine?

    可以看到括号变成了 [] 。

    Das obige ist der detaillierte Inhalt vonWas ist das Implementierungsprinzip komplexer Zahlen in der virtuellen Python-Maschine?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Verwandte Etiketten:
    Quelle:yisu.com
    Erklärung dieser Website
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
    Beliebte Tutorials
    Mehr>
    Neueste Downloads
    Mehr>
    Web-Effekte
    Quellcode der Website
    Website-Materialien
    Frontend-Vorlage