stm32 整数加法循环时间_CPython源码阅读10-整数运算

出现比较频繁的整数,我们把它放入小整数池,小整数池外边的整数,我们称为大整数。大整数是用digit数组实现的,就决定了大整数进行数学运算时难度比较大,看一下Cpython中如何实现的。

b4c8aa23d17231375a7e8ef6f5bad52f.png

整数对象、整数类型对象和整数运算之间的关系

整数加法在源码中:cpython-masterObjectslongobject.c

static PyObject *

long_add(PyLongObject *a, PyLongObject *b)

{

//定义z,用于保存a+b的临时对象

PyLongObject *z;

//检查ab是不是都指向PyLongObject

CHECK_BINOP(a, b);

//ab的 ob_size的绝对值是否都小于等于1;如是0,说明整数是0;如是1,一个元素,直接取出来。

//快速分支,大部分整数在这个分支截止

if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) {

//MEDIUM_VALUE拿出整数0或者digit[0] 0]

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) {

/* x_add received at least one multiple-digit int,

and thus z must be a multiple-digit int.

That also means z is not an element of

small_ints, so negating it in-place is safe. */

assert(Py_REFCNT(z) == 1);

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

}

ae9d7bca972bd7eacb138c50a0381d5a.png

long_add内部实现

long_add里边的if-else逻辑如下:

02b2fca2096dafdb72f062ee707b6f05.png

两数相加

将整数运算转换为整数绝对值运算,下边我们重点看两个整数绝对值是如何计算的

cpython-masterObjectslongobject.c

绝对值相加:

static PyLongObject *

x_add(PyLongObject *a, PyLongObject *b)

{

//获取a、b的ob_size的绝对值

Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b));

//a、b的临时结果存储

PyLongObject *z;

//循环变量

Py_ssize_t i;

//每个部分的运算结果

digit carry = 0;

//如果size_a < size_b,将a、b交换,将a、b的size交换

//相加按照相关,大的放在上边,小的放在下边,从右到左相加

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

}

//如果size_a >= size_b,则不需要交换

z = _PyLong_New(size_a+1);//考虑进位,长度比a和b中最大的加1

if (z == NULL)

return NULL;

for (i = 0; i < size_b; ++i) {//以b->ob_size为基准先遍历

carry += a->ob_digit[i] + b->ob_digit[i];

z->ob_digit[i] = carry & PyLong_MASK;//保证 z->ob_digit[i]不超过30位

carry >>= PyLong_SHIFT;//超出部分用于i+1,i+1比i多30位

}

for (; i < size_a; ++i) {//遍历完b之后,只剩a了

carry += a->ob_digit[i];

z->ob_digit[i] = carry & PyLong_MASK;//保证 z->ob_digit[i]不超过30位

carry >>= PyLong_SHIFT;//超出部分用于i+1,i+1比i多30位

}

z->ob_digit[i] = carry;//加上最后的进位

return long_normalize(z);//这个long_normalize函数作用就是从后往前依次检查ob_digit的元素,

//如果为0, 那么就将其ob_size减去1, 直到出现一个不为0的元素

}

PyLong_MASK// (1<<30)-1 = 2^30 - 1 说明后面30个位是1,前边两个位是0.

fa9b668467c8e954a25dea377ed6592a.png

PyLong_MASK和PyLong_SHIFT

cpython-masterObjectslongobject.c

绝对值相减:

static PyLongObject *

x_sub(PyLongObject *a, PyLongObject *b)

{

//获取a、b的ob_size的绝对值

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;//size_a > size_b 为1 否则就是-1

digit borrow = 0; //保存相减的结果

//确保a是两者中的大数

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) {//a、b的size相等,看一下里边的值是否也相等呢

/* Find highest digit where a and b differ: */

i = size_a;

while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])

; //如果都相等,i会变为-1

if (i < 0)

return (PyLongObject *)PyLong_FromLong(0);//a和b相等,直接返回0

if (a->ob_digit[i] < b->ob_digit[i]) {//a的某一位小于b的某一位,依旧要交换

sign = -1;

{ PyLongObject *temp = a; a = b; b = temp; }

}

size_a = size_b = i+1;//最终z的申请的ob_size的大小

}

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; /* Keep only one sign bit */

}

for (; i < size_a; ++i) {

borrow = a->ob_digit[i] - borrow;

z->ob_digit[i] = borrow & PyLong_MASK;

borrow >>= PyLong_SHIFT;

borrow &= 1; /* Keep only one sign bit */

}

assert(borrow == 0);

if (sign < 0) {

Py_SET_SIZE(z, -Py_SIZE(z));

}

return maybe_small_long(long_normalize(z));

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值