【数学笔记】编程中的数学小知识
2022-03-09 / 0 评论 / 66 阅读 / 8 点赞

【数学笔记】编程中的数学小知识

发光的神
2022-03-09 / 0 评论 / 66 阅读 / 正在检测是否收录...

简介

编程里藏了好多数学小知识,别看这些知识点基础,吃透了能让代码跑得更快、逻辑更通透!我把平时写代码常用的二进制位运算、等差数列求和、进位原理这些整理出来,结合Python代码掰扯清楚,记下来复习用,全是大白话,不搞虚的,重点是“能看懂、能直接用”。

一、二进制与位运算

在我们写代码时偶尔会碰到位运算,一开始我也懵,后来发现这玩意儿就是直接操弄二进制的0和1,比普通加减乘除快多了!Python里就四种核心位运算,和布尔逻辑的与、或、异或、非对应,先把规则和用法记死,用到的时候直接套就行。

位运算符号大白话通俗别名
按位与&俩位都为1才是1,否则0AND
按位或\只要有一个1就是1,否则0OR
按位异或^俩位不一样才是1,一样就是0XOR
按位取反~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)}")  # False

2. 按位或(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,也就是7

3. 按位异或(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)}")  # 6912

2. 二进制进位加法

计算机底层用的是二进制加法,核心是“逢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)

总结

  1. 位运算直接操作二进制,比普通运算快,重点记&判断奇偶、^交换变量、<<>>等价乘除2ⁿ;
  2. 等差数列求和别用循环,套公式:基础版$S = n×(a1+an)//2$,通用版加个公差d就行;
  3. 加法的核心是进位,十进制逢10进1,二进制逢2进1,手动实现一遍就能懂计算机加法的底层逻辑。
8

评论 (0)

取消
0:00