数学爱好者必看!对编程有用的10个优美数学公式
乍看之下,编程和数学似乎是截然不同的两个领域。编程是编写具有逻辑性且具体的代码的过程,而数学则是追求抽象且普遍真理的学问。然而,在计算机科学的底层,始终存在着数学的身影。算法的优化、数据科学、机器学习、计算机图形学,甚至日常应用程序的背后,都有优美的数学公式在默默且强大地发挥着作用。
在本文中,我们精选了10个不仅在数学上十分优美,而且在编程和算法语境下也非常实用且发挥重要作用的数学公式。我们将深入探讨每个公式背后的数学背景,并结合具体的Python和C++代码片段,极其详细地解说它们在编程一线是如何被应用的。
欢迎来到数学之美与编程实用性交织的世界。
1. 欧拉恒等式 (Euler’s Identity)
公式的优美性与概述
被誉为“人类的瑰宝”、“世界上最美的数学公式”的欧拉恒等式。它将数学中最重要的5个常数(自然对数的底 $e$、虚数单位 $i$、圆周率 $\pi$、乘法单位元 $1$、加法单位元 $0$)整合到了一个极其简单的公式中。
$$ e^{i\pi} + 1 = 0 $$这个恒等式是通过在更一般的欧拉公式 $e^{i\theta} = \cos\theta + i\sin\theta$ 中代入 $\theta = \pi$ 推导出来的。
在编程中的应用
在编程,尤其是计算机图形学和游戏开发中,欧拉公式是处理“旋转”的极其强大的工具。二维空间中点的旋转虽然也可以通过矩阵计算来实现,但使用复数会使计算变得极其简单和直观。在复平面上的旋转,只需乘以 $e^{i\theta}$ 即可实现,因此代码也非常简洁。
实现示例 (C++)
以下是一个使用C++标准库 <complex>,将二维坐标上的点旋转指定角度(弧度)的程序。
| |
详细解说: 这种方法的优点在于,能够将旋转矩阵的计算(4次乘法和2次加法)封装为复数的运算。此外,在三维空间中,使用的是其扩展概念“四元数(Quaternion)”。通过使用四元数,可以避免使用欧拉角时发生的致命问题“万向节死锁(Gimbal Lock)”,并实现平滑的球面线性插值(Slerp)。
2. 泰勒展开 (Taylor Series)
公式的优美性与概述
泰勒展开是一种将复杂函数(如三角函数、指数函数等)表示为无限多项式之和的数学方法。函数 $f(x)$ 在某一点 $a$ 附近的泰勒展开定义如下:
$$ f(x) = \sum_{n=0}^\infty \frac{f^{(n)}(a)}{n!}(x-a)^n $$特别是当 $a=0$ 时,被称为“麦克劳林展开”。
在编程中的应用
计算机(CPU和FPU)本质上只能执行加法、减法、乘法、除法等四则运算。那么,sin(x) 或 exp(x) 是如何计算的呢?在现代处理器中,通常使用 CORDIC 算法或切比雪夫近似等方法;而在软件层面上实现数学函数,或者为了追求性能而牺牲精度自己编写快速近似函数时,泰勒展开(或其变体)就会派上用场。
实现示例 (Python)
以下是使用麦克劳林展开来近似计算正弦函数(Sine)的Python代码。
$$ \sin(x) \approx x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} + \dots $$ | |
详细解说:
在上述代码中,输入值 x 被归一化到了 $[-\pi, \pi]$ 的范围内。这是因为泰勒展开具有一个特性:离展开中心(这里是0)越远,误差就会急剧增大(截断误差)。在编程中不可能进行无限的计算,因此要在有限的 terms 处截断计算,而管理由此产生的“舍入误差”与“截断误差”之间的权衡,正是数值计算编程的关键所在。
3. 贝叶斯定理 (Bayes’ Theorem)
公式的优美性与概述
贝叶斯定理是一个基于与某事件相关的先验知识(先验概率),来更新该事件发生概率(后验概率)的定理。它是概率论和统计学中最重要的公式之一。
$$ P(A|B) = \frac{P(B|A)P(A)}{P(B)} $$这里,$P(A|B)$ 表示在事件B发生的条件下,事件A发生的概率(后验概率)。
在编程中的应用
在机器学习和数据科学领域,它作为“朴素贝叶斯分类器(Naive Bayes Classifier)”被广泛应用。最典型的应用例子是垃圾邮件过滤。它能够基于过去的数据动态地计算:“如果这封邮件包含‘免费’这个词,那么它是垃圾邮件的概率是多少?”
graph TD
Email["接收邮件"] --> Extract["提取单词"]
Extract --> W1["单词: '免费'"]
Extract --> W2["单词: '金钱'"]
Extract --> Wn["单词: '会议'"]
W1 --> Prob["计算 P(垃圾邮件 | 单词)"]
W2 --> Prob
Wn --> Prob
Prob --> Bayes["应用贝叶斯定理"]
Bayes --> Class{"P(垃圾邮件) > 0.9?"}
Class -- 是 --> Spam["移至垃圾邮件文件夹"]
Class -- 否 --> Ham["发送至收件箱"]
实现示例 (Python)
以下是展示垃圾邮件过滤器基本逻辑的代码。
| |
详细解说:
在实际应用中(如朴素贝叶斯分类器),会将多个单词的概率相乘进行计算。但是,如果将数千个概率(0到1之间的值)相乘,由于计算机浮点数表示的限制(下溢),结果会变成零。因此,在实际编程中,将概率的乘积转换为“对数之和”(log(a * b) = log(a) + log(b))是一项必备技巧。
4. 香农熵 (Shannon Entropy)
公式的优美性与概述
由信息论之父克劳德·香农定义的“熵”,是一个量化信息源所具有的“不确定性”、“混乱度”或者“平均信息量”的数学公式。
$$ H(X) = - \sum_{i=1}^n P(x_i) \log_2 P(x_i) $$在编程中的应用
熵在文件数据压缩(霍夫曼编码或ZIP压缩算法的理论极限)、密码学中的随机数强度评估,以及机器学习中的“决策树(Decision Trees)”算法(如ID3和C4.5)中是不可或缺的存在。在构建决策树时,算法会寻找在划分数据后能使熵减少量(信息增益:Information Gain)达到最大的特征。
实现示例 (Python)
计算字符串(数据集)的熵以评估其信息量的函数。
| |
详细解说:
熵的单位是“比特(bits)”。如果熵为 1.5,这意味着平均下来至少需要 1.5 比特来表示该数据中的一个元素。在编程一线,它作为衡量压缩算法效率的基准,或是机器学习模型特征选择中的重要指标,被日常计算着。
5. 快速傅里叶变换 (Fast Fourier Transform - FFT)
公式的优美性与概述
将时域信号转换为频域信号的离散傅里叶变换(DFT)。其数学公式如下:
$$ X_k = \sum_{n=0}^{N-1} x_n e^{-i 2\pi k n / N} $$如果用简单粗暴的方式计算这个DFT,其时间复杂度为 $O(N^2)$,当数据量增加时,计算速度会呈爆炸性下降。利用分治法将其时间复杂度极大地优化到 $O(N \log N)$ 的算法就是“快速傅里叶变换(FFT)”。它被列为20世纪最重要的十大算法之一。
graph TD A["大小为 N 的输入数组"] --> B["分为偶数和奇数索引"] B --> C["偶数索引 (N/2)"] B --> D["奇数索引 (N/2)"] C --> E["对偶数部分进行递归 FFT"] D --> F["对奇数部分进行递归 FFT"] E --> G["使用旋转因子进行合并"] F --> G G --> H["输出频谱"]
在编程中的应用
FFT是支撑现代社会不可或缺的技术。从语音识别(Siri或Alexa)、MP3或JPEG/MPEG的数据压缩、LTE和Wi-Fi等数字通信,乃至非常巨大的整数乘法(Schönhage–Strassen算法),都能看到它的身影。
实现示例 (Python)
这是一个递归的 Cooley-Tukey 算法的简单实现示例。(※在实际业务中,会使用用C语言或汇编语言优化到极致的 FFTW 库或 numpy.fft)
| |
详细解说: 这个算法的核心在于利用了被称为“旋转因子(Twiddle factor)”的复数的对称性和周期性。通过消除重复计算的浪费,当 $N=1024$ 时,它将原本需要 $1,048,576$ 次的运算骤降至仅约 $10,240$ 次。这可以说是数学与算法融合产生的奇迹。
6. 半正矢公式 (Haversine Formula)
公式的优美性与概述
用于计算地球表面等球面上两点之间最短距离(大圆距离)的公式。
$$ a = \sin^2\left(\frac{\Delta\phi}{2}\right) + \cos\phi_1 \cos\phi_2 \sin^2\left(\frac{\Delta\lambda}{2}\right) $$$$ c = 2\cdot \text{atan2}\left(\sqrt{a}, \sqrt{1-a}\right) $$$$ d = R \cdot c $$(其中,$\phi$ 为纬度,$\lambda$ 为经度,$R$ 为地球半径)
在编程中的应用
在 GPS 追踪应用程序,以及诸如 Uber 或 Pokemon GO 等基于位置信息的服务中,当需要计算两个经纬度坐标之间的距离时,这是一个必不可少的公式。因为使用勾股定理的直线距离计算无法考虑地球的曲率,在长距离时会产生很大的误差。
实现示例 (Python)
一个接收两个坐标(纬度、经度)并返回它们之间距离(公里)的函数。
| |
详细解说:
虽然也可以使用球面三角学的余弦定理,但当两点之间的距离非常近(例如几米)时,由于浮点数计算精度的限制,很容易发生“灾难性相消(Catastrophic cancellation)”。由于半正矢公式使用了 sin^2,因此即使对于微小的距离,也能在数值上保持稳定的计算,这是其在编程上的一大优势。如果需要更高的精度,可以使用将地球视为椭球体的 Vincenty 公式(Vincenty’s formulae)。
7. 牛顿-拉弗森方法 (Newton-Raphson Method)
公式的优美性与概述
一种通过使用切线来迭代求解方程式 $f(x) = 0$ 的根的极其强大的求根算法。
$$ x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} $$它利用当前位置 $x_n$ 处的函数值 $f(x_n)$ 及其斜率(导数)$f'(x_n)$,来推测下一个需要探索的更准确的位置 $x_{n+1}$。
flowchart LR
Start["开始: 猜测初始值 x0"] --> Eval["计算 f(xn) 和 f'(xn)"]
Eval --> Check{"f(xn) ≈ 0 吗?"}
Check -- 是 --> Done["返回 xn 作为根"]
Check -- 否 --> Update["xn+1 = xn - f(xn) / f'(xn)"]
Update --> Eval
在编程中的应用
常用于图形引擎的渲染、物理模拟中的碰撞检测、优化问题等。值得一提的是,在传奇 FPS 游戏《雷神之锤III竞技场 (Quake III Arena)》的源代码中潜藏的“快速平方根倒数(Fast Inverse Square Root)”算法。这是一个仅应用一次牛顿法就以惊人的速度计算出 $1/\sqrt{x}$ 的骇客技巧,对于向量归一化来说是不可或缺的。
实现示例 (C++)
这里展示一个易于理解的例子:使用牛顿法计算标准的平方根 $\sqrt{N}$(即求解 $x^2 - N = 0$)。此时 $f(x) = x^2 - N$,$f'(x) = 2x$。
| |
详细解说:
牛顿法的最大魅力在于,在条件满足的情况下它能够实现“二次收敛(Quadratic convergence)”。这意味着每次迭代,正确答案的有效数字位数将大约增加一倍,收敛速度惊人。考虑到二分查找只是线性收敛,就可以明白利用导数(微小斜率)信息的强大之处。在《雷神之锤III》的技巧中,它使用了位运算的魔术数字 0x5f3759df 巧妙破解了 IEEE 754 浮点数的结构,从而以惊人的精度导出了牛顿法的初始值。
8. 贝塞尔曲线 (Bézier Curves)
公式的优美性与概述
一种使用多个控制点(Control Points)来定义平滑曲线的参数方程。最常用的三次贝塞尔曲线(Cubic Bézier Curve)具有 4 个点 $P_0, P_1, P_2, P_3$,并通过参数 $t \ (0 \le t \le 1)$ 决定曲线上的坐标 $B(t)$。
$$ B(t) = (1-t)^3 P_0 + 3(1-t)^2 t P_1 + 3(1-t) t^2 P_2 + t^3 P_3 $$在编程中的应用
贝塞尔曲线是计算机图形学的根基。从 Adobe Illustrator 等矢量绘图工具、字体(TrueType 或 OpenType)的渲染、CSS 的 cubic-bezier() 过渡动画和缓动函数,到游戏中相机路径的控制等,只要需要在程序中绘制“平滑的移动和形状”,就会使用到它。
实现示例 (Python)
这是一个根据 4 个控制点生成三次贝塞尔曲线上点集的代码。
| |
详细解说: 这个公式是展开了递归应用线性插值(Lerp: Linear Interpolation)的“德·卡斯特里奥算法(De Casteljau’s algorithm)”。它使用多项式计算(伯恩斯坦多项式)直接求解。在编程中,曲线被近似绘制为无数“微小直线”的集合。因此,可以通过调整 $t$ 的分辨率(steps)来控制性能与绘制质量之间的平衡。
9. 激活函数/Sigmoid 函数 (Sigmoid Function)
公式的优美性与概述
无论输入任何实数 $x \ ( -\infty < x < \infty )$,都会将其平滑地压缩(映射)到 $0$ 到 $1$ 之间的S型函数。
$$ \sigma(x) = \frac{1}{1 + e^{-x}} $$在编程中的应用
它在逻辑回归,以及神经网络(深度学习)的“激活函数(Activation Function)”中,历史上发挥了极其重要的作用。因为其输出落在0到1的范围内,所以最大的优势是可以将其结果解释为“概率”。
graph LR X1["输入 x1"] -->|"权重 w1"| Sum["求和: Σ(wi*xi) + b"] X2["输入 x2"] -->|"权重 w2"| Sum Sum --> Act["Sigmoid 函数: σ(x)"] Act --> Out["输出概率 (0 到 1)"]
实现示例 (Python)
这是一个将 Sigmoid 函数应用于输入数组(张量)的代码。
| |
详细解说:
在上面的代码中,针对 x >= 0 和其他情况进行分支处理,是为了防止编程特有的问题——“溢出(Overflow)”。例如当 $x = -1000$ 时,程序可能会尝试计算 $e^{1000}$ 而崩溃(或者返回 Inf),这是一种在数值计算中防止这种现象的技巧。目前,在深度学习的隐藏层中,从计算速度和解决梯度消失问题的角度来看,ReLU($f(x) = \max(0, x)$)已成为主流,但在二分类的输出层中,Sigmoid 函数依然保持着不可撼动的地位。
10. 欧几里得距离与勾股定理 (Euclidean Distance & Pythagorean Theorem)
公式的优美性与概述
这是流传自古希腊的几何学基础,也是定义 $n$ 维空间中两点间直线距离的公式。在二维空间中,它就是勾股定理($a^2 + b^2 = c^2$)本身。
三维空间中点 $P(x_1, y_1, z_1)$ 和 $Q(x_2, y_2, z_2)$ 之间的欧几里得距离 $d$ 表示如下:
$$ d = \sqrt{(x_2-x_1)^2 + (y_2-y_1)^2 + (z_2-z_1)^2} $$在编程中的应用
这是各种游戏开发、物理引擎、以及机器学习中“K近邻法(K-Nearest Neighbors)”和聚类(K-Means)等算法的核心计算。在游戏中,例如角色之间的碰撞检测(包围圆/包围球碰撞),每一帧都会被计算数百万次。
实现示例 (C++)
这是一个用于判断两个圆(球)是否发生碰撞的优化代码。
| |
详细解说:
如果完全按照数学公式计算,最后需要进行开平方 $\sqrt{\cdot}$。但在编程中,调用 sqrt() 函数对 CPU 来说是一项非常繁重的处理(消耗大量时钟周期)。因此,如果仅仅是为了比较距离, 在等式两边都保持平方状态下进行比较 (distanceSquared <= radiiSumSquared)是游戏编程中的常用手段。像这样利用数学等式或不等式的性质来降低计算负荷的优化,正是算法设计的妙趣所在。
总结
大家觉得如何呢?从欧拉恒等式到勾股定理,这10个公式并不仅仅是写在教科书上的理论概念。在日常编写的代码背后,它们作为核心跳动着,负责压缩数据、让机器学习模型进行预测、渲染平滑的动画以及实现快速搜索。
理解这些数学背景不仅是必须的,更是从一个仅仅调用现有库(如 math.sin 或 numpy.fft)的编码者,进阶成为能深入理解内部结构并发挥其极限的工程师的必经之路。下次编写代码时,不妨稍微展开想象,思考一下在这行代码背后,有哪些优美的数学公式正在运作。
Happy Coding and Math!
