首頁  >  文章  >  後端開發  >  Python虛擬機器中浮點數的實作原理是什麼?

Python虛擬機器中浮點數的實作原理是什麼?

王林
王林轉載
2023-04-21 18:43:09938瀏覽

    Float 資料結構

    在cpython 虛擬機器當中浮點數類型的資料結構定義如下所示:

    typedef struct {
        PyObject_HEAD
        double ob_fval;
    } PyFloatObject;

    上面的數據結構定義圖示如下:

    Python虛擬機器中浮點數的實作原理是什麼?

    • 在上面的資料結構當中最重要的一個欄位就是ob_fval,這個就是真實儲存浮點數的地方。

    • ob_refcnt 就是物件的參考計數。

    • ob_type 就是物件的型別。

    浮點數的相關方法

    建立float 物件

    和我們在前面所討論到的元組和列表物件一樣,在cpython 內部實作float 類型的時候也會為float 物件做一層中間層以加快浮點數的記憶體分配,具體的相關程式碼如下所示:

    #define PyFloat_MAXFREELIST    100
    static int numfree = 0;
    static PyFloatObject *free_list = NULL;

    在cpython 內部做多會快取100 個float 物件的記憶體空間,如果超過100 就會直接釋放記憶體了,這裡需要注意一點的是只用一個指標就可以將所有的float 物件快取起來,這一點是如何實現的。

    這是使用在物件PyFloatObject 當中的struct _typeobject *ob_type; 這個欄位實現的,用這個欄位指向下一個float 物件的記憶體空間,因為在free_list 當中的資料並沒有使用,因此可以利用這個特點節省一些記憶體空間。下面則是建立float 物件的具體過程:

    PyObject *
    PyFloat_FromDouble(double fval)
    {
        // 首先查看 free_list 当中是否有空闲的 float 对象
        PyFloatObject *op = free_list;
        if (op != NULL) {
            // 如果有 那么就将让 free_list 指向 free_list 当中的下一个 float 对象 并且将对应的个数减 1
            free_list = (PyFloatObject *) Py_TYPE(op);
            numfree--;
        } else {
          	// 否则的话就需要申请内存空间
            op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject));
            if (!op)
                return PyErr_NoMemory();
        }
        /* Inline PyObject_New */
        (void)PyObject_INIT(op, &PyFloat_Type); // PyObject_INIT 这个宏的主要作用是将对象的引用计数设置成 1
        op->ob_fval = fval;
        return (PyObject *) op;
    }

    加法

    下面是在cpython 當中浮點數的加法具體實現,整個過程比較簡單就是得到新的值,並且建立一個新的PyFloatObject 對象,並且將這個對象傳回。

    static PyObject *
    float_add(PyObject *v, PyObject *w)
    {
        double a,b;
        CONVERT_TO_DOUBLE(v, a); // CONVERT_TO_DOUBLE 这个宏的主要作用就是将对象的 ob_fval 这个字段的值保存到 a 当中
        CONVERT_TO_DOUBLE(w, b); // 这个就是将 w 当中的 ob_fval 字段的值保存到 b 当中
        a = a + b;
        return PyFloat_FromDouble(a); // 创建一个新的 float 对象 并且将这个对象返回
    }

    減法

    同理減法也是一樣的。

    static PyObject *
    float_sub(PyObject *v, PyObject *w)
    {
        double a,b;
        CONVERT_TO_DOUBLE(v, a);
        CONVERT_TO_DOUBLE(w, b);
        a = a - b;
        return PyFloat_FromDouble(a);
    }

    乘法

    static PyObject *
    float_mul(PyObject *v, PyObject *w)
    {
        double a,b;
        CONVERT_TO_DOUBLE(v, a);
        CONVERT_TO_DOUBLE(w, b);
        PyFPE_START_PROTECT("multiply", return 0)
        a = a * b;
        PyFPE_END_PROTECT(a)
        return PyFloat_FromDouble(a);
    }

    除法

    static PyObject *
    float_div(PyObject *v, PyObject *w)
    {
        double a,b;
        CONVERT_TO_DOUBLE(v, a);
        CONVERT_TO_DOUBLE(w, b);
        if (b == 0.0) {
            PyErr_SetString(PyExc_ZeroDivisionError,
                            "float division by zero");
            return NULL;
        }
        a = a / b;
        return PyFloat_FromDouble(a);
    }

    取反

    這裡加入了一行輸出語句,這個是為了後面方便我們進行測試的。

    static PyObject *
    float_neg(PyFloatObject *v)
    {
        printf("%.2lf 正在进行取反运算\n", v->ob_fval);
        return PyFloat_FromDouble(-v->ob_fval);
    }

    求絕對值

    static PyObject *
    float_abs(PyFloatObject *v)
    {
        printf("%.2lf 正在进行取 abs 运算\n", v->ob_fval);
        return PyFloat_FromDouble(fabs(v->ob_fval));
    }

    求 bool 值

    static int
    float_bool(PyFloatObject *v)
    {
        printf("%.2lf 正在进行取 bool 运算\n", v->ob_fval);
        return v->ob_fval != 0.0;
    }

    下圖是我們對於 cpython 對程式的修改!

    Python虛擬機器中浮點數的實作原理是什麼?

    下面是修改之後我們再次對浮點數進行操作的時候的輸出,可以看到的是輸出了我們在上面的程式碼當中加入的語句。

    Python虛擬機器中浮點數的實作原理是什麼?

    以上是Python虛擬機器中浮點數的實作原理是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除