Cpython中定点int计算是否越界问题的处理

文章详细阐述了Python中int类型在处理数值运算时如何防止溢出。针对单目负号运算、Ssize_t和size_t转换、加法及乘法可能的溢出情况,分别提出了检查机制和处理策略。例如,加法通过`(x^a)>0||(x^b)>0`判断是否溢出,乘法则结合CPU指令和浮点数比较来确定结果的有效性。
摘要由CSDN通过智能技术生成

1 针对int类型数据的处理

总所周之PyIntObject中int是按照c语言中的long进行存储的,其支持字符,字符串,long, size_t等各种数据类型转换。

1.1)针对自身有效范围,单目运算的负号越界处理。

/* Integer overflow checking for unary negation: on a 2's-complement
 * box, -x overflows iff x is the most negative long.  In this case we
 * get -x == x.  However, -x is undefined (by C) if x /is/ the most
 * negative long (it's a signed overflow case), and some compilers care.
 * So we cast x to unsigned long first.  However, then other compilers
 * warn about applying unary minus to an unsigned operand.  Hence the
 * weird "0-".
 */
#define UNARY_NEG_WOULD_OVERFLOW(x)	\
	((x) < 0 && (unsigned long)(x) == 0-(unsigned long)(x))

1.2)从Ssize_t(signed long)和size_t(unsigned long)转换过来时,判断是否超过long的最大值表示范围(0x7fffffffffffffff~ -0x7fffffffffffffff -1L),超过则通过PyLongObject中的_PyLong_FromByteArray处理;

1.3)判断加法是否溢出; (x^a) >= 0 || (x^b) >= 0 (减法将b取负号处理)

详见: python整数各位相加_Python判断整数相加溢出_weixin_39911056的博客-CSDN博客

static PyObject *
int_add(PyIntObject *v, PyIntObject *w)
{
	register long a, b, x;
	CONVERT_TO_LONG(v, a);
	CONVERT_TO_LONG(w, b);
	x = a + b;
	if ((x^a) >= 0 || (x^b) >= 0)
		return PyInt_FromLong(x);
	return PyLong_Type.tp_as_number->nb_add((PyObject *)v, (PyObject *)w);
}

1.4)乘法溢出处理

通过正常的CPU指令去进行预算,溢出时进行比特级别的运算。(其中升到long和double位宽进行运输)

static PyObject *
int_mul(PyObject *v, PyObject *w)
{
	long a, b;
	long longprod;			/* a*b in native long arithmetic */
	double doubled_longprod;	/* (double)longprod */
	double doubleprod;		/* (double)a * (double)b */

	CONVERT_TO_LONG(v, a);
	CONVERT_TO_LONG(w, b);
	longprod = a * b;
	doubleprod = (double)a * (double)b;
	doubled_longprod = (double)longprod;

	/* Fast path for normal case:  small multiplicands, and no info
	   is lost in either method. */
	if (doubled_longprod == doubleprod)
		return PyInt_FromLong(longprod);

	/* Somebody somewhere lost info.  Close enough, or way off?  Note
	   that a != 0 and b != 0 (else doubled_longprod == doubleprod == 0).
	   The difference either is or isn't significant compared to the
	   true value (of which doubleprod is a good approximation).
	*/
	{
		const double diff = doubled_longprod - doubleprod;
		const double absdiff = diff >= 0.0 ? diff : -diff;
		const double absprod = doubleprod >= 0.0 ? doubleprod :
							  -doubleprod;
		/* absdiff/absprod <= 1/32 iff
		   32 * absdiff <= absprod -- 5 good bits is "close enough" */
        // An approximatation。
		if (32.0 * absdiff <= absprod)
			return PyInt_FromLong(longprod);
		else
			return PyLong_Type.tp_as_number->nb_multiply(v, w);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值