溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python虛擬機(jī)中復(fù)數(shù)的實(shí)現(xiàn)原理是什么

發(fā)布時(shí)間:2023-03-14 11:30:43 來源:億速云 閱讀:93 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“Python虛擬機(jī)中復(fù)數(shù)的實(shí)現(xiàn)原理是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Python虛擬機(jī)中復(fù)數(shù)的實(shí)現(xiàn)原理是什么”吧!

    復(fù)數(shù)數(shù)據(jù)結(jié)構(gòu)

    在 cpython 當(dāng)中對(duì)于復(fù)數(shù)的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)如下所示:

    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;

    上面的數(shù)據(jù)結(jié)構(gòu)圖示如下:

    Python虛擬機(jī)中復(fù)數(shù)的實(shí)現(xiàn)原理是什么

    復(fù)數(shù)的數(shù)據(jù)在整個(gè) cpython 虛擬機(jī)當(dāng)中來說應(yīng)該算是比較簡單的了,除了一個(gè) PyObject 頭部之外就是實(shí)部和虛部了。

    • ob_refcnt,表示對(duì)象的引用記數(shù)的個(gè)數(shù),這個(gè)對(duì)于垃圾回收很有用處,后面我們分析虛擬機(jī)中垃圾回收部分在深入分析。

    • ob_type,表示這個(gè)對(duì)象的數(shù)據(jù)類型是什么,在 python 當(dāng)中有時(shí)候需要對(duì)數(shù)據(jù)的數(shù)據(jù)類型進(jìn)行判斷比如 isinstance, type 這兩個(gè)關(guān)鍵字就會(huì)使用到這個(gè)字段。

    • real,表示復(fù)數(shù)的實(shí)部。

    • imag,表示復(fù)數(shù)的虛部。

    復(fù)數(shù)的操作

    復(fù)數(shù)加法

    下面是 cpython 當(dāng)中對(duì)于復(fù)數(shù)加法的實(shí)現(xiàn),為了簡潔刪除了部分無用代碼。

    static PyObject *
    complex_add(PyObject *v, PyObject *w)
    {
        Py_complex result;
        Py_complex a, b;
        TO_COMPLEX(v, a); // TO_COMPLEX 這個(gè)宏的作用就是將一個(gè) PyComplexObject 中的 Py_complex 對(duì)象存儲(chǔ)到 a 當(dāng)中
        TO_COMPLEX(w, b);
        result = _Py_c_sum(a, b); // 這個(gè)函數(shù)的具體實(shí)現(xiàn)在下方
        return PyComplex_FromCComplex(result); // 這個(gè)函數(shù)的具體實(shí)現(xiàn)在下方
    }
     
    // 真正實(shí)現(xiàn)復(fù)數(shù)加法的函數(shù)
    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 */
        // 申請(qǐng)內(nèi)存空間
        op = (PyComplexObject *) PyObject_MALLOC(sizeof(PyComplexObject));
        if (op == NULL)
            return PyErr_NoMemory();
        // 將這個(gè)對(duì)象的引用計(jì)數(shù)設(shè)置成 1
        (void)PyObject_INIT(op, &PyComplex_Type);
        // 將復(fù)數(shù)結(jié)構(gòu)體保存下來
        op->cval = cval;
        return (PyObject *) op;
    }

    上面代碼的整體過程比較簡單:

    • 首先先從 PyComplexObject 提取真正的復(fù)數(shù)部分。

    • 將提取到的兩個(gè)復(fù)數(shù)進(jìn)行相加操作。

    • 根據(jù)得到的結(jié)果在創(chuàng)建一個(gè) PyComplexObject 對(duì)象,并且將這個(gè)對(duì)象返回。

    復(fù)數(shù)取反

    復(fù)數(shù)取反操作就是將實(shí)部和虛部取相反數(shù)就可以了,這個(gè)操作也比較簡單。

    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;
    }

    Repr 函數(shù)

    我們現(xiàn)在來介紹一下一個(gè)有趣的方法,就是復(fù)數(shù)類型的 repr 函數(shù),這個(gè)和類的 __repr__ 函數(shù)是作用是一樣的我們看一下復(fù)數(shù)的輸出是什么:

    >>> data = complex(0, 1)
    >>> data
    1j
    >>> data = complex(1, 1)
    >>> data
    (1+1j)
    >>> print(data)
    (1+1j)

    復(fù)數(shù)的 repr 對(duì)應(yīng)的 C 函數(shù)如下所示:

    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 = "";
        // 對(duì)應(yīng)實(shí)部等于 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. */
            // 將實(shí)部浮點(diǎn)數(shù)變成字符串
            pre = PyOS_double_to_string(v->cval.real, format_code,
                                        precision, 0, NULL);
            if (!pre) {
                PyErr_NoMemory();
                goto done;
            }
            re = pre;
            // 將虛部浮點(diǎn)數(shù)變成字符串
            im = PyOS_double_to_string(v->cval.imag, format_code,
                                       precision, Py_DTSF_SIGN, NULL);
            if (!im) {
                PyErr_NoMemory();
                goto done;
            }
            // 用什么括號(hào)包圍起來
            lead = "(";
            tail = ")";
        }
        result = PyUnicode_FromFormat("%s%s%sj%s", lead, re, im, tail);
      done:
        PyMem_Free(im);
        PyMem_Free(pre);
     
        return result;
    }

    我們現(xiàn)在修改源程序?qū)⑸厦娴?() 兩個(gè)括號(hào)變成 [],編譯之后執(zhí)行的結(jié)果如下所示:

    Python虛擬機(jī)中復(fù)數(shù)的實(shí)現(xiàn)原理是什么

    可以看到括號(hào)變成了 [] 。

    到此,相信大家對(duì)“Python虛擬機(jī)中復(fù)數(shù)的實(shí)現(xiàn)原理是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI