一、什么是 math 模块?
1.1 一句话定义
math 是 Python 的内置数学库,提供了几乎所有常用的数学函数和常量(三角函数、对数、阶乘、取整、π、e 等)。
1.2 生活比喻
- Python 内置运算(
+、-、*、/、**)= 你手上的计算器基本按键 - math 模块 = 科学计算器上的所有高级按键(sin、cos、log、√、π...)
1.3 导入方式
# 方式1:导入整个模块(推荐)import mathprint(math.pi) # 3.141592653589793print(math.sqrt(16)) # 4.0# 方式2:导入特定函数from math import sqrt, pi, sinprint(sqrt(16)) # 4.0print(pi) # 3.141592653589793# 方式3:导入所有(不推荐,容易命名冲突)from math import *
1.4 注意事项
import math# ⚠️ math 模块的函数只接受实数(int 或 float)# 不支持复数!复数用 cmath 模块math.sqrt(4) # ✅ 2.0math.sqrt(-4) # ❌ ValueError: math domain error# 如果需要复数运算:import cmathcmath.sqrt(-4) # ✅ 2j
二、数学常量
import math# ============ π(圆周率) ============print(math.pi)# 3.141592653589793# 用途:圆的周长、面积、三角函数等# ============ e(自然常数) ============print(math.e)# 2.718281828459045# 用途:自然对数、指数增长、复利计算等# ============ τ(tau = 2π) ============print(math.tau)# 6.283185307179586# 一个完整圆周 = τ 弧度(有些场景比 π 更直观)# ============ 无穷大 ============print(math.inf) # inf(正无穷)print(-math.inf) # -inf(负无穷)print(math.inf + 1) # inf(无穷加任何数还是无穷)print(math.inf > 999999999) # True# ============ NaN(非数字) ============print(math.nan) # nanprint(math.nan == math.nan) # False!(NaN 不等于任何值,包括自己)print(math.isnan(math.nan)) # True(用 isnan 判断)# ============ 验证常量 ============print(math.tau == 2 * math.pi) # True
2.1 常量的实际应用
import math# 计算圆的面积和周长radius = 5area = math.pi * radius ** 2circumference = 2 * math.pi * radius # 或 math.tau * radiusprint(f"半径={radius} 的圆:面积={area:.2f}, 周长={circumference:.2f}")# 半径=5 的圆:面积=78.54, 周长=31.42# 计算球体体积def sphere_volume(r): return (4 / 3) * math.pi * r ** 3print(f"半径=3 的球体积:{sphere_volume(3):.2f}") # 113.10# 角度转弧度degrees = 180radians = degrees * math.pi / 180 # 或 math.radians(degrees)print(f"{degrees}° = {radians:.4f} 弧度") # 180° = 3.1416 弧度
三、取整函数
3.1 ceil —— 向上取整(天花板)
import math# ceil = ceiling(天花板),总是往"大"的方向取整print(math.ceil(3.1)) # 4(往上到4)print(math.ceil(3.9)) # 4print(math.ceil(3.0)) # 3(已经是整数,不变)print(math.ceil(-3.1)) # -3(-3 比 -3.1 大,所以是 -3)print(math.ceil(-3.9)) # -3print(math.ceil(0.001)) # 1# 生活场景:# 你有 23 个苹果,每箱装 5 个,需要几个箱子?apples = 23per_box = 5boxes = math.ceil(apples / per_box)print(f"需要 {boxes} 个箱子") # 需要 5 个箱子(4箱装20个,第5箱装3个)
3.2 floor —— 向下取整(地板)
import math# floor = 地板,总是往"小"的方向取整print(math.floor(3.1)) # 3(往下到3)print(math.floor(3.9)) # 3print(math.floor(3.0)) # 3print(math.floor(-3.1)) # -4(-4 比 -3.1 小,所以是 -4)print(math.floor(-3.9)) # -4print(math.floor(0.999)) # 0# 生活场景:# 你有 100 元,每个面包 7 元,最多买几个?money = 100price = 7count = math.floor(money / price)print(f"最多买 {count} 个面包") # 最多买 14 个(14×7=98,剩2元)# ⚠️ 注意:对正数,floor 等同于 int() 截断print(math.floor(3.9)) # 3print(int(3.9)) # 3(一样)# 但对负数不同!print(math.floor(-3.1)) # -4(往小取)print(int(-3.1)) # -3(截断小数部分)
3.3 trunc —— 截断(去掉小数部分)
import math# trunc = truncate(截断),直接砍掉小数部分(朝零方向)print(math.trunc(3.9)) # 3print(math.trunc(3.1)) # 3print(math.trunc(-3.9)) # -3(朝零方向,不是 -4!)print(math.trunc(-3.1)) # -3print(math.trunc(0.999)) # 0# 对比:# 3.9 -3.9# ceil: 4 -3 (往大)# floor: 3 -4 (往小)# trunc: 3 -3 (朝零)# trunc 对正数等同于 floor,对负数等同于 ceil# 实际上 int() 和 trunc() 效果一样print(int(3.9)) # 3print(int(-3.9)) # -3
3.4 取整对比图
数轴: -4 -3 -2 -1 0 1 2 3 4 | | | | | | | | |对于 3.7: floor(3.7) = 3 ←──┐ trunc(3.7) = 3 ←──┤ (正数时相同) ceil(3.7) = 4 ←──┘对于 -3.7: floor(-3.7) = -4 ←──┐ trunc(-3.7) = -3 ←──┤ (负数时不同!) ceil(-3.7) = -3 ←──┘
3.5 其他取整相关
import math# ============ 判断是否为整数 ============print(math.isfinite(3.14)) # True(是有限数)print(math.isfinite(math.inf)) # False(无穷大不是有限数)print(math.isfinite(math.nan)) # False# ============ 判断是否为整数 ============print(math.isinf(math.inf)) # Trueprint(math.isinf(100)) # Falseprint(math.isnan(math.nan)) # Trueprint(math.isnan(100)) # False# ============ 判断是否为整数 ============# Python 3.12+ 有 math.is_integer()(对 float)# 通用方法:x = 5.0print(x == int(x)) # True(5.0 是整数)y = 5.3print(y == int(y)) # False(5.3 不是整数)# 或者用 float.is_integer()print((5.0).is_integer()) # Trueprint((5.3).is_integer()) # False
四、幂函数和对数函数
4.1 幂运算
import math# ============ pow(x, y):x 的 y 次方 ============print(math.pow(2, 10)) # 1024.0(2^10)print(math.pow(3, 3)) # 27.0(3^3)print(math.pow(2, 0.5)) # 1.4142...(2的平方根)print(math.pow(2, -1)) # 0.5(2的-1次方 = 1/2)# ⚠️ math.pow 总是返回 float!print(type(math.pow(2, 3))) # <class 'float'>print(type(2 ** 3)) # <class 'int'>(内置 ** 保持类型)# 一般直接用 ** 更方便:print(2 ** 10) # 1024(int)print(2 ** 0.5) # 1.4142...(float)# ============ sqrt(x):平方根 ============print(math.sqrt(16)) # 4.0print(math.sqrt(2)) # 1.4142135623730951print(math.sqrt(0.25)) # 0.5# math.sqrt(-1) # ❌ ValueError(负数没有实数平方根)# ============ cbrt(x):立方根(Python 3.11+) ============print(math.cbrt(27)) # 3.0print(math.cbrt(-8)) # -2.0(立方根可以是负数!)print(math.cbrt(64)) # 4.0# Python 3.11 之前用:print((-8) ** (1/3)) # ❌ 复数!(1+1.732j)print(math.copysign(abs(-8) ** (1/3), -8)) # ✅ -2.0# ============ exp(x):e 的 x 次方 ============print(math.exp(1)) # 2.718281828459045(就是 e)print(math.exp(2)) # 7.38905609893065(e²)print(math.exp(0)) # 1.0(e⁰ = 1)print(math.exp(-1)) # 0.36787944117144233(e⁻¹ = 1/e)# 对比:print(math.exp(1) == math.e) # True# ============ expm1(x):e^x - 1(x很小时更精确) ============# 当 x 非常小时,exp(x) - 1 会丢失精度x = 1e-15print(math.exp(x) - 1) # 1.1102230246251565e-15(有误差)print(math.expm1(x)) # 1e-15(精确!)# 场景:计算极小的增长率# 银行利率 0.0000000000001%,计算 e^r - 1rate = 1e-15print(math.expm1(rate)) # 精确结果
4.2 对数函数
import math# ============ log(x):自然对数(以 e 为底) ============print(math.log(math.e)) # 1.0(ln(e) = 1)print(math.log(1)) # 0.0(ln(1) = 0)print(math.log(10)) # 2.302585092994046(ln(10))print(math.log(math.e**3)) # 3.0(ln(e³) = 3)# ============ log(x, base):以 base 为底的对数 ============print(math.log(8, 2)) # 3.0(log₂(8) = 3,因为 2³=8)print(math.log(100, 10)) # 2.0(log₁₀(100) = 2)print(math.log(27, 3)) # 3.0(log₃(27) = 3)# ============ log2(x):以 2 为底(比 log(x,2) 更精确) ============print(math.log2(8)) # 3.0print(math.log2(1024)) # 10.0print(math.log2(0.5)) # -1.0# 应用场景:计算二进制位数n = 1000bits = math.ceil(math.log2(n + 1))print(f"表示 {n} 需要 {bits} 个二进制位") # 需要 10 个二进制位# ============ log10(x):以 10 为底(常用对数) ============print(math.log10(100)) # 2.0print(math.log10(1000)) # 3.0print(math.log10(0.01)) # -2.0# 应用场景:计算数字的位数num = 123456digits = math.floor(math.log10(num)) + 1print(f"{num} 有 {digits} 位数") # 123456 有 6 位数# ============ log1p(x):ln(1+x)(x很小时更精确) ============x = 1e-15print(math.log(1 + x)) # 1.1102230246251565e-15(有误差)print(math.log1p(x)) # 1e-15(精确!)# 和 expm1 是互逆运算:print(math.log1p(math.expm1(0.5))) # 0.5(完美还原)
4.3 对数函数对照表
| | |
|---|
math.log(x) | | log(e) |
math.log(x, base) | | log(8, 2) |
math.log2(x) | | log2(1024) |
math.log10(x) | | log10(1000) |
math.log1p(x) | | log1p(1e-15) |
math.exp(x) | | exp(1) |
math.expm1(x) | | expm1(1e-15) |
五、三角函数
5.1 角度与弧度
import math# ⚠️ 重要:math 的三角函数使用【弧度】,不是【角度】!# 360° = 2π 弧度# 180° = π 弧度# 90° = π/2 弧度# 45° = π/4 弧度# ============ 角度 → 弧度 ============print(math.radians(180)) # 3.141592653589793(= π)print(math.radians(90)) # 1.5707963267948966(= π/2)print(math.radians(45)) # 0.7853981633974483(= π/4)print(math.radians(360)) # 6.283185307179586(= 2π = τ)# ============ 弧度 → 角度 ============print(math.degrees(math.pi)) # 180.0print(math.degrees(math.pi / 2)) # 90.0print(math.degrees(1.0)) # 57.29577951308232# ============ 实用转换 ============def sin_deg(degrees): """计算角度的正弦值(输入角度,不是弧度)""" return math.sin(math.radians(degrees))def cos_deg(degrees): """计算角度的余弦值""" return math.cos(math.radians(degrees))print(sin_deg(30)) # 0.49999999999999994(≈ 0.5)print(cos_deg(60)) # 0.5000000000000001(≈ 0.5)print(sin_deg(90)) # 1.0
5.2 基本三角函数
import math# ============ sin(x):正弦 ============print(math.sin(0)) # 0.0print(math.sin(math.pi / 6)) # 0.4999...(sin 30° ≈ 0.5)print(math.sin(math.pi / 4)) # 0.7071...(sin 45° = √2/2)print(math.sin(math.pi / 2)) # 1.0(sin 90° = 1)print(math.sin(math.pi)) # 1.22e-16(≈ 0,浮点误差)# ============ cos(x):余弦 ============print(math.cos(0)) # 1.0(cos 0° = 1)print(math.cos(math.pi / 3)) # 0.5000...(cos 60° = 0.5)print(math.cos(math.pi / 2)) # 6.12e-17(≈ 0)print(math.cos(math.pi)) # -1.0(cos 180° = -1)# ============ tan(x):正切 ============print(math.tan(0)) # 0.0print(math.tan(math.pi / 4)) # 0.9999...(tan 45° ≈ 1)print(math.tan(math.pi / 3)) # 1.7320...(tan 60° = √3)# math.tan(math.pi / 2) # 极大值(tan 90° 趋向无穷)# ============ 特殊角度的值 ============print("\n=== 特殊角度 ===")angles = [0, 30, 45, 60, 90, 180, 270, 360]print(f"{'角度':>6} {'sin':>10} {'cos':>10} {'tan':>10}")print("-" * 40)for deg in angles: rad = math.radians(deg) s = f"{math.sin(rad):.4f}" c = f"{math.cos(rad):.4f}" if deg in [90, 270]: t = "∞" else: t = f"{math.tan(rad):.4f}" print(f"{deg:>6}° {s:>10} {c:>10} {t:>10}")
输出:
=== 特殊角度 === 角度 sin cos tan---------------------------------------- 0° 0.0000 1.0000 0.0000 30° 0.5000 0.8660 0.5774 45° 0.7071 0.7071 1.0000 60° 0.8660 0.5000 1.7321 90° 1.0000 0.0000 ∞ 180° 0.0000 -1.0000 -0.0000 270° -1.0000 -0.0000 ∞ 360° -0.0000 1.0000 -0.0000
5.3 反三角函数
import math# 反三角函数:已知比值,求角度(返回弧度)# ============ asin(x):反正弦 ============# 已知 sin(θ) = x,求 θprint(math.asin(0.5)) # 0.5236...(= π/6 = 30°)print(math.asin(1.0)) # 1.5708...(= π/2 = 90°)print(math.asin(0)) # 0.0# math.asin(2) # ❌ 值域是 [-1, 1]# 转为角度:print(math.degrees(math.asin(0.5))) # 30.0°# ============ acos(x):反余弦 ============print(math.acos(0.5)) # 1.0472...(= π/3 = 60°)print(math.acos(1.0)) # 0.0(cos 0° = 1)print(math.acos(-1.0)) # 3.1416...(= π = 180°)print(math.degrees(math.acos(0.5))) # 60.0°# ============ atan(x):反正切 ============print(math.atan(1.0)) # 0.7854...(= π/4 = 45°)print(math.atan(0)) # 0.0print(math.degrees(math.atan(1))) # 45.0°# ============ atan2(y, x):反正切(考虑象限) ============# atan2 比 atan 更好用!它能正确处理所有象限# 返回点 (x, y) 与正 x 轴的夹角print(math.atan2(1, 1)) # 0.785...(45°,第一象限)print(math.atan2(1, -1)) # 2.356...(135°,第二象限)print(math.atan2(-1, -1)) # -2.356...(-135°,第三象限)print(math.atan2(-1, 1)) # -0.785...(-45°,第四象限)# 对比 atan:print(math.atan(1/1)) # 0.785(只能得到 -90°~90°)print(math.atan(1/-1)) # -0.785(无法区分第二和第四象限!)# 实际应用:计算两点之间的角度def angle_between(x1, y1, x2, y2): """计算从点1到点2的方向角(度)""" dx = x2 - x1 dy = y2 - y1 angle_rad = math.atan2(dy, dx) return math.degrees(angle_rad)print(angle_between(0, 0, 1, 1)) # 45.0°(右上方)print(angle_between(0, 0, -1, 1)) # 135.0°(左上方)print(angle_between(0, 0, 0, 1)) # 90.0°(正上方)print(angle_between(0, 0, 1, 0)) # 0.0°(正右方)
5.4 双曲函数
import math# 双曲函数:和三角函数类似,但基于双曲线而非圆# 在物理(悬链线)、工程中有应用# ============ sinh(x):双曲正弦 ============print(math.sinh(0)) # 0.0print(math.sinh(1)) # 1.1752011936438014print(math.sinh(-1)) # -1.1752011936438014(奇函数)# ============ cosh(x):双曲余弦 ============print(math.cosh(0)) # 1.0print(math.cosh(1)) # 1.5430806348152437print(math.cosh(-1)) # 1.5430806348152437(偶函数)# ============ tanh(x):双曲正切 ============print(math.tanh(0)) # 0.0print(math.tanh(1)) # 0.7615941559557649print(math.tanh(100)) # 1.0(趋近于1)print(math.tanh(-100)) # -1.0(趋近于-1)# 应用:tanh 常用作神经网络的激活函数# 输出范围 (-1, 1),S 形曲线# ============ 反双曲函数 ============print(math.asinh(1.1752011936438014)) # ≈ 1.0print(math.acosh(1.5430806348152437)) # ≈ 1.0print(math.atanh(0.7615941559557649)) # ≈ 1.0# ============ 悬链线方程 ============# y = a * cosh(x/a) 描述悬挂的链条/电缆形状def catenary(x, a=1): """悬链线方程""" return a * math.cosh(x / a)# 打印悬链线for x_int in range(-5, 6): x = x_int * 0.5 y = catenary(x, a=2) bar = " " * int(y) + "●" print(f"x={x:5.1f} y={y:5.2f}{bar}")
六、特殊函数
6.1 阶乘
import math# ============ factorial(n):n 的阶乘 ============print(math.factorial(0)) # 1(0! = 1,数学定义)print(math.factorial(1)) # 1print(math.factorial(5)) # 120(5×4×3×2×1)print(math.factorial(10)) # 3628800print(math.factorial(20)) # 2432902008176640000(Python 支持大整数!)# ⚠️ 只接受非负整数# math.factorial(-1) # ❌ ValueError# math.factorial(3.5) # ❌ ValueError# 应用:排列组合# 5个人排成一排有多少种排法?print(f"5人排列:{math.factorial(5)} 种") # 120 种# ============ comb(n, k):组合数 C(n,k)(Python 3.8+) ============# 从 n 个中选 k 个(不考虑顺序)print(math.comb(5, 2)) # 10(C(5,2) = 5!/(2!×3!) = 10)print(math.comb(10, 3)) # 120print(math.comb(52, 5)) # 2598960(扑克牌5张的组合数)# ============ perm(n, k):排列数 P(n,k)(Python 3.8+) ============# 从 n 个中选 k 个(考虑顺序)print(math.perm(5, 2)) # 20(P(5,2) = 5!/(5-2)! = 5×4 = 20)print(math.perm(10, 3)) # 720# 对比:# comb(5,2) = 10(选2人组队,不分先后)# perm(5,2) = 20(选2人当正副班长,有先后)# ============ 验证关系 ============# P(n,k) = C(n,k) × k!n, k = 10, 3print(math.perm(n, k) == math.comb(n, k) * math.factorial(k)) # True
6.2 Gamma 函数
import math# ============ gamma(x):伽马函数 ============# Γ(n) = (n-1)!(对正整数)# 是阶乘在实数/复数上的推广print(math.gamma(1)) # 1.0(= 0! = 1)print(math.gamma(2)) # 1.0(= 1! = 1)print(math.gamma(3)) # 2.0(= 2! = 2)print(math.gamma(4)) # 6.0(= 3! = 6)print(math.gamma(5)) # 24.0(= 4! = 24)print(math.gamma(6)) # 120.0(= 5! = 120)# 非整数值:print(math.gamma(0.5)) # 1.7724538509055159(= √π)print(math.gamma(1.5)) # 0.8862269254527579(= √π/2)# ============ lgamma(x):ln|Γ(x)|(取对数,防止溢出) ============# 当 n 很大时,n! 会溢出,但 ln(n!) 不会print(math.lgamma(100)) # 359.134...(= ln(99!))print(math.lgamma(1000)) # 5905.22...(= ln(999!))# 对比:# math.factorial(100) → 一个巨大的整数(Python 可以处理)# 但在其他语言中会溢出,lgamma 是安全的选择# 验证:lgamma(n+1) = ln(n!)import mathn = 10print(math.lgamma(n + 1)) # 15.1044...print(math.log(math.factorial(n))) # 15.1044...(一样!)
6.3 误差函数
import math# ============ erf(x):误差函数 ============# 在概率论和统计学中非常重要# 与正态分布的累积分布函数相关print(math.erf(0)) # 0.0print(math.erf(1)) # 0.8427007929497149print(math.erf(2)) # 0.9953222650189527print(math.erf(-1)) # -0.8427...(奇函数)print(math.erf(10)) # 1.0(趋近于1)# ============ erfc(x):互补误差函数 = 1 - erf(x) ============print(math.erfc(0)) # 1.0print(math.erfc(1)) # 0.15729920705028513# 当 x 很大时,erfc 比 1-erf 更精确# 应用:计算正态分布概率def normal_cdf(x, mu=0, sigma=1): """正态分布的累积分布函数""" z = (x - mu) / (sigma * math.sqrt(2)) return 0.5 * (1 + math.erf(z))# P(X ≤ 1.96) 在标准正态分布中print(f"P(Z ≤ 1.96) = {normal_cdf(1.96):.4f}") # ≈ 0.9750print(f"P(Z ≤ 0) = {normal_cdf(0):.4f}") # = 0.5000
七、浮点数操作
7.1 fabs —— 绝对值(返回 float)
import mathprint(math.fabs(-3.14)) # 3.14print(math.fabs(3.14)) # 3.14print(math.fabs(0)) # 0.0print(math.fabs(-0.0)) # 0.0# 对比内置 abs():print(abs(-3.14)) # 3.14(一样)print(abs(-5)) # -5 → 5(返回 int)print(math.fabs(-5)) # 5.0(总是返回 float)
7.2 copysign —— 复制符号
import math# copysign(x, y):返回 x 的绝对值,但使用 y 的符号print(math.copysign(5, -1)) # -5.0(5 的大小,-1 的符号)print(math.copysign(-5, 1)) # 5.0(-5 的大小,1 的符号)print(math.copysign(5, 1)) # 5.0print(math.copysign(-5, -1)) # -5.0# 应用:确保方向正确speed = 10direction = -1 # 向左velocity = math.copysign(speed, direction)print(f"速度:{velocity}") # -10.0
7.3 fmod —— 取余(浮点数)
import math# fmod 和 Python 的 % 对负数处理不同!print(math.fmod(-7, 3)) # -1.0(结果的符号跟被除数一样)print(-7 % 3) # 2(Python 的 % 结果符号跟除数一样)print(math.fmod(7, -3)) # 1.0print(7 % -3) # -2# 对正数两者一样:print(math.fmod(7, 3)) # 1.0print(7 % 3) # 1# C 语言的 % 和 math.fmod 行为一致
7.4 fsum —— 精确求和
import math# 普通 sum 有浮点误差:numbers = [0.1] * 10print(sum(numbers)) # 0.9999999999999999(不精确!)print(math.fsum(numbers)) # 1.0(精确!)# 更多例子:print(sum([0.1, 0.2, 0.3])) # 0.6000000000000001print(math.fsum([0.1, 0.2, 0.3])) # 0.6(精确)# 原理:fsum 使用高精度中间累加,避免浮点误差累积# 代价:比普通 sum 慢一些# 适用场景:金融计算、科学计算等需要精确结果的场合prices = [19.99, 5.01, 3.50, 7.25, 12.75]print(f"普通求和:{sum(prices)}") # 48.5(碰巧对了)print(f"精确求和:{math.fsum(prices)}") # 48.5
7.5 prod —— 乘积(Python 3.8+)
import math# prod:计算所有元素的乘积print(math.prod([1, 2, 3, 4, 5])) # 120(1×2×3×4×5)print(math.prod([2, 3, 4])) # 24print(math.prod([])) # 1(空列表的乘积是1)print(math.prod([5])) # 5# 可以指定初始值print(math.prod([2, 3, 4], start=10)) # 240(10×2×3×4)# 对比 reduce:from functools import reduceimport operatorprint(reduce(operator.mul, [1, 2, 3, 4, 5])) # 120(一样)
7.6 gcd 和 lcm —— 最大公约数和最小公倍数
import math# ============ gcd:最大公约数(Greatest Common Divisor) ============print(math.gcd(12, 8)) # 4(12和8的最大公约数是4)print(math.gcd(100, 75)) # 25print(math.gcd(17, 13)) # 1(互质)print(math.gcd(0, 5)) # 5# 多个数(Python 3.9+)print(math.gcd(12, 8, 6)) # 2# 应用:化简分数def simplify_fraction(numerator, denominator): """化简分数""" g = math.gcd(abs(numerator), abs(denominator)) return numerator // g, denominator // gprint(simplify_fraction(12, 8)) # (3, 2) → 12/8 = 3/2print(simplify_fraction(100, 75)) # (4, 3) → 100/75 = 4/3# ============ lcm:最小公倍数(Least Common Multiple)(Python 3.9+) ============print(math.lcm(4, 6)) # 12(4和6的最小公倍数是12)print(math.lcm(3, 5)) # 15print(math.lcm(12, 8)) # 24# 多个数print(math.lcm(2, 3, 4)) # 12# 应用:计算周期# 红灯每 30 秒变一次,绿灯每 45 秒变一次,多久同时变?print(f"同时变化周期:{math.lcm(30, 45)} 秒") # 90 秒# 关系:lcm(a, b) × gcd(a, b) = a × ba, b = 12, 8print(math.lcm(a, b) * math.gcd(a, b) == a * b) # True
7.7 isclose —— 浮点数近似相等判断
import math# ⚠️ 浮点数不能直接用 == 比较!print(0.1 + 0.2 == 0.3) # False!(浮点误差)print(0.1 + 0.2) # 0.30000000000000004# ✅ 用 isclose 判断"近似相等"print(math.isclose(0.1 + 0.2, 0.3)) # True!# 参数:# math.isclose(a, b, rel_tol=1e-09, abs_tol=0.0)# rel_tol:相对容差(默认 1e-9,即十亿分之一)# abs_tol:绝对容差(默认 0)# 相对容差:|a-b| <= rel_tol * max(|a|, |b|)print(math.isclose(1000000, 1000001, rel_tol=1e-5)) # True(差1,相对差很小)print(math.isclose(1, 2, rel_tol=1e-5)) # False(差1,相对差很大)# 绝对容差:适合比较接近 0 的数print(math.isclose(1e-10, 2e-10, abs_tol=1e-9)) # Trueprint(math.isclose(1e-10, 2e-10)) # False(默认容差太小)# 实际应用:判断计算结果是否正确result = math.sqrt(2) ** 2print(math.isclose(result, 2.0)) # True(虽然可能有微小误差)
7.8 frexp 和 ldexp —— 浮点数分解
import math# ============ frexp(x):分解为尾数和指数 ============# x = mantissa × 2^exponent# 其中 0.5 <= |mantissa| < 1mantissa, exponent = math.frexp(8)print(f"8 = {mantissa} × 2^{exponent}") # 8 = 0.5 × 2^4# 验证:0.5 × 16 = 8 ✓mantissa, exponent = math.frexp(10)print(f"10 = {mantissa} × 2^{exponent}") # 10 = 0.625 × 2^4# 验证:0.625 × 16 = 10 ✓# ============ ldexp(x, i):frexp 的逆运算 ============# 计算 x × 2^iprint(math.ldexp(0.5, 4)) # 8.0(0.5 × 2⁴ = 8)print(math.ldexp(0.625, 4)) # 10.0(0.625 × 2⁴ = 10)# 验证互逆:x = 123.456m, e = math.frexp(x)print(math.ldexp(m, e)) # 123.456(还原!)
7.9 modf —— 分离整数和小数部分
import math# modf(x):返回 (小数部分, 整数部分)# ⚠️ 注意顺序:小数在前,整数在后!frac, integ = math.modf(3.75)print(f"小数部分:{frac}") # 0.75print(f"整数部分:{integ}") # 3.0frac, integ = math.modf(-3.75)print(f"小数部分:{frac}") # -0.75print(f"整数部分:{integ}") # -3.0# 应用:分离时间和分钟total_minutes = 137.5frac, hours = math.modf(total_minutes / 60)minutes = frac * 60print(f"{total_minutes}分钟 = {int(hours)}小时{minutes:.0f}分钟")# 137.5分钟 = 2小时17分钟(大约)
7.10 nextafter —— 下一个浮点数(Python 3.9+)
import math# nextafter(x, y):从 x 朝 y 方向的下一个可表示的浮点数# 比 1.0 大的最小浮点数print(math.nextafter(1.0, 2.0)) # 1.0000000000000002print(math.nextafter(1.0, 2.0) - 1.0) # 2.220446049250313e-16(机器精度)# 比 1.0 小的最大浮点数print(math.nextafter(1.0, 0.0)) # 0.9999999999999999# 比 0 大的最小正浮点数print(math.nextafter(0.0, 1.0)) # 5e-324(极小!)# 应用:测试边界条件# 确保某个值严格大于 1.0x = 1.0x_strictly_greater = math.nextafter(x, math.inf)print(x_strictly_greater > x) # True
7.11 ulp —— 最小精度单位(Python 3.9+)
import math# ulp = Unit in the Last Place(最后一位的单位)# 表示浮点数的精度print(math.ulp(1.0)) # 2.220446049250313e-16print(math.ulp(1000.0)) # 1.1368683772161603e-13print(math.ulp(0.0)) # 5e-324(最小正浮点数)# 数越大,精度越低(ulp 越大)print(math.ulp(1e100)) # 1.99584030953472e+84(精度很差了)
八、其他实用函数
8.1 degrees 和 radians
import math# 角度 ↔ 弧度 转换(前面已介绍,这里补充)# 批量转换angles_deg = [0, 30, 45, 60, 90, 120, 135, 150, 180]angles_rad = [math.radians(d) for d in angles_deg]print("角度 → 弧度:")for d, r in zip(angles_deg, angles_rad): print(f" {d:>3}° = {r:.4f} rad")# 弧度 → 角度rads = [0, math.pi/6, math.pi/4, math.pi/3, math.pi/2, math.pi]degs = [math.degrees(r) for r in rads]print("\n弧度 → 角度:")for r, d in zip(rads, degs): print(f" {r:.4f} rad = {d:.1f}°")
8.2 dist —— 欧几里得距离(Python 3.8+)
import math# dist(p, q):计算两点之间的欧几里得距离# 支持任意维度# 2D 距离p1 = (0, 0)p2 = (3, 4)print(math.dist(p1, p2)) # 5.0(经典的 3-4-5 直角三角形)# 3D 距离p1 = (0, 0, 0)p2 = (1, 2, 2)print(math.dist(p1, p2)) # 3.0(√(1+4+4) = √9 = 3)# 高维距离p1 = (1, 2, 3, 4, 5)p2 = (5, 4, 3, 2, 1)print(math.dist(p1, p2)) # 6.324...(√(16+4+0+4+16) = √40)# 对比手动计算:def manual_dist(p, q): return math.sqrt(sum((a - b) ** 2 for a, b in zip(p, q)))print(manual_dist((0, 0), (3, 4))) # 5.0(一样)# 应用:计算地图上两点的直线距离(简化版)def distance_km(lat1, lon1, lat2, lon2): """简化的距离计算(小范围近似)""" # 1度纬度 ≈ 111km # 1度经度 ≈ 111km × cos(纬度) dlat = (lat2 - lat1) * 111 dlon = (lon2 - lon1) * 111 * math.cos(math.radians(lat1)) return math.sqrt(dlat**2 + dlon**2)# 北京(39.9, 116.4) 到 天津(39.1, 117.2)d = distance_km(39.9, 116.4, 39.1, 117.2)print(f"北京到天津约 {d:.1f} km") # 约 120 km
8.3 hypot —— 斜边/欧几里得范数
import math# hypot(x, y):计算 √(x² + y²)(直角三角形斜边)# 比 sqrt(x**2 + y**2) 更不容易溢出print(math.hypot(3, 4)) # 5.0(3-4-5 三角形)print(math.hypot(5, 12)) # 13.0(5-12-13 三角形)print(math.hypot(1, 1)) # 1.4142...(√2)# Python 3.8+ 支持多维:print(math.hypot(1, 2, 2)) # 3.0(√(1+4+4) = √9)print(math.hypot(1, 2, 3, 4)) # 5.477...(√(1+4+9+16) = √30)# 为什么用 hypot 而不是 sqrt(x**2 + y**2)?# 当 x 或 y 极大时,x**2 可能溢出big = 1e200# math.sqrt(big**2 + big**2) # ❌ OverflowError!print(math.hypot(big, big)) # ✅ 1.4142e+200(正确处理)# 应用:计算向量的长度(模)def vector_length(x, y): return math.hypot(x, y)print(f"向量(3,4)的长度:{vector_length(3, 4)}") # 5.0
8.4 sumprod —— 点积(Python 3.12+)
import math# sumprod(p, q):计算两个序列的点积(内积)# 等价于 sum(a*b for a, b in zip(p, q))print(math.sumprod([1, 2, 3], [4, 5, 6])) # 32(1×4 + 2×5 + 3×6 = 32)print(math.sumprod([1, 0, 1], [0, 1, 0])) # 0(正交向量)# Python 3.12 之前:def dot_product(a, b): return sum(x * y for x, y in zip(a, b))print(dot_product([1, 2, 3], [4, 5, 6])) # 32
九、综合实战案例
9.1 几何计算工具
import mathclass Geometry: """几何计算工具类""" @staticmethod def circle_area(radius): """圆的面积""" return math.pi * radius ** 2 @staticmethod def circle_circumference(radius): """圆的周长""" return math.tau * radius # 2πr @staticmethod def triangle_area(a, b, c): """海伦公式:已知三边求面积""" s = (a + b + c) / 2 # 半周长 return math.sqrt(s * (s - a) * (s - b) * (s - c)) @staticmethod def triangle_area_sas(a, b, angle_deg): """已知两边及夹角求面积""" angle_rad = math.radians(angle_deg) return 0.5 * a * b * math.sin(angle_rad) @staticmethod def distance_2d(x1, y1, x2, y2): """两点距离""" return math.hypot(x2 - x1, y2 - y1) @staticmethod def angle_of_triangle(a, b, c): """余弦定理:已知三边求各角度(返回度)""" # cos(A) = (b² + c² - a²) / (2bc) cos_A = (b**2 + c**2 - a**2) / (2 * b * c) cos_B = (a**2 + c**2 - b**2) / (2 * a * c) cos_C = (a**2 + b**2 - c**2) / (2 * a * b) A = math.degrees(math.acos(cos_A)) B = math.degrees(math.acos(cos_B)) C = math.degrees(math.acos(cos_C)) return A, B, C @staticmethod def regular_polygon_area(n, side_length): """正 n 边形面积""" return (n * side_length**2) / (4 * math.tan(math.pi / n))# 使用geo = Geometry()print("=== 圆 ===")r = 5print(f"半径 {r}:面积 = {geo.circle_area(r):.2f}, 周长 = {geo.circle_circumference(r):.2f}")print("\n=== 三角形(三边 3, 4, 5) ===")a, b, c = 3, 4, 5print(f"面积 = {geo.triangle_area(a, b, c):.2f}")angles = geo.angle_of_triangle(a, b, c)print(f"三个角 = {angles[0]:.1f}°, {angles[1]:.1f}°, {angles[2]:.1f}°")print("\n=== 正六边形(边长 2) ===")print(f"面积 = {geo.regular_polygon_area(6, 2):.2f}")print("\n=== 两点距离 ===")print(f"(0,0) 到 (3,4) = {geo.distance_2d(0, 0, 3, 4):.2f}")
9.2 物理计算
import mathclass Physics: """物理计算工具""" # 常量 G = 6.674e-11 # 万有引力常数 (N⋅m²/kg²) g = 9.81 # 重力加速度 (m/s²) c = 3e8 # 光速 (m/s) @staticmethod def projectile_range(v0, angle_deg): """抛体运动的水平射程""" angle_rad = math.radians(angle_deg) return v0**2 * math.sin(2 * angle_rad) / Physics.g @staticmethod def projectile_max_height(v0, angle_deg): """抛体运动的最大高度""" angle_rad = math.radians(angle_deg) return v0**2 * math.sin(angle_rad)**2 / (2 * Physics.g) @staticmethod def projectile_time(v0, angle_deg): """抛体运动的飞行时间""" angle_rad = math.radians(angle_deg) return 2 * v0 * math.sin(angle_rad) / Physics.g @staticmethod def kinetic_energy(mass, velocity): """动能 E = ½mv²""" return 0.5 * mass * velocity**2 @staticmethod def gravitational_force(m1, m2, r): """万有引力 F = Gm₁m₂/r²""" return Physics.G * m1 * m2 / r**2 @staticmethod def pendulum_period(length): """单摆周期 T = 2π√(L/g)""" return 2 * math.pi * math.sqrt(length / Physics.g) @staticmethod def escape_velocity(mass, radius): """逃逸速度 v = √(2GM/R)""" return math.sqrt(2 * Physics.G * mass / radius)# 使用phy = Physics()print("=== 抛体运动(初速度 50 m/s) ===")for angle in [15, 30, 45, 60, 75]: r = phy.projectile_range(50, angle) h = phy.projectile_max_height(50, angle) t = phy.projectile_time(50, angle) print(f" {angle:>2}°: 射程={r:.1f}m, 最大高度={h:.1f}m, 飞行时间={t:.2f}s")print("\n=== 单摆周期 ===")for L in [0.5, 1.0, 2.0, 4.0]: T = phy.pendulum_period(L) print(f" 摆长 {L}m: 周期 = {T:.3f}s")print("\n=== 地球逃逸速度 ===")M_earth = 5.972e24 # kgR_earth = 6.371e6 # mv_esc = phy.escape_velocity(M_earth, R_earth)print(f" 逃逸速度 = {v_esc/1000:.2f} km/s") # ≈ 11.19 km/s
9.3 金融计算
import mathclass Finance: """金融计算工具""" @staticmethod def compound_interest(principal, rate, years, n=12): """ 复利计算 principal: 本金 rate: 年利率(如 0.05 表示 5%) years: 年数 n: 每年复利次数(12=月复利,365=日复利) """ amount = principal * (1 + rate / n) ** (n * years) return amount @staticmethod def continuous_compound(principal, rate, years): """连续复利 A = P × e^(rt)""" return principal * math.exp(rate * years) @staticmethod def doubling_time(rate, n=12): """资金翻倍所需时间""" # (1 + r/n)^(nt) = 2 # nt × ln(1 + r/n) = ln(2) # t = ln(2) / (n × ln(1 + r/n)) return math.log(2) / (n * math.log1p(rate / n)) @staticmethod def rule_of_72(rate_percent): """72法则:快速估算翻倍时间""" return 72 / rate_percent @staticmethod def present_value(future_value, rate, years): """现值计算(折现)""" return future_value / (1 + rate) ** years @staticmethod def loan_payment(principal, annual_rate, months): """等额本息月供""" r = annual_rate / 12 # 月利率 if r == 0: return principal / months payment = principal * r * (1 + r)**months / ((1 + r)**months - 1) return payment# 使用fin = Finance()print("=== 复利计算 ===")P = 10000 # 本金 1 万r = 0.05 # 年利率 5%t = 10 # 10 年print(f"本金 {P} 元,年利率 {r*100}%,{t} 年后:")print(f" 年复利:{fin.compound_interest(P, r, t, n=1):.2f} 元")print(f" 月复利:{fin.compound_interest(P, r, t, n=12):.2f} 元")print(f" 日复利:{fin.compound_interest(P, r, t, n=365):.2f} 元")print(f" 连续复利:{fin.continuous_compound(P, r, t):.2f} 元")print(f"\n=== 翻倍时间(年利率 5%) ===")exact = fin.doubling_time(0.05)approx = fin.rule_of_72(5)print(f" 精确计算:{exact:.2f} 年")print(f" 72法则估算:{approx:.2f} 年")print(f"\n=== 房贷月供 ===")loan = 1000000 # 100万rate = 0.042 # 年利率 4.2%years = 30monthly = fin.loan_payment(loan, rate, years * 12)total = monthly * years * 12interest = total - loanprint(f" 贷款 {loan/10000:.0f} 万,利率 {rate*100}%,{years} 年")print(f" 月供:{monthly:.2f} 元")print(f" 总还款:{total:.2f} 元")print(f" 总利息:{interest:.2f} 元")
9.4 统计分析
import mathclass Statistics: """基础统计工具""" @staticmethod def mean(data): """算术平均值""" return math.fsum(data) / len(data) @staticmethod def geometric_mean(data): """几何平均值""" # GM = (x1 × x2 × ... × xn)^(1/n) # 用对数避免溢出:GM = exp(mean(ln(xi))) log_sum = math.fsum(math.log(x) for x in data) return math.exp(log_sum / len(data)) @staticmethod def harmonic_mean(data): """调和平均值""" # HM = n / (1/x1 + 1/x2 + ... + 1/xn) return len(data) / math.fsum(1/x for x in data) @staticmethod def variance(data): """方差""" m = Statistics.mean(data) return math.fsum((x - m) ** 2 for x in data) / len(data) @staticmethod def std_dev(data): """标准差""" return math.sqrt(Statistics.variance(data)) @staticmethod def rms(data): """均方根(Root Mean Square)""" return math.sqrt(math.fsum(x**2 for x in data) / len(data))# 使用stats = Statistics()data = [2, 4, 4, 4, 5, 5, 7, 9]print(f"数据:{data}")print(f"算术平均:{stats.mean(data):.2f}")print(f"几何平均:{stats.geometric_mean(data):.2f}")print(f"调和平均:{stats.harmonic_mean(data):.2f}")print(f"方差:{stats.variance(data):.2f}")print(f"标准差:{stats.std_dev(data):.2f}")print(f"均方根:{stats.rms(data):.2f}")# 三种平均数的关系:调和 ≤ 几何 ≤ 算术print(f"\n验证:{stats.harmonic_mean(data):.4f} ≤ {stats.geometric_mean(data):.4f} ≤ {stats.mean(data):.4f}")# 应用:计算平均速度# 去程 60km/h,回程 40km/h,平均速度是多少?# 不是 (60+40)/2 = 50!应该用调和平均speeds = [60, 40]print(f"\n去程60,回程40,平均速度 = {stats.harmonic_mean(speeds):.1f} km/h")# 48.0 km/h(不是50!)
十、math 模块完整函数速查表
═══════════════════════════════════════════════════════ 常量═══════════════════════════════════════════════════════ math.pi 圆周率 π = 3.14159... math.e 自然常数 e = 2.71828... math.tau τ = 2π = 6.28318... math.inf 正无穷 math.nan 非数字═══════════════════════════════════════════════════════ 取整═══════════════════════════════════════════════════════ ceil(x) 向上取整(天花板) floor(x) 向下取整(地板) trunc(x) 截断(朝零方向)═══════════════════════════════════════════════════════ 幂和对数═══════════════════════════════════════════════════════ pow(x, y) x^y(返回float) sqrt(x) 平方根 √x cbrt(x) 立方根(3.11+) exp(x) e^x expm1(x) e^x - 1(小值精确) log(x) 自然对数 ln(x) log(x, base) 以 base 为底 log2(x) 以 2 为底 log10(x) 以 10 为底 log1p(x) ln(1+x)(小值精确)═══════════════════════════════════════════════════════ 三角函数(参数为弧度)═══════════════════════════════════════════════════════ sin(x) 正弦 cos(x) 余弦 tan(x) 正切 asin(x) 反正弦 acos(x) 反余弦 atan(x) 反正切 atan2(y, x) 反正切(考虑象限)═══════════════════════════════════════════════════════ 双曲函数═══════════════════════════════════════════════════════ sinh(x) 双曲正弦 cosh(x) 双曲余弦 tanh(x) 双曲正切 asinh(x) 反双曲正弦 acosh(x) 反双曲余弦 atanh(x) 反双曲正切═══════════════════════════════════════════════════════ 角度转换═══════════════════════════════════════════════════════ degrees(x) 弧度 → 角度 radians(x) 角度 → 弧度═══════════════════════════════════════════════════════ 特殊函数═══════════════════════════════════════════════════════ factorial(n) 阶乘 n! comb(n, k) 组合数 C(n,k)(3.8+) perm(n, k) 排列数 P(n,k)(3.8+) gamma(x) 伽马函数 Γ(x) lgamma(x) ln|Γ(x)| erf(x) 误差函数 erfc(x) 互补误差函数═══════════════════════════════════════════════════════ 浮点操作═══════════════════════════════════════════════════════ fabs(x) 绝对值(返回float) copysign(x,y) 复制符号 fmod(x, y) 取余(C风格) fsum(iterable) 精确求和 prod(iterable) 乘积(3.8+) gcd(a, b) 最大公约数 lcm(a, b) 最小公倍数(3.9+) isclose(a, b) 近似相等判断 frexp(x) 分解为尾数×2^指数 ldexp(x, i) x × 2^i modf(x) 分离整数和小数 nextafter(x,y) 下一个浮点数(3.9+) ulp(x) 最小精度单位(3.9+)═══════════════════════════════════════════════════════ 其他═══════════════════════════════════════════════════════ hypot(x, y) 斜边 √(x²+y²) dist(p, q) 欧几里得距离(3.8+) sumprod(p, q) 点积(3.12+) isfinite(x) 是否有限 isinf(x) 是否无穷 isnan(x) 是否NaN
十一、常见错误和注意事项
11.1 浮点精度问题
import math# ❌ 不要用 == 比较浮点数print(math.sin(math.pi) == 0) # False!(结果是 1.22e-16)# ✅ 用 iscloseprint(math.isclose(math.sin(math.pi), 0, abs_tol=1e-10)) # True# ❌ 不要期望精确结果print(math.sqrt(2) ** 2) # 2.0000000000000004(不是精确的2)# ✅ 用 iscloseprint(math.isclose(math.sqrt(2) ** 2, 2.0)) # True
11.2 定义域错误
import math# 以下都会报错:# math.sqrt(-1) # ValueError: math domain error# math.log(0) # ValueError: math domain error# math.log(-1) # ValueError: math domain error# math.asin(2) # ValueError(值域是[-1,1])# math.acos(2) # ValueError# math.factorial(-1) # ValueError# math.factorial(3.5)# ValueError# 安全写法:def safe_sqrt(x): if x < 0: return None # 或 raise ValueError return math.sqrt(x)def safe_log(x): if x <= 0: return None return math.log(x)
11.3 math vs 内置函数
import math# 有些功能 math 和内置都有,区别:print(abs(-5)) # 5(int)print(math.fabs(-5)) # 5.0(总是 float)print(2 ** 10) # 1024(int,精确)print(math.pow(2, 10))# 1024.0(float)print(sum([0.1]*10)) # 0.9999...(有误差)print(math.fsum([0.1]*10)) # 1.0(精确)# 建议:# 整数幂 → 用 **# 浮点幂 → 用 math.pow 或 **# 精确求和 → 用 math.fsum# 普通求和 → 用 sum(更快)
十二、学习路径建议
第1天:常量(pi, e)+ 取整(ceil, floor, trunc)第2天:幂和对数(sqrt, pow, log, exp)第3天:三角函数(sin, cos, tan + 角度转换)第4天:特殊函数(factorial, gcd, comb)第5天:浮点操作(isclose, fsum, hypot)第6天:综合练习(几何、物理、金融计算)第7天:了解 cmath(复数版本)和 numpy(数组版本)
十三、一句话总结
math 模块 = Python 的科学计算器
记住三个关键点:
- 三角函数用弧度(用
math.radians() 转换) - 浮点数比较用
math.isclose()(不要用 ==) - 精确求和用
math.fsum()(不要用 sum())