跨卷导读:函数、复合、逆与增长

从定义域、陪域和像集出发,连接复合、双射、逆函数、数列、ε-δ连续性、线性变换、随机变量与算法增长阶。

学习目标

  • 能区分定义域、陪域和像集,并用单射、满射和双射判断逆函数是否存在
  • 能检查复合函数的中间集合和错误通道,说明为什么先执行右侧函数
  • 能把数列递推、生成函数、线性变换和随机变量放回“输入—规则—输出”的框架
  • 能比较对数、线性、多项式和指数增长,并用一个可复查实验检验算法规模判断

先把函数写成一份集合合同

函数不是只有“输入变输出”的箭头,也不是所有带参数的程序都天然是数学函数。它需要声明输入集合、输出集合和规则,并保证每一个允许输入恰好对应一个输出。作者目录中第1卷第4章《斐波那契数列和生成函数》会把这种关系用于数列与生成函数;本页再把它连接到复合、逆和算法增长。作者目录用于核对原书章节边界。

先预测:若两个程序都接受一个整数并返回一个整数,它们就一定可以任意复合吗?不一定。前一个结果必须满足后一个函数的输入合同;如果程序还依赖时间、随机源或文件状态,这些依赖也必须被建模,否则“同输入同输出”的数学保证并不存在。

函数:复合、逆与函数族函数是编程与数学的共通语言函数复合 (f ∘ g)(x)xg2xf4x²+1g(x)=2x → f(g(x))=(2x)²+1逆函数 f⁻¹f:[0,∞)→[1,∞), f(x)=x²+1f⁻¹(y) = √(y - 1)限制定义域与陪域后才有双边逆函数族增长对比log n(慢)n(线性)n²(快)2ⁿ(爆炸)xy函数 ↔ 编程数学函数 f:X→Y ↔ 显式输入决定唯一输出的纯函数复合 f∘g = 可类型检查的函数组合 逆函数 = 双射的反向映射普通程序过程还可能依赖状态、I/O、时间与随机源
函数复合是「先执行一个变换再执行另一个」,逆函数是「撤销变换」。对数增长最慢(O(log n) 算法高效),指数增长最快(O(2ⁿ) 算法不可行)。函数是数学与编程的共通语言。

定义域、陪域与像集

决定哪些输入可以被讨论; 是函数箭头声明的目标; 是实际输出的集合。写作

f:XYf:X\to Y

时,XX 是定义域,YY 是陪域,而 f(X)f(X) 才是像集。三者分开,满射与逆函数的判断才不会出现歧义。

例如

f:RR,f(x)=x2f:\mathbb R\to\mathbb R,\qquad f(x)=x^2

是函数,因为每个实数都有唯一平方;但 f(2)=f(2)=4f(2)=f(-2)=4,所以它不是单射,像集是 [0,)[0,\infty),相对于陪域 R\mathbb R 也不是满射。如果改成

f:[0,)[0,),f(x)=x2,f:[0,\infty)\to[0,\infty),\qquad f(x)=x^2,

它才同时满足单射和满射,逆函数 f1(y)=yf^{-1}(y)=\sqrt y 的定义域也随之确定。

f : X → Y 是一份集合合同规则要求每个输入恰有一个输出,但允许多个输入命中同一个结果定义域 Xabc陪域 Y1234a、b、c 映到 1、2、3;4 在陪域中但未被命中,因此像集不等于陪域。若两个输入命中同一结果,不单射;若所有陪域元素都被命中,才满射。
先分清定义域、陪域和像集,再判断单射、满射与逆函数。

复合函数:中间类型必须接得上

g:XY,f:YZ,g:X\to Y,\qquad f:Y\to Z,

则复合函数 fgf\circ g 定义为先执行 gg 再执行 ff

(fg)(x)=f(g(x)),fg:XZ.(f\circ g)(x)=f(g(x)),\qquad f\circ g:X\to Z.

满足结合律

(fg)h=f(gh),(f\circ g)\circ h=f\circ(g\circ h),

但一般不满足交换律。令 f(x)=x2f(x)=x^2g(x)=x+1g(x)=x+1,则

(fg)(x)=(x+1)2,(gf)(x)=x2+1.(f\circ g)(x)=(x+1)^2,\qquad (g\circ f)(x)=x^2+1.

