python3解决位移溢出

本文探讨Python与JavaScript在位移运算上的不同,特别是在32位整数溢出处理上的区别。Python的int类型不会溢出,而JS则会截断。文中提供了一个Python函数int_overflow(val),用于模拟32位整数溢出效果,并实现了一个无符号右移函数unsigned_right_shift(n, i),用以匹配JS的>>>操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在观看该文章前,读者先可以看看这篇文章,清晰明了的介绍了位移的操作:https://www.cnblogs.com/yx729315991/p/6387711.html

因为要将js的一个签名算法移植到python上,遇到一些麻烦。
int无限宽度,不会溢出
算法中需要用到了32位int的溢出来参与运算,但是python的int是不会溢出的,达到界限后会自己转为long,所以很麻烦。

#使用-342686650:
ret = 123456789 << 20
print(ret)
得到结果129453825982464
print(bin(ret))
这个二进制是11101011011110011010001010100000000000000000000
明显已经超出32位了

在JS上
document.writeln(123456789 << 20);
得到结果是-783286272
这就是溢出后截取的,

在python上想实现溢出效果,找到一个函数
#这个函数可以得到32位int溢出结果,因为python的int一旦超过宽度就会自动转为long,永远不会溢出,有的结果却需要溢出的int作为参数继续参与运算
def int_overflow(val):
    maxint = 2147483647
    if not -maxint-1 <= val <= maxint:
        val = (val + (maxint + 1)) % (2 * (maxint + 1)) - maxint - 1
    return val


ret = int_overflow(123456789 << 20)
print(ret)
print(bin(ret))
现在得到结果是-783286272
二进制:-101110101100000000000000000000

负数使用无符号右移>>>
在JS中,可以使用 a>>>b来实现无符号位移,python中没有这个运算符,只能自己实现了

无符号右移>>>,就是将有符号int a和b转为无符号uint后,再进行普通右移>>运算

比如-1的有符号int就是-1,无符号int就是4294967295

我们自己实现>>>可以这样
#无符号右移
import ctypes
def unsigned_right_shitf(n,i):
    # 数字小于0,则转为32位无符号uint
    if n<0:
        n = ctypes.c_uint32(n).value
    # 正常位移位数是为正数,但是为了兼容js之类的,负数就右移变成左移好了
    if i<0:
        return -int_overflow(n << abs(i))
    #print(n)
    return int_overflow(n >> i)

ret = unsigned_right_shitf(-1,20)
print(ret)

结果等于4095
和JS上执行 -1 >>> 20 一样。

本文转载自:https://www.jianshu.com/p/24d11ab44ae6

### Python 中的位运算符及其使用 #### 1. 左移 (`<<`) 和 右移 (`>>`) 左移和右移是两种重要的位运算符,主要用于将整数的二进制形式向左或向右移动一定数量的位。 - **左移 (`<<`)** 将操作数的每一位向左移动指定的数量。左侧溢出的部分会被丢弃,右侧会填充零。这相当于将数值乘以 \(2^n\) 的效果(其中 n 是移动的位数)。 示例代码如下: ```python a = 5 # 二进制表示为 0101 result = a << 2 # 向左移动两位,结果为 010100 (即十进制的 20) print(result) # 输出: 20 ``` - **右移 (`>>`)** 将操作数的每一位向右移动指定的数量。对于无符号整数,高位被填入零;而对于有符号整数,取决于实现方式(通常是算术右移,保持符号位不变)。这相当于将数值除以 \(2^n\) 并向下取整的效果。 示例代码如下: ```python a = 5 # 二进制表示为 0101 result = a >> 1 # 向右移动一位,结果为 0010 (即十进制的 2) print(result) # 输出: 2 ``` --- #### 2. 按位取反 (`~`) 按位取反是对操作数的每一个二进制位执行反转操作。如果某一位是 `1` 则变为 `0`,如果是 `0` 则变为 `1`。需要注意的是,在 Python 中,整数是以补码的形式存储的,因此按位取反的结果可能是一个负数。 示例代码如下: ```python a = 9 # 十进制表示为 9, 二进制表示为 00001001 result = ~a # 结果为 -10 (因为 ~9 表示 -(9+1),这是基于补码计算得出) print(result) # 输出: -10 ``` --- #### 3. 应用场景 虽然位运算是底层开发的重要工具之一[^3],但在日常的应用层开发中也有一定的应用场景: - 数据压缩:通过位运算可以高效地打包多个布尔值到一个整数变量中。 - 性能优化:某些情况下,位运算比传统的加减法更高效。 - 图像处理:像素级别的颜色通道调整通常涉及大量的位运算。 --- #### 4. 综合示例 下面展示了一个综合使用的例子,涵盖了多种位运算符的功能: ```python class Geek: def __init__(self, value): self.value = value def __and__(self, other): # 重载 & return f"AND Result: {self.value & other.value}" def __or__(self, other): # 重载 | return f"OR Result: {self.value | other.value}" g1 = Geek(5) # 二进制表示为 0101 g2 = Geek(3) # 二进制表示为 0011 print(g1 & g2) # 调用了 __and__ 方法,输出 AND Result: 1 print(g1 | g2) # 调用了 __or__ 方法,输出 OR Result: 7 ``` 上述代码展示了如何自定义类并重载位运算符的行为[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值