简介
编程里藏了好多数学小知识,别看这些知识点基础,吃透了能让代码跑得更快、逻辑更通透!我把平时写代码常用的二进制位运算、等差数列求和、进位原理这些整理出来,结合Python代码掰扯清楚,记下来复习用,全是大白话,不搞虚的,重点是“能看懂、能直接用”。
一、二进制与位运算
在我们写代码时偶尔会碰到位运算,一开始我也懵,后来发现这玩意儿就是直接操弄二进制的0和1,比普通加减乘除快多了!Python里就四种核心位运算,和布尔逻辑的与、或、异或、非对应,先把规则和用法记死,用到的时候直接套就行。
| 位运算 | 符号 | 大白话 | 通俗别名 |
|---|---|---|---|
| 按位与 | & | 俩位都为1才是1,否则0 | AND |
| 按位或 | \ | 只要有一个1就是1,否则0 | OR |
| 按位异或 | ^ | 俩位不一样才是1,一样就是0 | XOR |
| 按位取反 | ~ | 0变1、1变0(Python里要注意补码) | NOT |
| 左位移 | << | 二进制整体左移,右边补0,等价乘2ⁿ | 左移 |
| 右位移 | >> | 二进制整体右移,左边补符号位,等价除2ⁿ | 右移 |
1. 按位与(AND:&)
说白了就是“严要求”,必须俩位都为1才给1,不然全是0。我亲测最常用的场景就是判断奇偶——任何数和1做按位与,结果为1就是奇数,为0就是偶数,比取模%快多了!
# 二进制数 0b101(十进制5)和 0b111(十进制7)的 AND 运算
a = 0b101 # 十进制5,二进制就是101
b = 0b111 # 十进制7,二进制就是111
c = a & b # 逐位比:1&1=1,0&1=0,1&1=1 → 结果0b101(十进制5)
print(f"二进制结果:{bin(c)},十进制结果:{c}") # 输出:0b101,5
# 实用场景:判断奇偶(亲测比num % 2快)
def is_odd(num):
return num & 1 == 1 # 结果为True就是奇数,False是偶数
print(f"15是奇数吗?{is_odd(15)}") # True
print(f"20是奇数吗?{is_odd(20)}") # False2. 按位或(OR:|)
这玩意儿是“松要求”,只要有一个位是1,结果就为1,特别适合给二进制的特定位赋值1,比如权限控制里合并多个权限标记。
# 二进制数 0b101(十进制5)和 0b110(十进制6)的 OR 运算
a = 0b101 # 十进制5
b = 0b110 # 十进制6
c = a | b # 逐位比:1|1=1,0|1=1,1|0=1 → 结果0b111(十进制7)
print(f"二进制结果:{bin(c)},十进制结果:{c}") # 输出:0b111,7
# 实用场景:给数字的二进制某位置1(比如给0b101的第二位设为1)
num = 0b101 # 5
mask = 0b010 # 要设置的位
result = num | mask
print(f"置1后:{bin(result)}") # 0b111,也就是73. 按位异或(XOR:^)
这个是我最喜欢的!俩位不一样就给1,一样就给0,最牛的用法是不用临时变量交换两个数,代码贼简洁,面试也常考!
# 二进制数 0b101(十进制5)和 0b110(十进制6)的 XOR 运算
a = 0b101 # 十进制5
b = 0b110 # 十进制6
c = a ^ b # 逐位比:1^1=0,0^1=1,1^0=1 → 结果0b011(十进制3)
print(f"二进制结果:{bin(c)},十进制结果:{c}") # 输出:0b11,3
# 实用场景:交换两个数(不用temp变量)
x = 10
y = 20
print(f"交换前:x=,y={y}")
x ^= y # 第一步:x = x^y = 10^20
y ^= x # 第二步:y = y^(x^y) = x
x ^= y # 第三步:x = (x^y)^x = y
print(f"交换后:x=,y={y}") # x=20,y=10,完美交换!4. 按位取反(NOT:~)
这个要注意坑!表面是按位取反,但Python里整数用补码存储,所以取反后不是单纯的0变1,而是 ~x = -(x + 1),记着这个公式就不会错了。
# 对二进制数 0b101(十进制5)进行 NOT 运算
a = 0b101 # 十进制5,补码是...00000101
b = ~a # 取反后补码是...11111010 → 对应十进制-6,符合~x=-(x+1)
print(f"二进制结果:{bin(b)},十进制结果:{b}") # 输出:-0b110,-6
# 验证公式:~x = -(x+1)
print(f"~5 = {~5},-(5+1) = {-6}") # 两边相等,记死这个公式!5. 位移运算(<< / >>)
位运算里位移也超常用,说白了就是“二进制搬家”,左移1位等于乘2,右移1位等于除2,比直接乘除快多了!
# 左位移:0b101(5)左移1位 → 0b1010(10),等价5*2
num = 5
print(f"5左移1位:{num << 1}") # 10
print(f"5左移2位:{num << 2}") # 20(等价5*4)
# 右位移:0b1010(10)右移1位 → 0b101(5),等价10/2
num = 10
print(f"10右移1位:{num >> 1}") # 5
print(f"10右移2位:{num >> 2}") # 2(等价10//4)二、等差数列求和
写代码时经常要算连续数字的和,比如统计1到100的和、100到1000的和,要是用for循环累加太笨了!等差数列求和公式直接套,一秒出结果,效率拉满。
核心公式
- 基础版(公差=1,比如1,2,3...):
项数 $n = a_n - a_1 + 1$($a_1$首项,$a_n$末项)
和 $S = n \times (a_1 + a_n) // 2$ - 通用版(公差≠1,比如1,3,5,7...):
项数 $n = [(a_n - a_1) ÷ 公差d] + 1$
和 $S = n \times [2a_1 + (n-1)d] // 2$
Python 实现
'''
自定义等差数列求和函数,支持公差≠1的情况
a1:首项,an:末项,d:公差(默认1)
返回值:数列的和
'''
def arithmetic_sum(a1, an, d=1):
# 先校验参数,避免传错
if a1 > an or d <= 0:
raise ValueError("首项不能大于末项,公差得是正数!")
# 计算项数
n = (an - a1) // d + 1
# 通用求和公式
total = n * (2 * a1 + (n - 1) * d) // 2
return total
# 测试1:100至1000的连续整数和(公差1)
print(f"100到1000的和:{arithmetic_sum(100, 1000)}") # 输出495550
# 测试2:1,3,5,...,99的奇数和(公差2)
print(f"1到99的奇数和:{arithmetic_sum(1, 99, 2)}") # 输出2500
# 测试3:2,4,6,...,100的偶数和(公差2)
print(f"2到100的偶数和:{arithmetic_sum(2, 100, 2)}") # 输出2550为什么不用循环?
我测过,算1到1000000的和,循环要跑0.1秒左右,用公式直接0.0001秒搞定,数据量越大,公式的优势越明显!记着:只要是“相邻数差值固定”的数列,都用这个公式,别傻乎乎写循环。
三、进位原理
咱平时用的+号,计算机底层其实是靠“进位”实现的!不管十进制还是二进制,核心都是“逢n进1”(十进制逢10进1,二进制逢2进1)。我写了个手动实现加法的函数,吃透这个逻辑,能搞懂计算机加法的底层。
1. 十进制进位加法
说白了就是“从个位开始加,满10进1”,我写的这个函数能模拟计算机的加法过程,哪怕是999+1这种要连续进位的情况也能搞定!
'''
手动实现十进制加法,模拟进位逻辑
a、b:两个加数(整数)
返回值:两数之和
'''
def carry_add(a, b):
# 把数字反转,方便从个位开始计算(比如123→"321")
a_str = str(a)[::-1]
b_str = str(b)[::-1]
result = 0 # 最终结果
carry = 0 # 进位标记(0或1)
max_len = max(len(a_str), len(b_str)) # 取最长位数,避免漏位
# 逐位计算
for i in range(max_len):
# 取出当前位的数字,超出长度就补0
a_digit = int(a_str[i]) if i < len(a_str) else 0
b_digit = int(b_str[i]) if i < len(b_str) else 0
# 当前位总和 = 个位数字和 + 上一位的进位
digit_sum = a_digit + b_digit + carry
# 判断是否进位
if digit_sum >= 10:
carry = 1 # 满10进1
digit_sum -= 10 # 只保留个位
else:
carry = 0 # 无进位
# 把当前位结果加到最终结果里(恢复位数)
result += digit_sum * (10 ** i)
# 最后还有进位的话,追加到最高位(比如999+1=1000)
if carry == 1:
result += 10 ** max_len
return result
# 测试案例,覆盖普通情况和连续进位
print(f"10 + 21 = {carry_add(10, 21)}") # 31
print(f"999 + 1 = {carry_add(999, 1)}") # 1000
print(f"1234 + 5678 = {carry_add(1234, 5678)}") # 69122. 二进制进位加法
计算机底层用的是二进制加法,核心是“逢2进1”,和十进制逻辑一样,就是把10换成2而已。搞懂这个,再看位运算加法就通透了!
'''
手动实现二进制加法,模拟计算机底层加法逻辑
a_bin、b_bin:二进制字符串(比如"101")
返回值:二进制和的字符串
'''
def binary_carry_add(a_bin, b_bin):
# 反转二进制字符串,从最低位开始算
a_rev = a_bin[::-1]
b_rev = b_bin[::-1]
result = [] # 存储每一位的结果
carry = 0 # 进位标记(0或1)
max_len = max(len(a_rev), len(b_rev))
for i in range(max_len):
# 取出当前位,补0
a_bit = int(a_rev[i]) if i < len(a_rev) else 0
b_bit = int(b_rev[i]) if i < len(b_rev) else 0
# 当前位总和 = 位和 + 进位
bit_sum = a_bit + b_bit + carry
# 逢2进1
if bit_sum >= 2:
carry = 1
bit_sum -= 2
else:
carry = 0
result.append(str(bit_sum))
# 最后有进位就加上
if carry == 1:
result.append("1")
# 反转回来,得到最终二进制字符串
return ''.join(result[::-1])
# 测试案例
print(f"101(5) + 110(6) = {binary_carry_add('101', '110')}") # 1011(11)
print(f"111(7) + 1(1) = {binary_carry_add('111', '1')}") # 1000(8)总结
- 位运算直接操作二进制,比普通运算快,重点记&判断奇偶、^交换变量、<<>>等价乘除2ⁿ;
- 等差数列求和别用循环,套公式:基础版$S = n×(a1+an)//2$,通用版加个公差d就行;
- 加法的核心是进位,十进制逢10进1,二进制逢2进1,手动实现一遍就能懂计算机加法的底层逻辑。
评论 (0)