副标题:程序员的数学急救包------无论你写Java、Python、Go还是Rust,看到∑就该想到一个for循环。
开篇灵魂拷问
翻开源码或者论文,你大概率会撞见这样的符号:

是不是瞬间头大?别慌。作为一个写了成千上万行循环的程序员,你有天然的优势------这些符号在代码世界里,全是循环和累加器。
本节目标:让你今后见到∑、∏、∫、Δ,条件反射般地在大脑中生成一个for循环或者while循环的代码片段。本文提供 Java / Python / JavaScript / C++ / Rust / Go 六种语言实现,覆盖99%后端与算法工程师技术栈。
1. ∑:高级版的 for 循环累加器
1.1 数学定义

LaTeX 源码(可复制)
\sum_{i=m}^{n} a_i = a_m + a_{m+1} + \dots + a_n
其中:
-
ii 是循环变量 (代码里的
i) -
mm 是起始值 (
range(m, n+1)的start) -
nn 是终止值 (
range的stop) -
aiai 是第 i 项表达式(循环体)
1.2 核心代码直译
| 语言 | 核心实现 |
|---|---|
| Python | total=0; for i in range(m, n+1): total+=a(i) |
| Java | int total=0; for(int i=m; i<=n; i++) total+=a(i); |
| JavaScript | let total=0; for(let i=m; i<=n; i++) total+=a(i); |
| C++ | int total=0; for(int i=m; i<=n; ++i) total+=a(i); |
| Rust | let mut total=0; for i in m..=n { total+=a(i); } |
| Go | total:=0; for i:=m; i<=n; i++ { total+=a(i) } |
1.3 面试题实战
题目 :计算 ,手写代码并分析时间复杂度。
解法一:循环法(直译数学符号)
Python
def sum_of_squares_loop(n=100):
s = 0
for i in range(1, n+1):
s += i * i
return s
Java
public class SumSquares {
public static int sumLoop(int n) {
int s = 0;
for (int i = 1; i <= n; i++) {
s += i * i;
}
return s;
}
}
JavaScript
function sumSquaresLoop(n = 100) {
let s = 0;
for (let i = 1; i <= n; i++) {
s += i * i;
}
return s;
}
C++
int sumSquaresLoop(int n = 100) {
int s = 0;
for (int i = 1; i <= n; ++i) {
s += i * i;
}
return s;
}
Rust
fn sum_squares_loop(n: i32) -> i32 {
let mut s = 0;
for i in 1..=n {
s += i * i;
}
s
}
Go
func sumSquaresLoop(n int) int {
s := 0
for i := 1; i <= n; i++ {
s += i * i
}
return s
}
-
时间复杂度:O(n)
-
空间复杂度:O(1)
解法二:公式法(数学降维打击)
平方和公式:

LaTeX 源码(可复制)
\sum_{i=1}^{n} i^2 = \frac{n(n+1)(2n+1)}{6}
各语言一行代码实现:
Python
def sum_of_squares_formula(n=100):
return n * (n + 1) * (2 * n + 1) // 6
Java
public static int sumFormula(int n) {
return n * (n + 1) * (2 * n + 1) / 6;
}
JavaScript
const sumSquaresFormula = n => n * (n + 1) * (2 * n + 1) / 6;
C++
int sumFormula(int n) {
return n * (n + 1) * (2 * n + 1) / 6;
}
Rust
fn sum_squares_formula(n: i32) -> i32 {
n * (n + 1) * (2 * n + 1) / 6
}
Go
func sumSquaresFormula(n int) int {
return n * (n + 1) * (2*n + 1) / 6
}
-
时间复杂度:O(1)
-
空间复杂度:O(1)
1.4 什么时候用循环,什么时候用公式?
| 场景 | 推荐方法 | 原因 |
|---|---|---|
| n很小(n < 1000) | 循环法 | 代码直观,性能差异可忽略 |
| n极大(n = 10^9) | 公式法 | O(1) vs O(n) 是天壤之别 |
| 通项公式极其复杂或不存在 | 循环法 | 数学没有闭式解,只能迭代 |
| 需要展示推导过程(面试) | 先写循环,再优化成公式 | 体现从直观到优化的思维过程 |
面试官心理 :你直接甩出公式,他只看到你背了题;你先写出循环,再指出可以数学优化,他看到的是工程思维 + 数学素养。
1.5 扩展:求和符号的更多用法
双重求和

LaTeX 源码(可复制)
\sum_{i=1}^{m} \sum_{j=1}^{n} a_{ij} = \sum_{j=1}^{n} \sum_{i=1}^{m} a_{ij}
对应嵌套循环:
Python
total = 0
for i in range(1, m+1):
for j in range(1, n+1):
total += a[i][j]
条件求和

