栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

读Python源码(二)Python整数如何进行加减运算

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

读Python源码(二)Python整数如何进行加减运算

简介:

本节主要目的要基本了解python中整数加减运算的实现,在此之前要先了解python中整数实现方式可以先查看(一)之后再看本节。

注:这里说明一下,下面介绍均已8个比特位举例。那么ob_digit 每一个元素我们认定最多只能占7位。从源码中类推过来,这样是为了防止两数相加溢出问题,比如255+255 这时8位肯定放不下了,只占7位最多127+127=254。

1.加法运算

在了解了整数实现之后,我们在同一文件下(longobject.c)可以发现long_add函数实现了两整数相加的运算,那么接下来我们就来一步一步分析其实现:

static PyObject *
long_add(PyLongObject *a, PyLongObject *b)
{
    PyLongObject *z;

    CHECK_BINOP(a, b);

    if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) {
        return PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b));
    }
    if (Py_SIZE(a) < 0) {
        if (Py_SIZE(b) < 0) {
            z = x_add(a, b);
            if (z != NULL) {
                
                assert(Py_REFCNT(z) == 1);
                Py_SIZE(z) = -(Py_SIZE(z));
            }
        }
        else
            z = x_sub(b, a);
    }
    else {
        if (Py_SIZE(b) < 0)
            z = x_sub(a, b);
        else
            z = x_add(a, b);
    }
    return (PyObject *)z;
}

从上面这段代码中首先可以看到当整数ob_digit长度<=1的时候是通过PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b))来求值的,那么接下来就简单看一下它的实现方式:

先将a,b的值通过C相加之后再由 PyLong_FromLong转成Python的整数对象,那么接下来我们就先看一下它是如何转换的。

PyObject *
PyLong_FromLong(long ival)
{
    PyLongObject *v;
    unsigned long abs_ival;
    unsigned long t;  
    int ndigits = 0;
    int sign;

    CHECK_SMALL_INT(ival);
    
    
    if (ival < 0) {
        
        abs_ival = 0U-(unsigned long)ival;
        sign = -1;
    }
    else {
        abs_ival = (unsigned long)ival;
        sign = ival == 0 ? 0 : 1;
    }
    
    
    if (!(abs_ival >> PyLong_SHIFT)) {
        v = _PyLong_New(1);
        if (v) {
            Py_SIZE(v) = sign;
            v->ob_digit[0] = Py_SAFE_DOWNCAST(
                abs_ival, unsigned long, digit);
        }
        return (PyObject*)v;
    }

    
    t = abs_ival;
    while (t) {
        ++ndigits;
        t >>= PyLong_SHIFT;
    }
    // 此处ndigits = 2
    v = _PyLong_New(ndigits);
    if (v != NULL) {
        digit *p = v->ob_digit;
        Py_SIZE(v) = ndigits*sign; // 此处v的ob_size=2
        t = abs_ival; //t重新赋值200
        while (t) {
            // 第一次 t & PyLong_MASK = 200 & 127 = 0100 1000 = 72
            // 第二次 t & PyLong_MASK = 1 & 127 = 0000 0001 = 1
            *p++ = Py_SAFE_DOWNCAST(
                t & PyLong_MASK, unsigned long, digit);
            t >>= PyLong_SHIFT;
        }
    }
    return (PyObject *)v;
}

通过上述介绍,我们应该可以清楚ob_size的绝对值小于等于1的Python整数是如何相加的。

那么接下来看其他情况:根据两个数正负来判断是执行x_add函数还是执行x_sub函数,我们均已举例说明的方式查看。

例1:a = -200, b = -600
解析:此时当执行x_add函数
分别将a,b转为python对象 
a = {ob_size: 2, ob_digit: [72, 1]}
b = {ob_size: 2, ob_digit: [88, 4]}
static PyLongObject *
x_add(PyLongObject *a, PyLongObject *b)
{
    // size_a = size_b = 2
    Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b));
    PyLongObject *z;
    Py_ssize_t i;
    digit carry = 0;

    
    if (size_a < size_b) {
        { PyLongObject *temp = a; a = b; b = temp; }
        { Py_ssize_t size_temp = size_a;
            size_a = size_b;
            size_b = size_temp; }
    }
    z = _PyLong_New(size_a+1);
    if (z == NULL)
        return NULL;
    
    for (i = 0; i < size_b; ++i) {
        
        carry += a->ob_digit[i] + b->ob_digit[i];
        
        z->ob_digit[i] = carry & PyLong_MASK;
        
        carry >>= PyLong_SHIFT;
    }
    for (; i < size_a; ++i) {
        carry += a->ob_digit[i];
        z->ob_digit[i] = carry & PyLong_MASK;
        carry >>= PyLong_SHIFT;
    }
    z->ob_digit[i] = carry;  // z->ob_digit[2] = 0
    return long_normalize(z);
}
最终结果:z = {ob_size: -2, ob_digit: [32, 6]} = -(32*128**0 + 6*128**1) = -800
例2:a = 200, b = -600
解析:此时执行x_sub(a, b)
将a,b分别转成python对象
a = {ob_size: 2, ob_digit: [72, 1]}
b = {ob_size: -2, ob_digit: [88, 4]}
将a和b带入x_sub
static PyLongObject *
x_sub(PyLongObject *a, PyLongObject *b)
{
    // size_a = size_b = 2
    Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b));
    PyLongObject *z;
    Py_ssize_t i;
    int sign = 1;
    digit borrow = 0;

    
    if (size_a < size_b) {
        sign = -1;
        { PyLongObject *temp = a; a = b; b = temp; }
        { Py_ssize_t size_temp = size_a;
            size_a = size_b;
            size_b = size_temp; }
    }
    else if (size_a == size_b) {
        
        i = size_a;
        while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
            ;
        
        if (i < 0)
            return (PyLongObject *)PyLong_FromLong(0);
        
        if (a->ob_digit[i] < b->ob_digit[i]) {
            sign = -1;  // 标志结果为负数
            { PyLongObject *temp = a; a = b; b = temp; }
        }
        size_a = size_b = i+1;
    }
    // 执行至此,a和b已交换
    z = _PyLong_New(size_a);
    if (z == NULL)
        return NULL;
    for (i = 0; i < size_b; ++i) {
        
        
        borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
        
        z->ob_digit[i] = borrow & PyLong_MASK;
        
        borrow >>= PyLong_SHIFT;
        
        borrow &= 1; 
    }
    for (; i < size_a; ++i) {
        borrow = a->ob_digit[i] - borrow;
        z->ob_digit[i] = borrow & PyLong_MASK;
        borrow >>= PyLong_SHIFT;
        borrow &= 1; 
    }
    assert(borrow == 0);
    if (sign < 0) {  // 本例此时成立
        Py_SIZE(z) = -Py_SIZE(z);
    }
    return long_normalize(z);
}
最终结果:z = {ob_size: -2, ob_digit: [16, 3]} = -(16*128**0 + 3*128**1) = -400
2.减法运算

 减法运算原理其实跟加法差不多的,就不在赘述了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/714579.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号