程序中的组合还要检查中间类型和前置条件。若第一个函数只能保证输出任意整数,而第二个函数要求正整数,表面类型相似也不能证明组合安全。

type Result<T> = { ok: true; value: T } | { ok: false; error: string };
 
function composeResult<A, B, C>(
  first: (input: A) => Result<B>,
  second: (input: B) => Result<C>,
): (input: A) => Result<C> {
  return (input) => {
    const intermediate = first(input);
    return intermediate.ok ? second(intermediate.value) : intermediate;
  };
}

这里错误通道也参与复合,失败不会被伪装成普通值;这正是把数学上的“定义域限制”翻译成程序合同的一种方式。

单射、满射、双射与逆

才能保证通常意义上的逆函数。若 f:XYf:X\to Y 是双射,则存在 f1:YXf^{-1}:Y\to X,并满足

f1f=idX,ff1=idY.f^{-1}\circ f=\operatorname{id}_X,\qquad f\circ f^{-1}=\operatorname{id}_Y.

只满足第一式可能是左逆,只满足第二式可能是右逆;只有双边逆才能把输入和输出完整地互相撤销。严格单调函数在区间上保证单射,但不自动保证相对于任意陪域满射。例如 ex:RRe^x:\mathbb R\to\mathbb R 严格递增,却没有命中非正实数;把陪域改成 (0,)(0,\infty) 后才成为双射,逆函数是 lny\ln y

限制定义域和陪域不是注释,而是逆函数成立的组成部分。压缩文件、序列化和解码也遵守同样的逻辑:若编码只对合法消息集合定义,就要明确集合边界;若解码可能失败,工程合同应返回成功值或错误,而不是假装无条件可逆。

复合与逆:箭头方向就是证明线索(f ∘ g)(x) 先走 g,再走 f;撤销需要两边都能回到原点X输入对象gY中间类型fZ输出对象逆映射只能在条件满足时回走双射:既不碰撞又覆盖目标,f⁻¹ ∘ f = id 且 f ∘ f⁻¹ = id。只有单射时可能有左逆,只有满射时可能有右逆;程序组合还要检查错误通道。
复合的箭头方向和中间类型决定可组合性;双边逆需要双射。

四卷中的函数形态

数列:从递推关系到封闭表达式

第1卷第4章的四个关键对象是:斐波那契数列等比数列与无穷级数生成函数递推关系与封闭表达式。它们把“每一项由前项决定”的关系逐步换成更适合整体计算的表示。

斐波那契数列可以写为

F(0)=0,F(1)=1,F(n+2)=F(n+1)+F(n).F(0)=0,\quad F(1)=1,\quad F(n+2)=F(n+1)+F(n).

这是递推关系;尝试 F(n)=rnF(n)=r^n 会得到特征方程 r2r1=0r^2-r-1=0,从而寻找封闭表达式。生成函数 F(x)=n0F(n)xnF(x)=\sum_{n\ge0}F(n)x^n 又把递推转成代数分式。每种表示都保留对象,却把不同的运算变得容易。

极限与连续:用量词控制误差

第3卷用 ε\varepsilonδ\delta 语言表达“输入靠近 aa 时输出靠近 LL”:

ε>0, δ>0,0<xa<δf(x)L<ε.\forall\varepsilon>0,\ \exists\delta>0,\quad 0<|x-a|<\delta\Rightarrow|f(x)-L|<\varepsilon.

量词顺序说明:先给定输出容差,再找能满足它的输入容差,最后对所有符合条件的输入负责。这种函数合同也为数值求根、连续性和误差分析提供了严格语言。

线性变换与随机变量

线性变换 T:VWT:V\to W 满足

T(αu+βv)=αT(u)+βT(v).T(\alpha u+\beta v)=\alpha T(u)+\beta T(v).

选定基后,矩阵表示变换,函数复合对应矩阵乘法,可逆矩阵对应双射线性变换。随机变量则是函数 X:ΩRX:\Omega\to\mathbb R,把复杂样本映射为可求期望的数值;指示器随机变量只输出 0 或 1。

函数增长:从表示到算法规模

比较

logn,n,nk,cn (c>1).\log n,\qquad n,\qquad n^k,\qquad c^n\ (c>1).