Python
sum(i for i in range(1, n+1) if i % 2 == 0)
2. ∏:高级版的 while 循环累乘器
2.1 数学定义

LaTeX 源码(可复制)
\prod_{i=1}^{n} a_i = a_1 \times a_2 \times \dots \times a_n
2.2 核心代码对照
计算阶乘
Python
def factorial(n):
result = 1
for i in range(1, n+1):
result *= i
return result
Java
public static long factorial(int n) {
long result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
JavaScript
function factorial(n) {
let result = 1;
for (let i = 1; i <= n; i++) result *= i;
return result;
}
C++
long long factorial(int n) {
long long result = 1;
for (int i = 1; i <= n; ++i) result *= i;
return result;
}
Rust
fn factorial(n: u64) -> u64 {
(1..=n).product()
}
Go
func factorial(n int) int {
res := 1
for i := 1; i <= n; i++ {
res *= i
}
return res
}
2.3 注意陷阱:空积与空和
-
空和
→ 累加器初始化为0,循环0次返回0。
-
空积
→ 累乘器初始化为1,循环0次返回1。
这在边界条件处理时极其重要。
Python 示例
def safe_sum(n):
return sum(range(1, n+1)) # n=0 时返回0
def safe_product(n):
result = 1
for i in range(1, n+1):
result *= i
return result # n=0 时返回1
3. ∫:当步长趋近于0时的求和
3.1 数学定义
积分 ∫abf(x)dx∫abf(x)dx 可以看作是把区间[a,b]切成无数个小矩形,求面积和。

LaTeX 源码(可复制)
\int_a^b f(x) dx \approx \sum_{k=0}^{N-1} f(a + k \cdot \Delta x) \cdot \Delta x
其中 ,N是划分份数。
3.2 代码实现:矩形法求定积分
计算(精确值为 1/3 ≈ 0.3333)
Python
def integral(f, a, b, n=10000):
dx = (b - a) / n
total = 0.0
for i in range(n):
total += f(a + i * dx) * dx
return total
f = lambda x: x**2
print(integral(f, 0, 1, 10000)) # 输出约0.33328333
Java
import java.util.function.Function;
public static double integral(Function<Double, Double> f, double a, double b, int n) {
double dx = (b - a) / n;
double total = 0.0;
for (int i = 0; i < n; i++) {
total += f.apply(a + i * dx) * dx;
}
return total;
}
JavaScript
function integral(f, a, b, n = 10000) {
const dx = (b - a) / n;
let total = 0;
for (let i = 0; i < n; i++) {
total += f(a + i * dx) * dx;
}
return total;
}
C++
#include <functional>
double integral(std::function<double(double)> f, double a, double b, int n = 10000) {
double dx = (b - a) / n;
double total = 0.0;
for (int i = 0; i < n; ++i) {
total += f(a + i * dx) * dx;
}
return total;
}
Rust
fn integral<F>(f: F, a: f64, b: f64, n: usize) -> f64
where
F: Fn(f64) -> f64,
{
let dx = (b - a) / n as f64;
(0..n).map(|i| f(a + i as f64 * dx) * dx).sum()
}
Go
func integral(f func(float64) float64, a, b float64, n int) float64 {
dx := (b - a) / float64(n)
total := 0.0
for i := 0; i < n; i++ {
total += f(a+float64(i)*dx) * dx
}
return total
}
3.3 精度与性能的权衡
| 划分份数 n | 近似值 | 误差 | 计算时间 |
|---|---|---|---|
| 10 | 0.285 | ~0.048 | 极快 |
| 100 | 0.32835 | ~0.005 | 很快 |
| 10,000 | 0.333283 | ~0.00005 | 快 |
| 1,000,000 | 0.333333 | 极小 | 较慢 |
经验法则:对于平滑函数,n=10,000 已足够应对大多数工程场景。
3.4 扩展:蒙特卡洛积分思想
除了均匀切分矩形,还可以随机扔点------这就是蒙特卡洛方法(下册第8章将详细展开)。核心思想

Python 示例
import random
def monte_carlo_integral(f, a, b, n=10000):
total = 0.0
for _ in range(n):
x = random.uniform(a, b)
total += f(x)
return (b - a) * total / n
4. Δ:差分,就是前后相减
4.1 数学定义

LaTeX 源码(可复制)
\Delta x_i = x_i - x_{i-1}
在时间序列、信号处理、物理模拟中到处都是Δ。
4.2 各语言实现
Python
def diff(arr):
return [arr[i] - arr[i-1] for i in range(1, len(arr))]
JavaScript
const diff = arr => arr.slice(1).map((v, i) => v - arr[i]);
C++
#include <vector>
std::vector<int> diff(const std::vector<int>& arr) {
std::vector<int> res;
for (size_t i = 1; i < arr.size(); ++i)
res.push_back(arr[i] - arr[i-1]);
return res;
}
Rust
fn diff(arr: &[i32]) -> Vec<i32> {
arr.windows(2).map(|w| w[1] - w[0]).collect()
}
Go
func diff(arr []int) []int {
res := make([]int, len(arr)-1)
for i := 1; i < len(arr); i++ {
res[i-1] = arr[i] - arr[i-1]
}
return res
}
4.3 二阶差分与导数的联系
二阶差分:

LaTeX 源码(可复制)
\Delta^2 x_i = \Delta(\Delta x_i) = x_i - 2x_{i-1} + x_{i-2}
Python 实现
def second_diff(arr):
return diff(diff(arr))
这与离散函数的"二阶导数"对应,在数值分析中用于近似曲率。
5. 综合实战:用循环思维拆解复杂公式
来看一个真实的公式------均方误差 MSE:

LaTeX 源码(可复制)
MSE = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2
5.1 四步拆解法演示(预告1.2节)
-
识符号:∑∑ 求和,yiyi 真实值,y^iy^i 预测值。
-
找结构:求和内部是差的平方,求和后除以n。
-
代数值:假设 y = [2,4,6],y_hat = [1,5,5]。
-
写代码:
Python 循环版
def mse_loop(y_true, y_pred):
n = len(y_true)
total = 0
for i in range(n):
total += (y_true[i] - y_pred[i]) ** 2
return total / n
Python 向量化版(NumPy)
import numpy as np
def mse_np(y_true, y_pred):
return np.mean((np.array(y_true) - np.array(y_pred)) ** 2)
Java 版
public static double mse(double[] yTrue, double[] yPred) {
double sum = 0.0;
for (int i = 0; i < yTrue.length; i++) {
double diff = yTrue[i] - yPred[i];
sum += diff * diff;
}
return sum / yTrue.length;
}
Rust 版
fn mse(y_true: &[f64], y_pred: &[f64]) -> f64 {
y_true.iter()
.zip(y_pred.iter())
.map(|(t, p)| (t - p).powi(2))
.sum::<f64>() / y_true.len() as f64
}
6. 符号→代码映射总表
| 数学符号 | 代码本质 | Python | Java | Go | Rust |
|---|---|---|---|---|---|
| ∑∑ | 累加循环 | sum(...) sum(...) |
for(int i..) 对于(智 i..) |
for i:=.. 对于 i:=.. |
(m..=n).sum() (M..=n).sum() |
| ∏∏ | 累乘循环 | math.prod 数学.prod |
for 乘 |
for 乘 |
(m..=n).product() (m..=n).product() |
| ∫∫ | 循环累加×dx | for + dx 对于 + dx |
for + dx 对于 + dx |
for + dx 对于 + dx |
map().sum() map().sum() |
| ΔΔ | 相邻差 | arr[i]-arr[i-1] |
同上 | 同上 | windows(2) Windows(2) |
课后习题
基础题(必做)
题1:将下列数学表达式翻译成Python函数。

提示:裂项相消法可得解析解 ,但请先用循环实现。
LaTeX 源码
S = \sum_{k=1}^{50} \frac{1}{k(k+1)}
面试题(大厂高频)
题2 (类似LeetCode 268):给定一个包含n个不同数字的数组,数字范围是0到n,找出缺失的那个数。要求分别用循环求和法 和异或法实现,并分析复杂度。
思路引导:0到n的和公式为 n(n+1)/2n(n+1)/2,减去数组实际和即为缺失数。
题3 :不使用math.factorial,用while循环实现一个函数approx_e(n_terms),根据泰勒展开式 计算自然常数e的近似值,项数为
n_terms。
题4 (性能挑战):分别用循环法和公式法计算 ,用
timeit对比时间,分析原因。
本节小结
| 掌握内容 | 检验标准 |
|---|---|
| ∑ 符号 | 能写循环实现任意求和,知道何时用公式优化 |
| ∏ 符号 | 能写累乘,注意空积为1 |
| ∫ 符号 | 能用矩形法近似计算简单积分 |
| Δ 符号 | 能计算序列差分 |
| 多语言迁移 | 至少能用两种语言实现本节核心函数 |
下节预告:1.2 希腊字母速查表 + 公式阅读实战------我们将拿Transformer论文开刀,当场拆解多头注意力公式,并给出四步拆解法的完整演示。
本文配套代码已上传至 GitHub 仓库 self-learners-league/beauty-of-operators-and-formulas,各语言实现见 volume1/chapter1/1.1_sigma_pi_integral/ 目录。习题答案将在专栏完结后统一发布在附录D。
本文为《算符与公式之美·高级卷(上册)》第1章第1节内容,版权所有,未经授权禁止转载。