长期看,对数增长慢于任意正次幂,固定次幂慢于指数。 可以解释二分查找、比较排序与指数枚举的规模差异,但不能替代有限输入的基准测试:常数、缓存、分支和输入分布都可能改变实际表现。

函数形态:从递推到增长阶同一个“输入—输出”框架可以承载离散、线性和随机对象数列函数a : N → R线性变换T : V → W随机变量X : Ω → Rlog nncⁿ对数 → 线性 → 多项式 → 指数:长期增长越来越快实际性能仍需结合常数、输入分布、缓存和基准测试判断。
函数形态跨越数列、矩阵和随机变量;渐近增长只描述长期尺度。

编程中的函数合同

数学函数给程序设计三条约束:影响结果的时间、配置、随机源和数据库快照应该成为显式输入;定义域外输入、解析失败和数值溢出应该进入显式错误通道;前一函数的输出合同必须满足后一函数的输入合同。

普通程序过程不一定是纯函数。它可能依赖 I/O、全局状态或随机设备;若希望把它建模为确定函数,可以把随机种子或状态加入输入和输出:

F:(input,state)(output,next state).F:(\text{input},\text{state})\to(\text{output},\text{next state}).

这样做不是为了把每个系统都伪装成数学对象,而是为了明确哪些依赖已经被记录,哪些错误还没有被覆盖。可替换、可缓存和局部推理都建立在这份合同上。

三步动手复习

分步1 / 3

1. 合同:把一个函数写完整

对平方函数分别选择定义域和陪域,判断它何时单射、何时满射,最后写出逆函数的合法范围。用图中的箭头检查是否有碰撞和未命中元素。

f : X → Y 是一份集合合同规则要求每个输入恰有一个输出,但允许多个输入命中同一个结果定义域 Xabc陪域 Y1234a、b、c 映到 1、2、3;4 在陪域中但未被命中,因此像集不等于陪域。若两个输入命中同一结果,不单射;若所有陪域元素都被命中,才满射。
先分清定义域、陪域和像集,再判断单射、满射与逆函数。

本章练习

练习

问题 1:集合合同。f:RRf:\mathbb R\to\mathbb Rf(x)=x2f(x)=x^2,分别判断它是否为单射、满射,并给出一个能拥有逆函数的定义域与陪域。

问题 2:复合顺序。f(x)=x2f(x)=x^2g(x)=x+1g(x)=x+1,计算 (fg)(x)(f\circ g)(x)(gf)(x)(g\circ f)(x),说明它们为什么通常不相等。

问题 3:递推表示。 对斐波那契递推 F(n+2)=F(n+1)+F(n)F(n+2)=F(n+1)+F(n),写出对应的特征方程,并说明它与封闭表达式的关系。

问题 4:增长验证。 为什么不能只用渐近阶断言一个算法在所有实际输入上都更快?请列出至少两项需要记录的实验条件。

本章回顾

  • 函数由定义域、陪域、规则和唯一输出共同构成;像集是实际命中的结果集合。
  • 单射避免碰撞,满射覆盖陪域,双射同时满足二者并允许双边逆。
  • 复合函数先执行右侧函数,中间集合和错误通道必须兼容。
  • 第1卷的斐波那契数列、等比数列与无穷级数、生成函数和递推关系都可以放进函数框架。
  • ε\varepsilonδ\delta 语言、线性变换和随机变量展示了函数概念在不同对象上的迁移。
  • 渐近阶比较长期增长,实际性能仍需结合常数、输入分布和可复现基准。
  • 编程函数合同必须显式表达状态依赖、前置条件、后置条件和失败路径。

名词解释

本章出现的专业名词,用大白话再讲一遍。

定义域

函数允许接收的输入集合;分母、根式、对数和前置条件都可能进一步限制它。

陪域

函数声明的目标集合,不等于函数实际命中的像集。

像集

定义域中所有输入经过函数规则后实际得到的输出集合。

复合函数

先执行一个函数,再把输出交给另一个函数的组合;箭头顺序决定计算顺序。

双射

既是单射又是满射的函数,因此每个输出恰好对应一个输入并存在双边逆。

渐近阶

描述输入规模变大时函数或算法主导增长速度的记号,不等于每个具体输入的精确耗时。

资料与写作方式声明

本章以结城浩《数学女孩》系列前四卷目录权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…