[{"content":"集合论 集合是一个无顺序的结构，包含 $0$ 个或多个对象。\n常用的集合 描述 $\\textbf{N}$ 自然数集：$\\textbf{N} = \\{ 0, 1, 2, \\cdots \\}$ $\\textbf{Z}$ 整数集：$\\textbf{Z} = \\{\\cdots, -2, -1, 0, 1, 2, \\cdots\\}$ $\\textbf{R}$ 实数集 $\\oslash$ 空集：$\\oslash = \\{\\} = \\{x \\mid \\textbf{False}\\}$ 也可表示为： $\\lnot\\ \\exist\\ x : x \\in \\oslash$ 集合间的运算 运算 含义 表达式 $$S \\subset T$$ 集合 $S$ 是 $T$ 的真子集 $S \\subseteq T$ 但是 $T \\nsubseteq S$ $|S|$ 集合 $S$ 中元素的个数 $$A \\cup B$$ 集合 $A$ 与 $B$ 的并集 $A \\cup B = \\{x \\mid x \\in A \\lor x \\in B\\}$ $$A \\cap B$$ 集合 $A$ 与 $B$ 的交集 $A \\cap B = \\{x \\mid x \\in A \\land x \\in B\\}$ $$A - B$$ 集合 $A$ 与 $B$ 的差，在集合 $A$ 但不在集合 $B$ 中的元素 $$A - B = \\{x \\mid x \\in A \\land x \\notin B\\} = \\{x \\mid \\lnot(x \\in A \\to x \\in B)\\}$$ $$\\overline{A}$$ 集合 $A$ 相对于全集 $U$ 的补集 $$A \\oplus B$$ 集合 $A$ 与 $B$ 的对称差 在集合 $A$ 和 $B$ 但不在其交集的元素 集合内的元素也可以是集合，例如 $S = \\{ x | x \\subseteq \\{1, 2, 3\\} \\} = \\{\\oslash, \\{1\\}, \\{2\\}, \\{3\\}, \\{1,2\\}, \\{1,3\\}, \\{2,3\\}, \\{1,2,3\\}\\}$\n注意：$1 \\ne \\{1\\} \\ne \\{\\{1\\}\\}$\n特别地，若 $A \\cap B = \\oslash$，则称集合 $A$ 和 $B$ 不连接（disjoint）。\n幂集 集合 $S$ 的所有子集称作集合 $S$ 的幂集，记作 $P(S) = \\{x \\mid x \\subseteq S\\}$。\n例如，$P(\\{a,b\\}) = \\{\\oslash, \\{a\\}, \\{b\\}, \\{a,b\\}\\}$\n我们有以下结论：$\\mid P(S) \\mid = 2^{\\mid S \\mid}$\n笛卡尔积 定义 $A \\times B :\\equiv \\{(a,b) \\mid a \\in A \\land b \\in B\\}$ 为集合 $A$ 与 $B$ 的笛卡尔积。\n例如，$\\{a,b\\} \\times \\{1,2\\} = \\{(a,1), (a,2), (b,1), (b,2)\\}$\n具有以下结论：\n$|A \\times B| = |A| \\cdot |B|$。 $\\lnot \\forall AB: A \\times B = B \\times A$，即笛卡尔积不具备交换律。 集合间的关系 集合 $A$ 与 $B$ 之间的关系 $R$ 是 $A \\times B$ 的一个子集，记作：$R: A \\leftrightarrow B$\n通常，我们用 $aRb$ 表示 $(a,b) \\in R$，即元素 $a$ 与 $b$ 具备关系 $R$。\n常见的关系 表示 空关系 $\\oslash$ 恒等关系 $\\mathrm{i}d_A : \\{(a,a) \\mid (a \\in A)\\}$ 逆关系 $R^{-1} :\\equiv \\{(b,a) \\mid (a,b) \\in R\\}$ 关系的性质\n性质 定义 自反性 对于 $A$ 上的关系 $R$，$\\forall a \\in A$，都有 $aRa$ 对称性 当且仅当关系 $R$ 满足 $R = R^{-1}$，即 $(a,b) \\in R \\leftrightarrow (b,a) \\in R$ 反对称性 当且仅当关系 $R$ 满足 $(\\forall a)(\\forall b) ((a \\in A \\land b \\in A) \\Rightarrow ((a,b) \\in R \\land (b,a) \\in R) \\Rightarrow a = b)$ 传递性 当且仅当关系 $R$ 满足 $\\forall a,b,c$，都有 $(a,b) \\in R \\land (b,c) \\in R \\rightarrow (a,c) \\in R$ 当集合上的关系同时满足一些性质时，则称该关系为一种特殊的关系。\n特殊关系 定义 等价关系 同时满足自反性、对称性和传递性 偏序关系 同时满足自反性、反对称性和传递性 通过集合论，我们可以形式化地给出自然数的定义：\n$$\r\\begin{array}{c}\\begin{align*}\r0 \u0026= \\oslash \\\\\r1 \u0026= \\{0\\} = \\{\\oslash\\} = \\oslash \\cup \\{\\oslash\\} = 0 \\cup \\{0\\} \\\\\r2 \u0026= \\{0, 1\\} = \\{\\oslash, \\{\\oslash\\}\\} = 1 \\cup \\{1\\} = 0 \\cup \\{0\\} \\cup \\{1\\} \\\\\r3 \u0026= \\{0, 1, 2\\} = \\{\\oslash, \\{\\oslash\\}, \\{\\oslash \\cup \\{\\oslash\\}\\}\\} = 2 \\cup \\{2\\} = 0 \\cup \\{0\\} \\cup \\{1\\} \\cup \\{2\\} \\\\\r\u0026 \\cdots \\\\\rn+1 \u0026= n \\cup \\{n\\}\r\\end{align*}\r\\end{array}$$ 函数 函数定义为从集合 $A$ 到集合 $B$ 的一种对应关系，记作 $f: A \\rightarrow B$。\n集合的描述 数据类型 某个类型的所有可能成员都具备一些共同特征，这时我们称它们属于同一个类型。\nZ语言就是在类型的集合论上建立起来的。\n类型集合 定义 BuildIn types Z语言的内置类型，无需定义即可使用。\nInteger：记作 $Z$，可使用 \u0026ldquo;+, -, *, div, mod\u0026rdquo; 运算 Natural：Integer类型的子集，记作 $N$，必须为非负数。$N1$ 则表示正整数 Basic types 在名称周围添加方括号来声明，可附带注释。例如：\n$[\\mathrm{PERSON}] \\qquad \\text{the set of all persons}$ Free types 通过列举其元素来定义的数据类型，例如：\n$\\text{freeType} ::= \\text{element}_1 \\mid \\text{element}_2 \\mid \\cdots \\text{element}_n$ 变量 Z语言的每个变量名在赋值前必须先声明，格式为 $v: \\text{TYPE}$\n示例：$\\text{chauffeur}: \\text{PERSON}$\n集合 Z语言中的集合可以通过在括号内列举它的所有值来声明。\n集合中的元素值的类型必须是先前声明过的类型，否则视为非法值。\n运算 表示 幂集 $\\mathbb{P} S$ 差 $S \\backslash T$ 并集 $S \\cup T$ 交集 $S \\cap T$ 划分 $S \\cup T = U \\land S \\cap T = \\oslash$ 用集合描述系统 特点：以状态的转换为核心描述系统行为；系统的操作（函数）通过描述其执行如何改变系统状态来定义。\n步骤 操作 ① 定义描述目标系统状态的变量以及与这些变量相关的任何不变的性质 ② 定义初始操作，将变量的值设置为满足不变性质的某个初始状态 ③ 定义对状态的操作，满足在改变状态的同时保持不变的性质 ④ 定义查询操作，使其在不改变系统状态的前提下获取系统信息 案例：乘客登机系统\n模式 模式是一种结构化的规格说明。\n模式表达 格式 表示 图表格式 $\\begin{array}{l} \\text{SchemaName} \\\\ \\left| \\begin{array}{l} \\text{Declarations} \\\\ \\hline \\text{Predicate} \\\\ \\hline \\end{array} \\right.\\end{array}$ 文字格式 $\\text{SchemaName} == [\\ \\text{Declarations} \\mid \\text{Predicate} \\ ]$ 内容 规范 声明 每行声明均被视为以分号结尾，若干行构成一个序列 谓词 若干行谓词被视为以运算符连接 不含谓词部分的模式 只声明新变量，不施加约束谓词 局部变量 模式里声明的变量，在其他模式里引用时需要明确包含该定义的模式 全局变量 在规格说明始终可以引用，以公理定义声明；值不能被规格说明运算改变 模式推演 模式可作为单元，进行类似逻辑运算的操作\n修饰 修饰（Decoration）：表示一个模式在执行了某些操作后的值，可表示为\n$$\\begin{array}{l} \\text{S} \\\\ \\left\\| \\begin{array}{l} a,b:N \\\\ \\hline a \u003c b \\\\ \\hline \\end{array} \\right. \\end{array} \\begin{array}{l} \\text{S'} \\\\ \\left\\| \\begin{array}{l} a',b':N \\\\ \\hline a' \u003c b' \\\\ \\hline \\end{array} \\right. \\end{array}$$包含 包含（Inclusion）： 一个模式的声明可以包含另一个模式，会将被包含模式的声明和谓词合并，可表示为\n$$\\begin{array}{l} \\text{IncludeS} \\\\ \\left\\| \\begin{array}{l} c:N \\\\ S \\\\ \\hline c\u003c10 \\\\ \\hline \\end{array} \\right.\\end{array}$$合取与析取 合取（Conjunction）：将两个模式取交，得到一个新模式，其声明原来两个模式的合并，谓词是原来两个模式的与\n析取（Disjunction）：将两个模式取并，得到一个新模式，其声明原来两个模式的合并，谓词是原来两个模式的或\nDelta \u0026amp; Xi Delta convention 表示模式的改变，可以类比为复制一份，可表示为\n$$\\begin{array}{l} \\Delta\\text{S} \\\\ \\left\\| \\begin{array}{l} a,b:N \\\\ a',b':N \\\\ \\hline a \u003c b \\\\ a' \u003c b' \\\\ \\hline \\end{array} \\right.\\end{array}$$Xi convention 表示模式的改变，可以类比为复制一份，它的声明比Delta convention更强，可表示为\n$$\\begin{array}{l} \\Xi\\text{S} \\\\ \\left\\| \\begin{array}{l} a,b:N \\\\ a',b':N \\\\ \\hline a \u003c b \\\\ a' \u003c b' \\\\ a=a' \\\\ b=b' \\\\ \\hline \\end{array} \\right.\\end{array}$$其他 运算 含义 重命名（Renaming） $$\\text{newSchemaName} ==\\\\ \\text{oldSchemaName} [\\text{newName1/oldName1}, \\text{newName2/oldName2}, \\cdots]$$ 隐藏（Hide） 隐藏声明中的变量，让它只存在于谓词的运算符中，语法：$$\\text{newSchemaName} == \\text{oldSchemaName} \\ (\\text{varName1}, \\text{ varName2}, \\cdots) $$ 投影（Project） 隐藏除指定变量之外的变量，语法：$$\\text{newSchemaName} == \\text{oldSchemaName} \\uparrow (\\text{varName1}, \\text{varName2}, \\cdots)$$ 合成（Composition） 表示执行 $S$ 后执行 $T$，隐藏了中间变量 输入和输出变量 输入变量：变量名 + ?\n输出变量：变量名 + !\n举例：\n$$\\begin{array}{l} \\text{Add} \\\\ \\left\\| \\begin{array}{l} a?,b?:N \\\\ sum!:N \\\\ \\hline sum! = a? + b? \\\\ \\hline \\end{array} \\right.\\end{array}$$谓词、量词与关系 谓词与量词 谓词 定义 零元谓词 事实的陈述，独立于单个变量 一元谓词 反映对象（个体）的特性 二元谓词 一对对象（个体）的关系 量词 记号 含义 全称量词 $$\\forall \\ \\text{declaration} \\mid \\text{constraint} \\cdot \\text{predicate}$$ $\\text{declaration}$ 给出一些变量，$\\text{contraint}$ 约束为确定的值，$\\text{predicate}$ 均为真 存在量词 $$\\exist \\ \\text{declaration} \\mid \\text{constraint} \\cdot \\text{predicate}$$ $\\text{declaration}$ 给出一些变量，$\\text{contraint}$ 约束为确定的值，$\\text{predicate}$ 对于一些值为真 唯一量词 $$\\exist_1 \\ \\text{declaration} \\mid \\text{constraint} \\cdot \\text{predicate}$$ 只存在一个值使得 $\\text{declaration}$ 为真 集合推导：通过给定条件（谓词）来定义集合。表示为 $\\{\\text{declaration} \\mid \\text{constraint} \\cdot \\text{expression}\\}$\n例如：$\\{x: Z \\mid \\text{Even}(x) \\cdot x^2 \\}$ 表示偶数的平方的集合。\nZ中的关系 声明关系 $$R: X \\leftrightarrow Y \\quad (X \\leftrightarrow Y == \\mathbb{P}(X \\times Y))$$举例：\n$$\\begin{align*} \u0026[\\text{COUNTRY}] \\quad \\text{the set of all countries} \\\\ \u0026[\\text{LANGUANGE}] \\quad \\text{the set of all languages} \\\\ \u0026\\text{speaks}: \\text{COUNTRY} \\leftrightarrow \\text{LANGUAGE} \\end{align*}$$ 映射与关系\n$x \\mapsto y == (x,y)$ 表示 $x$ 与 $y$ 有关\n有以下等价关系：\n$$xRy == x \\mapsto y \\in R == (x,y) \\in R$$ 概念 内容 定义域（Domain） $\\text{dom} R == \\{a \\mid (\\exist \\ b)((a,b) \\in R) \\}$ 值域（Range） $\\text{ran} R == \\{b \\mid (\\exist \\ a)((a,b) \\in R)\\}$ 像（Image） 对于 $S \\subseteq \\text{dom} R$，$R(|S|)$ 是 $S$ 对应值的集合 常用关系 关系 记法 中缀关系 $\\_\\ R\\ \\_ : X \\leftrightarrow Y$ 反转关系 $R\\sim \\ : Y \\leftrightarrow X$ 组合关系 若 $R: X \\leftrightarrow Y$，$Q: Y \\leftrightarrow Z$，则 $R;Q: X \\leftrightarrow Z$，$Q \\circ R == R;Q$ 恒等关系 $\\text{id} X == \\{x:X \\cdot x \\mapsto x\\}$ 限制 记号 定义域限制 $S \\triangleleft R$，表示关系 $R$ 的定义域限制在 $S$ 内 值域限制 $R \\triangleright S$，表示关系 $R$ 的值域限制在 $S$ 内 定义域去除 $S \\ntriangleleft R$，表示关系 $R$ 的定义域去掉 $S$ 值域去除 $R \\ntriangleright S$，表示关系 $R$ 的值域去掉 $S$ 闭包 记号 传递闭包 $x R^+ y$ 自反传递闭包 $R^* = R^+ \\cup \\text{id} X$ 案例：使用关系定义家庭成员关系 $$\\begin{align*} \u0026 \\text{[PERSON]} \\\\ \u0026 \\text{father, mother}: \\text{PERSON} \\leftrightarrow \\text{PERSON} \\\\ \u0026 \\text{parent}: \\text{PERSON} \\leftrightarrow \\text{PERSON} \\\\ \u0026 \\text{sibling}: \\text{PERSON} \\leftrightarrow \\text{PERSON} \\\\ \u0026 \\text{ancestor}: \\text{PERSON} \\leftrightarrow \\text{PERSON} \\\\ \\\\ \u0026 \\text{parent}: \\text{father} \\cup \\text{mother} \\\\ \u0026 \\text{sibling}: (\\text{parent}; \\text{parent}\\sim) \\ \\backslash \\text{id} \\ \\text{PERSON} \\\\ \u0026 \\text{ancestor}: \\text{parent}^+ \\\\ \\end{align*}$$ 函数 定义 Z语言中的函数是一种特殊的关系，可为一对一或多对一。定义域有限的函数也称作映射。\n记法：$f: X + \\rightarrow Y$（从 $X$ 到 $Y$ 的函数）\n当 $x \\in \\text{dom}f$ 且最多只对应一个 $y$ 时，等价于关系 $f: X \\leftrightarrow Y, x \\in \\text{dom}f \\Rightarrow \\exist_1 y:Y \\cdot xfy$\n若 $\\text{source}$ 不全在 $\\text{domain}$ 中，则称为部分函数；\n若 $\\text{source}$ 全在 $\\text{domain}$ 中，则称为全函数。\n分类 定义 单射 一对一的关系，部分函数中记作 $f: X \u0026gt;+ \\rightarrow Y$，全函数中记作 $f: X \u0026gt; \\rightarrow Y$ 满射 函数的值域是整个 $\\text{target}$，部分函数记作 $f: X + \\rightarrow \u0026gt; Y$，全函数中记作 $f: X \\rightarrow \u0026gt; Y$ 双射 既是单射又是满射的函数，记作 $f: X \u0026gt; \\rightarrow \u0026gt; Y$ 函数重写 对于一个已知函数，指定其定义域的一个子集，在对应的值域赋予其新的值。\n例如，若 $f: X +\\rightarrow Y$，$g: X +\\rightarrow Y$，其中 $f$ 被 $g$ 重写为新的函数 $f \\oplus g$，则有：\n$f \\oplus g == (\\text{dom} g \\ntriangleleft f) \\cup g$（即 $f$ 的定义域去掉 $g$ 的定义域，再并上 $g$） 当 $x$ 在 $f$ 的定义域而不在 $g$ 的定义域中时，$f \\oplus g\\ x = f \\ x$ 当 $x$ 在 $g$ 的定义域中时，$f \\oplus g\\ x = g \\ x$ ","date":"2026-03-15T00:00:00Z","permalink":"https://rd806.github.io/passage/software/formal_methods/","title":"形式化方法"},{"content":"数据库系统研究的是：如何用计算机有效地组织和管理数据\n关系数据模型 数据库与DBMS 概念 数据（Data） 数据库存储的基本对象，数字、文本、图形、音频、视频等均可看作数据 语义 数据的标签，具备语义的数据才可成为信息 数据库（Database） 长期存储在计算机内的、有组织的、可共享的数据的集合 数据库管理系统（DBMS） 位于用户与操作系统之间的一层数据管理软件，通过调用系统资源操作和管理数据 关系数据模型 概念 关系数据模型 用于描述数据的符号语言，它包括结构、操作和约束等3个部分。 关系（Relation） 二维的表格 属性（Attribute） 关系列的表头，描述了该列内容的实际含义 模式（Scheme） 关系与其属性的范式 元组（Tuples） 关系的具体内容 域（Domains） 关系的数据类型 键（Key） 关系的其中一个元素 关系数据库语言 关系代数用于在关系数据模型上查询和修改数据，它的输入和输出均为关系，因此可视为一个封闭的代数系统。\nSQL语句的核心就是关系代数。\nSQL的功能远低于C语言和Java，为什么使用它？\n关系代数的用途十分广泛。 SQL的编译十分便捷，易于优化。 关系代数（RA） 代数（Algebra）是操作数（Operands）和运算符（Operators）的集合。\n通过关系代数的运算符和各种关系相连接。可以得到关系表达式。例如：\n$$ R(t,y,l,i,s,p) := \\sigma_{\\mathrm{length} \\leqslant 100}(\\mathrm{Movies}) $$ $$ S(t,y,l,i,s,p) := \\sigma_{\\mathrm{studioName='Fox'}}(\\mathrm{Movies}) $$ $$ Answer(title, year) := \\pi_{t,y}(R \\cap S) $$事实上，所有表达式都可以写成树 的形式。上式即可表达为：\n集合运算 集合操作 符号 作用 并（Union） $R \\cup S$ 关系 $R$ 和 $S$ 中所有的内容，相同的只出现一次 交（Intersection） $R \\cap S$ 关系 $R$ 和 $S$ 中共同存在的内容 差（Difference） $R - S$ 关系 $R$ 中存在但不在关系 $S$ 中 对应的SQL语言：\n1(SELECT * FROM R) UNION (SELECT * FROM S); --- 并 2(SELECT * FROM R) INTERSECT (SELECT * FROM S); --- 交 3(SELECT * FROM R) EXCEPT (SELECT * FROM S); --- 差 集合运算中的关系 $R$ 和 $S$ 的属性必须相同且排列顺序一致，且每个属性在两者中的域（数据类型）必须相同。\n投影运算 从关系 $R$ 生成一个仅包含 $R$ 部分属性的新关系（Project），可表示为 $\\pi_{A_1, A_2, \\cdots, A_n}(R)$\n对应的SQL语言：\n1SELECT A1, A2, ..., An FROM R; 选择运算 生成关系 $R$ 满足条件 $C$ 的元组子集作为一个新关系，结果关系的模式与原关系的相同（SELECTION）。可表示为：$\\sigma_{C}(R)$\n用集合表示则可写作：$\\sigma_{C}(R) = \\{ t | t \\in R \\land C(t) = \\mathrm{true} \\}$\n对应的SQL语言：\n1SELECT * FROM R WHERE C; 笛卡尔积 选择关系 $R$ 的一个元素为有序对的第一个元素，关系 $S$ 的一个元素为第二个元素，以此类推形成的新关系（Cartesian Product）。可表示为：$R \\times S$\n对应的SQL语言：\n1SELECT * FROM R CROSS JOIN S; 自然连接 设 $A_1, A_2, \\cdots, A_n$ 为关系 $R$ 和 $S$ 中所有共同属性，当两者的共同属性的内容完全一致时则合并为一个关系，合并的结果应包含关系 $R$ 和 $S$ 中的所有属性（Natural Joins）。可表示为：$R \\bowtie S$\n对应的SQL语言：\n1SELECT * FROM R NATURAL JOIN S; $\\theta$-连接 关系 $R$ 与 $S$ 先做笛卡尔积，在从中选择满足条件 $C$ 的部分（Theta-Joins）。可表示为 $ R \\bowtie_{C} S $\n对应的SQL语言：\n1SELECT * FROM R INNER JOIN S ON C; 重命名 将关系 $R$ 重命名为关系 $S$，$R$ 中对应的属性重命名为 $A_1, A_2, \\cdots, A_n$。可表示为 $\\rho_{S(A_1, A_2, \\cdots, A_n)}(R)$\n对应的SQL语言：\n1SELECT a_1 AS A_1, a_2 AS A_2, ..., a_n AS A_n FROM R AS S; SQL语言 SQL语句分类：\n分类 全称 说明 DDL Data Definition Language 数据定义语言，用于定义数据库对象 DML Data Manipulation Language 数据操作语言，用于数据库中数据的增删改 DQL Data Query Language 数据查询语言，用于查询数据库中表的记录 DCL Data Control Language 数据控制语言，用于创建数据库用户、控制数据库访问权限 SQL的数据类型 数字类型 大小 描述 TINYINT 1 byte 小整数集 SMALLINT 2 bytes 大整数集 MEDIUMINT 3 bytes 大整数集 INT 4 bytes 大整数集 BIGINT 8 bytes 极大整数集 FLOAT 4 bytes 单精度浮点数集 DOUBLE 8 bytes 双精度浮点数集 DECIMAL 依赖精度值（总数位）和标度值（小数位） 精确定点数 字符串类型 大小 描述 CHAR() 0-255 bytes 定长字符串 VARCHAR() 0-65,535 bytes 变长字符串 TINYBLOB 0-255 bytes 二进制数据 TINYTEXT 0-255 bytes 短文本字符串 BLOB 0-65,535 bytes 二进制长文本数据 TEXT 0-65,535 bytes 长文本数据 MEDIUMBLOB 0-16,777,215 bytes 二进制中等长度文本数据 MEDIUMTEXT 0-16,777,215 bytes 中等长度文本数据 LONGBLOB 0-4,294,967,295 bytes 二进制极大文本数据 LONGTEXT 0-4,294,967,295 bytes 极大文本数据 日期类型 大小 格式 描述 DATA 3 YYYY-MM-DD 日期值 TIME 3 HH:MM:SS 时间值或持续时间 TEAR 1 YYYY 年份值 DATETIME 8 YYYY-MM-DD HH:MM:SS 混合日期和时间值 TIMESTAMP 4 YYYY-MM-DD HH:MM:SS 时间戳 空值NULL 出现情况 值本身未知、值不适用于目标对象、用作保留值 运算法则 对NULL进行算术操作，结果仍为NULL 对NULL进行逻辑操作，结果为UNKNOWN 空值NULL不是常量，不可将其用作操作数。\n布尔类型 约定值 TRUE 1 FALSE 0 UNKNOWN 1/2 布尔操作的法则：\nAND操作符返回两者约定值较小的那个。 OR操作符返回两者约定值较大的那个。 布尔变量v反转后为1-v。 例如，若执行SQL语句\n1SELECT * FROM Movies WHERE length\u0026lt;=120 OR length\u0026gt;120; 若某些元组的length值为NULL，条件的返回值则为UNKNOWN，将不会出现在结果中。\nDDL 数据定义语言，用于定义数据库对象\n查询 1/* -- 数据库操作 -- */ 2-- 查询所有数据库 3SHOW DATABASES; 4 5-- 查询当前数据库 6SELECT DATABASE(); 7 8-- 查询当前数据库中所有表 9SHOW TABLE; 10 11 12/* -- 表操作 -- */ 13-- 查询表结构 14DESC 表名; 15 16-- 查询指定表的建表语句 17SHOW CREATE TABLE 表名; 创建 1/* -- 数据库操作 -- */ 2-- 创建数据库 3CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLLATE 排序规则]; 4 5-- 使用数据库 6USE 数据库名; 7 8 9/* -- 表操作 -- */ 10-- 创建表 11CREATE TABLE 表名 ( 12 字段1 字段1类型 PRIMARY KEY, [COMMENT \u0026#39;这是主键\u0026#39;], 13 字段2 字段2类型 [COMMENT \u0026#39;字段2注释\u0026#39;], 14 字段3 字段3类型 [COMMENT \u0026#39;字段3注释\u0026#39;], 15 ... 16) [COMMENT \u0026#39;表注释\u0026#39;]; 17 18-- 示例 19CREATE TABLE movie ( 20 name CHAR(30), 21 address VARCHAR(255), 22 cert INT PRIMARY KEY [COMMENT \u0026#39;主键\u0026#39;], 23 networth INT 24); 25 26CREATE TABLE studio ( 27 name CHAR(50) PRIMARY KEY, 28 address VARCHAR(255), 29 presc INT, 30 FOREIGN KEY (presc) REFERENCES movie(cert) [COMMENT \u0026#39;外键\u0026#39;] 31); MySQL中建议使用字符集UTF8mb4。\n参见：MySQL的数据类型 修改 1--- 添加字段 2ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT \u0026#39;注释\u0026#39;] [约束]; 3 4--- 修改数据类型 5ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度); 6 7--- 修改字段名和字段类型 8ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT \u0026#39;注释\u0026#39;] [约束]; 9 10--- 修改表名 11ALTER TABLE 表名 RENAME TO 新表名; 删除 1--- 删除字段 2ALTER TABLE 表名 DROP 字段名; 3 4-- 删除表 5DROP TABLE [IF EXISTS] 表名; 6 7-- 删除指定表，并重新创建该表 8TRUNCATE TABLE 表名; 9 10--- 删除数据库 11DROP DATABASE [IF EXISTS] 数据库名; DML 数据操作语言，用于数据库中数据的增删改。\n添加数据（Insertion） 1-- 给指定字段添加数据 2INSERT INTO 表名(字段名1, 字段名2, ...) VALUES(值1,值2,...); 3 4-- 给全部字段添加数据 5INSERT INTO 表名 VALUES(值1,值2,...); 6 7/* -- 批量添加数据 -- */ 8-- 指定字段名添加 9INSERT INTO 表名(字段名1,字段名2,...) VALUES(值1,值2,...),(值1,值2,...),(...); 10 11-- 全部添加 12INSERT INTO 表名 VALUES(值1,值2,...),(值1,值2,...),(值1,值2,...); 注意：\n插入数据时，指定的字段顺序需要与值的顺序相对应。 字符串和日期型数据应包含在引号中。 插入数据的大小应该在字段的指定范围内。 修改数据（Updates） 1UPDATE 表名 SET 字段名1=值1,字段名2=值2,... [WHERE 条件]; 2-- 作用是修改满足条件的一行数据对应字段的值，不是修改字段名 3-- 如果没有修改条件，则会修改整张表中所有数据 删除数据（Deletion） 1DELETE FROM 表名 [WHERE 条件]; 2-- 如果没有修改条件，则会修改整张表中所有数据 3-- DELETE语句不能删除某一个字段的值，可以使用UPDATE将该字段值设为NONE DQL 数据查询语言，用于查询数据库中表的记录。它完整的参数可包含如下内容：\n1SELECT [字段列表] FROM [表名列表] WHERE [条件列表] GROUP BY [分组字段列表] 2HAVING [分组后筛选列表] ORDER BY [排序字段列表] LIMIT [分页参数]; 基本条件查询 1SELECT L FROM R WHERE C [ORDER BY 排序规则]; 它与关系代数 $\\pi_{L}(\\sigma_{C}(R))$ 对应。\n常用运算符总结：\n运算符 功能 运算符 功能 \u0026gt; 大于 IN(...) 在in之后的列表中的值（多选一） \u0026gt;= 大于等于 LIKE ' ' 模糊匹配 \u0026lt; 小于 IS NULL 数据为空 \u0026lt;= 小于等于 AND 或 \u0026amp;\u0026amp; 逻辑与 = 等于 OR 或 || 逻辑或 \u0026lt;\u0026gt; 或 != 不等于 NOT 或 ! 逻辑非 BETWEEN\u0026hellip;AND\u0026hellip; 在某个范围之间（含端点） LIKE后可接一个通配符，用于模糊匹配字段\n\u0026quot;Star ____\u0026quot;将匹配字段中含有一个Star和4个字符的字符串。 %\u0026quot;s%将匹配包含's的字符串。 SQL允许使用ESCAPE命令来排除特定的字符，例如'x%%x%' ESCAPE 'x'将匹配以%开头和结尾的字符串。 查询结果可通过参数ORDER BY排序，默认为升序排列。可通过ORDER BY DESC指定为降序排列，ORDER BY ASC为升序排列。\n多表查询 FROM后可接多个表，例如\n1SELECT name FROM Movies, MovieExec WHERE title=\u0026#34;Star Wars\u0026#34; AND producerC# = cert#; 其中title和producerC#位于表Movies中、cert#位于表MovieExec中，则查询结果将返回producerC#与cert#字段相同，且title为\u0026quot;Star Wars\u0026quot;的内容。\n反身查询 若要在同一张表中查询元组内部元素之间的关系，则需对该表设置两个副本再进行查询。\n例如，查询哪两个Star有相同的address，则输入：\n1SELECT Star1.name, Star2.name 2FROM MovieStar Star1, MovieStar Star2 3WHERE Star1.address = Star2.address AND Star1.name \u0026lt; Star2.name 必须设置两个副本Star1和Star2，否则条件判断将始终为TRUE。\n对应的关系代数为：\n$$\\pi_{A_1, A_5}(\\sigma_{A_2 = A_6 \\ \\mathrm{AND}\\ A_1 \u003c A_5}(\\rho_{M(A_1, A_2, A_3, A_4)}(\\mathrm{MovieStar}) \\times \\rho_{N(A_5, A_6, A_7, A_8)}(\\mathrm{MovieStar})))$$子查询 查询也可成为其他查询的一部分，像这样嵌套在查询内部的查询称作子查询。\n子查询可返回单个常量，用于WHERE语句；也可以返回一个关系；还可以在FROM语句中后接元组变量。\n这里主要展示返回标量值的子查询。\n标量值（Scalar）：元组的一个组成部分。例如元组 Movies(title, year, length, genre, studioName, producerC#)中，若使用SQL查询：\n1SELECT producerC# FROM Movies WHERE title=\u0026#39;Star Wars\u0026#39;; 返回值即为一个标量值。\n示例：\n1SELECT name FROM MovieExec 2WHERE cert# = (SELECT producerC# FROM Movies WHERE title=\u0026#39;Star Wars\u0026#39;); 分组与聚合 聚合：将关系中的某些列合并。\n聚合操作符 作用 SUM 对数值列求和 AVG 对数值列求平均值 MIN 数值列的最小值 MAX 数值列的最大值 COUNT 列中值的数量 分组：将元组的值分为若干组。GROUP BY后接一组分组属性，元组根据分组属性的值进行分组。\n分组后筛选：HAVING后接关于组的条件。\n关系数据库设计 依赖（Dependency）涉及如何构建一个良好的关系数据库模式，以及当一个模式存在缺陷时如何改进的问题，并使用“异常”来指代这些问题。\n函数依赖 定义 如果两个元组在属性 $A_1, A_2, \\cdots, A_n$ 上一致（即它们对应属性的分量值都相等），那么它们必定在其他属性上 $B_1, B_2, \\cdots, B_m$ 上也一致。记作 $$A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$$ 即 $B_1, B_2, \\cdots, B_m$ 函数依赖 $A_1, A_2, \\cdots, A_n$，或称 $A_1, A_2, \\cdots, A_n$ 函数决定 $B_1, B_2, \\cdots, B_m$。\n若 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$ 成立，则以下各式均成立： $$\\begin{array}{c} A_1 A_2 \\cdots A_n \\rightarrow B_1 \\\\ A_1 A_2 \\cdots A_n \\rightarrow B_2 \\\\ \\cdots \\\\ A_1 A_2 \\cdots A_n \\rightarrow B_m \\end{array}$$ 如果关系 $R$ 的每个实例都满足一个确定的函数依赖 $f$，那么称 $R$ 满足 函数依赖 $f$，即在 $R$ 上声明了一个约束。\n关系的键 若属性集 $\\{A_1, A_2, \\cdots, A_n\\}$ 满足：\n它们决定关系的所有其他属性，即关系 $R$ 不可能存在两个不同的元组具备相同的 $A_1, A_2, \\cdots, A_n$ 值。 在 $\\{A_1, A_2, \\cdots, A_n\\}$ 的所有真子集均不能决定关系 $R$ 的所有其他属性，即键必须是最小的。 则称 $\\{A_1, A_2, \\cdots, A_n\\}$ 是关系 $R$ 的键。\n可以将关系 $R$ 中的键类比为 $n$ 维线性空间的一个 $n$ 元向量组 $[\\bm{e}_1, \\bm{e}_2, \\cdots, \\bm{e}_n]$，它可以表示该空间内的所有向量。\n有时，一个关系可能会有多个可行的键，这时需指定其中一个为主键（Primary key）。\n一个包含键的属性集就称为超建。\n容易得出，每个键都是该关系的超键（$A \\subseteq A$）\n函数依赖的规则 函数依赖的规则给出了推导函数依赖的一般方法。\n分解/结合规则 函数依赖 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$ 等价于下列函数依赖的集合： $$\\begin{array}{c} A_1 A_2 \\cdots A_n \\rightarrow B_1 \\\\ A_1 A_2 \\cdots A_n \\rightarrow B_2 \\\\ \\cdots \\\\ A_1 A_2 \\cdots A_n \\rightarrow B_m \\end{array}$$从左到右称作函数依赖的分解规则，从右到左称作函数依赖的结合规则。\n平凡函数依赖 对于函数依赖 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$，若满足 $$\\{B_1 B_2 \\cdots B_m\\} \\subseteq \\{A_1 A_2 \\cdots A_n\\}$$ 则称其为 平凡函数依赖。\n若 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$，且 $\\{B_1, B_2, \\cdots, B_m\\} - \\{A_1, A_2, \\cdots, A_n\\} = \\{C_1, C_2, \\cdots, C_k\\}$，则有 $$A_1 A_2 \\cdots A_n \\rightarrow C_1 C_2 \\cdots C_k$$ 这称为平凡依赖规则。如图所示： 平凡依赖规则 属性的闭包 设 $\\{A_1, A_2, \\cdots, A_n\\}$ 是属性集合，$S$ 是函数依赖的集合，则 $S$ 下属性集合 $\\{A_1, A_2, \\cdots, A_n\\}$ 的闭包定义为：满足 $S$ 中所有函数依赖关系的属性集合 $B$，记作 $\\{A_1, A_2, \\cdots, A_n\\}^+$\n计算属性闭包的方法：\n设 $X$ 是属性集合 $\\{A_1, A_2, \\cdots, A_n\\}$ 的闭包，首先令 $X = \\{A_1, A_2, \\cdots, A_n\\}$。 反复寻找函数依赖 $B_1 B_2 \\cdots B_n \\rightarrow C$ ，使得 $B_1, B_2, \\cdots, B_n$ 在 $X$ 中且 $C$ 不再 $X$ 中。然后把 $C$ 加入 $X$。 重复这个过程，直至无法再添加新的元素到 $X$ 中，计算结束，此时 $\\{A_1, A_2, \\cdots, A_n\\}^+ = X$。 传递规则 若关系 $R$ 满足 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$ 和 $B_1 B_2 \\cdots B_m \\rightarrow C_1 C_2 \\cdots C_k$，则有 $$A_1 A_2 \\cdots A_n \\rightarrow C_1 C_2 \\cdots C_k$$ Armstrong公理\n公理 定义 自反律 如果 $\\{B_1 B_2 \\cdots B_m\\} \\subseteq \\{A_1 A_2 \\cdots A_n\\}$，那么 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$ 增广律 如果 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$，那么 $A_1 A_2 \\cdots A_n C_1 C_2 \\cdots C_k \\rightarrow B_1 B_2 \\cdots B_m C_1 C_2 \\cdots C_k$ 传递律 如果 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$ 且 $B_1 B_2 \\cdots B_m \\rightarrow C_1 C_2 \\cdots C_k$，那么 $A_1 A_2 \\cdots A_n \\rightarrow C_1 C_2 \\cdots C_k$ 函数依赖的投影 记 $R_1 = \\pi_{L} (R)$，函数依赖集合 $S$ 的投影是满足下列条件的函数依赖的集合：\n从 $S$ 推断而来 只包含 $R_1$ 的属性 模式设计 关系的分解 将关系进行分解（decompose）可用来消除异常。\n给定关系 $R(A_1, A_2, \\cdots, A_n)$，把它分解为关系 $S(B_1, B_2, \\cdots, B_m)$ 和 $T(C_1, C_2, \\cdots, C_k)$，需满足：\n$\\{A_1, A_2, \\cdots, A_n\\} = \\{B_1, B_2, \\cdots, B_m\\} \\cup \\{C_1, C_2, \\cdots C_k\\}$ $S = \\pi_{B_1, B_2, \\cdots, B_m} (R)$ $T = \\pi_{C_1, C_2, \\cdots, C_k} (R)$ BC范式 分解的目的就是将一个关系用多个不存在异常的关系替换，即在一个简单的条件下保证异常不存在，这个条件就称作BC范式（BCNF）。\n定义：当且仅当如果关系 $R$ 中非平凡函数依赖 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$ 成立，则 $\\{A_1, A_2, \\cdots, A_n\\}$ 是关系 $R$ 的超键。此时称关系 $R$ 为BC范式。\n换言之，就是每个非平凡函数依赖的左侧必须包含该关系的键。\n分解为BC范式 目标：将任何一个关系模式分解为带有以下性质的、具有多个属性的子集：\n以这些子集为模式的关系都属于BCNF。 原始关系中的数据都被正确地反映在分解后的关系上，简单而言就是原始关系应能从分解后的几个关系实例中重构。 对于任意关系 $R$ 和函数依赖集合 $S$，有BCNF分解算法：\n检验 $R$ 是否为BCNF，若是，直接返回 $R$。 如果存在违反BCNF的函数依赖，假设为 $X \\rightarrow Y$。计算 $X$ 的闭包 $X^+$。选择 $R_1 = X^+$ 作为一个关系模式，并使另一个关系模式 $R_2$ 包含属性 $X$ 以及不在 $X^+$ 的属性。 计算 $R_1$ 和 $R_2$ 的函数依赖集合，记为 $S_1$ 和 $S_2$，并递归地分解 $R_1$ 和 $R_2$，返回最终分解的集合。 分解的优劣 一个分解应当具有3个性质：\n性质 特点 消除异常 信息可恢复 能够从分解后的各个元组中恢复原始关系。 依赖的保持 如果函数依赖的投影在分解后的关系上成立，能确保对分解后的关系用连接重构获取原始关系仍然满足原来的函数依赖 事实上，没有一种分解能同时具备以上3个性质。\n从分解中恢复信息 若可以通过分解后的各个关系重构原关系 $R$，则称该分解含有无损连接。\n设关系 $R(X,Y,Z)$，且具备函数依赖 $X \\rightarrow Y$，则可以依据BCNF分解算法将关系分解为 $R_1(X,Y)$ 和 $R_2(Y,Z)$，且 $$R = \\pi_{X \\cup Y}(R) \\bowtie \\pi_{Y \\cup Z}(R)$$ 即该分解包含无损连接。\n无损连接的检验 设关系 $R$ 被分解为若干关系，它们的属性集分别为 $S_1, S_2, \\cdots, S_k$，在 $R$ 上成立的函数依赖集合为 $F$。则 $\\pi_{S_1}(R) \\bowtie \\pi_{S_2}(R) \\bowtie \\cdots \\bowtie \\pi_{S_k}(R) = R$ 成立当且仅当连接结果中的每个元组都属于 $R$。这称为无损连接的chase检验。\n依赖的保持 在某些情况下，把一个关系分解为一系列BCNF关系时，无法同时拥有无损连接和依赖保持两种性质。\n第三范式 定义：如果一个关系 $R$ 满足只要 $A_1 A_2 \\cdots A_n \\rightarrow B_1 B_2 \\cdots B_m$ 是非平凡函数依赖，那么或者 $\\{A_1, A_2 ,\\cdots, A_n\\}$ 是超键，或者每个属于 $B_1, B_2, \\cdots, B_n$ 但不属于 $A$ 的属性都是某个键的成员。\n如果一个属性是某个键的成员，则常被成为“主属性”。因此，3NF的条件等价于：对于每个非平凡FD，或者其左边是超键，或者其右边仅由主属性构成。\n多值依赖 MySQL MySQL是目前流行的数据库管理系统，使用SQL语法操作和管理。\n准备工作 1# 安装MYSQL 2sudo apt-get install mysql-server 3 4# 启动MySQL服务 5sudo service mysql start 6 7# 登录MySQL 8mysql -u \u0026#39;用户名\u0026#39; -p \u0026#39;密码\u0026#39; 配置MySQL 首先进入MySQL界面，然后操作：\n设置用户密码 1ALTER USER \u0026#39;root\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED WITH mysql_native_password BY \u0026#39;你的新密码\u0026#39;; 2FLUSH PRIVILEGES; 3EXIT; 退出后以新的密码即可登录MySQL。\n允许远程访问 在Shell中输入：\n1sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf 找到bind-address，将其修改为0.0.0.0或注释掉该行。\n保存后重启服务：\n1sudo service mysql restart 创建新用户 1CREATE USER \u0026#39;新用户名\u0026#39;@\u0026#39;%\u0026#39; IDENTIFIED BY \u0026#39;新密码\u0026#39;; 2GRANT ALL PRIVILEGES ON *.* TO \u0026#39;新用户名\u0026#39;@\u0026#39;%\u0026#39; WITH GRANT OPTION; 3FLUSH PRIVILEGES; 退出后以新的用户名和密码即可登录MySQL。\n通用语法 单行或多行书写，以分号结尾。 可以使用空格/缩进。 SQL语句不区分大小写，关键字建议大写。 单行注释：--注释内容或# 注释内容；多行注释：/* 注释内容 */。 其他参照SQL语言 。 openGauss 数据库管理可视化 面对单调的SQL代码是非常无聊的，因此通过软件可视化管理数据库是不错的选择。\n软件 介绍 版本 Navicat Navicat是一款综合性的数据库管理软件，允许通过一个界面连接和管理多个数据库（其实这个功能大多数类似软件都有）。 Navicat提供多个版本，其中只有Navicat Premium Lite可免费使用（貌似还要注册一个账号）。 DBeaver 功能与Navicat类似 它提供免费的社区版下载，而且不用注册账号，就像JetBrain全家桶 MySQL Workbench MySQL的官方提供的可视化管理工具 免费，但是没有中文支持。 ","date":"2026-03-14T00:00:00Z","image":"https://rd806.github.io/passage/cs/database/mysql_hu_79a1fd304a36f4b0.jpg","permalink":"https://rd806.github.io/passage/cs/database/","title":"数据库系统"},{"content":"并行计算概述 并行计算基本概念 基本概念 内容 计算 数学计算、数据处理、IT服务 性能 FLOPS（浮点计算数/秒） 浮点计算能力 计算机主频每时钟周期的浮点指令数 产生原因 满足不断增长的计算力需求：用多个处理器同时解决一个问题 计算机硬件与网络技术的发展 单处理器性能提升受限 存储、I/O速率远低于处理器 并行化方法 域分解 首先确定数据如何划分到各个处理器，然后确定每个处理器所需要做的事情。\n任务分解 首先将任务划分到各个处理器，然后确定各个处理器需要处理的数据。\n流水线 将一个任务拆分成多个步骤，通过不同步骤在时间上的重叠达到“并行”的效果。\n并行计算硬件环境 PRAM模型 PRAM全称为Parallel Random Access Machine，它具备以下特点：\n每个处理器可同时从共享的内存中读取数据到自己的寄存器 每个处理器执行计算过程，数据存储在本地寄存器 每个处理器可同时将数据写入到共享的内存（存在潜在冲突） PRAM模型 PRAM模型可以衍生出以下模型：\n模型 特点 EREW 任意两个处理器不能并发读，也不能并发写 CREW 可以并发读，但不能并发写 CRCW 可以并发读，也可以并发写 根据PRAM模型，可以对前缀求和 作出并行算法设计：\n处理器 SIMD体系 SIMD是一条指令同时操作多个数据，适合数据级并行的计算机体系结构。\nFlynn分类法（Flynn\u0026rsquo;s Taxonomy）是计算机体系结构领域最经典的分类方法之一。它根据指令流（Instruction Stream）——机器执行的指令序列，和数据流（Data Stream）——由指令流调用的数据序列两个维度的\u0026quot;单\u0026quot;（Single）或\u0026quot;多\u0026quot;（Multiple）组合，将计算机体系结构分为四类：\n类型 全称 指令流 数据流 典型代表 特征 SISD Single Instruction Single Data 单 单 早期单核CPU（如Intel 8086）、传统冯·诺依曼架构 顺序执行，一次处理一个任务的一\u0026gt; 份数据 SIMD Single Instruction Multiple Data 单 多 GPU、向量处理器、Intel SSE/AVX指令集 一条指令同时操作多个数据，适合数据级并行 MISD Multiple Instruction Single Data 多 单 极少见，主要用于容错系统（如航天器冗余控制） 多个指令同时处理同一数据，理论意义大于实际 MIMD Multiple Instruction Multiple Data 多 多 多核CPU、分布式计算集群、高性能服务器 多个独立指令流处理多个数据流，实现任务级并行 多核处理器 进入21世纪，曾预言“CPU主频18个月翻一番”的摩尔定律不再适用于当下处理器的发展方向。\n限制单核性能主要有以下几个方面：\n功耗墙：CPU越小，单位面积产生的热量越多，散热越困难。 存储墙：CPU缓存占据了70%以上的芯片面积，限制了性能的进一步提升。 多核处理器的特点：\n多个复杂度适中，相对低功耗的处理核心并行工作。 CPU时钟频率基本不变、 GPU GPU将更多元件用于数据处理，而非控制和存储。\n可以将GPU视作超大规模并行协处理器和SPMD（单程序多数据）模式，实现了数据并行。\n互连网络 静态互连网络：处理单元之间有固定连接的一类网络，在程序执行期间这种点到点的链接保持不变：\n分类 特点 一维线性阵列 每个节点只与其左右近邻相连（$N$个节点用$N-1$条边串接） 二维网孔 每个节点只与其上、下、左、右的近邻相连（边界结点除外） 二叉树 与完全二叉树的结构类似 超立方 更为复杂的空间结构 动态网络：用交换开关构成的，可按应用程序的要求动态地改变连接组态。包括总线、交叉开关等\n内存访问模式 并行计算系统的体系结构 体系结构 特点 PVP（Parallel Vector Processor） 含有为数不多、功能强大的定制向量处理器 SMP（Symmetric Multiprocessor） 多个处理器通过总线或交叉开关连接到共享存储器 MMP（Massively Parallel Processor） 处理节点采用微处理器，系统中有物理上的分布式存储器 多线程并行程序设计 多线程基本概念 线程（Thread）是进程上下文（contex）中执行的代码序列，也称作轻量级进程。\n在支持多线程的系统中，进程是资源分配的实体，线程是被调度执行的基本单元。\n线程与进程的比较 内容 调度 线程是CPU调度的基本单位，进程是资源拥有的基本单位。同一进程中线程的切换不会引起进程切换，从而避免频繁的系统调用。 并发性 不仅进程之间可以并发执行，一个进程的多个线程之间也可以并发执行，一个进程下可设置多个线程 拥有资源 进程是拥有资源的独立单位；线程不拥有系统资源，但可以访问其所属进程的资源，即一个进程的资源可供其所有线程共享。 系统开销 进程在创建或销毁时系统均需要为之分配或回收资源，进程切换时系统需保存当前进程的所有设置；线程切换时只需保存和设置少量寄存器的内容，同一进程的线程之间的通信比较容易。 在计算机中，系统通过线程池管理线程。一个线程池可维护多个线程，等待调度器分配可并发执行的任务。避免了在短处理时间任务时创建与销毁线程的代价。\n共享存储访问 计算机采用层次结构存储系统。\n竞态条件与临界区 但是这样会出现竞态条件（Race Conditions）：当两个或多个线程试图在同一时刻访问共享内存或读写某些共享数据时，寄存器的值可能无法及时更新，导致最后的结果取决于线程的执行顺序。\n为了解决这一困境，提出了临界区的概念：包含访问共享数据的代码。因此，在临界区内，任意时刻至多只能有一个线程在执行相关代码。\n互斥锁 互斥锁（mutex）是实现线程同步的一种方法。线程对共享资源访问之前必须先获得锁，否则线程将保持等待状态，直到该锁可用。\n实例分析 假设现有一段长文本，要求统计其中3的个数\n普通的串行代码应为：\n1int *array; 2int length; 3int count; 4 5int countThree() { 6 int i; 7 count = 0; 8 for (i=0; i\u0026lt;length; i++) { 9 if (array[i] == 3) { 10 count++; 11 } 12 } 13 return count; 14} 运用域分解并行化方法，将其划分为若干个子数据段：\n1int t; 2int *array; 3int length; 4int count; 5 6int countThree() { 7 int i; 8 count = 0; 9 // 创建线程 10 for (i=0; i\u0026lt;t; i++) { 11 thread_create(countThree_thread, i); 12 } 13 return count; 14} 15 16void countThree_thread(int id) { 17 int length_per_thread = length / t; 18 int start = id*length_per_thread; 19 20 for (i = start; i\u0026lt;start+length_per_thread; i++) { 21 if (array[i] == 3) { 22 // 加互斥锁 23 mutex_lock(m); 24 count ++; 25 // 解锁 26 mutex_unlock(m); 27 } 28 } 29} 但是，此并行算法的性能远不及串行算法：\n这是因为加锁会消耗时间，同时所有线程两两互斥可看作串行逻辑，并没有变化。\n改进方法：加锁过程应当放在循环计数外。当每个线程分别计数完成后，再将各个数目相加得到总数目。\n1... 2int private_count[MaxThreads]; 3mutex m; 4 5void countThree_thread(int id) { 6 int length_per_thread = length / t; 7 int start = id*length_per_thread; 8 9 for (i = start; i\u0026lt;start+length_per_thread; i++) { 10 if (array[i] == 3) { 11 private_count[id]++; 12 } 13 } 14 // 汇总时必须加锁，防止出现竞争 15 mutex_lock(m); 16 count += private_count[id]; 17 mutex_unlock(m); 18} 修改后并行效率大幅提升，但仍与串行有差距。这是因为计算机系统的cache一致性与伪共享，虽然不同线程的private_count形式上互不干扰，但在缓存中可能处于一个缓存块中，在更新数据时会发生阻塞。\n一种解决办法是强行将计数器的占用加大，使它们分别位于不同的缓存块中。\nPThread多线段 主要操作函数：\n函数 功能 pthread_create 创建一个线程 pthread_cancel 终止另一个线程 pthread_detach 分离线程 pthread_equal 检查两个线程的id是否相等 pthread_exit 退出线程但不退出进程 pthread_join 等待一个线程 pthread_self 获得自己的线程id Java多线程 创建方法：\n通过Thread类的子类实现多线程。 定义一个实现Runnable接口的类实现多线程。 ","date":"2026-03-11T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/parallel_computing/","title":"并行计算"},{"content":"程序 = 数据结构 + 算法\n计算机科学并不只是关于计算机，就像天文学并不只关于望远镜一样。—— Edsger Dijkstra\n参考资料：点击此处 算法的基本概念 算法是对特定问题求解的一种描述，是指令的有限序列。\n算法 特点 有穷性、确定性、可行性、输入、输出。 正确算法 对于每一个输入都最终停止，而且产生了正确的输出 不正确算法 在某个输入上不停止；对所有输入都停止但对某输入产生不正确的结构 近似算法 对所有输入都停止 复杂度 时间复杂度：基本运算（原子操作）的执行次数；空间复杂度：算法所需存储空间的大小 基本运算 解决给定问题时占支配地位的运算。讨论一个算法的优劣通常只考虑基本运算 算法分析的数学基础 记号 含义 $\\lfloor x \\rfloor$ 小于等于 $x$ 的最大整数 $\\lceil x \\rceil$ 大于等于 $x$ 的最小整数 $\\log n$ $\\log n = \\log_{2} n$ $\\ln n$ $\\ln n = \\log_{\\mathrm{e}} n$ 复杂性函数的阶 渐进复杂性 当输入规模 $n$ 趋近于极限时的复杂性\n复杂性函数 定义 $$T(n) = \\varOmega(f(n))$$ 如果存在 $c\u0026gt;0$ 与正整数 $n_0 \\leqslant 1$，当 $n \\geqslant n_0$ 时，都有 $T(n) \\geqslant c \\cdot f(n)$ 成立，则称 $T(n)$ 是 $f(n)$ 的高阶，它给出了算法复杂度的下界 $$T(n) = O(f(n))$$ 如果存在 $c\u0026gt;0$ 与正整数 $n_0 \\leqslant 1$，当 $n \\geqslant n_0$ 时，都有 $T(n) \\leqslant c \\cdot f(n)$ 成立，则称 $T(n)$ 是 $f(n)$ 的低阶，它给出了算法复杂度的上界 $$T(n) = \\varTheta(f(n))$$ 如果存在 $c_1, c_2 \u0026gt; 0$ 与正整数 $n_0 \\leqslant 1$，当 $n \\geqslant n_0$ 时，都有 $c_2 f(n) \\leqslant T(n) \\leqslant c_1 f(n)$ 恒成立，则称 $T(n)$ 与 $f(n)$ 同阶 严格低阶函数集合 $o(g(n)) = \\{ f(n) | 对任意 c\u0026gt;0，都存在正整数 n_0，使得当 n\u0026gt;n_0 时都有 0 \\leqslant f(n) \\leqslant c \\cdot g(n) \\}$ 严格高阶函数集合 $\\omega(g(n)) = \\{ f(n) | 对任意 c\u0026gt;0，都存在正整数 n_0，使得当 n\u0026gt;n_0 时都有 0 \\leqslant c \\cdot g(n) \\leqslant f(n) \\}$ 严格上界 若 $f(n) \\in o(g(n))$，称 $g(n)$ 是 $f(n)$ 的严格上界，记作 $f(n) = o(g(n))$ 严格下界 若 $f(n) \\in \\omega(g(n))$，称 $g(n)$ 是 $f(n)$ 的严格下界，记作 $f(n) = \\omega(g(n))$ 例如，对于 $f(n) = 3n^3+2n^2$，取 $n_0 = 1$，当 $n \\geqslant n_0 = 1$ 时：\n取 $c_1 = 5$，有 $T(n) \\leqslant 5n^3$ 成立，即有 $T(n) = \\varOmega(n^3)$\n取 $c_2 = 3$，有 $T(n) \\geqslant 3n^3$ 成立，即有 $T(n) = O(n^3)$\n若 $f(n) = o(g(n))$，则有 $\\displaystyle \\lim_{n \\to \\infty} \\frac{f(n)}{g(n)} = 0$\n若 $f(n) = \\omega(g(n))$，当且仅当 $g(n) \\in o(f(n))$\n函数阶的性质 性质 表达式 传递性 $f(n) = \\varTheta(g(n))$ 且 $g(n) = \\varTheta(h(n))$，则有 $f(n) = \\varTheta(h(n))$ 自反性 $f(n) = \\varTheta(f(n))$，$f(n) = \\Omega(f(n))$，$f(n) = O(f(n))$ 对称性 若 $f(n) = \\Omega(g(n))$，则有 $g(n) = O(f(n))$ 反对称性 $f(n) = O(g(n))$，当且仅当 $g(n) \\in \\Omega(f(n))$ 并非所有函数都是可比的，例如 $f(n) = n$ 和 $g(n) = n^{1+\\sin n}$\n多项式时间的算法之间有差距，但一般可接受。\n指数量级的算法对于较大的 $n$ 无使用价值。\n和的估计与界限 直接求和 $\\displaystyle \\sum_{k=1}^{n} a_k \\leqslant n \\max_{1 \\leqslant k \\leqslant n} a_k$\n例如：$\\displaystyle \\sum_{k=1}^{n} k \\leqslant \\sum_{k=1}^{n} n \\leqslant n^2$\n对于所有 $k\u0026gt;0$，都有 $\\frac{a_{k+1}}{a_k} \\leqslant r \u0026lt; 1$，则 $\\displaystyle \\sum_{k=1}^{n} a_k \\leqslant \\sum_{k=1}^{n} a_0 r^k \\leqslant \\frac{a_0}{1-r}$\n求和转换为积分 当 $f(x)$ 单调递增时，有 $\\displaystyle \\int_{m-1}^{n} f(x) \\mathrm{d}x \\leqslant \\sum_{k=m}^{n} f(x) \\leqslant \\int_{m}^{n+1} f(x) \\mathrm{d}x $\n当 $f(x)$ 单调递减时，有 $\\displaystyle \\int_{m}^{n+1} f(x) \\mathrm{d}x \\leqslant \\sum_{k=m}^{n} f(x) \\leqslant \\int_{m-1}^{n} f(x) \\mathrm{d}x $\n例如，在算法分析中经常出现的 $\\log n!$ 可作如下分析：\n由对数运算性质可知，\n$$ \\log n! = \\sum_{k=1}^{n} \\log k $$ 则有上界：\n$$ \\sum_{k=1}^{n} \\log k \\leqslant \\int_{1}^{n+1} \\log x \\mathrm{d}x $$ 积分求和的上界 同理，可知下界：\n$$ \\sum_{k=1}^{n} \\log k \\geqslant \\int_{0}^{n} \\log x \\mathrm{d}x $$ 积分求和的下界 综合两式可得：$\\log n! = \\varTheta(n\\log n)$，该求和公式在快速排序等算法中有重要作用。\n递归方程 逐层展开法 案例：归并排序的递归方程\n$$T(n) = \\left\\{ \\begin{matrix} \\begin{align*} \u0026\\varTheta(1), \u0026 n=1 \\\\\\\\ \u00262T\\displaystyle \\left(\\frac{n}{2}\\right) + \\varTheta(n), \u0026 n \\geqslant 1 \\end{align*} \\end{matrix} \\right.$$将其展开可得：\n$$\\begin{align*} T(n) \u0026= n + 3T\\left(\\left\\lfloor \\frac{n}{4} \\right\\rfloor\\right) \\\\\\\\ \u0026= n + 3\\left(\\left\\lfloor \\frac{n}{4} \\right\\rfloor + 3T\\left( \\left\\lfloor \\frac{n}{16} \\right\\rfloor \\right)\\right) \\\\\\\\ \u0026= n + 3\\left\\lfloor \\frac{n}{4} \\right\\rfloor + 3^2 \\left\\lfloor \\frac{n}{4^2} \\right\\rfloor + 3^3 \\left\\lfloor \\frac{n}{4^3} \\right\\rfloor + \\cdots + 3^k T \\left(\\left\\lfloor \\frac{n}{4^k} \\right\\rfloor \\right) \\end{align*}$$深度 $k = \\log_{4}n$，最底层有 $3^k = 3^{\\log_{4}n} = n^{\\log_{4}3}$ 个，则有\n$$T(n) = \\sum_{i=0}^{(\\log_{4}n) - 1} 3^i \\cdot \\frac{n}{4^i} + \\varTheta(n^{\\log_{4}3}) \\leqslant 4n + \\varTheta(n^{\\log_{4}3}) = O(n)$$变量替换法 设递归方程为：\n$$T(n) = 2T(\\sqrt{n}) + \\log n$$令 $m = \\log n$，则 $n = 2^m$，$\\displaystyle T(2^m) = 2T\\left(2^{\\frac{m}{2}}\\right) + m$\n令 $S(m) = T(2^m)$，则 $\\displaystyle S\\left(\\frac{m}{2}\\right) = T\\left(2^{\\frac{m}{2}}\\right)$\n于是 $\\displaystyle S(m) = 2S\\left(\\frac{m}{2}\\right) + m = \\varTheta(m \\log m)$\n回代可得 $T(n) = \\varTheta(\\log n (\\log (\\log n)))$\nMaster定理 求解形如 $\\displaystyle T(n) = a \\cdot T\\left(\\frac{n}{b}\\right) + f(n)$ 的递归方程（其中 $a \\geqslant 1$，$b \\geqslant 1$ 是常数，$f(n)$ 是正函数）。\n若 $f(n) = O(n^{(\\log_{b} a)-\\varepsilon})$，常数 $\\varepsilon \u0026gt; 0$，则有 $T(n) = \\varTheta(n^{\\log_{b}a})$ 若 $f(n) = \\varTheta(n^{\\log_{b} a})$，则有 $T(n) = \\varTheta(n^{\\log_b a} \\log n)$ 若 $f(n) = \\varOmega(n^{(\\log_{b} a) + \\varepsilon})$，常数 $\\varepsilon \u0026gt; 0$，且对所有 $n$，都有 $af(\\frac{n}{b}) \\leqslant c \\cdot f(n)$ （$c\u0026lt;1$ 且为常数），则有 $T(n) = \\varTheta(f(n))$ 直观理解：用 $f(n)$ 与 $n^{\\log_b a}$ 的阶比较\n若 $n^{\\log_b a}$ 的阶更大，即 $f(n)$ 的阶不仅小于 $n^{\\log_b a}$，而且还小于 $n^{\\log_b a}/n^{\\varepsilon}$，则 $T(n) = \\varTheta(n^{\\log_b a})$ 若 $f(n) = \\varTheta(n^{\\log_b a})$，即 $f(n)$ 与 $n^{\\log_b a}$ 同阶，则有 $T(n) = \\varTheta(n^{\\log_b a} \\log n) = \\varTheta(f(n)\\log n)$ 若 $f(n)$ 的阶更大，即 $f(n)$ 的阶不仅大于 $n^{\\log_b a}$，而且还大于 $n^{\\log_b a} \\cdot n^{\\varepsilon}$，则 $T(n) = \\varTheta(f(n))$ Master定理证明（点击展开） 对 $\\displaystyle f(n) = a T(\\frac{n}{b}) + f(n)$ 展开可得 $$ T(n) = \\varTheta(n^{\\log_b a}) + \\sum_{i=0}^{k-1} a^i \\cdot f(\\frac{n}{b^i}) $$ 其中 $n = b^k$，$k = \\log_b n$，$a^k = a^{\\log_b n} = n^{\\log_b a}$\n令 $\\displaystyle g(n) = \\sum_{i=0}^{k-1} a^i f\\left( \\frac{n}{b^i} \\right)$， 则有 $T(n) = \\varTheta(n^{\\log_b a}) + g(n)$\n若 $f(n) = O(n^{(\\log_b a) - \\varepsilon})$，则有 $$\\begin{align*} g(n) \u0026= O \\left(\\sum_{i=0}^{k-1} a^i \\left(\\frac{n}{b^i}\\right)^{(\\log_b a)-\\varepsilon} \\right) = O \\left( n^{(\\log_b a)-\\varepsilon} \\sum_{i=0}^{k-1} \\left(\\frac{ab^{\\varepsilon}}{b^{\\log_b a}}\\right)^i \\right) \\\\ \u0026= O \\left( n^{(\\log_b a)-\\varepsilon} \\frac{n^{\\varepsilon} - 1}{b^{\\varepsilon} - 1} \\right) = O(n^{\\log_b a}) \\end{align*}$$ 故 $T(n) = \\varTheta(n^{\\log_b a}) + g(n) = \\varTheta(n^{\\log_b a})$\n若 $f(n) = \\varTheta(n^{\\log_b a})$，则有 $$\\begin{align*} g(n) \u0026= \\varTheta \\left( \\sum_{i=0}^{k-1} a^i \\frac{n}{b^i}^{\\log_b a} \\right) = \\varTheta \\left( n^{\\log_b a} \\sum_{i=0}^{k-1} 1 \\right) \\\\ \u0026= \\varTheta(n^{\\log_b a} k) = \\varTheta(n^{\\log_b a} \\log_b n) = \\varTheta(n^{\\log_b a} \\log n) \\end{align*}$$ 故 $T(n) = \\varTheta(n^{\\log_b a}) + g(n) = \\varTheta(n^{\\log_b a} \\log n)$\n若 $f(n) = \\varOmega(n^{(\\log_b a) + \\varepsilon})$，且对所有充分大的 $n$ 有 $$\\begin{align*} a f(\\frac{n}{b}) \u0026\\leqslant c f(n) \\\\ a f(\\frac{n}{b^2}) \u0026\\leqslant c f(\\frac{n}{b}) \\\\ \u0026\\cdots \\\\ a f(\\frac{n}{b^i}) \u0026\\leqslant c f(\\frac{n}{b^{i-1}}) \\end{align*}$$ 两边分别相乘得 $\\displaystyle a^i f(\\frac{n}{b^i}) \\leqslant c^i f(n)$，则有 $$g(n) = \\sum_{i=0}^{k-1} a^i f(\\frac{n}{b^i}) \\leqslant \\sum_{i=0}^{k-1} c^i f(n) = f(n) \\sum_{i=0}^{k-1} c^i \\leqslant f(n) \\cdot \\frac{1}{1-c} = \\varTheta(f(n))$$ 故 $T(n) = \\varTheta(n^{\\log_b a}) + g(n) = \\varTheta(f(n))$\n推广形式：若 $f(n) = \\varTheta(n^{\\log_b a} \\log^{k} n)$，其中 $k \\geqslant 0$，则有 $T(n) = \\varTheta(n^{\\log_b a} \\log^{k+1} n)$\n算法实例 算法：递归法\r算法：分治法\r其他算法\r","date":"2026-03-09T00:00:00Z","image":"https://rd806.github.io/passage/cs/algorithm/daniil-komov-7lzjMwexxnU-unsplash_hu_284a5e90bcb695e2.jpg","permalink":"https://rd806.github.io/passage/cs/algorithm/","title":"算法设计与分析"},{"content":"理论和实践均表明，进行与Minecraft相关的开发活动是提升面向对象编程水平的有效途径！\n以下是我2026年寒假智斗\u0026quot;org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT\u0026quot;的成果。\nMC常量 物品ID Minecraft的物品ID主要有两套系统：数字ID（老版本用）和英文ID（新版本用）。\n在1.13或更高版本，务必使用英文ID。\nBukkit提供了Material的枚举类，可以通过物品的英文ID获取对应的物品。例如：\n1Material.BOOK // 书 2Material.PAPER // 纸 格式代码 当前，MC的格式代码有§和\u0026amp;两种格式,用来设置文本的颜色与格式。在聊天框、书籍等均可生效。\n\u0026amp;实际上是代码中用来方便替代§。因此\u0026amp;6与§6的效果完全一样。\n在Windows系统输入§：按住Alt，然后在小键盘依次按0167，松开Alt即可输入。\n常用代码 §0 黑色 §1 深蓝色 §2 深绿色 §3 深青色 §4 深红色 §5 紫色 §6 金色 §7 灰色 §8 深灰色 §9 蓝色 §a 绿色 §b 青色 §c 红色 §d 粉红色 §e 黄色 §f 白色 §k 随机字符 §l 粗体 §m 删除线 §n 下划线 §o 斜体 §r 重置 1// 使用方式 2lore.add(\u0026#34;§5紫色文本§r§7灰色文本\u0026#34;); // 紫色后重置为灰色 3lore.add(\u0026#34;§r§c红色文本§r§a绿色文本\u0026#34;); // 分别设置颜色 若使用\u0026amp;，则还需要一层转译：\n1lore = ChatColor.translateAlternateColorCodes(\u0026#39;\u0026amp;\u0026#39;, \u0026#34;\u0026amp;5紫色文本\u0026amp;r\u0026amp;7灰色文本\u0026#34;); ","date":"2026-02-22T00:00:00Z","permalink":"https://rd806.github.io/passage/minecraft/plugin/","title":"Minecraft服务器插件"},{"content":"概述 概念 定义 网络 节点和边之间的无向关系 计算机网络 联网的计算机构成的系统，包括主机节点（Web应用）和数据交换节点 （路由器） 互联网 许多网络通过互联方式联系在一起。 互联网是设备和协议的集合体。\n从“组成结构”看互联网：\n组成结构 定义 网络边缘（Internet edge） 包括客户端和服务器，接入网和物理介质 网络核心（Internet core） 互相连接的路由器，也称作“网络之网络” 从“提供服务”看互联网：\n组成结构 定义 协议（protocol） 定义了网络实体之间发送和接收消息的格式、顺序以及在消息传输、接收时采取的动作 标准（RFC） 由IETF制定，定义消息的格式、信息发送的顺序等内容 网络边缘 主机 包括客户端和服务器，任务是发送数据包\n数据包：将应用程序产生的消息分解成的较小的块称为数据包，长度通常记作 $L$，单位为比特。\n记互联网的传输速率为 $R$（也称为链路容量或带宽，单位 $\\text{bits/s}$），则可定义数据包传输延迟为将 $L$ 比特数据包传送到链路所需的时间 $$D = \\frac{L}{R}$$接入网 接入网连接主机与边缘路由，包括以下几类：\n类型 特点 线缆接入 HFC（光纤/同轴电缆混合）连接到DSL。下行40Mbps1.2Gbps，上行30100Mbps 数字接入 利用现有的有线电话线路连接到DSL。下行2452Mbps，上行3.516Mbps 无线接入 无线局域网（WLAN），范围不超过一个建筑物，速率在450Mbps 蜂窝网络：由运营商提供，范围在10km数量级，速率在10Mbps 物理介质 概念 含义 物理链路 数据发送和接收端之间的物理连接 导向性介质 信号在固体介质中传播，如铜、光纤、同轴电缆 非导向性介质 信号自由传播，如无线电磁波 常用的物理介质\n介质 特点 双绞线（TP） 由两根绝缘铜线组成，五类线可达100Mbps~1Gbps，六类线可达10Gbps 同轴电缆 由两个同心铜导体组成，可双向传输，拥有多个通道，每个通道可达100Mbps 光纤 由玻璃纤维组成，传递光信号，进行高速点对点传输，可达10~100Gbps，不受电磁干扰 电磁波 信号分布在电磁波的各个频段，受反射、遮挡、干扰的影响较大。常见的有WiFi、蜂窝网络、蓝牙、卫星信号等 网络核心 网络核心可以看作一系列互相连接的路由器，每个路由器都有多个输入端和输出端。网络核心不运行应用程序，只转发数据包。\n网络核心的两大功能：\n转发（交换）：将到达的数据包从路由器的输入链路移动到输出链路。 路由：规划数据包传输所需要经过的路径。 分组交换 基本原理：\n主机将应用数据拆分成数据包。 数据包通过源到目标路径的一条链路，从一个路由器转发到下一个路由器。 每个数据包在链路上的传输互相独立。 存储转发：整个数据包必须完整到达路由器后才能转发到下一条链路上。 传输延迟：以 $R$ $\\text{bps}$ 在链路上传输 $L$ $\\text{bit}$ 需要时间 $\\displaystyle \\frac{L}{R}$ 秒，这段时间称为传输延迟。一般地，若端到端之间有 $n$ 条链路，每条链路的传输速率为 $R_{i}$ $\\text{bps}$，则传输大小为 $L$ $\\text{bit}$ 的数据包需要的总延迟为 $\\displaystyle \\sum_{i=1}^{n} \\frac{L}{R_i}$ 秒\n排队与丢包：如果一段时间内到达链路的速率超过链路的传输速率，则数据包将会在路由器上的缓冲区排队。若缓冲区已满，多余的数据包则可能被丢弃，称为丢包。\n发生丢包时，丢失的数据包可能由上一个节点重传、由源重发或完全不进行响应。\n排队与丢包 电路交换 为源到目的地的“呼叫”分配并预留端到端的资源，即为收发两端分配专用的、独占的资源。\n电路交换常用于传统的电话中。通话时，两台电话之间分配了专用的通信资源，即使没有数据传输，在挂断之前资源不会被释放。\n电路交换中，为了更好地利用资源，出现了FDM（频分）和TDM（时分）技术。\n分组方式 内容 FDM 将电磁频率划分为多个窄频段，为每个呼叫分配专用频段，以该频段的最大速率传输 TDM 将时间划分为多个时段，为每个呼叫周期性地分配时段，在其所属时段以电磁波的最大速率传输 ISP与互联网 主机通过接入互联网服务提供商（ISP）连接到互联网，不同的ISP必须互相连接。由此形成复杂的网络结构。\nISP与互联网 网络协议 为什么采用分层结构？\n有利于识别系统各组成部分及其相互关系。 分层结构有利于系统维护和更新。 协议栈 概念 应用层（application） 支持网络应用 传输层（transport） 进程间的数据传输 网络层（network） 规划数据从源到目的地的路线 链路层（link） 相邻网络结点之间的数据传输 物理层（physical） 传输字节信息 网络评价指标 延迟 延迟来源 记号 内容 处理延迟 $d_{\\text{proc}}$ 检查字节错误、确定输出链路带来的延迟 排队延迟 $d_{\\text{queue}}$ 数据包在队列中等待传输带来的延迟 传输延迟 $d_{\\text{trans}}$ 数据包转发带来的延迟，通常为 $\\displaystyle \\frac{L}{R}$ 传播延迟 $d_{\\text{prop}}$ 数据包在链路上传输带来的延迟，通常为 $\\displaystyle \\frac{d}{s}$ 总延迟：$d_{\\text{nobal}} = d_{\\text{proc}} + d_{\\text{queue}} + d_{\\text{trans}} + d_{\\text{prop}}$\n吞吐量 发送端向接收端发送比特的速率，通常记作 $R$，单位为 $\\text{bits/s}$\n若发送端到接收端有多段链路，则称限制吞吐量的链路为瓶颈链路（即吞吐量最小的链路）。\n","date":"2026-01-31T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/network/","title":"计算机网络"},{"content":"本实验的所有内容均在proxy.c文件中完成。\n感谢hankeke303 大佬提供的思路！\nPart I：实现顺序的代理服务器 实现顺序的代理服务器实际上就是一个tiny服务器的复刻。\nmain函数 main函数参考书上 P672 的实例：\nmain函数 现在的代理服务器只支持GET方法。如果客户端请求其他方法（如POST），我们发送给它一个错误信息，并返回到主程序，主程序随后关闭连接并等待下一个连接请求。否则，读并且忽略任何请求报头。\n1int main(int argc, char **argv) 2{ 3 int listenfd, connfd; 4 char hostname[MAXLINE], port[MAXLINE]; 5 socklen_t clientlen; 6 struct sockaddr_storage clientaddr; 7 8 9 // 检查命令输入是否正确 10 if (argc != 2) { 11 fprintf(stderr, \u0026#34;usage: %s \u0026lt;port\u0026gt; \\n\u0026#34;, argv[0]); 12 exit(1); 13 } 14 15 listenfd = Open_listenfd(argv[1]); 16 // 主循环 17 while (1) { 18 clientlen = sizeof(clientaddr); 19 connfd = Accept(listenfd, (SA *)\u0026amp;clientaddr, \u0026amp;clientlen); 20 21 Getnameinfo((SA *) \u0026amp;clientaddr, clientlen, hostname, MAXLINE, 22 port, MAXLINE, 0); 23 24 printf(\u0026#34;Accepted connection from (%s, %s)\\n\u0026#34;, hostname, port); 25 } 26 27 printf(\u0026#34;%s\u0026#34;, user_agent_hdr); 28 return 0; 29} 解析URL 首先在程序中定义一个URL结构体，存放一个URL的host、端口和路径。\n1// URL 结构体 2typedef struct { 3 char host[MAXLINE]; 4 char port[MAXLINE]; 5 char path[MAXLINE]; 6} URL; 对于一个传入的URL字符串，首先忽略掉 http:// 这种协议标识，可以通过查找//字符串来实现。\n然后，我们找到第一个/字符，在这个字符后面的就是路径了。如果找不到这个字符，我们就认为访问的是根路径/。随后我们将这个字符设置为\\0，方便之后端口的读取。我们通过:字符来定位端口，:后面的就是端口，如果找不到: 那么就认为端口是80，然后我们将这个字符设置为\\0。\n最后，剩下的字符串就是host了。\n1void parseURL(char *s, URL *url) { 2 // 忽略\u0026#34;http\u0026#34;，查找 \u0026#34;//\u0026#34; 字符串 3 char *ptr = strstr(s, \u0026#34;//\u0026#34;); 4 5 if (ptr != NULL) { 6 s = ptr+2; 7 } 8 9 // 找到第一个 \u0026#39;/\u0026#39; 字符，其后为路径 10 ptr = strchr(s, \u0026#39;/\u0026#39;); 11 if (ptr != NULL) { 12 strcpy(url-\u0026gt;path, ptr); 13 *ptr = \u0026#39;\\0\u0026#39;; // 在原字符串中截断路径部分 14 } 15 16 // \u0026#39;:\u0026#39; 之后为端口号 17 ptr = strchr(s, \u0026#39;:\u0026#39;); 18 if (ptr != NULL) { 19 strcpy(url-\u0026gt;port, ptr + 1); 20 *ptr = \u0026#39;\\0\u0026#39;; 21 } 22 else { 23 // 默认端口为80 24 strcpy(url-\u0026gt;port, \u0026#34;80\u0026#34;); 25 } 26 27 strcpy(url-\u0026gt;host, s); 28} 以http://www.example.com:8080/path/to/file为例：\n步骤 操作 查找//子字符串 指针指向www.example.com:8080/path 查找第一个/字符 ptr指向/，s变为www.example.com:8080，url-\u0026gt;path得到/path/to/file 查找:字符 ptr指向:，s变为www.example.com，url-\u0026gt;port得到8080 获取主机名 剩余部分就是主机名，复制到url-\u0026gt;host，url-\u0026gt;host得到www.example.com 函数说明：\nstrchr是C语言标准库\u0026lt;string.h\u0026gt;中的一个函数，用于在字符串中查找指定字符的第一次出现位置。如果找到了指定字符，返回该字符在字符串中第一次出现的位置的指针；如果没有找到指定字符，返回NULL。 strcpy是C语言标准库\u0026lt;string.h\u0026gt;中的一个函数，用于将一个字符串复制到另一个字符串中。它会复制源字符串的内容（包括字符串的结束符\\0），返回目标字符串的起始地址。 readClient函数 readClient函数会从客户端读取请求的全部内容，并生成即将发送到服务端的新请求。\n首先，从第一行读取URL扔给parseURL函数提取。\n然后，设置默认的Hosts header为URL中的host。接着从接下来读取到的headers中，如果是Hosts那么就更新Hosts，如果是User-Agent、Connection和Proxy-Connection，那么就忽略（因为我们有我们要设定的专属header）。其余的header收集起来，稍后一并作为新请求发过去。\n最后，向新请求字符串中写入我们生成的HTTP头和headers。\n1void readClient(rio_t *rio, URL *url, char *data) { 2 char host[MAXLINE]; 3 char line[MAXLINE]; 4 char other[MAXLINE]; 5 char method[MAXLINE], urlstr[MAXLINE], version[MAXLINE]; 6 7 Rio_readlineb(rio, line, MAXLINE); 8 sscanf(line, \u0026#34;%s %s %s\\n\u0026#34;, method, urlstr, version); 9 parseURL(urlstr, url); 10 11 sprintf(host, \u0026#34;Host: %s\\r\\n\u0026#34;, url-\u0026gt;host); 12 while (Rio_readlineb(rio, line, MAXLINE) \u0026gt; 0) { 13 if (strcmp(line, \u0026#34;\\r\\n\u0026#34;) == 0) { 14 break; 15 } 16 if (strncmp(line, \u0026#34;Host\u0026#34;, 4) == 0) { 17 strcpy(host, line); 18 } 19 if (strncmp(line, \u0026#34;User-Agent\u0026#34;, 10) \u0026amp;\u0026amp; strncmp(line, \u0026#34;Connection\u0026#34;, 10) 20 \u0026amp;\u0026amp; strncmp(line, \u0026#34;Proxy-Connection\u0026#34;, 16)) { 21 strcat(other, line); 22 } 23 } 24 25 sprintf(data, \u0026#34;%s %s HTTP/1.0\\r\\n\u0026#34; 26 \u0026#34;%s%s\u0026#34; 27 \u0026#34;Connection: close\\r\\n\u0026#34; 28 \u0026#34;Proxy-Connection: close\\r\\n\u0026#34; 29 \u0026#34;%s\\r\\n\u0026#34;, method, url-\u0026gt;path, host, user_agent_hdr, other); 30} doit函数 doit函数的功能是处理成功连接的套接字接口。\n1void doit(int connfd) { 2 rio_t rio; 3 char line[MAXLINE]; 4 Rio_readinitb(\u0026amp;rio, connfd); 5 6 URL url; 7 char data[MAXLINE]; 8 readClient(\u0026amp;rio, \u0026amp;url, data); 9 10 int serverfd = open_clientfd(url.host, url.port); 11 if (serverfd \u0026lt; 0) { 12 printf(\u0026#34;Connection failed!\\n\u0026#34;); 13 } 14 15 rio_readinitb(\u0026amp;rio, serverfd); 16 Rio_writen(serverfd, data, strlen(data)); 17 18 int len; 19 while ((len = Rio_readlineb(\u0026amp;rio, line, MAXLINE)) \u0026gt; 0) { 20 Rio_writen(connfd, line, len); 21 } 22 23 Close(serverfd); 24} Part II：处理多个并发请求 这一部分的任务是实现处理并发请求。\nmain函数 参考书上 P709 的实现。\n引入线程的main函数 1int main(int argc, char **argv) 2{ 3 int listenfd, connfd; 4 char hostname[MAXLINE], port[MAXLINE]; 5 socklen_t clientlen; 6 struct sockaddr_storage clientaddr; 7 8 // 引入线程 9 pthread_t tid; 10 11 // 检查命令输入是否正确 12 if (argc != 2) { 13 fprintf(stderr, \u0026#34;usage: %s \u0026lt;port\u0026gt; \\n\u0026#34;, argv[0]); 14 exit(1); 15 } 16 17 // 创建线程 18 sbuf_init(\u0026amp;sbuf, SBUFSIZE); 19 for (int i = 0; i \u0026lt; NTHREADS; i++) { 20 Pthread_create(\u0026amp;tid, NULL, thread, NULL); 21 } 22 23 listenfd = Open_listenfd(argv[1]); 24 // 主循环 25 while (1) { 26 clientlen = sizeof(clientaddr); 27 connfd = Accept(listenfd, (SA *)\u0026amp;clientaddr, \u0026amp;clientlen); 28 29 Getnameinfo((SA *) \u0026amp;clientaddr, clientlen, hostname, MAXLINE, 30 port, MAXLINE, 0); 31 32 printf(\u0026#34;Accepted connection from (%s, %s)\\n\u0026#34;, hostname, port); 33 // 在循环内部不再是直接执行，而是加入缓冲区 34 sbuf_insert(\u0026amp;sbuf, connfd); 35 } 36 37 printf(\u0026#34;%s\u0026#34;, user_agent_hdr); 38 return 0; 39} 同时加入线程执行函数：\n1// 线程执行函数 2void *thread(void *vargp) { 3 Pthread_detach(pthread_self()); 4 while (1) { 5 int connfd = sbuf_remove(\u0026amp;sbuf); 6 doit(connfd); 7 Close(connfd); 8 } 9} SBUF包 SBUF用于构造生产者-消费者程序，具体实现参考书上 P705-P706 的相关内容。\n1// SBUF 结构体 2typedef struct { 3 int *buf; /* Buffer array */ 4 int n; /* Maximum number of slots */ 5 int front; /* buf[(front+1)%n] is first item */ 6 int rear; /* buf[rear%n] is last item */ 7 sem_t mutex; /* Protects accesses to buf */ 8 sem_t slots; /* Counts available slots */ 9 sem_t items; /* Counts available items */ 10} sbuf_t; 11 12/* Create an empty, bounded, shared FIFO buffer with n slots */ 13/* $begin sbuf_init */ 14void sbuf_init(sbuf_t *sp, int n) 15{ 16 sp-\u0026gt;buf = Calloc(n, sizeof(int)); 17 sp-\u0026gt;n = n; /* Buffer holds max of n items */ 18 sp-\u0026gt;front = sp-\u0026gt;rear = 0; /* Empty buffer iff front == rear */ 19 Sem_init(\u0026amp;sp-\u0026gt;mutex, 0, 1); /* Binary semaphore for locking */ 20 Sem_init(\u0026amp;sp-\u0026gt;slots, 0, n); /* Initially, buf has n empty slots */ 21 Sem_init(\u0026amp;sp-\u0026gt;items, 0, 0); /* Initially, buf has zero data items */ 22} 23/* $end sbuf_init */ 24 25/* Clean up buffer sp */ 26/* $begin sbuf_deinit */ 27void sbuf_deinit(sbuf_t *sp) 28{ 29 Free(sp-\u0026gt;buf); 30} 31/* $end sbuf_deinit */ 32 33/* Insert item onto the rear of shared buffer sp */ 34/* $begin sbuf_insert */ 35void sbuf_insert(sbuf_t *sp, int item) 36{ 37 P(\u0026amp;sp-\u0026gt;slots); /* Wait for available slot */ 38 P(\u0026amp;sp-\u0026gt;mutex); /* Lock the buffer */ 39 sp-\u0026gt;buf[(++sp-\u0026gt;rear)%(sp-\u0026gt;n)] = item; /* Insert the item */ 40 V(\u0026amp;sp-\u0026gt;mutex); /* Unlock the buffer */ 41 V(\u0026amp;sp-\u0026gt;items); /* Announce available item */ 42} 43/* $end sbuf_insert */ 44 45/* Remove and return the first item from buffer sp */ 46/* $begin sbuf_remove */ 47int sbuf_remove(sbuf_t *sp) 48{ 49 int item; 50 P(\u0026amp;sp-\u0026gt;items); /* Wait for available item */ 51 P(\u0026amp;sp-\u0026gt;mutex); /* Lock the buffer */ 52 item = sp-\u0026gt;buf[(++sp-\u0026gt;front)%(sp-\u0026gt;n)]; /* Remove the item */ 53 V(\u0026amp;sp-\u0026gt;mutex); /* Unlock the buffer */ 54 V(\u0026amp;sp-\u0026gt;slots); /* Announce available slot */ 55 return item; 56} Part III：缓存Web对象 第3个任务就是实现缓存一些网页对象。\n具体地，当我们的代理访问了一个服务器网页的时候，我们需要将这个网页缓存下来，在之后的请求中就不需要再次从服务器那里请求这个网页了。\n但是，缓存的大小不是无限的，这就需要我们在缓存使用满的时候驱逐一部分已经缓存的网页出去。本实验要求我们使用LRU（最近最少使用）的方法，也就是找到上一次访问时间最远的对象替换掉。\nmain函数 1int main(int argc, char **argv) 2{ 3 int listenfd, connfd; 4 char hostname[MAXLINE], port[MAXLINE]; 5 socklen_t clientlen; 6 struct sockaddr_storage clientaddr; 7 8 // 引入线程 9 pthread_t tid; 10 11 // 检查命令输入是否正确 12 if (argc != 2) { 13 fprintf(stderr, \u0026#34;usage: %s \u0026lt;port\u0026gt; \\n\u0026#34;, argv[0]); 14 exit(1); 15 } 16 17 // 创建线程 18 sbuf_init(\u0026amp;sbuf, SBUFSIZE); 19 for (int i = 0; i \u0026lt; NTHREADS; i++) { 20 Pthread_create(\u0026amp;tid, NULL, thread, NULL); 21 } 22 // 初始化缓存 23 initCache(); 24 25 listenfd = Open_listenfd(argv[1]); 26 // 主循环 27 while (1) { 28 clientlen = sizeof(clientaddr); 29 connfd = Accept(listenfd, (SA *)\u0026amp;clientaddr, \u0026amp;clientlen); 30 31 Getnameinfo((SA *) \u0026amp;clientaddr, clientlen, hostname, MAXLINE, 32 port, MAXLINE, 0); 33 34 printf(\u0026#34;Accepted connection from (%s, %s)\\n\u0026#34;, hostname, port); 35 // 在循环内部不再是直接执行，而是加入缓冲区 36 sbuf_insert(\u0026amp;sbuf, connfd); 37 } 38 39 printf(\u0026#34;%s\u0026#34;, user_agent_hdr); 40 return 0; 41} 读者-写者模型 读者-写者模型实现了多个读者可以同时读取，但是读-写、写-写会互斥。在本实验中采用的是读者优先的策略。\n1// 读者-写者模型 2void readBegin(Cache *c) { 3 P(\u0026amp;c-\u0026gt;mutex); 4 if (++c-\u0026gt;read_cnt == 1) P(\u0026amp;c-\u0026gt;w); 5 V(\u0026amp;c-\u0026gt;mutex); 6} 7 8void readEnd(Cache *c) { 9 P(\u0026amp;c-\u0026gt;mutex); 10 if (--c-\u0026gt;read_cnt == 0) V(\u0026amp;c-\u0026gt;w); 11 V(\u0026amp;c-\u0026gt;mutex); 12} 13 14void writeBegin(Cache *c) { 15 P(\u0026amp;c-\u0026gt;w); 16} 17 18void writeEnd(Cache *c) { 19 V(\u0026amp;c-\u0026gt;w); 20} 缓存相关 缓存结构 1typedef struct Cache { 2 bool empty; // 是否为空 3 URL url; // 缓存 URL 4 char data[MAX_OBJECT_SIZE]; // 缓存内容 5 int lru; // 上次访问时间 6 int read_cnt; 7 sem_t mutex, w; // 读者-写者模型相关信号量 8} Cache; 缓存函数 初始化缓存\n1// 缓存初始化 2void initCache() { 3 for (int i = 0; i \u0026lt; MAX_CACHE; ++i) { 4 cache[i].empty = 1; 5 Sem_init(\u0026amp;cache[i].mutex, 0, 1); 6 Sem_init(\u0026amp;cache[i].w, 0, 1); 7 } 8} 寻找缓存：枚举每一个缓存，判断是否为空，如果不为空判断URL 是否相等。\n1Cache *getCache(URL *url) { 2 Cache *ans = NULL; 3 for (int i = 0; i \u0026lt; MAX_CACHE \u0026amp;\u0026amp; ans == NULL; ++i) { 4 readBegin(\u0026amp;cache[i]); 5 if (!cache[i].empty \u0026amp;\u0026amp; urlEqual(\u0026amp;cache[i].url, url)) { 6 ans = \u0026amp;cache[i]; 7 } 8 readEnd(\u0026amp;cache[i]); 9 } 10 if (ans != NULL) { 11 updateLRU(ans); 12 } 13 return ans; 14} 插入缓存\n1// 插入缓存 2void insCache(URL *url, char *data) { 3 Cache *pos = NULL; 4 for (int i = 0; i \u0026lt; MAX_CACHE \u0026amp;\u0026amp; pos == NULL; ++i) { 5 readBegin(\u0026amp;cache[i]); 6 if (cache[i].empty) { 7 pos = \u0026amp;cache[i]; 8 } 9 readEnd(\u0026amp;cache[i]); 10 } 11 // fprintf(stderr, \u0026#34;insCache: pos = %#p\\n\u0026#34;, pos); 12 if (pos != NULL) { 13 fillCache(pos, url, data); 14 return; 15 } 16 17 int minLRU = __INT_MAX__; 18 for (int i = 0; i \u0026lt; MAX_CACHE; ++i) { 19 readBegin(\u0026amp;cache[i]); 20 if (!cache[i].empty \u0026amp;\u0026amp; cache[i].lru \u0026lt; minLRU) { 21 minLRU = cache[i].lru; 22 pos = \u0026amp;cache[i]; 23 } 24 readEnd(\u0026amp;cache[i]); 25 } 26 fillCache(pos, url, data); 27} 更新 LRU\n1// 更新 LRU 2void updateLRU(Cache *c) { 3 static int clock = 0; 4 writeBegin(c); 5 c-\u0026gt;lru = ++clock; 6 writeEnd(c); 7} 装载缓存\n1// 装载缓存 2void fillCache(Cache *c, URL *url, char *data) { 3 writeBegin(c); 4 c-\u0026gt;empty = 0; 5 urlCopy(\u0026amp;c-\u0026gt;url, url); 6 strcpy(c-\u0026gt;data, data); 7 writeEnd(c); 8 updateLRU(c); 9} 辅助函数，用来判断URL是否相等和复制URL\n1bool urlEqual(const URL *a, const URL *b) { 2 return strcmp(a-\u0026gt;host, b-\u0026gt;host) == 0 \u0026amp;\u0026amp; 3 strcmp(a-\u0026gt;port, b-\u0026gt;port) == 0 \u0026amp;\u0026amp; 4 strcmp(a-\u0026gt;path, b-\u0026gt;path) == 0; 5} 6 7void urlCopy(URL *a, const URL *b) { 8 strcpy(a-\u0026gt;host, b-\u0026gt;host); 9 strcpy(a-\u0026gt;port, b-\u0026gt;port); 10 strcpy(a-\u0026gt;path, b-\u0026gt;path); 11} 实验总结 本次的Proxy实验可以看作是对I/O、网络编程和并发编程的一次综合运用。通过实现一个简单却具有重要实际应用价值的网络代理服务器帮助我们回顾了这三部分的基本原理和核心思想。我同时进一步认识到进程（线程）作为计算机系统最成功概念的意义。\n在实验过程中，我进一步巩固了LRU算法，同时意识到只要程序涉及到线程的并发运行，就必须考虑到代码的健壮性，这对我今后的学习和实践都具有重要的价值。\n","date":"2025-12-28T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/cslab/proxy/","title":"Proxy实验"},{"content":"《深入理解计算机系统》（第三版）一书中提供了很多代码实例，但我一直没有运行过。现在就以第11章 P662 “echo客户端和服务端的示例”为例运行一下。\n本次实验均在 WSL2 的 Ubuntu-22.04 系统上进行。\n准备头文件 该书中的许多代码都包含了一个名为csapp.h的头文件。Linux系统本身并不包含它，需要自行准备。\n下载源代码 点击此处 进入本书配套的网站，找到You can download a tarfile字段，点击链接下载压缩文件。\n配套网站 配置环境 接下来需要将下载的压缩包中csapp.h和csapp.c文件解压出来，放到系统的/usr/include文件夹中。\n先进入csapp.h和csapp.c所在的文件夹，然后执行：\n1sudo mv csapp.h /usr/include 2sudo mv csapp.c /usr/include 此时，应该能在/usr/include看到这两个文件。\n编译并运行 源代码 echoserveri.c文件：\n1/* 2 * echoserveri.c - An iterative echo server 3 */ 4/* $begin echoserverimain */ 5#include \u0026#34;csapp.h\u0026#34; 6 7void echo(int connfd) 8{ 9 size_t n; 10 char buf[MAXLINE]; 11 rio_t rio; 12 13 Rio_readinitb(\u0026amp;rio, connfd); 14 while((n = Rio_readlineb(\u0026amp;rio, buf, MAXLINE)) != 0) { //line:netp:echo:eof 15 printf(\u0026#34;server received %d bytes\\n\u0026#34;, n); 16 Rio_writen(connfd, buf, n); 17 } 18} 19 20int main(int argc, char **argv) 21{ 22 int listenfd, connfd, port, clientlen; 23 struct sockaddr_in clientaddr; 24 struct hostent *hp; 25 char *haddrp; 26 if (argc != 2) { 27 fprintf(stderr, \u0026#34;usage: %s \u0026lt;port\u0026gt;\\n\u0026#34;, argv[0]); 28 exit(0); 29 } 30 port = atoi(argv[1]); 31 32 listenfd = Open_listenfd(port); 33 while (1) { 34 clientlen = sizeof(clientaddr); 35 connfd = Accept(listenfd, (SA *)\u0026amp;clientaddr, \u0026amp;clientlen); 36 37 /* determine the domain name and IP address of the client */ 38 hp = Gethostbyaddr((const char *)\u0026amp;clientaddr.sin_addr.s_addr, 39 sizeof(clientaddr.sin_addr.s_addr), AF_INET); 40 haddrp = inet_ntoa(clientaddr.sin_addr); 41 printf(\u0026#34;server connected to %s (%s)\\n\u0026#34;, hp-\u0026gt;h_name, haddrp); 42 43 echo(connfd); 44 Close(connfd); 45 } 46 exit(0); 47} 48/* $end echoserverimain */ echoclient.c文件\n1/* 2 * echoclient.c - An echo client 3 */ 4/* $begin echoclientmain */ 5#include \u0026#34;csapp.h\u0026#34; 6 7int main(int argc, char **argv) 8{ 9 int clientfd, port; 10 char *host, buf[MAXLINE]; 11 rio_t rio; 12 13 if (argc != 3) { 14 fprintf(stderr, \u0026#34;usage: %s \u0026lt;host\u0026gt; \u0026lt;port\u0026gt;\\n\u0026#34;, argv[0]); 15 exit(0); 16 } 17 host = argv[1]; 18 port = atoi(argv[2]); 19 20 clientfd = Open_clientfd(host, port); 21 Rio_readinitb(\u0026amp;rio, clientfd); 22 23 while (Fgets(buf, MAXLINE, stdin) != NULL) { 24 Rio_writen(clientfd, buf, strlen(buf)); 25 Rio_readlineb(\u0026amp;rio, buf, MAXLINE); 26 Fputs(buf, stdout); 27 } 28 Close(clientfd); //line:netp:echoclient:close 29 exit(0); 30} 31/* $end echoclientmain */ 生成可执行文件 执行命令\n1gcc echoserveri.c -o echoserveri 2gcc echoclient.c -o echoclient 得到可执行文件echoserveri和echoclient。\n运行服务端和客户端 新建两个终端，分别运行echoserveri和echoclient文件。\n服务端终端：\n1# 服务端启动时输入端口号 2./echoserveri \u0026lt;port\u0026gt; 客户端终端：\n1# 客户端启动时输入主机名和端口号 2./echoclient \u0026lt;host\u0026gt; \u0026lt;port\u0026gt; 3 4# 之后可以输入内容 5# 观察服务端终端的内容 运行结果 ","date":"2025-12-15T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/csapp/","title":"运行《深入理解计算机系统》的代码"},{"content":"感谢hankeke303大佬 提供的思路！\n实验目的 在这个实验中，我们将编写一个用于C程序的动态存储分配器，即实现malloc、free和realloc函数。鼓励以创造性的方式进行探索设计，并实现一个正确、高效和快速的分配器。\n以下四个函数是需要实现的函数，它们在mm.h中声明并在mm.c中定义。\n函数 简要作用 mm_init() 调用mm_init执行任何必要的初始化，例如分配初始堆区域。如果在执行初始化时出现问题，则返回值应为-1，否则为0。 mm_malloc() mm_malloc例程返回一个指向至少大小为size字节的分配块有效负载的指针。 mm_free() mm_free例程释放ptr指向的块。它不返回任何内容。只有当传递的指针（ptr）是由先前的mm_malloc或mm_realloc调用返回的，并且尚未被释放时，此例程才保证可工作。 mm_realloc() mm_realloc例程返回一个指向至少大小为size字节的分配区域的指针。 测试程序通过计算性能指数 $P$ 来计算分配器的性能，该指数是空间利用率和吞吐量的加权和。 $$ P = wU + (1 − w) \\cdot \\mathrm{min} \\left\\{ 1, \\ \\frac{T}{T_{\\mathrm{libc}}} \\right\\} $$ 其中，$U$ 是空间利用率，$T$ 是吞吐量，$T_{\\mathrm{libc}}$ 是在默认trace下 libc的malloc吞吐量，$w$ 的默认值为 $0.6$。\n性能指标更倾向于空间利用率而不是吞吐量。\n宏定义 大致和书上使用的宏定义相同，不过最后有几个和分离适配的链表相关，LIST_PRE和 LIST_NEXT表示这个块上存储上一块和下一块的位置的指针，LIST_HEAD表示第 $i$ 个大小类的头指针，GET_XXX是这三个宏定义的解引用版本。\n操作空闲链表的基本常数和宏 1/* $begin mallocmacros */ 2/* Basic constants and macros */ 3#define WSIZE 4 /* Word and header/footer size (bytes) */ //line:vm:mm:beginconst 4#define DSIZE 8 /* Double word size (bytes) */ 5#define CHUNKSIZE (1\u0026lt;\u0026lt;12) /* Extend heap by this amount (bytes) */ //line:vm:mm:endconst 6 7#define MAX(x, y) ((x) \u0026gt; (y)? (x) : (y)) 8 9/* Pack a size and allocated bit into a word */ 10#define PACK(size, alloc) ((size) | (alloc)) //line:vm:mm:pack 11 12/* Read and write a word at address p */ 13#define GET(p) (*(unsigned int *)(p)) //line:vm:mm:get 14#define PUT(p, val) (*(unsigned int *)(p) = (unsigned int)(val)) //line:vm:mm:put 15 16/* Read the size and allocated fields from address p */ 17#define GET_SIZE(p) (GET(p) \u0026amp; ~0x7) //line:vm:mm:getsize 18#define GET_ALLOC(p) (GET(p) \u0026amp; 0x1) //line:vm:mm:getalloc 19 20/* Given block ptr bp, compute address of its header and footer */ 21#define HDRP(bp) ((char *)(bp) - WSIZE) //line:vm:mm:hdrp 22#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) //line:vm:mm:ftrp 23 24/* Given block ptr bp, compute address of next and previous blocks */ 25#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE))) //line:vm:mm:nextblkp 26#define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE))) //line:vm:mm:prevblkp 27 28/* 分离适配链表相关 */ 29#define LIST_PRE(bp) (bp) 30#define LIST_NEXT(bp) ((void *)((char *)bp + WSIZE)) 31#define LIST_HEAD(x) ((void *)((char *)(heap) + WSIZE * (x))) 32#define GET_PRE(bp) ((void *)GET(LIST_PRE(bp))) 33#define GET_NEXT(bp) ((void *)GET(LIST_NEXT(bp))) 34#define GET_HEAD(x) ((void *)GET((char *)(heap) + WSIZE * (x))) 35/* $end mallocmacros */ 需要注意的是，在这一段进行了如下的修改：\n1- #define PUT(p, val) (*(unsigned int *)(p) = (val)) 2+ #define PUT(p, val) (*(unsigned int *)(p) = (unsigned int)(val)) 如果采用书上的方案，编译时将会出现warning: assignment to ‘unsigned int’ from ‘void *’ makes integer from pointer without a cast [-Wint-conversion]。这个警告是因为在 C 语言中，直接将void*指针赋值给unsigned int类型会导致类型不匹配。\n如果不更改，编译时将会警告很多次（表现为报错数十行，虽然不影响运行结果）。\n这样，我们可以写出一个确定大小类编号的函数：\n1int getlist(size_t size) { 2 for (int i = 0; i \u0026lt; 19; ++i) { 3 if (size \u0026lt;= (1 \u0026lt;\u0026lt; (i + 4))) { 4 return i; 5 } 6 } 7 return 19; 8} 函数实现 初始化 在书上 P600 提供了一个简易版本：\n初始化空闲块 1int mm_init(void) 2{ 3 if ((heap = mem_sbrk(24 * WSIZE)) == (void*)-1) { 4 return -1; 5 } 6 7 // 申请 (20+4)*4 个字节的空间 8 for (int i = 0; i \u0026lt; 20; ++i) { 9 PUT(LIST_HEAD(i), NULL); 10 } 11 12 PUT(LIST_HEAD(20), 0); 13 PUT(LIST_HEAD(21), PACK(DSIZE, 1)); 14 PUT(LIST_HEAD(22), PACK(DSIZE, 1)); 15 PUT(LIST_HEAD(23), PACK(0, 1)); 16 17 // 将堆扩展`CHUNKSIZE`字节，并且创建初始的空闲块 18 if (extend_heap(CHUNKSIZE / WSIZE) == NULL) { 19 return -1; 20 } 21 return 0; 22} 其中，extend_heap函数用来将堆扩展CHUNKSIZE字节，并且创建初始的空闲块。此刻，分配器已初始化了，并且准备好接受来自应用的分配和释放请求。\nextend_heap函数 1void *extend_heap(size_t size) { 2 size = ((size % 2) ? size + 1 : size) * WSIZE; 3 void *bp = mem_sbrk(size); 4 5 if (bp == (void *)-1) { 6 return NULL; 7 } 8 9 PUT(HDRP(bp), PACK(size, 0)); 10 PUT(FTRP(bp), PACK(size, 0)); 11 PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); 12 13 return coalesce(bp); 14} 内存块管理 插入 这里，我们确保了每个大小块中，所有空闲块都是按照大小排序的，头指针指向的为最小的块，越向后大小越大。\n因此，在插入的时候，我们要在链表中找到合适的位置才能插入。\n1// 链表插入 2void ins(void *bp) { 3 // 根据大小选择链表 4 size_t size = GET_SIZE(HDRP(bp)); 5 int list = getlist(size); 6 // 若链表为空 7 if (GET_HEAD(list) == NULL) { 8 // 直接作为链表第一个元素 9 PUT(LIST_NEXT(bp), NULL); 10 PUT(LIST_HEAD(list), bp); 11 PUT(LIST_PRE(bp), NULL); 12 } 13 else { 14 void *p, *q; 15 for (p = GET_HEAD(list), q = NULL; p; q = p, p = GET_NEXT(p)) { 16 if (GET_SIZE(HDRP(p)) \u0026gt;= size) { 17 if (q == NULL) { 18 PUT(LIST_HEAD(list), bp); 19 } 20 else { 21 PUT(LIST_NEXT(q), bp); 22 } 23 // 插入链表 24 PUT(LIST_NEXT(bp), p); 25 PUT(LIST_PRE(p), bp); 26 PUT(LIST_PRE(bp), q); 27 return; 28 } 29 } 30 31 // 当前块最大 32 if (q == NULL) { 33 PUT(LIST_HEAD(list), bp); 34 } 35 else { 36 PUT(LIST_NEXT(q), bp); 37 } 38 PUT(LIST_NEXT(bp), p); 39 if (p) { 40 PUT(LIST_PRE(p), bp); 41 } 42 PUT(LIST_PRE(bp), q); 43 } 44} 删除 删除部分就简单了，不需要区分是哪种适配，只需要修改原本的前驱、后继的相关指针即可。\n1// 链表删除 2void del(void *bp) { 3 // 根据块大小选择链表 4 size_t size = GET_SIZE(HDRP(bp)); 5 int list = getlist(size); 6 // 删除的就是头结点 7 if (GET_PRE(bp) == NULL) { 8 PUT(LIST_HEAD(list), GET_NEXT(bp)); 9 } 10 else { 11 // 前驱节点的 next 指向当前节点的后继 12 PUT(LIST_NEXT(GET_PRE(bp)), GET_NEXT(bp)); 13 } 14 // 更新后继节点的前驱指针 15 if (GET_NEXT(bp)) { 16 // 后继的前驱指针指向删除结点的前驱 17 PUT(LIST_PRE(GET_NEXT(bp)), GET_PRE(bp)); 18 } 19} 合并与切割 合并的过程是将连续的空闲块合成一个。因为我们采用了立即合并的思路，只要有新的空闲块诞生就立刻合并，保证了任意时刻空闲块都是不连续的。\n具体的方法是判断新的空闲块的前一个块和后一个块是不是空闲的，将相邻的空闲块在原来的链表中删除，合并在一起，插入新的链表。\n1// 合并空闲块 2void *coalesce(void *bp) { 3 // fprintf(stderr, \u0026#34;coalesce %#p begin\\n\u0026#34;, bp); 4 size_t pre_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp))); 5 size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); 6 size_t size = GET_SIZE(HDRP(bp)); 7 // fprintf(stderr, \u0026#34;coalesce %#p middle %d %d %lu\\n\u0026#34;, bp, prea, nexta, size); 8 9 // 若需要合并，先删除原来的 bp 内存块，重新分配大小后再插入链表中 10 11 // 前后内存块均已分配 12 if (pre_alloc \u0026amp;\u0026amp; next_alloc) ; 13 // 前面块已分配，后面块空闲 14 else if (pre_alloc \u0026amp;\u0026amp; !next_alloc) { 15 del(NEXT_BLKP(bp)); 16 size += GET_SIZE(HDRP(NEXT_BLKP(bp))); 17 PUT(HDRP(bp), PACK(size, 0)); 18 PUT(FTRP(bp), PACK(size, 0)); 19 } 20 // 前面块空闲，后面块已分配 21 else if (!pre_alloc \u0026amp;\u0026amp; next_alloc) { 22 del(PREV_BLKP(bp)); 23 size += GET_SIZE(HDRP(PREV_BLKP(bp))); 24 bp = PREV_BLKP(bp); 25 PUT(HDRP(bp), PACK(size, 0)); 26 PUT(FTRP(bp), PACK(size, 0)); 27 } 28 // 前后内存块均空闲 29 else if (!pre_alloc \u0026amp;\u0026amp; !next_alloc) { 30 del(NEXT_BLKP(bp)); 31 del(PREV_BLKP(bp)); 32 size += GET_SIZE(HDRP(PREV_BLKP(bp))) + GET_SIZE(HDRP(NEXT_BLKP(bp))); 33 bp = PREV_BLKP(bp); 34 PUT(HDRP(bp), PACK(size, 0)); 35 PUT(FTRP(bp), PACK(size, 0)); 36 } 37 38 // 插入更新后的 bp 内存块 39 ins(bp); 40 // fprintf(stderr, \u0026#34;coalesce %#p end\\n\u0026#34;, bp); 41 return bp; 42} 切割就是在需要使用空闲块的时候，将一个空闲块切割成需要的已分配块，和新的空闲块。因为空闲块的大小至少为4，因此如果空闲块大小和需要分配的大小之差小于4，我们直接将整个空闲块分配掉，否则需要切割出来。\n1// 分割块 2void place(void *bp, size_t size) { 3 size_t bsize = GET_SIZE(HDRP(bp)); 4 del(bp); 5 if (bsize - size \u0026gt;= 4 * WSIZE) { 6 PUT(HDRP(bp), PACK(size, 1)); 7 PUT(FTRP(bp), PACK(size, 1)); 8 bp = NEXT_BLKP(bp); 9 PUT(HDRP(bp), PACK(bsize - size, 0)); 10 PUT(FTRP(bp), PACK(bsize - size, 0)); 11 ins(bp); 12 } 13 else { 14 PUT(HDRP(bp), PACK(bsize, 1)); 15 PUT(FTRP(bp), PACK(bsize, 1)); 16 } 17} 寻找空闲块 1// 寻找空闲块 2void *find_fit(size_t size) { 3 for (int list = getlist(size); list \u0026lt; 20; ++list) { 4 for (void *bp = GET_HEAD(list); bp; bp = GET_NEXT(bp)) { 5 // 找到第一个满足条件的块 6 if (GET_SIZE(HDRP(bp)) \u0026gt;= size) { 7 return bp; 8 } 9 } 10 } 11 return NULL; 12} 核心 动态内存分配的核心函数包括mm_malloc，mm_free和mm_realloc。\n分配 mm_malloc函数 1void *mm_malloc(size_t size) 2{ 3 // 忽略异常请求 4 if (size == 0) { 5 return NULL; 6 } 7 8 // 分配器必须调整请求块的大小，从而为头部和脚部留有空间， 9 // 满足双字对齐的要求 10 11 if (size \u0026lt;= DSIZE) { 12 size = 2 * DSIZE; 13 } 14 else { 15 size = size + DSIZE; 16 } 17 size = (size + DSIZE - 1) / DSIZE * DSIZE; 18 19 // 寻找空闲块 20 void *bp = find_fit(size); 21 if (bp != NULL) { 22 place(bp, size); 23 return bp; 24 } 25 26 // 未找到空闲块，则分割新的内存空间 27 if ((bp = extend_heap(MAX(size, CHUNKSIZE) / WSIZE)) == NULL) { 28 return NULL; 29 } 30 place(bp, size); 31 return bp; 32} 释放 mm_free函数比较简单，将这个块的头部、脚部标记为空闲块，调用coalesce合并空闲块并插入链表即可。\nmm_free函数 1void mm_free(void *ptr) 2{ 3 // 忽略异常请求 4 if (ptr == NULL) { 5 return; 6 } 7 size_t size = GET_SIZE(HDRP(ptr)); 8 9 // 将这个块的头部、脚部标记为空闲块 10 PUT(HDRP(ptr), PACK(size, 0)); 11 PUT(FTRP(ptr), PACK(size, 0)); 12 13 // 释放后检查能否合并 14 coalesce(ptr); 15} 再分配 1void *mm_realloc(void *ptr, size_t size) 2{ 3 void *oldptr = ptr; 4 void *newptr; 5 size_t copySize; 6 7 newptr = mm_malloc(size); 8 if (newptr == NULL) 9 return NULL; 10 copySize = GET_SIZE(HDRP(ptr)); 11 if (size \u0026lt; copySize) 12 copySize = size; 13 memcpy(newptr, oldptr, copySize); 14 mm_free(oldptr); 15 return newptr; 16} 总结 本次的动态内存分配实验是对链表这种数据结构的一次具体应用，让我体会到链表和指针在执行内存管理任务时的巨大作用，同时我也感受到C语言因具有指针这种特殊数据类型而相较于其他高级语言展现出无可比拟的优势。\n在实验中，我多次参考了书本上的案例，但同时也发现其代码存在的不健壮性。这提醒我在编写程序时应学会与时俱进，及时修改可能出现的漏洞和错误，才能保证程序在多种条件下依然能够正常运行。\n","date":"2025-11-23T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/cslab/malloc/","title":"Malloc实验"},{"content":"以下推送制作方法和原则适用于宣怀X-Club\n基本原则 突出有效信息。 简洁，减少“炫技”成分。 秀米操作简介 排版 基础格式 字号 16 行间距 2 字体 加粗，居中 其他 默认 若要表示强调，将字号变大并调整颜色\n组件 属性 介绍 组前距和组后距 调整单个组件上下的距离。使用%作为单位，可以保持跨平台的观感一致性 重叠顺序 设置组件所在的图层，数值越高图层越在上方 常用组件 样式 标题 图片 只用基础格式。特别地，多张图片可以使用左右滑动格式或svg图集 分隔线 ","date":"2025-11-14T00:00:00Z","permalink":"https://rd806.github.io/passage/media/passage/","title":"推送制作技巧"},{"content":"PA3：存储管理\n实现高速缓存 经过实践，高速缓存的一级和二级结构最好同时实现，否则会在分页控制中出现难以预料的bug！\n定义高速缓存结构 新建文件/nemu/include/memory/cache.h，填写以下内容：\n宏定义缓存块： 1#ifndef __CACHE_H__ 2#define __CACHE_H__ 3 4#include \u0026#34;common.h\u0026#34; 5 6// 定义高速缓存参数 7#define CACHE_E_L1 8 8#define CACHE_E_L2 16 9#define CACHE_BLOCK 64 10#define CACHE_SIZE_L1 64*1024 11#define CACHE_SIZE_L2 4*1024*1024 12 13... 14 15#endif 缓存块的结构体定义： 1// 定义一级缓存 2struct cache_l1 { 3 bool valid; 4 int tag; 5 uint8_t byte[CACHE_BLOCK]; 6} cache_L1[CACHE_SIZE_L1 / CACHE_BLOCK]; 7 8// 定义二级缓存 9struct cache_l2 { 10 bool valid; 11 bool dirty; 12 int tag; 13 uint8_t byte[CACHE_BLOCK]; 14} cache_L2[CACHE_SIZE_L2 / CACHE_BLOCK]; 15 16// 定义高速缓存函数 17void init_cache(); 18uint32_t cache_read_L1(hwaddr_t addr); 19uint32_t cache_read_L2(hwaddr_t addr); 20void cache_write_L1(hwaddr_t addr, size_t len, uint32_t data); 21void cache_write_L2(hwaddr_t addr, size_t len, uint32_t data); 高速缓存的读写函数 新建文件/nemu/src/memory/cache.c\n缓存的初始化 1void init_cache(){ 2 int i; 3 for(i = 0; i \u0026lt; CACHE_SIZE_L1 / CACHE_BLOCK; i++) { 4 cache_L1[i].valid = false; 5 cache_L1[i].tag = 0; 6 memset(cache_L1[i].byte, 0, CACHE_BLOCK); 7 } 8 for(i = 0; i \u0026lt; CACHE_SIZE_L2 / CACHE_BLOCK; i++) { 9 cache_L2[i].dirty = false; 10 cache_L2[i].valid = false; 11 cache_L2[i].tag = 0; 12 memset(cache_L2[i].byte, 0, CACHE_BLOCK); 13 } 14} 读取缓存块中的内容 1uint32_t cache_read_L1(hwaddr_t addr) { 2 // 取出地址中set的部分（右移block位并 \u0026amp; 1111111） 3 // set = 7 byte (set = 2^s = 128) 4 // offset = 6 byte (block = 2^e = 64) 5 uint32_t set = (addr \u0026gt;\u0026gt; 6) \u0026amp; 0x7f; 6 bool hit = false; 7 int i; 8 // 一级缓存中找到相应set 9 for(i = set * CACHE_E_L1; i \u0026lt; (set + 1) * CACHE_E_L1; i++) { 10 if(cache_L1[i].tag == (addr \u0026gt;\u0026gt; 13) \u0026amp;\u0026amp; cache_L1[i].valid) { // 如果tag和地址相符合并且valid == true 11 hit = true; 12 return i; 13 } 14 } 15 16 // 一级缓存中找空内存块 17 for(i = set * CACHE_E_L1; i \u0026lt; (set + 1) * CACHE_E_L1; i++) { 18 // 找到空的地方退出 19 if (!cache_L1[i].valid) { 20 break; 21 } 22 } 23 // 到最后仍然没有找到空的地方，执行随机替换算法 24 if(i == (set + 1) * CACHE_E_L1) { 25 srand(0); 26 i = set * CACHE_E_L1 + rand() % CACHE_E_L1; 27 } 28 cache_L1[i].valid = true; 29 cache_L1[i].tag = addr \u0026gt;\u0026gt; 13; 30 int j = cache_read_L2(addr);; 31 memcpy(cache_L1[i].byte, cache_L2[j].byte, CACHE_BLOCK); 32 33 return i; 34} 35 36uint32_t cache_read_L2(hwaddr_t addr){ 37 uint32_t s = (addr \u0026gt;\u0026gt; 6) \u0026amp; ((1 \u0026lt;\u0026lt; 12) - 1); 38 uint32_t block = (addr \u0026gt;\u0026gt; 6) \u0026lt;\u0026lt; 6; 39 int i; 40 bool hit = false; 41 for (i = s * CACHE_E_L2; i \u0026lt; (s + 1) * CACHE_E_L2; i++) { 42 if (cache_L2[i].tag == (addr \u0026gt;\u0026gt; 18) \u0026amp;\u0026amp; cache_L2[i].valid) { 43 hit = true; 44 break; 45 } 46 } 47 if (!hit) { 48 int j; 49 for (i = s * CACHE_E_L2; i \u0026lt; (s + 1) * CACHE_E_L2; i++) { 50 if (!cache_L2[i].valid) 51 break; 52 } 53 if (i == (s + 1) * CACHE_E_L2) { 54 srand(0); 55 i = s * CACHE_E_L2 + rand() % CACHE_E_L2; 56 if (cache_L2[i].dirty) { 57 uint8_t mask[BURST_LEN * 2]; 58 memset(mask, 1, BURST_LEN * 2); 59 for (j = 0; j \u0026lt; CACHE_BLOCK / BURST_LEN; j++) { 60 call_ddr3_write(block + j * BURST_LEN, cache_L2[i].byte + j * BURST_LEN, mask); 61 }\t62 } 63 } 64 cache_L2[i].valid = true; 65 cache_L2[i].tag = addr \u0026gt;\u0026gt; 18; 66 cache_L2[i].dirty = false; 67 for (j = 0; j \u0026lt; BURST_LEN; j++){ 68 call_ddr3_read(block + j * BURST_LEN, cache_L2[i].byte + j * BURST_LEN); 69 } 70 } 71 return i; 72} 数据写入缓存块 1void cache_write_L1(hwaddr_t addr, size_t len, uint32_t data) { 2 uint32_t set = (addr \u0026gt;\u0026gt; 6) \u0026amp; 0x7f; 3 uint32_t offset = addr \u0026amp; (CACHE_BLOCK - 1); 4 int i; 5 bool hit = false; 6 for (i = set * CACHE_E_L1; i \u0026lt; (set + 1) * CACHE_E_L1; i++) { 7 if (cache_L1[i].tag == (addr \u0026gt;\u0026gt; 13) \u0026amp;\u0026amp; cache_L1[i].valid) { 8 hit = true; 9 break; 10 } 11 } 12 // 写直通 13 if (hit) { 14 memcpy(cache_L1[i].byte + offset, \u0026amp;data, len); 15 } 16 cache_write_L2(addr, len, data); 17} 18 19void cache_write_L2(swaddr_t addr, size_t len, uint32_t data) { 20 uint32_t set = (addr \u0026gt;\u0026gt; 6) \u0026amp; ((1 \u0026lt;\u0026lt; 12) - 1); 21 uint32_t offset = addr \u0026amp; 0x3f;\t22 int i; 23 bool hit = false; 24 for (i = set * CACHE_E_L2; i \u0026lt; (set + 1) * CACHE_E_L2; i++) { 25 if (cache_L2[i].tag == (addr \u0026gt;\u0026gt; 13) \u0026amp;\u0026amp; cache_L2[i].valid) { 26 hit = true; 27 break; 28 } 29 } 30 if (!hit){ 31 i = cache_read_L2(addr); 32 } 33 cache_L2[i].dirty = true; 34 memcpy(cache_L2[i].byte + offset, \u0026amp;data, len); 35} 修改内存读写逻辑 在/nemu/src/memory/memory.c中，修改hwaddr_read和hwaddr_write两个函数：\n1uint32_t hwaddr_read(hwaddr_t addr, size_t len) { 2 uint32_t offset = addr \u0026amp; (CACHE_BLOCK - 1); 3 uint32_t block = cache_read_L1(addr); 4 uint8_t temp[4]; 5 memset(temp, 0, sizeof(temp)); 6 if (offset + len \u0026gt;= CACHE_BLOCK) { 7 uint32_t second_block = cache_read_L1(addr + len); 8 memcpy(temp, cache[block].byte + offset, CACHE_BLOCK - offset); 9 memcpy(temp + CACHE_BLOCK - offset, cache[second_block].byte, len - (CACHE_BLOCK - offset)); 10 } else { 11 memcpy(temp, cache[block].byte + offset, len); 12 } 13 int zero = 0; 14 uint32_t result = unalign_rw(temp + zero, 4) \u0026amp; (~0u \u0026gt;\u0026gt; ((4 - len) \u0026lt;\u0026lt; 3)); 15 return result; 16} 17 18void hwaddr_write(hwaddr_t addr, size_t len, uint32_t data) { 19 cache_write_L1(addr, len, data); 20} 实现分段机制 修改kernel 首先需要在kernel中加入切换到保护模式的代码：在kernel/include/common.h中定义宏IA32_SEG，然后重新编译kernel。\n1- //#define IA32_SEG 2+ #define IA32_SEG 这一步必须完成！如果你是CV大佬，很容易漏掉这个步骤！\n定义段寄存器 在CPU_state结构中添加GDTR，CR0和各种段寄存器，包括CS, DS, ES, SS, 其具体结构参考i386手册。\n在libcommon/x86-inc目录下的头文件中定义了一些和x86相关的宏和结构体，你可以在NEMU中包含这些头文件来使用它们。\n1// 段寄存器 2enum {R_ES, R_CS, R_SS, R_DS}; 3 4// 定义段寄存器结构体 5typedef struct { 6 uint16_t selector; 7 uint16_t attribute; 8 uint32_t limit; 9 uint32_t base; 10} Segment_Reg; 11 12... 13 14typedef struct { 15 ... 16 17 // GDTR寄存器 18 struct GDTR { 19 uint32_t base; 20 uint16_t limit; 21 } gdtr; 22 23 // CR0和CR3寄存器由 /lib-common/x86-inc/cpu.h 定义 24 CR0 cr0; 25 CR3 cr3; 26 27 // 设置段寄存器 28 union { 29 struct { 30 Segment_Reg sreg[4];\t31 }; 32 struct { 33 Segment_Reg es, cs, ss, ds; 34 }; 35 }; 36 37} CPU_state; 完善指令集 添加lgdt指令。\n添加opcode为0F 20和0F 22的mov指令，使得我们可以设置/读出CR0。\n添加opcode为8E的mov指令，使得我们可以设置段寄存器。\n为了设置CS寄存器, 你需要实现ljmp指令\n实现段寄存器的捆绑规则 在Operand结构体中添加成员sreg，位置：/nemu/include/cpu/decode/operand.h 1typedef struct { 2 uint32_t type; 3 size_t size; 4 union { 5 uint32_t reg; 6- swaddr_t addr; 7+\tstruct { 8+\tswaddr_t addr; 9+\tuint8_t sreg; 10+\t}; 11 uint32_t imm; 12 int32_t simm; 13 }; 14 uint32_t val; 15 char str[OP_STR_SIZE]; 16} Operand; 修改所有调用swaddr_read()和swaddr_write()的代码，为它们添加段寄存器的参数。具体要求如下： 指令 实现要求 opcode为A0, A1, A2, A3 的mov指令 使用DS寄存器 一些堆栈操作指令 隐式使用SS寄存器 instr_fetch() 总是使用CS寄存器 monitor中，x和p命令读出内存时 使用DS寄存器 bt命令打印栈帧链 使用SS寄存器 字符串操作指令使用的段寄存器 请查阅 i386 手册 修改内存读写函数 设置CR0后，如果发现CR0的PE位为 1，则进入IA-32保护模式，从此所有虚拟地址的访问（包括swaddr_read()和 swaddr_write()）都需要经过段级地址转换。\n为了实现段级地址转换，需要对/nemu/src/memory/memory.c中的swaddr_read()和swaddr_write()函数作少量修改：\n1uint32_t swaddr_read(swaddr_t addr, size_t len) { 2#ifdef DEBUG 3 assert(len == 1 || len == 2 || len == 4); 4#endif 5 lnaddr_t lnaddr = seg_translate(addr, len, current_sreg); 6 return lnaddr_read(lnaddr, len); 7} 8 9// swaddr_write()函数采取类似操作 其中sreg记录了当前段级地址转换所用到的段寄存器的编码。关于段寄存器的编码，请查阅i386手册。\n然后实现seg_translate()函数。再次提醒，在 NEMU 中，只有进入保护模式之后才会进行段级地址转换。\n1lnaddr_t seg_translate(swaddr_t addr, size_t len, uint8_t sreg_id) { 2 if (cpu.cr0.protect_enable == 0) { 3 return addr; 4 } 5 else { 6 return cpu.sreg[sreg_id].base + addr; 7 } 8} 实现分页机制 思考题 GDT能有多大 段选择符的结构中，INDEX有13位，故GDT最大能容纳2^13个段描述符\n为什么是线性地址？ 不可以。虚拟地址需要经GDT中的段表翻译才能得出地址，而如果GDTR中存放虚拟地址则找不到GDT在哪里了。\n如何提高寻找段描述符的效率 可以按照高速缓存的思想，建立类似cache 和 TLB 的结构来提高寻找效率。\n段式存储管理的缺点 分段管理要求分配一大段连续的存储空间，难以实现并且容易造成大量的外部碎片出现。\n页式存储管理的优点 没有外部碎片，并且不再需要大段连续的存储空间，提高了内存的利用率。\n一些问题 Q：为什么页表表项中的基地址信息只有20位而不是32位\nA：分页基地址有20位是8086的传统，在8086的分段机制中，每个段的基地址由seg_reg（即段寄存器的值）\u0026laquo;4得到，而段寄存器是16位的，左移4位得到20位的基地址。\nQ：表项和CR3中的基地址都是物理地址，这是必须的吗？能否采用虚拟地址或者线性地址？\nA：是必须的，如果cr3中的基地址是虚拟地址，则无从寻找页表翻译成物理地址，进入鸡生蛋蛋生鸡的死循环。至于其他表项的虚拟地址与线性地址问题同理。\nQ：为什么不采用一级页表？采用一级页表会有什么缺点？\nA：多级页表可以有效地节约内存空间，如果仅采用一级页表，将可能导致较大的页表长期驻留在内存中。\n空指针是“空”的吗？ 空指针只是未分配或者未指向内存任何位置的指针，并不是“NULL”的。\n在扁平模式下如何进行保护 对于数据有不同的访问权限，未达到需要的权限时不能进行写操作\n地址映射\n分页机制\n因为这里定义的ｘ生成的地址是虚拟地址，超过了物理地址的界限，报错0xc014a000 outside of the physical memory。而kvm.c中的虚拟地址都经过了va_to_pa的转换，在物理地址范围之内。\n进行反汇编后，其地址如下：\nc01003d6: e8 65 09 00 00 call c0100d40\n该call指令的opcode为e8，实现的是跳转到：该条指令的下一条指令的首地址+偏移量的位置。由于未进行寻址，故不需要进行虚实地址转化。\n分页的环境下，在没有初始化页表时，0～128M的虚拟地址到物理地址的映射相当于一个简易的页表，使得高位的地址可以通过该虚拟地址（即经过va_to_pa）访问到物理地址，从而进行初始化页表的操作。\ninit_mm()函数执行退出时。该函数将nemu映射到了高位地址并且将之前的PDE全部置为无效，此时返回main.c时，栈中保存的返回地址需要经过虚实转换，可由于页面被置为了无效，所以报错。 查看汇编代码，直接调用此函数时，nemu运行在物理地址上，由于在init_mm中将之前的PDE都置为无效，所以在loader()函数寻址时页面无效，导致报错。\n","date":"2025-11-11T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/cslab/nemu/part3/","title":"NEMU-PART III"},{"content":" 依旧期末速通……\n随机事件与概率 随机事件的关系与运算 关系 表示 包含 $B \\subset A$ 相等 $B = A$ 并 $A \\cup B$ 交 $A \\cap B = AB$ 互斥 $AB = \\varnothing$ 对立 $\\overline{A}$ 差 $A-B$ 运算 表示 交换律 $A \\cap B = AB$，$AB = BA$ 结合律 $(A \\cap B) \\cap C = A \\cap (B \\cap C)$，$AB = BA$ 分配律 $(A \\cap B) \\cup C = (AC) \\cup (BC)$，$(A \\cup B) \\cup C = (A \\cup C) \\cap (B \\cup C)$ 对偶律 $\\overline{A \\cup B} = \\overline{A}\\overline{B}$，$\\overline{AB} = \\overline{A} \\cup \\overline{B}$ 概率及其性质 性质 表示 有限可加性 $\\displaystyle P\\left(\\bigcup_{i=1}^{n} A_i \\right)= \\sum_{i=1}^{n} P(A_i)$ 对立事件 $P\\left(\\overline{A}\\right) = 1-P(A)$ 减法公式 $P(A-B) = P(A\\overline{B}) = P(A) - P(AB)$ 单调性 若 $A \\subset B$，则 $P(A) \\leqslant P(B)$ 容斥原理 对任意两个事件 $A，B$，有 $P(A \\cup B) = P(A) + P(B) - P(AB)$ 一般的，对于 $n$ 个事件 $A_i$，有 $$\\begin{align*} P\\left(\\bigcup_{i=1}^{n} A_i \\right) = \\sum_{i=1}^{n} P(A_i) \u0026- \\sum_{1 \\leqslant i \u003c j \\leqslant n} P(A_i A_j) \\\\ \u0026+ \\sum_{1 \\leqslant i \u003c j \u003c k \\leqslant n} P(A_i A_j A_k) - \\cdots + (-1)^{n-1} P(A_1 A_2 \\cdots A_n) \\end{align*}$$ 古典概型与几何概型 概型 计算 古典概型 $$P(A) = \\frac{k}{n} = \\frac{\\text{事件}A\\text{中所含样本点的个数}}{\\text{样本空间}\\varOmega\\text{中所含样本点总数}}$$ 几何概型 $$P(A) = \\frac{A \\text{的度量}}{\\varOmega \\text{的度量}}$$ 条件概率与乘法公式 条件概率 $$P(B|A) = \\frac{P(AB)}{P(A)}$$性质：\n$P(\\overline{B} |A) = 1 - P(B|A) $ $P(B_1 \\cup B_2 | A) = P(B_1 | A) + P(B_2 | A) - P(B_1 B_2 | A) $ 乘法公式 $$ P(AB) = P(A) P(B|A) $$ $$P(A_1 A_2 \\cdots A_n) = P(A_1) P(A_2|A_1) P(A_3|A_1 A_2) \\cdots P(A_n|A_1 A_2 \\cdots A_{n-1})$$全概率公式 若 $A_1，A_2，\\cdots A_n，B$ 是 $E$ 中的事件，且满足 $A_1 \\cup A_2 \\cup \\cdots \\cup A_n = \\varOmega$，则 $$P(B) = \\sum_{i=1}^{n} P(A_i) P(B|A_i)$$案例：敏感性问题调查\n步骤 要求 设计问题 你的生日是否在7月1日之前 要调查的问题 操作 被调查者在没有旁人的情况下，独自一人回答问题 在一个袋子中放入若干个红球和白球，被调查者从袋子中随机抽一个球，看过颜色后放回. 若抽到白球则回答问题1；若抽到红球则回答问题2 被调查者只回答“是”或“否” 分析结果 设共收到 $n$ 张答卷，其中有 $k$ 张答卷回答“是”；同时，在人数较多的场合中，任选一人其生日在7月1日之前的概率为 $0.5$；袋子中红球的比率为 $\\alpha$，则有等式 $$\\frac{k}{n} = p \\cdot \\alpha + 0.5 \\cdot (1-\\alpha)$$ 可知问题2回答“是”的概率 $$p=\\frac{\\dfrac{k}{n}-0.5(1-\\alpha)}{\\alpha}$$ 贝叶斯公式 $$P(A_i |B) = \\frac{P(A_i B)}{P(B)} = \\frac{P(A_i)P(B|A_i)}{\\displaystyle \\sum_{i=1}^{n} P(A_i)P(B|A_i)}$$事件的独立性 设 $n$ 个事件 $A_1，A_2，\\cdots，A_n$，若对任意 $k=2，3，\\cdots，n$ 和任意一组 $1 \\leqslant i_1 \u0026lt; i_2 \u0026lt; \\cdots \u0026lt; i_k \\leqslant n$，都有 $$P(A_{i_1} A_{i_2} \\cdots A_{i_k}) = P(A_{i_1}) P(A_{i_2}) \\cdots P(A_{i_k})$$ 则称事件 $A_1，A_2，\\cdots，A_n$ 相互独立.\n随机变量及其分布 概率分布函数 设 $X$ 是随机变量，对任意给定实数 $x \\in (-\\infty, +\\infty)$，令 $$F(x) = P\\{X \\leqslant x\\}$$ 则称 $F(x)$ 为随机变量 $X$ 的概率分布函数.\n分布函数 $F(x)$ 具有以下性质：\n性质 表示 非负性 对任意实数 $x$，都有 $0 \\leqslant F(x) \\leqslant 1$，且 $\\displaystyle F(-\\infty) = \\lim_{x \\to -\\infty} F(x) = 0$，$\\displaystyle F(+\\infty) = \\lim_{x \\to +\\infty} F(x) = 1$ 单调不减性 $\\forall x_1 \u0026lt; x_2$，有 $F(x_1) \\leqslant F(x_2)$ 右连续性 $\\forall a \\in \\textbf{R}$，有 $\\displaystyle \\lim_{x \\to a^+} F(x) = F(a+0) = F(a)$ 区间概率：$P\\{x_1 \u0026lt; X \\leqslant x_2\\} = P\\{X \\leqslant x_2\\} - P\\{X \\leqslant x_1\\} = F(x_2) - F(x_1)$ 样本点概率：$P\\{X = a\\} = F(a+0) - F(a-0)$ 离散型随机变量的分布 概率分布律 设离散型随机变量所有可能取值为 $x_k，k=1,2,\\cdots$，则称 $X$ 取各个可能值的概率 $$P\\{X = x_k\\} = p_k$$ 为随机变量 $X$ 的概率分布律. 可用表格表示为\n$X$ $x_1$ $x_2$ $\\cdots$ $x_k$ $\\cdots$ $P_X$ $p_1$ $p_2$ $\\cdots$ $p_k$ $\\cdots$ 且有：$\\displaystyle \\sum_{i=0}^{\\infty} p_k = 1$\n常用分布 类型 概率分布律 记法 两点分布 $P\\{X = 0\\} = 1-p，P\\{X = 1\\} = p$ $X \\sim B(1,p)$ 二项分布 $\\displaystyle P\\{X=k\\} = \\mathrm{C}_{n}^{k} p^k (1-p)^{n-k}，k=0,1,2,\\cdots,n \\quad (0\u0026lt;p\u0026lt;1)$ $X \\sim B(n,p)$ 泊松分布 $\\displaystyle P\\{X=k\\} = \\frac{\\lambda^k \\mathrm{e}^{-\\lambda}}{k!}，k=0,1,2,\\cdots,n$ $X \\sim P(\\lambda)$ 超几何分布 $\\displaystyle P\\{X=k\\} = \\frac{\\mathrm{C}_M^k \\mathrm{C}_{N-M}^{n-k}}{\\mathrm{C}_{N}^{n}}，k=0,1,2,\\cdots,\\text{min}\\{n,M\\}$ $X \\sim H(N,M,n)$ 几何分布 $P\\{X=k\\} = (1-p)^{k-1}p，k=0,1,2,\\cdots$ $X \\sim G(p)$ 泊松定理 设 $\\displaystyle p_n = \\frac{\\lambda}{n}$，$\\lambda \u0026gt; 0$ 是常数，则对任一非负整数 $k$，有 $$\\lim_{n \\to \\infty} \\mathrm{C}_n^k p_n^k(1-p_n)^{n-k} = \\frac{\\lambda^k \\mathrm{e}^{-\\lambda}}{k!}$$ 根据泊松定理，当 $n$ 很大且 $p$ 很小时，二项分布可以近似为泊松分布，此时有 $\\lambda = np$，且 $$\\mathrm{C}_n^k p_n^k(1-p_n)^{n-k} = \\frac{\\lambda^k \\mathrm{e}^{-\\lambda}}{k!}$$ 几何分布的无记忆性 如果 $X \\sim G(p)$，则对任意正整数 $m$，$n$，都有 $$P\\{X\u003em+n \\ |\\ X\u003em\\} = P\\{X\u003en\\}$$连续型随机变量的分布 概率密度函数 设随机变量 $X$ 的分布函数为 $F(x)$，若存在非负函数 $f(x)$，使得对任意实数 $x \\in \\textbf{R}$，均有 $$F(x) = \\int_{-\\infty}^{x} f(t) \\mathrm{d}t$$ 则称随机变量 $X$ 为连续型随机变量，称 $f(x)$ 为概率密度函数.\n常用分布 类型 概率密度函数 记法 均匀分布 $\\displaystyle f(x) = \\left\\{ \\begin{matrix} \\displaystyle \\frac{1}{b-a}，\u0026amp; a \\leqslant x \\leqslant b \\\\ \\\\ 0，\u0026amp; 其他 \\end{matrix} \\right.$ $X \\sim U(a,b)$ 指数分布 $\\displaystyle f(x) = \\left\\{ \\begin{matrix} \\lambda\\mathrm{e}^{-\\lambda x}，\u0026amp; x \\geqslant b \\\\ \\\\ 0，\u0026amp; 其他 \\end{matrix} \\right.$ $X \\sim Exp(\\lambda)$ 正态分布 $\\displaystyle f(x) = \\frac{1}{\\sqrt{2\\pi} \\sigma} \\mathrm{e}^{-\\frac{(x-\\mu)^2}{2\\sigma^2}}，-\\infty \u0026lt; x \u0026lt; \\infty$ $X \\sim N(\\mu,\\sigma^2)$ 指数分布的性质 无记忆性：如果 $X \\sim Exp(\\lambda)$，则对任意 $s\u0026gt;0$，$t\u0026gt;0$，都有 $$P\\{X\u003es+t \\ |\\ X\u003es\\} = P\\{X\u003et\\}$$正态分布的性质 正态分布的概率密度函数 $f(x)$ 以 $x=\\mu$ 为对称轴，因此 $\\displaystyle F(\\mu) = \\frac{1}{2}，F(\\mu-x) = 1-F(\\mu+x)$.\n特别地，称 $\\mu=0，\\sigma=1$ 的正态分布为标准正态分布，其概率密度函数记作 $\\varphi(x)$，分布函数记作 $\\varPhi(x)$. 则对任意正态分布 $N(\\mu,\\sigma^2)$，有 $$P\\{x_1 \u003c X \\leqslant x_2\\} = F(x_2) - F(x_1) = \\varPhi\\left(\\frac{x_2-\\mu}{\\sigma}\\right) - \\varPhi\\left(\\frac{x_1-\\mu}{\\sigma}\\right) $$ 若 $X \\sim N(\\mu, \\sigma^2)$，令 $Y=aX+b$，则随机变量 $Y \\sim N(a\\mu+b,(a\\sigma)^2)$.\n随机变量函数的分布 离散型随机变量函数的分布 若 $y_k = g(x_k)$，且已知\n$X$ $x_1$ $x_2$ $\\cdots$ $x_k$ $\\cdots$ $P_X$ $p_1$ $p_2$ $\\cdots$ $p_k$ $\\cdots$ 则可直接写出 $Y$ 的概率分布律：\n$Y$ $y_1=g(x_1)$ $y_2=g(x_2)$ $\\cdots$ $y_k=g(x_k)$ $\\cdots$ $P_Y$ $p_1$ $p_2$ $\\cdots$ $p_k$ $\\cdots$ 连续型随机变量函数的分布 若 $X$ 是连续型随机变量，$y=g(x)$ 是单值实函数，则先求 $Y$ 的分布函数 $F_Y(y)$，再对 $F_Y(y)$ 求导得随机变量 $Y$ 的概率密度函数 $f_Y(y)$.\n随机变量 $X$ 对应的概率密度函数为 $f(x)$，随机变量 $Y$ 满足 $Y = g(X)$，则可得 $$F_Y(y) = P\\{Y \\leqslant y\\} = P\\{g(X) \\leqslant y\\} = P\\{a \u003c X \u003c b\\}$$ 其中 $a$，$b$ 是关于 $y$ 的函数.\n多维随机变量及其分布 联合分布函数与边缘分布函数 联合分布函数 设 $(X,Y)$ 是二维随机变量，对于任意实数 $x,y \\in \\textbf{R}$，称二元函数 $$F(x,y) = P\\{X \\leqslant x,Y\\leqslant y\\}$$ 为 $(X,Y)$ 的联合分布函数.\n联合分布函数具有以下性质：\n性质 内容 非负性 对任意 $(x,y) \\in \\textbf{R}^2$，有 $0 \\leqslant F(x,y) \\leqslant 1$；$F(-\\infty,-\\infty) = 0$，$F(+\\infty,+\\infty) = 1$ 单调不减性 $F(x,y)$ 分别关于 $x$ 和 $y$ 单调不减 右连续性 $F(x,y)$ 分别关于 $x$ 和 $y$ 右连续 恒等式 $\\forall x_1 \u0026lt; x_2，y_1 \u0026lt; y_2$，有 $$P\\{ x_1 \u003c X \\leqslant x_2,y_1 \u003c Y \\leqslant y_2 \\} = F(x_2,y_2) - F(x_1,y_2) - F(x_2,y_1) + F(x_1,y_1) \\geqslant 0$$ 边缘分布函数 $X$ 的边缘分布函数 $\\displaystyle F_X(x) = P\\{X \\leqslant x\\} = F(x,+\\infty) = \\lim_{y \\to +\\infty} F(x,y)$ $Y$ 的边缘分布函数 $\\displaystyle F_Y(x) = P\\{Y \\leqslant y\\} = F(+\\infty,y) = \\lim_{x \\to +\\infty} F(x,y)$ 二维随机变量的独立性 设 $(X,Y)$ 是二维随机变量，联合分布函数为 $F(x,y)$，边缘分布函数分别为 $F_X(x)，F_Y(y)$. 若对于任意 $(x,y) \\in \\textbf{R}^2$，都有 $$F(x,y) = F_X(x) F_Y(y)$$ 则称随机变量 $X$ 和 $Y$ 相互独立.\n两个随机变量相互独立等价于由 $X$ 表示的任一事件与由 $Y$ 表示的任一事件都相互独立.\n二维离散型随机变量及其分布 联合概率分布律 设二维离散型随机变量 $(X,Y)$ 的所有可能取值为 $(x_i,y_j)$，则称 $$P\\{X=x,\\ Y=y\\}=p_{ij}$$ 为随机变量 $(X,Y)$ 的联合概率分布律，可用表格表示为：\n$Y$ \\ $X$ $x_1$ $x_2$ $\\cdots$ $x_i$ $\\cdots$ $y_1$ $p_{11}$ $p_{21}$ $\\cdots$ $p_{i1}$ $\\cdots$ $y_2$ $p_{12}$ $p_{22}$ $\\cdots$ $p_{i2}$ $\\cdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $y_j$ $p_{1j}$ $p_{2j}$ $\\cdots$ $p_{ij}$ $\\cdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ 边缘概率分布律 随机变量 $X$ 的边缘概率分布律：$\\displaystyle P\\{X=x_i\\} = \\sum_{i=1}^{+\\infty} p_{ij} = p_{i \\cdot}$\n随机变量 $Y$ 的边缘概率分布律：$\\displaystyle P\\{Y=y_j\\} = \\sum_{j=1}^{+\\infty} p_{ij} = p_{\\cdot j}$\n可以表示在表格中：\n$Y$ \\ $X$ $x_1$ $x_2$ $\\cdots$ $x_i$ $\\cdots$ $p_Y$ $y_1$ $p_{11}$ $p_{21}$ $\\cdots$ $p_{i1}$ $\\cdots$ $p_{\\cdot 1}$ $y_2$ $p_{12}$ $p_{22}$ $\\cdots$ $p_{i2}$ $\\cdots$ $p_{\\cdot 2}$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $y_j$ $p_{1j}$ $p_{2j}$ $\\cdots$ $p_{ij}$ $\\cdots$ $p_{\\cdot j}$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $\\vdots$ $p_X$ $p_{1 \\cdot}$ $p_{2 \\cdot}$ $\\cdots$ $p_{i \\cdot}$ $\\cdots$ 条件概率分布律 $$P\\{X=x_i \\ |\\ Y=y_j\\} = \\frac{p_{ij}}{p_{\\cdot j}}$$独立性 对于二元离散型随机变量 $(X,Y)$，则 $X$ 与 $Y$ 相互独立等价于对任意的 $i,j = 1,2,\\cdots,$ 都有 $$P\\{X=x_i \\ |\\ Y=y_j\\} = p_{i \\cdot} p_{\\cdot j}$$二维连续型随机变量及其分布 联合概率密度函数 设二维随机变量 $(X,Y)$ 的联合分布函数为 $F(x,y)$，若存在非负实函数 $f(x,y)$，使得对于任意 $(x,y) \\in \\textbf{R}^2$，都有 $$F(x,y) = \\int_{-\\infty}^{x} \\mathrm{d}s \\int_{-\\infty}^{y} f(s,t) \\mathrm{d}t$$ 则称 $(X,Y)$ 为二维连续型随机变量，并称 $f(x,y)$ 为 $(X,Y)$ 的联合概率密度函数.\n联合概率密度函数具有以下性质：\n非负性：对任意 $(x,y) \\in \\textbf{R}^2$，有 $f(x,y) \\geqslant 0$ 规范性：$\\displaystyle F(x,y) = \\int_{-\\infty}^{+\\infty} \\mathrm{d}s \\int_{-\\infty}^{+\\infty} f(s,t) \\mathrm{d}t = 1$ 可导性：$\\displaystyle \\frac{\\partial^2 F(x,y)}{\\partial x \\partial y} = f(x,y)$ 边缘概率密度函数 对于二维连续型随机变量 $(X,Y)$，联合概率密度函数 $f(x,y)$，边缘概率密度函数分别为 $f_X(x)$ 和 $f_Y(y)$，则有 $$f_X(x) = \\int_{-\\infty}^{+\\infty} f(x,y) \\mathrm{d}y $$ $$ f_Y(y) = \\int_{-\\infty}^{+\\infty} f(x,y) \\mathrm{d}x$$常用分布 二维均匀分布 设 $(X,Y)$ 是二维连续型随机变量，$G$ 是平面上一有界区域，且联合概率密度函数满足 $$f(x,y) = \\left\\{ \\begin{matrix} \\displaystyle \\frac{1}{S_G} \u0026 (x,y) \\in G \\\\\\\\ 0 \u0026 其他 \\end{matrix} \\right.$$ 其中 $S_G$ 表示区域 $G$ 的面积.\n二维正态分布 设 $(X,Y)$ 是二维连续型随机变量，且联合概率密度函数满足 $$f(x,y) = \\frac{1}{2\\pi \\sigma_{1} \\sigma_{2} \\sqrt{1-\\rho^2} } \\cdot \\mathrm{exp}\\left\\{ \\frac{1}{2(1-\\rho^2)} \\left[ \\left( \\frac{x-\\mu_{1}}{\\sigma_{1}} \\right)^2 - \\frac{2\\rho(x-\\mu_{1})(y-\\mu_{2})}{\\sigma_{1}\\sigma_{2}} + \\left( \\frac{y-\\mu_{2}}{\\sigma_{2}} \\right)^2 \\right] \\right\\}$$ 二维正态分布的性质\n二维正态分布的边缘分布仍是正态分布，反之未必成立. 二维正态随机变量的条件分布仍是正态分布. 二维随机变量 $(X,Y) \\sim N(\\mu_{1},\\mu_{2}; \\sigma_{1}^{2}, \\sigma_{2}^{2}; \\rho)$，则 $(X,Y)$ 相互独立的充要条件是 $\\rho = 0$. 条件概率密度函数 设 $(X,Y)$ 为二维连续型随机变量，在条件 $Y=y$ 下，随机变量 $X$ 的条件分布函数为 $F_{X\\ |\\ Y} (x\\ |\\ y)$，条件概率密度函数为 $f_{X\\ |\\ Y} (x\\ |\\ y)$\n$$f_{X\\ |\\ Y} = \\frac{f(x,y)}{f_Y(y)} $$ $$ f_{Y\\ |\\ X} = \\frac{f(x,y)}{f_X(x)}$$ 随机变量的边缘密度函数只与该随机变量有关，而与另一个变量无关.\n条件密度通常情况下与两个随机变量都有关系.\n独立性 设 $(X,Y)$ 是二维连续型随机变量，联合概率密度函数为 $f(x,y)$，边缘密度函数分别为 $f_X(x)$ 和 $f_Y(y)$，则 $X$ 和 $Y$ 相互独立的等价于对任意的 $(x,y) \\in \\textbf{R}^2$，在平面上几乎处处成立 $$f(x,y) = f_X(x) f_Y(y)$$易知，连续型随机变量 $(X,Y)$ 相互独立还等价于 $$f_{X\\ |\\ Y}(x\\ |\\ y) = f_X(x)，x \\in \\textbf{R} \\quad 或 \\quad f_{Y\\ |\\ X}(y\\ |\\ x) = f_Y(y)，y \\in \\textbf{R}$$二维随机变量函数的分布 二维离散型随机变量函数的分布 设 $(X,Y)$ 为二维离散型随机变量，则由函数 $Z=g(X,Y)$ 确定的随机变量也是离散型随机变量.\n求随机变量 $Z$ 的分布：\n确定 $Z$ 的所有可能值. 逐个计算 $Z$ 取每个可能值的概率. 二维连续型随机变量函数的分布 常见的二维连续型随机变量函数\n$Z=X+Y$ 设 $(X,Y)$ 的联合概率密度函数为 $f(x,y)$，$(x,y) \\in \\textbf{R}^2$，边缘密度函数分别为 $f_X(x)$，$f_Y(y)$. 对任意实数 $z$，随机变量 $Z$ 的概率密度函数 $$f_Z(z) = \\int_{-\\infty}^{+\\infty} f(x,z-x) \\mathrm{d}x $$ $$f_Z(z) = \\int_{-\\infty}^{+\\infty} f(z-y,y) \\mathrm{d}y $$ 称上述两式为 $X$ 与 $Y$ 的卷积公式，记作 $f_Z = f_X * f_Y$\n$M=\\mathrm{max}\\{X,Y\\}$ $$F_M(z) = P\\{\\mathrm{max}\\{X,Y\\} \\leqslant z\\} = P\\{X \\leqslant z, Y \\leqslant z\\} = F(z,z)$$ 若 $X$ 与 $Y$ 相互独立，则 $F_M(z) = F_X(z) F_Y(z)$\n$N=\\mathrm{min}\\{X,Y\\}$ $$F_N(z) = P\\{\\mathrm{min}\\{X,Y\\} \\leqslant z\\} = 1-P\\{X\u003ez, Y\u003ez\\}$$ 若 $X$ 与 $Y$ 相互独立，则 $F_M(z) = 1-[1-F_X(z)] \\cdot [1-F_Y(z)]$\n随机变量的数字特征 数学期望 随机变量的数学期望 类型 概率分布 数学期望 离散型随机变量 概率分布律：$P\\{X=x_k\\}=p_k$，$k=1,2,\\cdots$ $\\displaystyle E(X) = \\sum_{k=1}^{\\infty} x_k p_k$ 连续型随机变量 概率分布函数：$f(x)$ $\\displaystyle E(X) = \\int_{-\\infty}^{+\\infty} xf(x) \\mathrm{d}x$ 随机变量函数的数学期望 设 $X$ 是随机变量，令 $Y=g(X)$ 类型 概率分布 $E(Y)$ 离散型随机变量 概率分布律：$P\\{X=x_k\\} = p_k$ $\\displaystyle E(Y) = E[g(X)] = \\sum_{k=1}^{\\infty} g(x_k) P\\{X=x_k\\}$ 连续型随机变量 概率密度函数：$f(x)$ $\\displaystyle E(Y) = E[g(X)] = \\int_{-\\infty}^{+\\infty} g(x)f(x) \\mathrm{d}x$ 设 $(X,Y)$ 是二维随机变量，令 $Z=g(X,Y)$. 类型 概率分布 $E(Z)$ 离散型随机变量 联合概率分布律：$P\\{X=x_i,\\ Y=y_j\\} = p_{ij}$ $\\displaystyle E(Z) = \\sum_{i=1}^{\\infty} \\sum_{j=1}^{\\infty} g(x_i,y_i) p_{ij}$ 连续型随机变量 联合概率密度函数：$f(x,y)$ $\\displaystyle E(Z) = \\int_{-\\infty}^{+\\infty} \\int_{-\\infty}^{+\\infty} g(x,y) f(x,y) \\mathrm{d}x\\mathrm{d}y$ 数学期望的性质 设 $c$ 是常数，则 $E(c) = c$ 若 $a$，$b$ 是常数，则 $E(aX+b) = aE(X)+b$ $E(X+Y) = E(X)+E(Y)$ 设 $X$，$Y$ 相互独立，则 $E(XY) = E(X)E(Y)$ 方差 方差的定义 设随机变量 $X$ 的数学期望 $E(X)$ 存在，若随机变量 $[X-E(X)]^2$ 的数学期望 $E[X-E(X)]^2$ 存在，则记随机变量 $X$ 的方差 $$D(X) = \\mathrm{Var}(X) = E[X-E(X)]^2 $$ 方差的算术平方根记作标准差 $$\\sigma(X) = \\sqrt{D(X)}$$将方差的定义式展开，可得：\n$$D(X) = E(X^2)-[E(X)]^2$$基本性质 $D(c) = 0$ $D(aX+b) = a^2 D(X)$ 若随机变量 $X$ 与 $Y$ 独立，则 $D(X+Y) = D(X) + D(Y)$ $D(X) = 0$ 的充要条件是 $P\\{X=c\\} = 1$ 设实函数 $f(x) = E(X-x)^2$，即当 $x=E(X)$ 时，$f(x)$ 取最小值 $D(X)$，即 $D(X) \\leqslant E(X-x)^2$ 常用分布的数学期望与方差 分布 表示 期望 方差 $0-1$ 分布 $B(1,p)$ $p$ $p(1-p)$ 二项分布 $B(n,p)$ $np$ $np(1-p)$ 泊松分布 $P(\\lambda)$ $\\lambda$ $\\lambda$ 几何分布 $G(p)$ $\\displaystyle \\frac{1}{p}$ $\\displaystyle \\frac{1-p}{p^2}$ 分布 表示 期望 方差 均匀分布 $U(a,b)$ $\\displaystyle \\frac{a+b}{2}$ $\\displaystyle \\frac{(b-a)^2}{12}$ 指数分布 $Exp(\\lambda)$ $\\displaystyle \\frac{1}{\\lambda}$ $\\displaystyle \\frac{1}{\\lambda^2}$ 正态分布 $N(\\mu,\\sigma^2)$ $\\mu$ $\\sigma^2$ 协方差与相关系数 协方差 设 $(X,Y)$ 是二维随机变量，则称 $$\\mathrm{Cov}(X,Y) = E\\{[X-E(X)] [Y-E(Y)]\\}$$ 为随机变量 $X$ 与 $Y$ 的协方差.\n性质：\n$\\mathrm{Cov}(X,Y) = E(XY)-E(X)E(Y)$ $\\mathrm{Cov}(X,X) = D(X)$ $\\mathrm{Cov}(X,Y) = \\mathrm{Cov}(Y,X)$ $\\mathrm{Cov}(X+Y,Z) = \\mathrm{Cov}(X,Z) + \\mathrm{Cov}(Y,Z)$ $\\mathrm{Cov}(aX+b,cY+d) = ac\\mathrm{Cov}(X,Y)$ $D(X \\pm Y) = D(X) + D(Y) \\pm 2 \\mathrm{Cov}(X,Y)$ 相关系数 设 $(X,Y)$ 是二维随机变量，则称 $$\\rho_{X,Y} = \\frac{\\mathrm{Cov}(X,Y)}{\\sqrt{D(X)} \\sqrt{D(Y)}}$$ 为随机变量 $X$ 与 $Y$ 的相关系数.\n性质：\n$ | \\rho_{X,Y} \\leqslant 1 |$ $ | \\rho_{X,Y} | = 1 $ 等价于 $X$ 与 $Y$ 以概率 $1$ 有线性关系 大数定律与中心极限定理 切比雪夫不等式 设随机变量 $X$ 具有数学期望 $E(X) = \\mu$，方差 $D(X) = \\sigma^2$，则对于任意正数 $\\varepsilon$，有 $$P\\{ |X - E(X)| \\geqslant \\varepsilon\\} \\leqslant \\frac{D(X)}{\\varepsilon^2}$$大数定律 依概率收敛 设随机变量序列 $X_1, X_2 \\cdots, X_n, \\cdots$，若存在随机变量 $X$，使得对任意 $\\varepsilon \u0026gt; 0$，恒有 $$\\lim_{n \\to \\infty} P\\{ |X_n -X| \u003c \\varepsilon \\} = 1$$ 则称序列 $X_1, X_2 \\cdots, X_n, \\cdots$ 依概率收敛于 $X$，记为 $X_n \\xrightarrow{P} X$\n大数定律 切比雪夫大数定律：设 $X_1, X_2 \\cdots, X_n, \\cdots$ 是一列两两不相关的随机变量序列，且方差有界（即存在常数 $C\u0026gt;0$，使得对于任意 $i$，都有 $D(X_i) \\leqslant C$）. 令 $\\displaystyle Y_n = \\frac{1}{n} \\sum_{i=1}^{n} X_i$，则有 $$Y_n \\xrightarrow{P} E(Y_n)$$伯努利大数定律：在 $n$ 重伯努利试验中，设在每次试验中事件 $A$ 发生的概率均为 $p(0\u0026lt;p\u0026lt;1)$，$\\mu_n$ 为 $n$ 重伯努利试验中事件 $A$ 发生的次数，则 $$ \\frac{\\mu_n}{n} \\xrightarrow{P} p$$辛钦大数定律：设 $X_1, X_2 \\cdots, X_n, \\cdots$ 是独立同分布的随机变量序列，且数学期望存在，即 $E(X_i) = \\mu (i = 1,2,\\cdots,n,\\cdots)$，则 $$ \\frac{1}{n} \\sum_{i=1}^{n} X_i \\xrightarrow{P} \\mu $$中心极限定理 设随机变量序列 $X_1, X_2 \\cdots, X_n, \\cdots$ 独立同分布，且 $E(X_i) = \\mu$，$D(X_i) = \\sigma^2 \u0026gt; 0$，则随机变量 $$Y_i = \\frac{\\displaystyle \\sum_{i=0}^{n} X_i - n\\mu}{\\sqrt{n}\\sigma}$$ 的分布函数 $F_n(x)$ 满足 $$\\lim_{n \\to \\infty} F_n(x) = \\lim_{n \\to \\infty} P\\{Y_n \\leqslant x\\} = \\frac{1}{\\sqrt{2\\pi}} \\int_{-\\infty}^{x} \\mathrm{e}^{-\\frac{y^2}{2}} \\mathrm{d}y，x \\in \\textbf{R}$$该定理表明，当 $n \\to \\infty$ 时，随机变量 $Y_n$ 的分布将趋近于标准正态分布 $N(0,1)$. 即：当 $n$ 充分大时，独立同分布的 $n$ 个随机变量 $X_1, X_2 \\cdots, X_n$ 之和 $\\displaystyle S_n = \\sum_{i=1}^{n} X_i$ 将近似地服从正态分布 $N(n\\mu, n\\sigma^2)$\n设在独立重复试验序列中，事件 $A$ 发生的概率为 $p$，随机变量 $Y_n$ 表示事件 $A$ 在 $n$ 次试验中发生的次数，则对于任意实数 $x$，有 $$\\lim_{n \\to \\infty} \\left\\{ \\frac{Y_n - np}{\\sqrt{np(1-p)}} \\leqslant x \\right\\} = \\frac{1}{\\sqrt{2\\pi}} \\int_{-\\infty}^{x} \\mathrm{e}^{-\\frac{y^2}{2}} \\mathrm{d}y$$或者表示为：\n$$P\\{ a \u003c X \u003c b \\} = \\varPhi\\left( \\frac{b-np}{\\sqrt{np(1-p)}} \\right) - \\varPhi\\left( \\frac{a-np}{\\sqrt{np(1-p)}} \\right)$$数理统计的基本概念与抽样分布 基本概念 总体与样本 概念 定义 总体 研究对象的某项数量指标的值的全体称为总体 个体 总体中的每个元素称为个体 样本 从一个总体 $X$ 中随机地抽取 $n$ 个个体组成的向量 $(X_1,X_2,\\cdots,X_n)$ 称为总体 $X$ 的一个样本 随机样本的要求\n独立性：$X_1,X_2,\\cdots,X_n$ 是相互独立的随机变量； 代表性：样本的每个个体 $X_i$ 与总体 $X$ 具有相同的分布. 经验分布函数 设 $(X_1,X_2,\\cdots,X_n)$ 是从总体 $X$ 中抽取的容量为 $n$ 的样本，$(x_1,x_2,\\cdots,x_n)$ 是样本的观测值，将样本观测值从小到大排列得到 $x_{(1)} \\leqslant x_{(2)} \\leqslant \\cdots \\leqslant x_{(n)}$，对任意实数 $x$，称 $$F_n(x) = \\frac{1}{n} \\sum_{i=0}^{n} I_{\\{x_{(i)} \\leqslant x\\}}$$ 为总体 $X$ 的经验分布函数.\n当样本容量 $n$ 足够大时，经验分布函数 $F_n(x)$ 是总体分布函数的一个良好近似.\n统计量及其分布 统计量 样本矩 表示 样本均值 $\\displaystyle \\overline{X} = \\frac{1}{n} \\sum_{i=0}^{n} X_i$ 样本方差 $\\displaystyle S^2 = \\frac{1}{n-1} \\sum_{i=1}^{n} (X_i - \\overline{X})^2$ 样本标准差 $\\displaystyle S = \\sqrt{\\frac{1}{n-1} \\sum_{i=1}^{n} (X_i - \\overline{X})^2 }$ 样本的 $k$ 阶原点矩 $\\displaystyle A_k = \\frac{1}{n} \\sum_{i=1}^{n} X_i^k$ 样本的 $k$ 阶中心矩 $\\displaystyle M_k = \\frac{1}{n} \\sum_{i=1}^{n} (X_i - \\overline{X})^k$ 统计中的常用分布 $\\chi^2$ 分布 内容 定义 设随机变量 $X_1, X_2 \\cdots, X_n, \\cdots$ 相互独立，且均服从 $N(0,1)$ 分布，则随机变量 $$Y = X_1^2 + X_2^2 + \\cdots + X_n^2$$ 服从自由度是 $n$ 的 $\\chi^2$ 分布，记为 $Y \\sim \\chi_n^2$ 性质 设随机变量 $ Y \\sim \\chi_n^2$，则 $E(Y) = n$，$D(Y) = 2n$ 设随机变量 $Y_1 \\sim \\chi_m^2$，$Y_2 \\sim \\chi_n^2$，且 $Y_1$ 和 $Y_2$ 相互独立，则 $Y_1 + Y_2 \\sim \\chi_{m+n}^2$ $t$ 分布 内容 定义 设随机变量 $X \\sim N(0,1)$，$Y \\sim \\chi_n^2$，且 $X$ 和 $Y$ 相互独立，则称随机变量 $$T = \\frac{X}{\\sqrt{Y/n}}$$ 服从自由度是 $n$ 的 $t$ 分布，记为 $T \\sim t_n$ 性质 $t$ 的概率密度函数 $f(x;n)$ 关于 $y$ 轴对称，且当 $n \\to \\infty$ 时，$t$ 分布趋于标准正态分布 $F$ 分布 内容 定义 设随机变量 $X \\sim \\chi_m^2$，$Y \\sim \\chi_n^2$，且 $X$ 和 $Y$ 相互独立，则称随机变量 $$F = \\frac{X/m}{Y/n}$$ 服从第一自由度是 $m$，第二自由度是 $n$ 的 $F$ 分布，记作 $F \\sim F_{m,n}$ 性质 若 $F \\sim F_{m,n}$，则 $\\displaystyle \\frac{1}{F} \\sim F_{m,n}$ 若 $T \\sim t_n$，则 $T^2 \\sim F_{1,n}$ 抽样分布定理 设 $(X_1,X_2,\\cdots,X_n)$ 是来自正态总体 $X \\sim N(\\mu,\\sigma^2)$ 的样本，样本均值为 $\\displaystyle \\overline{X} = \\frac{1}{n} \\sum_{i=1}^{n} X_i$，样本方差为 $\\displaystyle S^2=\\frac{1}{n-1} \\sum_{i=1}^{n} (X_i-\\overline{X})^2$，则\n$\\displaystyle \\overline{X} \\sim N(\\mu,\\frac{\\sigma^2}{n})$\n$\\displaystyle \\frac{\\sqrt{n}(\\overline{X}-\\mu)}{S} \\sim t_{n-1}$\n$\\displaystyle \\frac{(n-1)S^2}{\\sigma^2} \\sim \\chi_{n-1}^2$\n${X}$ 与 $S^2$ 相互独立\n抽样分布定理常用来构造一些已知分布的统计量.\n参数估计 通过样本来估计总体的参数，称为参数估计.\n参数的点估计 设总体 $X$ 的分布类型已知，但其中含有未知数 $\\theta = (\\theta_1, \\cdots, \\theta_k)$. 从样本出发构造适当的统计量 $\\hat{\\theta}_i = \\hat{\\theta}_i(X_1,X_2,\\cdots,X_n)$ 作为参数 $\\theta_i$ 的估计量，当取得样本观测值 $(x_1,x_2,\\cdots,x_n)$ 后，就用 $\\hat{\\theta}_i = \\hat{\\theta}_i(x_1,x_2,\\cdots,x_n)$ 作为未知参数 $\\theta_i$ 的估计值.\n矩估计法 设总体 $X$ 含有 $k$ 个未知参数 $\\theta_1, \\theta_2, \\cdots, \\theta_k$，且 $X$ 的 $m$ 阶原点矩 $\\alpha_m = E(X^m)$ 存在，$m=1,2,\\cdots,k$，，令 $$\\left \\{\\begin{array}{c} \\alpha_1(\\theta_1, \\cdots, \\theta_k) = A_1 \\\\ \\\\ \\alpha_2(\\theta_1, \\cdots, \\theta_k) = A_2 \\\\\\\\ \\cdots \\ \\cdots \\ \\cdots \\ \\cdots \\\\\\\\ \\alpha_k(\\theta_1, \\cdots, \\theta_k) = A_k \\\\ \\end{array} \\right. $$ 解这个方程组，其解都是样本的函数，记为 $$\\hat{\\theta_i} = \\hat{\\theta_i}(X_1, X_2, \\cdots, X_n)，i=1,2,\\cdots,k$$ 当总体含有两个未知参数时，通常我们使用 $$\\left \\{ \\begin{array}{c} \\begin{align*} \u0026 E(\\theta_1, \\cdots, \\theta_k) = \\overline{X} \\\\ \\\\ \u0026 D(\\theta_1, \\cdots, \\theta_k) = \\frac{(n-1)S^2}{n} \\end{align*} \\end{array} \\right. $$ 求出参数.\n最大似然估计法 设总体 $X$ 的概率分布为 $f(x;\\theta)$，$\\theta = (\\theta_1,\\theta_2,\\cdots,\\theta_k)$ 为未知参数，$(X_1,X_2,\\cdots,X_n)$ 是从该总体中抽取的样本，则它们的联合概率分布为 $$L(x_1, x_2, \\cdots, x_n;\\theta) = \\prod_{i=1}^{n} f(x_i,\\theta)$$ 将其设作 $\\theta$ 的函数 $L(\\theta)$ 称其为 $\\theta$ 的似然函数.\n对给定的样本值 $(x_1,x_2,\\cdots,x_n)$，若存在 $\\hat{\\theta}$ 使得 $$L(\\hat{\\theta}) = \\underset{\\theta \\in \\mathrm{H}}{\\mathrm{max}} L(\\theta)$$ 则称 $\\hat{\\theta}$ 是参数 $\\theta$ 的最大似然估计值.\n若 $L(\\hat{\\theta})$ 不单调，则可取 $l(\\theta) = \\ln L(\\theta)$，对 $l(\\theta)$ 求导可得到最大值点 $\\hat{\\theta}$. 若 $L(\\hat{\\theta})$ 单调递增，则 $\\hat{\\theta}$ 取端点处的值. 估计量的优良性准则 准则 定义 无偏性 设 $\\hat{\\theta}$ 是参数 $\\theta$ 的估计量，若 $E(\\hat{\\theta}) = \\theta$ 对一切 $\\theta$ 均成立，则称 $\\hat{\\theta}$ 为 $\\theta$ 的无偏估计量，记为 $\\mathrm{UE}$ 有效性 设 $\\hat{\\theta_1}$ 和 $\\hat{\\theta_2}$ 均为 $\\theta$ 的无偏估计量，若 $D(\\hat{\\theta_1}) \u0026lt; D(\\hat{\\theta_2})$，则称 $\\hat{\\theta_1}$ 比 $\\hat{\\theta_2}$ 有效 相合估计 设 $\\hat{\\theta}_n = \\hat{\\theta}_n(X_1,X_2,\\cdots,X_n)$ 是未知参数 $\\theta$ 的估计序列，若 $\\hat{\\theta}_n$ 依概率收敛 于 $\\theta$，则称 $\\hat{\\theta}_n$ 是 $\\theta$ 的相合估计量或一致估计量 区间估计 基本概念 设 $\\theta$ 为总体中的未知参数，$(X_1,X_2,\\cdots,X_n)$ 是从总体中抽取的样本. 如果存在两个估计量 $\\hat{\\theta_1} = \\hat{\\theta}_1(X_1,X_2,\\cdots,X_n)$ 和 $\\hat{\\theta}_2 = \\hat{\\theta_2}(X_1,X_2,\\cdots,X_n)$，对于给定的 $\\alpha (0\u0026lt;\\alpha\u0026lt;1)$ 有 $$P\\{\\hat{\\theta}_1 \u003c \\theta \u003c \\hat{\\theta}_2\\} \\geqslant 1-\\alpha$$ 则称：\n基本概念 内容 置信区间 区间 $(\\hat{\\theta}_1,\\hat{\\theta}_2)$ 置信度 $1-\\alpha$ 置信下界 $\\hat{\\theta}_1$ 置信上界 $\\hat{\\theta}_2$ 构造置信区间的一般步骤：\n构造样本 $(X_1,X_2,\\cdots,X_n)$ 和待估参数 $\\theta$ 的函数 $g(X_1,X_2,\\cdots,X_n)$，要求除 $\\theta$ 外，$g$ 不含任何其他未知参数，并且 $g$ 的分布完全已知（通常为标准正态分布、$\\chi^2$ 分布、$t$ 分布、$F$ 分布等）且与 $\\theta$ 无关； 对于给定的置信度 $1-\\alpha$，由关系式 $$P\\{a \u003c g(X_1,X_2,\\cdots,X_n,\\theta) \u003c b\\} \\geqslant 1-\\alpha$$ 确定适当的常数 $a$，$b$； 上式等价于 $$P\\{\\hat{\\theta}_1(X_1,X_2,\\cdots,X_n) \u003c g(X_1,X_2,\\cdots,X_n,\\theta) \u003c \\hat{\\theta}_2(X_1,X_2,\\cdots,X_n)\\} \\geqslant 1-\\alpha$$ 于是 $(\\theta_1,\\theta_2)$ 就是 $\\theta$ 的置信度至少为 $1-\\alpha$ 的置信区间. 设 $X$ 是随机变量，$\\alpha(0\u0026lt;\\alpha\u0026lt;1)$ 是任意给定的正数，若存在 $x_{\\alpha}$ 使得 $P\\{X \\geqslant x_{\\alpha}\\} = \\alpha$，则称 $x_{\\alpha}$ 为 $X$ （或它的概率分布）的 $\\alpha$ 上侧分位数.\n分布 上侧分位数的性质 正态分布 若 $X \\sim N(0,1)$，若 $\\alpha \\leqslant 0.5$，则 $P\\{X \\leqslant x_{1-\\alpha}\\} = P\\{X \\geqslant x_{\\alpha}\\} = \\alpha$，所以 $x_{\\alpha} = -x_{\\alpha}$ $t$ 分布 若 $T \\sim t_{n}$，则有 $t_n(1-\\alpha) = t_n(\\alpha)$ $F$ 分布 若 $F \\sim F_{m,n}$，则有 $\\displaystyle F_{n,m}(1-\\alpha)= \\frac{1}{F_{m,n}(\\alpha)}$ 单个正态总体参数的置信区间 设总体 $X \\sim N(\\mu,\\sigma^2)$，$(X_1,X_2,\\cdots,X_n)$ 是取自总体 $X$ 的样本，对给定的置信度 $1-\\alpha$，分别求参数 $\\mu$ 和 $\\sigma^2$ 的区间估计.\n估计量 条件 枢轴量 置信区间 $\\mu$ $\\sigma^2$ 已知 $\\displaystyle Z=\\frac{\\overline{X}-\\mu}{\\sigma /\\sqrt{n}} \\sim N(0,1) $ $\\displaystyle \\left(\\overline{X} - z_{\\frac{\\alpha}{2}} \\frac{\\sigma}{\\sqrt{n}},\\ \\overline{X} + z_{\\frac{\\alpha}{2}} \\frac{\\sigma}{\\sqrt{n}} \\right)$ $\\mu$ $\\sigma^2$ 未知 $\\displaystyle T=\\frac{\\overline{X}-\\mu}{S/\\sqrt{n}} \\sim t_{n-1}$ $\\displaystyle \\left(\\overline{X}-t_{n-1}\\left(\\frac{\\alpha}{2}\\right) \\frac{S}{\\sqrt{n}},\\ \\overline{X}+t_{n-1}\\left(\\frac{\\alpha}{2}\\right) \\frac{S}{\\sqrt{n}} \\right) $ $\\sigma^2$ $\\mu$ 未知 $\\displaystyle \\chi^2 = \\frac{(n-1)S^2}{\\sigma^2} \\sim \\chi_{n-1}^2$ $\\displaystyle \\left(\\frac{(n-1)S^2}{\\displaystyle \\chi_{n-1}^2 \\left(\\frac{\\alpha}{2}\\right)}, \\ \\frac{(n-1)S^2}{\\displaystyle \\chi_{n-1}^2 \\left(1-\\frac{\\alpha}{2}\\right)} \\right)$ 两个正态总体参数的置信区间 估计量 条件 枢轴量 置信区间 $\\mu_1 - \\mu_2$ 方差已知 $\\displaystyle Z = \\frac{\\overline{X}-\\overline{Y}-(\\mu_1-\\mu_2)}{\\displaystyle \\sqrt{\\frac{1}{m} \\sigma_1^2 + \\frac{1}{n} \\sigma_2^2}} \\sim N(0,1)$ $\\displaystyle \\left(\\overline{X}-\\overline{Y}-z_{\\frac{\\alpha}{2}} \\sqrt{\\frac{1}{m}\\sigma_1^2 + \\frac{1}{n}\\sigma_2^2}, \\ \\overline{X}-\\overline{Y}+z_{\\frac{\\alpha}{2}} \\sqrt{\\frac{1}{m}\\sigma_1^2 + \\frac{1}{n}\\sigma_2^2} \\right)$ $\\mu_1 - \\mu_2$ 方差未知但相等 $\\displaystyle T = \\frac{\\overline{X}-\\overline{Y}-(\\mu_1-\\mu_2)}{\\displaystyle S_w\\sqrt{\\frac{1}{m} + \\frac{1}{n}}} \\sim t_{m+n-2}$ $\\displaystyle \\left(\\overline{X}-\\overline{Y}-\\lambda, \\ \\overline{X}-\\overline{Y}+\\lambda\\right)$ 其中 $\\displaystyle \\lambda = t_{m+n-2}\\left(\\frac{\\alpha}{2}\\right)S_w \\sqrt{\\frac{1}{m}+\\frac{1}{n}}$ $\\displaystyle \\frac{\\sigma_1^2}{\\sigma_2^2}$ 均值未知 $\\displaystyle F = \\frac{S_2^2}{S_1^2} \\cdot \\frac{\\sigma_1^2}{\\sigma_2^2}\\sim F_{n-1,m-1}$ $\\displaystyle \\left(F_{n-1,m-1}\\left(1-\\frac{\\alpha}{2}\\right)\\frac{S_1^2}{S_2^2}, \\ F_{n-1,m-1}\\left(\\frac{\\alpha}{2}\\right)\\frac{S_1^2}{S_2^2} \\right)$ 假设检验 假设检验是对总体的分布类型或分布类型中的未知参数提出假设，然后根据抽取的样本构造适当的统计量，对假设的真伪作出具有一定可靠性的判断.\n基本概念 提出假设时，称：\n定义 含义 $H_0$ 原假设或零假设 $H_1$ 备择假设或对立假设 小概率原理 小概率事件在一次试验中几乎不可能发生 检验统计量 检验假设的统计量 拒绝域 $W = \\{|Z| \\geqslant z_{\\alpha/2}\\}$：拒绝原假设 $H_0$ 的区间 接受域 $W = \\{|Z| \u0026lt; z_{\\alpha/2}\\}$：接受原假设 $H_0$ 的区间 一般步骤 根据实际问题的需求，提出原假设 $H_0$ 和备择假设 $H_1$； 根据 $H_0$ 内容，选取合适的检验统计量； 对给定的显著性水平 $\\alpha$，确定小概率事件（即拒绝域）$W$； 判断：若样本观测值落入拒绝域 $W$，则拒绝原假设 $H_0$，否则不拒绝原假设 $H_0$. 两类错误 第一类错误：当原假设 $H_0$ 为真时，样本观测值却落在了拒绝域，犯了“弃真”的错误. 可知犯第一类错误的最大概率为 $$P\\{拒绝 H_0 \\ |\\ H_0 为真\\} = \\alpha$$第二类错误：当原假设 $H_0$ 不真时，样本观测值却落在了接受域，犯了“采伪”的错误，记犯第二类错误的概率 $$P\\{不拒绝 H_0 \\ |\\ H_0 不真\\} = \\beta$$ 注意：\n对检验结果来说，拒绝 $H_0$ 是有说服力的，接受 $H_0$ 是没有说服力的. 原假设 $H_0$ 和备择假设 $H_1$ 不是平等的. 在提出假设时，应当尽量使后果更严重的错误成为第一类错误. 正态总体的假设检验 单个正态总体 检验法 条件 原假设 备择假设 检验统计量 拒绝条件 $Z$ 检验 $\\sigma^2 = \\sigma_0^2$ $\\mu = \\mu_0$ $\\mu \\ne \\mu_0$ $\\displaystyle Z = \\frac{\\overline{X}-\\mu_0}{\\sigma_0 / \\sqrt{n}}$ $\\{|Z| \\geqslant z_{\\alpha / 2}\\}$ $\\mu \\leqslant \\mu_0$ $\\mu \u0026gt; \\mu_0$ $\\{Z \\geqslant z_{\\alpha}\\}$ $\\mu \\geqslant \\mu_0$ $\\mu \u0026lt; \\mu_0$ $\\{Z \\leqslant -z_{\\alpha}\\}$ $t$ 检验 $\\sigma$ 未知 $\\mu = \\mu_0$ $\\mu \\ne \\mu_0$ $\\displaystyle T = \\frac{\\overline{X}-\\mu_0}{S/\\sqrt{n}}$ $\\{|T| \\geqslant t_{n-1}(\\alpha / 2)\\}$ $\\mu \\leqslant \\mu_0$ $\\mu \u0026gt; \\mu_0$ $\\{T \\geqslant t_{n-1}(\\alpha)\\}$ $\\mu \\geqslant \\mu_0$ $\\mu \u0026lt; \\mu_0$ $\\{T \\leqslant -t_{n-1}(\\alpha)\\}$ $\\chi^2$ 检验 $\\mu = \\mu_0$ $\\sigma^2 = \\sigma_0^2$ $\\sigma^2 \\ne \\sigma_0^2$ $\\displaystyle \\chi^2 = \\frac{\\displaystyle \\sum_{i=1}^n(X_i-\\mu_0)^2}{\\sigma_0^2}$ $\\{\\chi^2 \\leqslant \\chi_n^2\\left(1-\\alpha/2\\right) \\ 或\\ \\chi^2 \\geqslant \\chi_n^2(\\alpha/2)\\}$ $\\sigma^2 \\leqslant \\sigma_0^2$ $\\sigma^2 \u0026gt; \\sigma_0^2$ $\\{\\chi^2 \\geqslant \\chi_n^2(\\alpha)\\}$ $\\sigma^2 \\geqslant \\sigma_0^2$ $\\sigma^2 \u0026lt; \\sigma_0^2$ $\\{\\chi^2 \\leqslant \\chi_n^2(1-\\alpha)\\}$ $\\chi^2$ 检验 $\\mu$ 未知 $\\sigma^2 = \\sigma_0^2$ $\\sigma^2 \\ne \\sigma_0^2$ $\\displaystyle \\chi^2 = \\frac{(n-1)S^2}{\\sigma_0^2}$ $\\{\\chi^2 \\leqslant \\chi_{n-1}^2\\left(1-\\alpha/2\\right) \\ 或\\ \\chi^2 \\geqslant \\chi_{n-1}^2(\\alpha/2)\\}$ $\\sigma^2 \\leqslant \\sigma_0^2$ $\\sigma^2 \u0026gt; \\sigma_0^2$ $\\{\\chi^2 \\geqslant \\chi_{n-1}^2(\\alpha)\\}$ $\\sigma^2 \\geqslant \\sigma_0^2$ $\\sigma^2 \u0026lt; \\sigma_0^2$ $\\{\\chi^2 \\leqslant \\chi_{n-1}^2(1-\\alpha)\\}$ 两个正态总体 检验法 条件 原假设 备择假设 检验统计量 拒绝条件 $Z$ 检验 $\\sigma_1^2$，$\\sigma_2^2$ 已知 $\\mu_1 = \\mu_2$ $\\mu_1 \\ne \\mu_2$ $\\displaystyle Z = \\frac{\\overline{X}-\\overline{Y}}{\\displaystyle \\sqrt{\\frac{\\sigma_1^2}{m} + \\frac{\\sigma_2^2}{n}}}$ $\\{|Z| \\geqslant z_{\\alpha / 2}\\}$ $\\sigma_1^2$，$\\sigma_2^2$ 未知 $\\mu \\leqslant \\mu_0$ $\\mu_1 \u0026gt; \\mu_2$ $\\{Z \\geqslant z_{\\alpha}\\}$ $t$ 检验 $\\sigma_1^2$，$\\sigma_2^2$ 未知且$\\sigma_1^2 = \\sigma_2^2$ $\\mu_1 = \\mu_2$ $\\mu_1 \\ne \\mu_2$ $\\displaystyle T = \\frac{\\overline{X}-\\overline{Y}}{\\displaystyle S_w\\sqrt{\\frac{1}{m} + \\frac{1}{n}}}$ $\\{|T| \\geqslant t_{m+n-2}(\\alpha / 2)\\}$ $\\mu_1 \\leqslant \\mu_2$ $\\mu_1 \u0026gt; \\mu_2$ $\\{T \\geqslant t_{m+n-2}(\\alpha)\\}$ $t$ 检验 成对数据 $\\mu_1 = \\mu_2$ $\\mu_1 \\ne \\mu_2$ $\\displaystyle T = \\frac{\\overline{D}}{S_d/\\sqrt{n}}$ $\\{|T| \\geqslant t_{n-1}(\\alpha / 2)\\}$ $\\mu_1 \\leqslant \\mu_2$ $\\mu_1 \u0026gt; \\mu_2$ $\\{T \\geqslant t_{n-1}(\\alpha)\\}$ $F$ 检验 $\\mu_1$。$\\mu_2$ 未知 $\\sigma_1^2 = \\sigma_2^2$ $\\sigma_1^2 \\ne \\sigma_2^2$ $\\displaystyle F = \\frac{S_1^2}{S_2^2}$ $\\{F \\leqslant F_{m-1,n-1}(1-\\alpha/2) \\\\ 或\\ F \\geqslant F_{m-1,n-1}(\\alpha/2)\\}$ $\\sigma_1^2 \\leqslant \\sigma_2^2$ $\\sigma_1^2 \u0026gt; \\sigma_2^2$ $\\{F \\geqslant F_{m-1,n-1}(\\alpha)\\}$ ","date":"2025-11-07T00:00:00Z","image":"https://rd806.github.io/passage/math/probability/rohit-choudhari-JS3RDAnRUB8-unsplash_hu_16c3aa1724f7c4d4.jpg","permalink":"https://rd806.github.io/passage/math/probability/","title":"概率论与数理统计"},{"content":"排版与排版工具 排版是指对文字、图片等元素的布局处理，使之符合我们的阅读习惯。\n排版工具 特点 Word 所见即所得 方正书版 暂时未知（没用过） $\\LaTeX$ 使用 $\\TeX$ 语句编辑 TeX环境配置 本文使用Tex Live为例。\nTeXLive介绍 TeXLive 是目前 Windows 平台和 Linux 平台上最主流的 $\\LaTeX$ 发行版。\n$\\LaTeX$ 发行版，是指将 $\\LaTeX$ 编译引擎（如 pdflatex、xelatex、lualatex 等）、宏包（如 beamer、pgf/tikz 等）、模板（比如一些学校的毕业论文模板）、字体、配套工具（如 tlmgr、texworks 等）打包在一起的、开箱即用的 $\\LaTeX$ 套件。\n下载TeXLive镜像 到某个国内的 CTAN 镜像站下载最新版的 TeXLive 镜像，比如：清华大学开源软件镜像站 。\n目前最新的 TeXLive 版本为 2025，该文件夹下包含3个.iso文件，它们仅有文件名不同，内容完全相同，可以任选一个下载。该文件夹下还包含有md5摘要文件，也可以下载下来以备校验。\n校验安装镜像（可选）：\r进入到 TeXLive 和md5文件所在的文件夹，执行命令\nWindows系统：\n1certutil -hashfile texlive2025.iso md5 Linux系统：\n1md5sum texlive2025.iso 你应该可以得到 TeXLive 2025 镜像文件的md5值：69b4a8882983d9ea521730b5f42175e7。\n挂载镜像并启动安装程序 Windows系统 找到 TeXLive 文件，右击并选择“挂载”选项，可以看到磁盘管理器中出现新的盘符（如E:）。\n然后打开PowerShell或cmd，运行：\n1Z:\\install-tl-windows.bat --no-gui 或者直接点击install-tl-windows.bat启动安装程序。\nLinux系统 在Shell中执行\n1sudo mkdir /mnt/texlive 2sudo mount \u0026#34;TeXLive文件位置\u0026#34; /mnt/texlive 安装TeXLive TeX语法 宏包 $\\TeX$ 中的宏包类似于“扩展组件”，提供原生 $\\TeX$ 中没有的功能。\n文档元素 ","date":"2025-10-29T00:00:00Z","image":"https://rd806.github.io/passage/guide/texstudio/bozhin-karaivanov-R5dKk1oXPAM-unsplash_hu_49e7f70373d6beb8.jpg","permalink":"https://rd806.github.io/passage/guide/texstudio/","title":"Tex排版"},{"content":"感谢之一Yo大佬 提供的思路！\n实验目的 更加熟悉进程控制和信号的概念。你将通过编写一个简单的Unix shell程序来实现这一目标，实现对作业的控制。\nShell介绍 详细介绍（太长不看）\rShell是一个交互式命令行解释器，代表用户运行程序。Shell重复地打印提示符，等待stdin上输入的命令行，然后根据命令行的内容执行一些操作。\n命令行是一系列由空白分隔的ASCII文本单词。命令行中的第一个单词要么是内置命令的名称，要么是可执行文件的路径名。其余的单词是命令行参数。如果第一个单词是内置命令，Shell立即在当前进程中执行该命令。否则，该单词被假定为可执行程序的路径名。在这种情况下，Shell创建一个子进程，然后在子进程的上下文中加载并运行程序。作为解释单个命令行的结果创建的子进程总称为作业。一般来说，一个作业可以由通过Unix管道连接的多个子进程组成。\n如果命令行以一个 \u0026ldquo;\u0026amp;\u0026rdquo; 结尾，那么作业在后台运行，这意味着Shell在打印提示并等待下一个命令行之前不等待作业终止。否则，作业在前台运行，这意味着Shell等待作业终止后才等待下一个命令行。因此，在任何时候，最多只能有一个作业在前台运行。但是，任意数量的作业可以在后台运行。\n本篇博客将会详细介绍 CSAPP 的 ShellLab 完成过程，实现一个简易（lou）的 shell。tsh 拥有以下功能：\n可以执行外部程序 支持四个内建命令，名称和功能为： 名称 功能 quit 退出终端 jobs 列出所有后台作业 bg \u0026lt;job\u0026gt; 继续在后台运行一个处于停止状态的后台作业，\u0026lt;job\u0026gt; 可以是 PID 或者 %JID 形式 fg \u0026lt;job\u0026gt; 将一个处于运行或者停止状态的后台作业转移到前台继续运行 按下 Ctrl + C 终止前台作业 按下 Ctrl + Z 停止前台作业 实验材料中已经写好了一些函数，只要求我们实现下列核心函数：\n名称 功能 eval 解析并执行指令 builtin_cmd 识别并执行内建指令 do_bgfg 执行 fg 和 bg 指令 waitfg 阻塞终端直至前台任务完成 sigchld_handler 捕获 SIGCHLD 信号 sigint_handler 捕获 SIGINT 信号 sigtstp_handler 捕获 SIGTSTP 信号 函数实现 eval函数 在《深入理解计算机系统》第525页给出了eval函数的核心代码：\neval函数 但是在 Shell 实验中，还应当满足以下要求：\n父进程在fork子进程之前必须使用sigprocmask阻塞SIGCHLD信号，然后在通过调用addjob将子进程添加到作业列表后，再次使用sigprocmask解除对这些信号的阻塞。 由于子进程继承了其父进程的阻塞向量，子进程必须确保在执行新程序之前解除对SIGCHLD信号的阻塞。父进程需要以这种方式阻塞SIGCHLD信号，以避免在父进程调用addjob之前，子进程被sigchld_handler收回（因此从作业列表中删除）的竞争条件。 在fork之后但在execve之前，子进程应调用setpgid(0, 0)，将子进程放入一个新的进程组，其组ID与子进程的PID相同。这确保在前台进程组中只有一个进程，即shell。 setpgid函数将进程pid的进程组改为pgid。如果pid是 0, 那么就使用当前进程的PID。 如果pgid是 0，那么就用pid指定的进程的PID作为进程组 ID。\n例如，如果进程 15213 是调用进程，那么setpgid(0, 0)会创建一个新的进程组，其进程组 ID 是 15213，并且把进程 15213 加人到这个新的进程 组中。\n1void eval(char *cmdline) 2{ 3 char* argv[MAXARGS]; // 命令参数 4 char buf[MAXLINE]; // 保存命令行 5 int bg; // 判断 job 运行在 bg 还是 fg 6 pid_t pid; 7 8 sigset_t mask_all, mask_one, prev_mask; 9 sigfillset(\u0026amp;mask_all); 10 sigemptyset(\u0026amp;mask_one); 11 sigaddset(\u0026amp;mask_one, SIGCHLD); 12 13 strcpy(buf, cmdline); 14 bg = parseline(cmdline, argv); 15 16 // 忽略空指令 17 if (argv[0] == NULL) 18 return; 19 20 if (!builtin_cmd(argv)) { 21 // 创建子进程前阻塞SIGCHLD信号 22 sigprocmask(SIG_BLOCK, \u0026amp;mask_one, \u0026amp;prev_mask); 23 if ((pid = Fork()) == 0) { 24 // 子进程必须确保在执行新程序之前解除对SIGCHLD信号的阻塞 25 sigprocmask(SIG_SETMASK, \u0026amp;prev_mask, NULL); 26 // 将子进程放入一个新的进程组 27 setpgid(0, 0); 28 if (execve(argv[0], argv, environ) \u0026lt; 0) { 29 printf(\u0026#34;%s: Command not found.\\n\u0026#34;, argv[0]); 30 exit(0); 31 } 32 } 33 34 /* 35 父进程需要阻塞SIGCHLD信号，以避免在父进程调用addjob之前， 36 子进程被sigchld_handler收回 37 */ 38 sigprocmask(SIG_BLOCK, \u0026amp;mask_one, NULL); 39 // 将子进程添加到作业列表 40 addjob(jobs, pid, bg ? BG : FG, cmdline); 41 42 43 if (!bg) { 44 waitfg(pid); 45 } else { 46 printf(\u0026#34;[%d] (%d) %s\u0026#34;, pid2jid(pid), pid, cmdline); 47 } 48 49 // 再次使用sigprocmask解除对这些信号的阻塞 50 sigprocmask(SIG_SETMASK, \u0026amp;prev_mask, NULL); 51 } 52 53 return; 54} 其中Fork()函数定义可以在《深入理解计算机系统》第512页找到：\nFork函数 builtin_cmd函数 在《深入理解计算机系统》第525页同样给出了builtin_cmd函数的核心代码：\nbuiltin_cmd函数 Shell 程序要实现的builtin_cmd比这个要多一些分支语句，主要用来判断quit、jobs、bg和fg命令。\n1int builtin_cmd(char **argv) 2{ 3 // 识别和解释内置命令：quit、fg、bg和jobs 4 // 指令 tsh \u0026gt; quit 5 if(!strcmp(argv[0], \u0026#34;quit\u0026#34;)) { 6 exit(0); 7 } 8 // 指令 tsh \u0026gt; fg 和 tsh \u0026gt; bg 9 else if(!strcmp(argv[0], \u0026#34;fg\u0026#34;) || !strcmp(argv[0], \u0026#34;bg\u0026#34;)) { 10 do_bgfg(argv); 11 return 1; 12 } 13 // 指令 tsh \u0026gt; jobs 14 else if(!strcmp(argv[0], \u0026#34;jobs\u0026#34;)) { 15 listjobs(jobs); 16 return 1; 17 } 18 else if(!strcmp(argv[0], \u0026#34;\u0026amp;\u0026#34;)) { 19 return 1; 20 } 21 22 return 0; /* not a builtin command */ 23} waitfg函数 阻塞终端直至前台任务完成意味着主程序需要显式地等待某个信号处理程序运行，一种合适的解决方法是使用sigsuspend函数。\n1void waitfg(pid_t pid) 2{ 3 // 等待前台作业完成 4 sigset_t mask; 5 sigemptyset(\u0026amp;mask); 6 7 // sigsuspend函数提高执行效率 8 while(fgpid(jobs)) { 9 sigsuspend(\u0026amp;mask); 10 } 11 return; 12} 还有一种思路是使用sleep函数。\n1while(!pid) { 2 sleep(1); 3} 当这段代码正确执行时，它太慢了。如果在while之后pause之前收到信号，程序必须等相当长的一段时间才会再次检查循环的终止条件。使用像 nanosleep这样更髙精度的休眠函数也是不可接受的，因为没有很好的方法来确定休眠的间隔。间隔太小，循环会太浪费；间隔太大，程序又会太慢。\ndo_bgfg函数 在builtin_cmd中最重要的就是do_bgfg函数，负责作业的状态转换。\n首先获取任务的PID，若为空则报错；否则发送SIGCONT信号给进程组中的每一个进程。\n为了做到将SIGCONT信号发送给进程组中的每一个进程，需要将kill函数的pid参数取负值，不然就只发给指定的进程了。具体可参见kill函数在《深入理解计算机系统》第530页的定义：\nkill函数的定义位于《深入理解计算机系统》第530页：\nkill函数 1void do_bgfg(char **argv) 2{ 3 char* cmd = argv[0]; 4 char* id = argv[1]; 5 struct job_t* job; 6 7 if (id == NULL) { 8 printf(\u0026#34;%s command requires PID or %%jobid argument\\n\u0026#34;, cmd); 9 return; 10 } 11 12 // 根据 jid/pid 获取作业 13 if (id[0] == \u0026#39;%\u0026#39;) { 14 if ((job = getjobjid(jobs, atoi(id + 1))) == NULL) { 15 printf(\u0026#34;%s: No such job\\n\u0026#34;, id); 16 return; 17 } 18 } 19 else if (atoi(id) \u0026gt; 0) { 20 if ((job = getjobpid(jobs, atoi(id))) == NULL) { 21 printf(\u0026#34;(%d): No such process\\n\u0026#34;, atoi(id)); 22 return; 23 } 24 } 25 else { 26 printf(\u0026#34;%s: argument must be a PID or %%jobid\\n\u0026#34;, cmd); 27 return; 28 } 29 30 // 状态转移 31 if (!strcmp(cmd, \u0026#34;fg\u0026#34;)) { 32 job-\u0026gt;state = FG; 33 kill(-job-\u0026gt;pid, SIGCONT); 34 waitfg(job-\u0026gt;pid); 35 } 36 else if (!strcmp(cmd, \u0026#34;bg\u0026#34;)) { 37 job-\u0026gt;state = BG; 38 kill(-job-\u0026gt;pid, SIGCONT); 39 printf(\u0026#34;[%d] (%d) %s\u0026#34;, job-\u0026gt;jid, job-\u0026gt;pid, job-\u0026gt;cmdline); 40 } 41 return; 42} 信号处理 sigchld_handler函数 1void sigchld_handler(int sig) 2{ 3 int old_errno = errno; 4 pid_t pid; 5 int status; 6 sigset_t mask_all, prev_mask; 7 sigfillset(\u0026amp;mask_all); 8 9 while ((pid = waitpid(-1, \u0026amp;status, WNOHANG | WUNTRACED)) \u0026gt; 0) { 10 // 终止作业 11 if (WIFEXITED(status) || WIFSIGNALED(status)) { 12 sigprocmask(SIG_BLOCK, \u0026amp;mask_all, \u0026amp;prev_mask); 13 14 // ctrl-c 终止 15 if (WIFSIGNALED(status)) { 16 printf(\u0026#34;Job [%d] (%d) terminated by signal 2\\n\u0026#34;, pid2jid(pid), pid); 17 } 18 19 deletejob(jobs, pid); 20 sigprocmask(SIG_SETMASK, \u0026amp;prev_mask, NULL); 21 } 22 // 停止作业 23 else if (WIFSTOPPED(status)) { 24 sigprocmask(SIG_BLOCK, \u0026amp;mask_all, \u0026amp;prev_mask); 25 26 struct job_t* job = getjobpid(jobs, pid); 27 job-\u0026gt;state = ST; 28 printf(\u0026#34;Job [%d] (%d) stopped by signal 20\\n\u0026#34;, job-\u0026gt;jid, job-\u0026gt;pid); 29 30 sigprocmask(SIG_SETMASK, \u0026amp;prev_mask, NULL); 31 } 32 } 33 34 errno = old_errno; 35 return; 36} 处理Ctrl + C 1void sigint_handler(int sig) 2{ 3 // 获取SIGINT（ctrl-c）信号 4 int olderrno = errno; 5 6 // 获取当前正在前台的任务的PID 7 pid_t pid = fgpid(jobs); 8 // 判断任务是否存在 9 if(pid \u0026gt; 0) { 10 // -pid表示进程组 |pid| 的所有进程 11 kill(-pid, SIGKILL); 12 } 13 errno = olderrno; 14 return; 15} 处理Ctrl + Z 同理可得： 1void sigtstp_handler(int sig) 2{ 3 // 获取SIGTSTP（ctrl-z）信号 4 int olderrno = errno; 5 6 pid_t pid = fgpid(jobs); 7 if(pid \u0026gt; 0) { 8 kill(-pid, SIGTSTP); 9 } 10 errno = olderrno; 11 return; 12} 总结 通过这次实验，我加深了对进程控制和信号处理的理解，同时对于并发现象有了更直观的认识。即使是一个简易的Shell程序，也需要考虑任务的排队、信号阻塞等问题，要在心中有整体设计观念。同时在完成实验的过程中我大量参考了书本内容，也提醒我在今后的学习和实验中要注重书本的工具作用。\n另外，在评测平台测试时，第一次测试时由于在Command not found后多加了一个句点而导致判错。这启示我在编程时应当小心谨慎，认真阅读要求，并且仔细检查，方能提高正确率和效率。\n","date":"2025-10-19T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/cslab/shell/","title":"Shell实验"},{"content":"图像的表示 在计算机（实际上是任何电子产品）中，图像的本质是一个分块矩阵。\n$$ \\bm{Image} = \\left[\\begin{matrix} \\bm{P}_{11} \u0026 \\bm{P}_{12} \u0026 \\cdots \u0026 \\bm{P}_{1n} \\\\ \\bm{P}_{21} \u0026 \\bm{P}_{22} \u0026 \\cdots \u0026 \\bm{P}_{2n} \\\\ \\vdots \u0026 \\vdots \u0026 \u0026 \\vdots \\\\ \\bm{P}_{m1} \u0026 \\bm{P}_{m2} \u0026 \\cdots \u0026 \\bm{P}_{mn} \\end{matrix}\\right] $$其中每个小矩阵 $\\bm{P}_{ij}$ 以 $RGB$ 的格式存储了该处的颜色信息。\n像素 像素是构成数字图像的最小、最基本的单位。可以把它想象成一块块微小的、带有颜色的“马赛克”或“积木”。\n例如，对于这一张图片：\n示例图片 当将其放大到一定倍数后，将出现这个情况：\n示例图片放大 可以看出，图片变成了一个个排列整齐的色块。我们把这些色块称作像素块。每个像素块对应上述的每个小矩阵 $\\bm{P}_{ij}$。它具有以下几个性质：\n像素块是排列整齐、均匀的正方形区域。 每个像素块只能有一种颜色。 由性质2，像素块还可以看作是：图像中不可再分的最小颜色区域。\n我们日常生活中常见的图片是 $n*m$ 像素，就表示图片的长有 $n$ 个像素块，宽（或常称作高）有 $m$ 个像素块。其中 $m$ 和 $n$ 分别代表图像矩阵的行数和列数。\n由此可见，当 $n$ 和 $m$ 的数值越大，图片可容纳的像素块就越多，表示的信息就越丰富；相应地，占用的存储空间也就越大。\n色值 色值表示了像素块储存的颜色信息，目前最流行的色值表示方法为 $RGB$ 色值。\n每个 $RGB$ 色值有3个信息位，分别表示 红色（Red）、绿色（Green）、蓝色（Blue），取值范围均为 $[0,255]$ 的整数。相应的数值越大，表明该颜色在总颜色的占比越高。\n例如 $[255,0,0]$ 就表示纯红色，$[255,255,255]$ 表示白色，$[0,0,0]$ 表示黑色。所以，上述的每个小矩阵\n$$\\bm{P_{ij}} = [R,G,B]$$其中 $R$，$G$，$B$ 分别是取值 $[0,255]$ 的整数。\n红、绿、蓝是光的三基色，因此将此三种颜色按一定比例混合就可以产生我们可见的所有颜色。\n在一些图像处理软件中，$RGB$ 的范围被定义成 $[0,1]$。实际上，这就是 $[0,255]$ 到 $[0,1]$ 上的一个压缩映射。这时，$10$ 就表示 $\\displaystyle \\frac{10}{255}$；$255$ 就表示 $1$。\n$RGB$ 色值还有一种表示方法，即通过 # + 6位16进制数 表示。因为10进制的 $[0,255]$ 恰好对应16进制的 $[00,FF]$，所以需要6个数位表示。\n例如 $\\# 000000$ 对应 $[0,0,0]$，$\\# FFFFFF$ 对应 $[255,255,255]$。\n图像混合 由图像的表示原理可知，所有图像的操作本质上是对像素块的操作。\n正片叠底 正片叠底，简单而言就是将两张图像合并为一张图像的过程。具体操作就是取两个图像对应的像素块，对其 $RGB$ 色值分别相乘，再除以 $255$。\n定义新运算 $*$ 称为正片叠底运算：\n对任意两个图像矩阵 $\\bm{I}_1$，$\\bm{I}_2$，取其重叠部分，有\n$$\\begin{align*} \\bm{I_1} * \\bm{I_2} \u0026= \\left[\\begin{matrix} \\bm{A}_{11} \u0026 \\bm{A}_{12} \u0026 \\cdots \u0026 \\bm{A}_{1n} \\\\ \\bm{A}_{21} \u0026 \\bm{A}_{22} \u0026 \\cdots \u0026 \\bm{A}_{2n} \\\\ \\vdots \u0026 \\vdots \u0026 \u0026 \\vdots \\\\ \\bm{A}_{m1} \u0026 \\bm{A}_{m2} \u0026 \\cdots \u0026 \\bm{A}_{mn} \\end{matrix}\\right] * \\left[\\begin{matrix} \\bm{B}_{11} \u0026 \\bm{B}_{12} \u0026 \\cdots \u0026 \\bm{B}_{1n} \\\\ \\bm{B}_{21} \u0026 \\bm{B}_{22} \u0026 \\cdots \u0026 \\bm{B}_{2n} \\\\ \\vdots \u0026 \\vdots \u0026 \u0026 \\vdots \\\\ \\bm{B}_{m1} \u0026 \\bm{B}_{m2} \u0026 \\cdots \u0026 \\bm{B}_{mn} \\end{matrix}\\right] \\\\ \\\\ \u0026= \\frac{1}{255} \\left[\\begin{matrix} \\bm{A}_{11} \\cdot \\bm{B}_{11} \u0026 \\bm{A}_{12} \\cdot \\bm{B}_{12} \u0026 \\cdots \u0026 \\bm{A}_{1n} \\cdot \\bm{B}_{1n} \\\\ \\bm{A}_{21} \\cdot \\bm{B}_{21} \u0026 \\bm{A}_{22} \\cdot \\bm{B}_{22} \u0026 \\cdots \u0026 \\bm{A}_{2n} \\cdot \\bm{B}_{2n} \\\\ \\vdots \u0026 \\vdots \u0026 \u0026 \\vdots \\\\ \\bm{A}_{m1} \\cdot \\bm{B}_{m1} \u0026 \\bm{A}_{m2} \\cdot \\bm{B}_{m2} \u0026 \\cdots \u0026 \\bm{A}_{mn} \\cdot\\bm{B}_{mn} \\end{matrix}\\right] \\end{align*}$$容易知道，对于运算 $*$，满足以下性质：\n封闭性：任何两张图像正片叠底后仍是一张图像（这不废话么……）。 可结合性：$$(\\bm{A}*\\bm{B})*\\bm{C} = \\bm{A}*(\\bm{B}*\\bm{C})$$ 即多张图像正片叠底，最终效果与正片叠底顺序无关。 可交换性：$$\\bm{A}*\\bm{B} = \\bm{B}*\\bm{A}$$ 即两张图像正片叠底，最终效果与哪张图像作为底图无关。 具有零元 $$ \\bm{\\theta} = \\left[\\begin{matrix} \\bm{O} \u0026 \\bm{O} \u0026 \\cdots \u0026 \\bm{O} \\\\ \\bm{O} \u0026 \\bm{O} \u0026 \\cdots \u0026 \\bm{O} \\\\ \\vdots \u0026 \\vdots \u0026 \u0026 \\vdots \\\\ \\bm{O} \u0026 \\bm{O} \u0026 \\cdots \u0026 \\bm{O} \\end{matrix}\\right] $$ 其中 $\\bm{O} = [0,0,0]$。 即任何一张图像与纯黑图像正片叠底，都将得到纯黑图像。 具有幺元（单位元）$$ \\bm{e} = \\left[\\begin{matrix} \\bm{E} \u0026 \\bm{E} \u0026 \\cdots \u0026 \\bm{E} \\\\ \\bm{E} \u0026 \\bm{E} \u0026 \\cdots \u0026 \\bm{E} \\\\ \\vdots \u0026 \\vdots \u0026 \u0026 \\vdots \\\\ \\bm{E} \u0026 \\bm{E} \u0026 \\cdots \u0026 \\bm{E} \\end{matrix}\\right] $$ 其中 $\\bm{E} = [255,255,255]$。\n即任何一张图像与纯白图像正片叠底，都将得到原图像。 因此运算 $*$ 构成一个独异点（雾）。\n由性质4和5可知，正片叠底实现了“去白留黑”。\n容易看出，图层混合是对图像对应的像素块做相同的操作，定义图层混合运算仅需给出对于像素块的操作。\n反色 反色，通俗地讲就是将图像颜色“反转”，也就是每个像素块的颜色都变成 $[255-R,255-G,255-B]$。\n定义运算 $!$ 为反色运算，则\n$$ !\\bm{Image} = \\bm{e}-\\bm{Image} = [255-R,255-G,255-B] $$特别地，有：\n$$!\\bm{e} = \\bm{\\theta} \\\\ !\\bm{\\theta} = \\bm{e}$$经过反色操作，图像的黑色会变成白色，白色会变成黑色。\n滤色 滤色计算公式为：$!((!\\bm{A}) * (!\\bm{B})) = \\bm{e}-(\\bm{e}-\\bm{A})*(\\bm{e}-\\bm{B})$\n特别地，取 $\\bm{B} = \\bm{e}$，即与纯白图片滤色，则有\n$$!((!\\bm{A}) * (!\\bm{B})) = \\bm{e}-\\bm{\\theta} * (\\bm{e}-\\bm{A}) = \\bm{e}-\\bm{\\theta} = \\bm{e}$$取 $\\bm{B} = \\bm{\\theta}$，即与纯黑图片滤色，则有\n$$!((!\\bm{A}) * (!\\bm{B})) = \\bm{e}-\\bm{e} * (\\bm{e}-\\bm{A}) = \\bm{e}-(\\bm{e}-\\bm{A}) = \\bm{A}$$由上述公式可知，滤色实现了“去黑留白”。\n变亮\u0026amp;变暗 定义运算 $\\mathrm{MAX}$ 为变亮运算，$\\mathrm{MIN}$ 为变暗运算。分析每一个像素块，则：\n$$ \\begin{align*} \\mathrm{MAX}(\\bm{A}, \\bm{B}) \u0026= [\\mathrm{max}(R_1,R_2),\\mathrm{max}(G_1,G_2),\\mathrm{max}(B_1,B_2)] \\\\ \\\\ \\mathrm{MIN}(\\bm{A}, \\bm{B}) \u0026= [\\mathrm{min}(R_1,R_2),\\mathrm{min}(G_1,G_2),\\mathrm{min}(B_1,B_2)] \\end{align*}$$","date":"2025-10-12T00:00:00Z","image":"https://rd806.github.io/passage/interesting/math_in_images/jye-RuTMP0iI_ek-unsplash_hu_cf92822af7286e28.jpg","permalink":"https://rd806.github.io/passage/interesting/math_in_images/","title":"图像处理的数学原理"},{"content":"PA2：指令系统\n实验目的：\n掌握i386（IA-32）指令格式。 掌握NEMU平台的指令周期。 运行用户程序 任务：编写几条指令的helper函数, 使得第一个简单的C程序可以在NEMU中运行起来。\n流程：\nmake run运行NEMU。 按c执行程序。 查看报错信息，观察出现未知指令的内存地址和对应操作码。 编写对应的指令文件xxx-template.h，xxx.h，xxx.c。 在all-instr.h中添加对应的头文件。 在exec.c中对应位置添加操作名称。 添加call指令 查找call指令对应的Opcode等信息，可知操作码为e8。\ncall指令 编写call-template.h 1#include \u0026#34;cpu/exec/template-start.h\u0026#34; 2 3#define instr call 4 5// call + 相对偏移量（视为一个立即数） 6make_helper(concat(call_i_, SUFFIX)) { 7 // 解码偏移量（立即数） 8 int len = concat(decode_i_, SUFFIX)(cpu.eip + 1); 9 // 压栈操作 (push) 10 reg_l(R_ESP) -= DATA_BYTE; 11 // eip寄存器的下一位地址写入esp (mov) 12 MEM_W(reg_l(R_ESP), cpu.eip + len + 1); 13 // 加上立即数偏移量，实现跳转 14 cpu.eip += (DATA_TYPE_S)op_src-\u0026gt;val; 15 // 更新eip寄存器 16 print_asm(\u0026#34;call: 0x%x\u0026#34;, cpu.eip + len + 1); 17 return len + 1; 18} 19 20// call + 寄存器 21make_helper(concat(call_rm_, SUFFIX)) { 22 // 解码寄存器/内存 23 int len = concat(decode_rm_, SUFFIX)(eip + 1); 24 reg_l(R_ESP) -= DATA_BYTE; 25 MEM_W(reg_l(R_ESP), cpu.eip + len + 1); 26 cpu.eip = (DATA_TYPE_S)op_src-\u0026gt;val - len - 1; 27 print_asm(\u0026#34;call: %s\u0026#34;, op_src-\u0026gt;str); 28 return len + 1; 29} 30 31#include \u0026#34;cpu/exec/template-end.h\u0026#34; call指令示意 编写call.c 1#include \u0026#34;cpu/exec/helper.h\u0026#34; 2 3#define DATA_BYTE 1 4#include \u0026#34;call-template.h\u0026#34; 5#undef DATA_BYTE 6 7#define DATA_BYTE 2 8#include \u0026#34;call-template.h\u0026#34; 9#undef DATA_BYTE 10 11#define DATA_BYTE 4 12#include \u0026#34;call-template.h\u0026#34; 13#undef DATA_BYTE 14 15make_helper_v(call_i) 16make_helper_v(call_rm) 编写call.h 1#ifndef __CALL_H__ 2#define __CALL_H__ 3 4make_helper(call_i_v); 5make_helper(call_rm_v); 6 7#endif 在nemu/src/cpu/exec/all-instr.h中包含call.h，并在nemu/src/cpu/exec/exec.c中的opcode_table中填写相应的helper函数。 添加test指令 test指令 test指令其实相当于进行AND按位与操作，但是test是不会改变操作数的，只会改变EFLAGS寄存器中的标志位。\n标志位 名称 功能 CF 进位标志 如果运算的结果最高位产生了进位或借位，其值为1，否则为0。 PF 奇偶标志 计算运算结果里1的奇偶性，偶数为1，否则为0。 ZF 零标志 相关指令结束后判断是否为0，结果为0，其值为1，否则为0。 SF 符号标志 相关指令结束后判断正负，结果为负，其值为1，否则为0。 I 中断使能标志 表示能否响应外部中断，若能响应外部中断，其值为1，否则为0。 DF 方向标志 当DF为1，ESI、EDI自动递减，否则自动递增。 OF 溢出标志 反映有符号数运算结果是否溢出，如果溢出，其值为1，否则为0。 编写test-template.h 1#include \u0026#34;cpu/exec/template-start.h\u0026#34; 2 3#define instr test 4 5static void do_execute() { 6 // 两个操作数进行与运算 7 DATA_TYPE result = op_dest-\u0026gt;val \u0026amp; op_src-\u0026gt;val; 8 9 cpu.eflags.CF = 0; 10 cpu.eflags.OF = 0; 11 12 // 在/nemu/src/cpu/eflags.c中定义的函数 13 // 可根据结果自动修改eflags寄存器的值 14 update_eflags_pf_zf_sf((DATA_TYPE_S)result); 15 print_asm_template1(); 16} 17make_instr_helper(i2a) 18make_instr_helper(i2rm) 19make_instr_helper(r2rm) 20 21#include \u0026#34;cpu/exec/template-end.h\u0026#34; 程序中经常使用一些缩写，并已成为约定俗成的惯例。\n例如，为了方便理解，通常把to用2代替。因此i2rm表示立即数传到寄存器/内存中，r2rm表示寄存器传到寄存器/内存中。\ni18n与此类似，是internationalization的缩写，表示“国际化”。\n编写test.c 1#include \u0026#34;cpu/exec/helper.h\u0026#34; 2 3#define DATA_BYTE 1 4#include \u0026#34;test-template.h\u0026#34; 5#undef DATA_BYTE 6 7#define DATA_BYTE 2 8#include \u0026#34;test-template.h\u0026#34; 9#undef DATA_BYTE 10 11#define DATA_BYTE 4 12#include \u0026#34;test-template.h\u0026#34; 13#undef DATA_BYTE 14 15make_helper_v(test_i2a) 16make_helper_v(test_i2rm) 17make_helper_v(test_r2rm) 编写test.h 1#ifndef _TEST_H_ 2#define _TEST_H_ 3 4make_helper(test_i2a_b); 5make_helper(test_i2rm_b); 6make_helper(test_r2rm_b); 7 8make_helper(test_i2a_v); 9make_helper(test_i2rm_v); 10make_helper(test_r2rm_v); 11 12#endif 添加je指令 je指令 添加je指令有两种方法，一种是参考普通指令的执行方式，用static void do_execute创建函数并使用make_instr_helper()；另一种是直接定义一个新的make_jcc_helper()宏。这里采用后者，因为这样所有条件跳转如jne，jg，jge等都可以用make_jcc_helper()的宏实现。\n1#include \u0026#34;cpu/exec/template-start.h\u0026#34; 2 3// 条件跳转指令译码过程复杂，make_instr_helper无法使用，需要重新定义 4#define make_jcc_helper(cc) \\ 5 make_helper(concat4(j, cc, _, SUFFIX)) { \\ 6 int len = concat(decode_si_, SUFFIX)(eip + 1); \\ 7 print_asm(str(concat(j,cc)) \u0026#34; %x\u0026#34;,cpu.eip+op_src-\u0026gt;val+1+len+(DATA_BYTE == 4)); \\ 8 if (concat(check_cc_, cc)()) { \\ 9 cpu.eip += op_src-\u0026gt;val; \\ 10 } \\ 11 return len + 1; \\ 12 } 13 14#include \u0026#34;cpu/exec/template-end.h\u0026#34; 在include/cpu/eflags.h中定义比较函数：\n1static inline bool check_cc_e() { 2 return cpu.eflags.ZF == 1; 3} 这样在调用make_je_helper时就会使用check_cc_e函数判断是否更新eflags寄存器的值。\n添加其他指令 push指令 push指令 操作流程：\n① esp寄存器值减4，表示栈顶指针下移一个地址的长度。\n② 将读入的数据写入地址中，表示数据入栈。\ncmp指令 cmp指令 操作流程：\n① 记录源操作数-目标操作数的值。\n② 用所得的值更新eflags寄存器。\npop指令 pop指令 操作流程：\n① 向译码出的对象操作数中写入栈顶数据。\n② 栈顶指针加4，回到push前的状态。\nret指令 ret指令 操作流程：\n① 使eip跳转到esp中存放的地址处。\n② 栈顶指针加4。\n实现更多指令 jbe指令 在jcc-template.h指令中添加be字段，并在eflags.h中补充check_cc_be函数。\nleave指令 leave指令 操作流程：\n① 使esp指向ebp（栈底）所指的位置。\n② ebp指向esp所存的地址。\n③ 栈顶指针加4。\nadd指令 实现浮点数定点化 什么是定点化 我们约定最高位为符号位，接下来的15位表示整数部分，低16位表示小数部分，即约定小数点在第15和第16位之间（从第0位开始）。从这个约定可以看到，FLOAT类型其实是实数的一种定点表示。\n更通俗的解释是：定点化数的小数点位置是固定的；或者说，定点化数的小数位数是确定的。\n定点数 由这个定义，可以得出以下结论：\n对于一个实数a，它的FLOAT类型表示A = a * 2^16 = a \u0026lt;\u0026lt; 16。\n定点数的运算 在lib-common/FLOAT.h中定义定点数与整型的基本运算：\n1static inline int F2int(FLOAT a) { 2\t// 将定点数转换为整型 3\treturn (a \u0026gt;\u0026gt; 16); 4} 5 6static inline FLOAT int2F(int a) { 7\t// 将整型转换为定点数 8\treturn (a \u0026lt;\u0026lt; 16); 9} 10 11static inline FLOAT F_mul_int(FLOAT a, int b) { 12\t// 定点数与整型相乘 13\treturn a * b; 14} 15 16static inline FLOAT F_div_int(FLOAT a, int b) { 17\t// 定点数与整型相除 18\treturn a / b; 19} 在lib-common/FLOAT/FLOAT.c中定义浮点数到定点数的转化和定点数的运算：\n定义浮点数结构 1// 接收IEEE编码的浮点数 2typedef union { 3\tstruct { 4\tuint32_t m : 23;\t// 尾数位 5\tuint32_t e : 8;\t// 指数位 6\tuint32_t s : 1;\t// 符号位 7\t}; 8\tuint32_t val; 9} Float; 将浮点数转化为定点数 回忆浮点数的计算公式：对于一段32位长的浮点数编码，它对应的浮点数值为：$V = (-1)^s \\times M \\times 2^E$\n其中 $E = 1 - bias$，$M = 1 + f$\n1FLOAT f2F(float a) { 2\t/* You should figure out how to convert `a\u0026#39; into FLOAT without 3\t* introducing x87 floating point instructions. Else you can 4\t* not run this code in NEMU before implementing x87 floating 5\t* point instructions, which is contrary to our expectation. 6\t* 7\t* Hint: The bit representation of `a\u0026#39; is already on the 8\t* stack. How do you retrieve it to another variable without 9\t* performing arithmetic operations on it directly? 10\t*/ 11 12\tFloat f; 13\tvoid *temp = \u0026amp;a; 14\tf.val = *(uint32_t *) temp; // 联合体val接收IEEE编码 15 16\tuint32_t m = f.m | (1 \u0026lt;\u0026lt; 23);\t// 为尾数位添加1 17\t// 计算偏移量 18\tint shift = (int)f.e - (127+23-16); 19\t20\t// 对m执行偏移操作 21\tif(shift \u0026gt; 0) { 22\tm \u0026lt;\u0026lt;= shift; 23\t} 24\telse { 25\tm \u0026gt;\u0026gt;= (-shift); 26\t} 27 28\treturn (__sign(f.val) ? -m : m); 29} 浮点数转定点数 实现定点数的运算\n运行integral和quadratic-eq，补充缺失指令\n为简易调试器增加变量支持 在nemu/src/monitor/debug/elf.c文件中：\n1//sym是我们需要匹配的符号名称，success指针用于设置是否匹配成功 2uint32_t look_up_symtab(char *sym){ 3 int i; 4 //遍历符号表逐个匹配符号 5 for(i=0;i \u0026lt; nr_symtab_entry;i++){ 6 //逐个提取符号信息中的符号类别 7 uint8_t type = ELF32_ST_TYPE(symtab[i].st_info); 8 //当遇到类别为FUNC或者OBJECT时候匹配符号名 9 if((type == STT_FUNC || type == STT_OBJECT) \u0026amp;\u0026amp; strcmp(strtab + symtab[i].st_name, sym) == 0){ 10 //匹配成功后返回符号的地址 11 return symtab[i].st_value; 12 } 13 } 14 printf(\u0026#34;No sym found\u0026#34;); 15 return 0; 16} 实现kernel加载 kernel/src/elf/elf.c\n1... 2\t/* TODO: fix the magic number with the correct one */ 3 //修改为elf文件的魔数 4\tconst uint32_t elf_magic = 0x464c457f; 5\tuint32_t *p_magic = (void *)buf; 6\tnemu_assert(*p_magic == elf_magic); 7 8\t/* Load each program segment */ 9 //初始化ph指向program header开头，buf指向elf文件的开头，e_phoff为program header偏移量 10 ph = (void *)buf + elf-\u0026gt;e_phoff; 11 //eph指向program header的末尾，e_phnum为program header中segment的数量 12 //遍历program header表，加载需要加载的segment 13\tfor(Elf32_Phdr *eph = ph + elf-\u0026gt;e_phnum;ph \u0026lt; eph;ph++) { 14\t/* Scan the program header table, load each segment into memory */ 15\tif(ph-\u0026gt;p_type == PT_LOAD) { 16 uint32_t addr = ph-\u0026gt;p_vaddr; //存储segment加载到的目标地址 17\t/* TODO: read the content of the segment from the ELF file 18\t* to the memory region [VirtAddr, VirtAddr + FileSiz) 19\t*/ 20 //利用函数从当前segment中读取filesiz大小的数据到目标地址 21 ramdisk_read((void *)addr, ELF_OFFSET_IN_DISK + ph-\u0026gt;p_offset,ph-\u0026gt;p_filesz); 22\t23\t/* TODO: zero the memory region 24\t* [VirtAddr + FileSiz, VirtAddr + MemSiz) 25\t*/ 26 //通过函数将未初始化的数据置0 27 memset((void *)addr + ph-\u0026gt;p_filesz,0,ph-\u0026gt;p_memsz - ph-\u0026gt;p_filesz); 28... 进入PA3 → ","date":"2025-09-17T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/cslab/nemu/part2/","title":"NEMU-PART II"},{"content":" 磨刀不误砍柴工！！！\n实验目的：\n掌握i386（IA-32）指令格式。 掌握NEMU平台的指令周期。 切换用户程序 修改工程目录下的Makefile文件，更换NEMU的用户程序：\n1- USERPROG := obj/testcase/mov 2+ USERPROG := obj/testcase/mov-c 同理，将mov-c更换为testcase/src目录下的其他文件，例如add、bubble-sort等，即可执行对应的用户程序。\n了解NEMU的指令集 X86系列处理器采用变长指令字结构，各种指令长度随指令功能而异。\n要实现一条指令，首先你需要知道这条指令的格式和功能。格式决定如何解释，功能决定如何执行。这些信息都在 instruction set page（i386 手册第17 章）。\ni386 手册中的汇编语言格式都是 Intel 格式，而 objdump（反汇编）的默认格式是 AT\u0026amp;T 格式，两者的源操作数和目的操作数位置不一样，千万不要把它们混淆了！\n指令格式 x86指令的一般格式如下：\nx86指令的一般格式 Opcode（操作码）必定出现，其余组成部分可能不出现。Opcode决定是否出现ModR/M；SIB、Displacement、Immediate由ModR/M决定。 对于某些组成部分，其长度并不是固定的。 给定一条具体指令的二进制形式，其组成部分的划分是有办法确定的，不会产生歧义 例如对于以下指令：\n指令示例 它的划分如下：\n示例指令划分 ModR/M部分为什么解析出了disp32[--][--]？\nModR/M内部这一个字节的组成，分为了三个部分，具体每个部分的编码都对应着右边表内的含义，以ModR/M内的编码为基准进行查表就能够解析出对应的含义。\n例如例子中的ModR/M部分编码是84（十六进制），对应二进制就是10000100，对应回格式中的部分就是Mod部分为10，R/M部分为100，二者在右边表中可以对应出一行，这一行的对应指令就是disp32[--][--]。disp32代表偏移量（displacement）为32位的，两个[--][--]就代表我们需要解析SIB中的编码部分才能得到偏移量的具体数值。\n阅读Opcode Table 以mov指令的第一种形式为例：\nmov指令 列数 具体含义 Description 将一个8位寄存器中的数据传送到8位的寄存器或者内存中，其中r/m表示“寄存器或内存”。 Opcode 88表示这条指令的opcode的首字节是0x88，/r表示后面跟一个ModR/M字节，并且 ModR/M字节中的reg/opcode域解释成通用寄存器的编码。 Instruction r8表示8位寄存器；r/m8表示8位寄存器或内存，具体由mod字段决定。 通用寄存器编码 接下来的两种形式也就不难看懂了：但这两种形式的Opcode都是一样的，难道不会出现歧义吗？\nx86是通过指令一般格式中的 operand-size prefix来区分上面这两种形式的。\nOperand-size prefix的编码是0x66，作用是指示当前指令需要改变操作数的长度。在 IA-32 中，通常如果这个前缀没有出现，操作数长度默认是 32 位；当这个前缀出现的时候，操作数长度就改变成16位。\n换句话说，如果把一个开头为89 ...的比特串解释成指令，它就应该被解释成MOV r/m32, r32的形式；如果比特串的开头是66 89...，它就应该被解释成MOV r/m16, r16。\nC语言宏定义 在C语言中，可以使用命令#define来定义宏。宏不负责检查语法的正确性。\n1// 常规的宏 2#define PI 3.1415926 3// 带参数的宏 4#define putchar(x) putc(x, stdout) 5 6// 使用宏进行连接 7#define concat(x, y) x ## y 例如：\n1#define make_helper(name) int name(swaddr_t eip) 这个宏定义就代表了以下的两行代码是同一个代码，我们使用的时候看到的是上面部分函数，但是程序执行的时候实际上是在执行下面的函数（实际上就是同一个函数）：\n1make_helper(exec) 2int exec(swaddr_t eip) 在C语言中，宏必须定义在一行中。\n若需通过换行提高代码可读性，可使用\\附在每行末尾。\nNEMU的指令周期 取指 核心流程\n1void cpu_exec(volatile uint32_t n) { 2 ... 3 4 for(; n\u0026gt;0; n--) { 5 int instr_len = exec(cpu.eip); // 执行当前%eip所指向的指令 6 cpu.eip += instr_len; // %eip指向下一条指令 7 } 8 9 ... 10} 函数exec：\n1make_helper(exec) { //等价于 int exec(swaddr_t eip) 2 ops_decoded.opcode = instr_fetch(eip, 1); // 表示读取一个字节的操作码 3 return opcode_table[ops_decoded.opcode](eip); // 返回一个函数 4} 其中，函数instr_fetch()负责取指：\n1static inline uint32_t instr_fetch(swaddr_t addr, size_t len) { 2 return swaddr_read(addr, len); 3} instr_fetch()从eip处提取Opcode，存储到ops_decoded.opcode中。\n译码 所有指令的规则如下：\n内容 规则 指令 指令名称，具体由i386手册确定 形式 i2r，将立即数移动到寄存器 i2rm，将立即数移动到寄存器或内存 r2rm，将寄存器移动到寄存器或内存 操作数后缀 b表示操作数长度为8，v表示无法确定操作数长度，可能是16或32 通过opcode_table，根据提取到的Opcode找到对应的指令处理函数（如mov_i2r_v）。\n执行 对于同一指令的不同形式，它们的执行阶段是相同的。如mov_i2rm和mov_rm2r，它们的执行阶段都是将源操作数存储到目标操作数中。 对于不同指令的同一种形式，它们的译码阶段是相同的。如mov_i2rm和sub_rm2r，它们的译码阶段都是识别出一个立即数和一个rm操作数。 对于同一条指令同一种形式的不同长度，它们的译码阶段和执行阶段都非常类似。如mov_i2rm_b，mov_i2rm_w和mov_i2rm_l。它们都是识别出一个立即数和一个rm操作数，然后把立即数存入rm操作数。 访存 访存指令 写回 指令执行完后，eip指向下一条指令。\n编写指令的流程 编写指令模板文件xxx-template.h ① 在文件头尾分别包含cpu/exec/template-start.h和cpu/exec/template-end.h。\n② 定义宏instr为指令名称。\n③ 定义函数static void do_execute()，实现该指令的通用执行过程。\n④ 定义helper函数\n（1）若指令的译码方式在nemu/include/cpu/decode/decode.h中已经存在，那么可以考虑使用宏 make_instr_helper()来构造helper函数（大部分 helper 函数都可以通过这种方式构造）。\n（2）否则可以考虑添加相应的译码函数或者不使用make_instr_helper(), 而是直接使用make_helper()来定义helper函数，在函数体中直接进行译码，并调用do_execute()（可以参考nemu/src/cpu/exec/data-mov/xchg-template.h中的xchg_a2r指令类型。\n编写指令实例化文件xxx.c\n① 包含cpu/exec-helper.h。\n② 通过分别将宏DATA_BYTE定义成 1, 2, 4, 分别对指令模板文件xxx-template.h进行实例化。\n③ 若一个helper函数只会在某些操作数长度中用到，可以在xxx-template.h中通过条件编译的功能来指定（可以参考nemu/src/cpu/exec/data-mov/xchg-template.h中的xchg_a2r指令类型）。\n④ 必要时通过宏make_helper_v()定义相应的重载函数，根据指令的操作数长度前缀确定调用哪一个helper函数。\n编写指令头文件xxx.h，声明helper函数的原型。\n在nemu/src/cpu/exec/all-instr.h中包含xxx.h。\n在nemu/src/cpu/exec/exec.c中的opcode_table中填写相应的helper函数\n编写指令的流程 进入PA2 → ","date":"2025-09-16T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/cslab/nemu/part2-pre/","title":"NEMU-PART II Pre"},{"content":" 你说得对，但是NEMU是一个基于X86-64处理器模拟的IA-32操作系统。NEMU运行在一个被称作Docker的容器，在这里，被容器选中的人将被授予gcc，导引C语言之力。你将扮演一位名为Debug的神秘用户，编写众多C语言程序，在调试中找出FAIL的原因，同时逐步发掘Hit Bad Trap的真相。\n目标：制作一个32位的操作系统\n什么是NEMU 在X86-64处理器的机器上模拟一个32位操作系统（一个用来执行其它程序的程序！），它包括4个连贯的实验内容：\n阶段 任务 PA1 简易调试器 PA2 指令系统 PA3 存储管理 PA4 中断与I/O 认识NEMU NEMU的结构 NEMU的结构 调试器操作指令集 在nemu/src/monitor/debug/ui.c中定义了调试器的结构：\n1static struct { 2 char *name; 3 char *description; 4 // 函数指针，可指向*name，*description 5 int (*handler) (char *); 6} cmd_table [] = { 7 { \u0026#34;help\u0026#34;, \u0026#34;Display informations about all supported commands\u0026#34;, cmd_help }, 8 { \u0026#34;c\u0026#34;, \u0026#34;Continue the execution of the program\u0026#34;, cmd_c }, 9 { \u0026#34;q\u0026#34;, \u0026#34;Exit NEMU\u0026#34;, cmd_q }, 10 11 /* TODO: Add more commands */ 12 /* 接下来若想定义新的操作，格式为 13 { \u0026#34;name\u0026#34;, \u0026#34;description\u0026#34;, function}, 14 */ 15}; 几个有用的函数 函数 作用 Log() printf()的升级版，专门用来输出调试信息，同时还会输出使用Log()所在的源文件，行号和函数，当输出的调试信息过多的时候，可以很方便地定位到代码中的相关位置 Assert() assert()的升级版，当测试条件为假时，在assertion fail之前可以输出一些信息 panic() 用于输出信息并结束程序，相当于无条件的assertion fail swaddr_read() / swaddr_write() 访问模拟的内存 strtok() 一个简单的字符串分割工具，用于解析命令 sscanf() 可以从字符串中读入格式化的内容, 使用它有时候可以很方便地实现字符串的解析 PA1：简易调试器 机器永远是对的！ 未经过测试的每行代码永远是错误的！ RTFM！（阅读手册！） 实现正确的寄存器结构体 寄存器 在/nemu/include/cpu/reg.h中，原寄存器结构体定义为：\n1typedef struct { 2 struct { 3 uint32_t _32; 4 uint16_t _16; 5 uint8_t _8[2]; 6 } gpr[8]; 7 8 /* Do NOT change the order of the GPRs\u0026#39; definitions. */ 9 uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi; 10 ... 11} CPU_state; 使用结构体，每一个寄存器均独立存在，而X86系统的寄存器是共享的，例如 %eax 的后16位即为 %ax。因此应使用联合体的形式定义寄存器，这样对 %ax 操作时也会相应地改变 %eax 的值。\n1typedef struct { 2 union { 3 union { 4 uint32_t _32; 5 uint16_t _16; 6 uint8_t _8[2]; 7 } gpr[8]; 8 9 /* Do NOT change the order of the GPRs\u0026#39; definitions. */ 10 struct { 11 uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi; 12 };\t13 }; 14 ... 15} CPU_state; 实现调试器的功能 回顾nemu/src/monitor/debug/ui.c中对调试器的定义，需增加新的操作指令。\n指令名 示例 功能 si si 10 单步执行 info info r 打印寄存器状态 info w 打印监视点状态 x x N EXPR 扫描内存 p p EXPR 表达式求值 w w EXPR 设置监视点 d d N 删除监视点 1static struct { 2 char *name; 3 char *description; 4 int (*handler) (char *); 5} cmd_table [] = { 6 ... 7 // 定义单步执行操作，关键字为 si，以此类推 8 { \u0026#34;si\u0026#34;, \u0026#34;Single step execution\u0026#34;, cmd_si }, 9 { \u0026#34;info\u0026#34;, \u0026#34;Show register or monitor\u0026#39;s infomation\u0026#34;, cmd_info }, 10 { \u0026#34;x\u0026#34;, \u0026#34;Scan Memory\u0026#34;, cmd_x }, 11 ... 12}; 单步执行 在nemu/src/monitor/debug/ui.c中定义新的操作函数：\n1static int cmd_si(char *args) { 2 char *arg = strtok(NULL, \u0026#34; \u0026#34;); // 获取第二个字符 3 int step = 0; // 待操作步数 4 int i = 0; 5 6 if (arg == NULL) { 7 cpu_exec(1); 8 } 9 else { 10 sscanf(arg, \u0026#34;%d\u0026#34;, \u0026amp;step); // 将arg转换为整型数 11 if (step \u0026lt;= 0) { 12 printf(\u0026#34;Illegal input!\u0026#34;); 13 } 14 else { 15 for(; i\u0026lt;step; i++) { 16 cpu_exec(1); 17 } 18 } 19 } 20 return 0; 21} 报错请查看：\r使用循环时，循环变量的初始化应在循环结构之前，否则会报错： 1nemu/src/monitor/debug/ui.c:55: error: \u0026#39;for\u0026#39; loop initial declarations are only allowed in C99 mode 2nemu/src/monitor/debug/ui.c:55: note: use option -std=c99 or -std=gnu99 to compile your code 读取函数应使用 sscanf。 打印寄存器状态 同理，定义操作函数cmd_info\n1static int cmd_info(char *args) { 2 char *arg = strtok(NULL, \u0026#34; \u0026#34;); // 获取第二个字符 3 int i = 0; 4 5 if (*arg == \u0026#39;r\u0026#39;) { // 参数为\u0026#39;r\u0026#39;时打印寄存器的值 6 for(; i\u0026lt;8; i++) { 7 // 打印eax, ecx, edx, ebx, esp, ebp, esi, edi 8个寄存器 8 printf(\u0026#34;%s\\t\\t\u0026#34;, regsl[i]); // 打印寄存器名称 9 // 先打印16进制值，再打印10进制值（仿GDB） 10 // \u0026#34;\\t\u0026#34; 为制表符，让输出更美观 11 printf(\u0026#34;0x%08x\\t\\t%d\\n\u0026#34;, cpu.gpr[i]._32, cpu.gpr[i]._32); 12 } 13 // 打印%eip 寄存器 14 printf(\u0026#34;eip\\t\\t0x%08x\\t\\t%d\\n\u0026#34;, cpu.eip, cpu.eip); 15 } 16 else { 17 printf(\u0026#34;Illegal input!\\n\u0026#34;); 18 } 19 20 return 0; 21} 扫描内存 1static int cmd_x(char *args) { 2 char *arg_1 = strtok(NULL, \u0026#34; \u0026#34;); // 获取第1个参数 N 3 char *arg_2 = strtok(NULL, \u0026#34; \u0026#34;); // 获取第2个参数 EXPR 4 int i = 0; 5 int j = 0; 6 7 int N; 8 swaddr_t address;\t9 10 sscanf(arg_1, \u0026#34;%d\u0026#34;, \u0026amp;N); 11 sscanf(arg_2, \u0026#34;%x\u0026#34;, \u0026amp;address);\t// 获取起始内存地址 12 13 for(; i\u0026lt;N; i++) { 14 // 每行打印4个值 15 if (j%4 == 0) { 16 printf(\u0026#34;0x%x:\u0026#34;, address); 17 } 18 19 // 每4字节打印一个值 20 printf(\u0026#34;0x%08x \u0026#34;, swaddr_read(address, 4)); 21 address += 4; 22 j++; 23 24 // 4个值后换行 25 if (j%4 == 0) { 26 printf(\u0026#34;\\n\u0026#34;); 27 } 28 } 29 30 printf(\u0026#34;\\n\u0026#34;); 31 return 0; 32} 表达式求值 阶段1：词法分析\n定义token 在/nemu/src/monitor/debug/expr.c中，观察token结构体，它包含两个数据type和str：\n1typedef struct token { 2 int type; // 记录token的类型 3 char str[32]; // 记录token的具体数据 4} Token; 容易发现，当token为+, -, \u0026amp;等单运算符时，只需要记录它的type即可，因为它们的type唯一标识了各自的具体数据。\n在/nemu/src/monitor/debug/expr.c的列举类中，定义token的类型。\n1enum { 2 NOTYPE = 256, 3 NUM = 1, // 10进制数 4 REGISTER = 2, // 寄存器 5 HEX = 3, // 16进制数 6 EQ = 4, // 相等 7 NOTEQ = 5, // 不相等 8 OR = 6, // 或运算 9 AND = 7, // 与运算 10 POINT, // 指针 11 NEG 12 13 /* TODO: Add more token types */ 14 15}; 定义了枚举类后，相应的字段和数字就确定了唯一对应的关系。例如，type = NUM和type = 1均表示10进制整数。\n定义正则表达式 在/nemu/src/monitor/debug/expr.c中，定义正则表达式：\n1static struct rule { 2 char *regex; 3 int token_type; 4} rules[] = { 5 6 /* TODO: Add more rules. 7 * Pay attention to the precedence level of different rules. 8 */ 9 10 {\u0026#34; +\u0026#34;,\tNOTYPE}, // spaces 空格 11 12 {\u0026#34;\\\\+\u0026#34;, \u0026#39;+\u0026#39;}, // plus 运算符 13 {\u0026#34;\\\\-\u0026#34;, \u0026#39;-\u0026#39;}, 14 {\u0026#34;\\\\*\u0026#34;, \u0026#39;*\u0026#39;}, 15 {\u0026#34;\\\\/\u0026#34;, \u0026#39;/\u0026#39;}, 16 17 {\u0026#34;\\\\$[a-z]+\u0026#34;, REGISTER}, // 数据 18 {\u0026#34;0x[0-9a-fA-F]+\u0026#34;, HEX}, 19 {\u0026#34;[0-9]+\u0026#34;, NUM}, 20 21 {\u0026#34;==\u0026#34;, EQ}, // equal 22 {\u0026#34;!=\u0026#34;, NOTEQ}, 23 24 {\u0026#34;\u0026amp;\u0026amp;\u0026#34;, AND}, // 逻辑运算符 25 {\u0026#34;\\\\|\\\\|\u0026#34;, OR}, 26 {\u0026#34;!\u0026#34;, \u0026#39;!\u0026#39;}, 27 28 {\u0026#34;\\\\(\u0026#34;, \u0026#39;(\u0026#39;}, // 括号 29 {\u0026#34;\\\\)\u0026#34;, \u0026#39;)\u0026#39;}, 30}; 正则表达式的作用是识别当前表达式的具体内容。例如，对于表达式4 + 3 * ( 2 - 1 )，正则表达式的识别结果应为：\n识别token 识别token 在/nemu/src/monitor/debug/expr.c中的make_token函数可以帮助我们实现这一工作。\n1static bool make_token(char *e) { 2 ... 3 while(e[position] != \u0026#39;\\0\u0026#39;) { 4 ... 5 for(i = 0; i \u0026lt; NR_REGEX; i ++) { 6 ... 7 // 清空token值，防止每次运算相互干扰 8 int j = 0; 9 for(; j \u0026lt; 32; j++) { 10 tokens[nr_token].str[j] = \u0026#39;\\0\u0026#39;; 11 } 12 13 // tokens.type的赋值函数 14 switch(rules[i].token_type) { 15 case 256: 16 break; 17 18 // 输入10进制数、寄存器、16进制数 19 case NUM: 20 tokens[nr_token].type = NUM; 21 strncpy(tokens[nr_token].str, \u0026amp;e[position - substr_len], substr_len); 22 nr_token++; 23 break; 24 25 // REGISTER，HEX，EQ，NOTEQ，AND，OR与之类似 26 27 ... 28 29 // 输入单运算符 30 case \u0026#39;+\u0026#39;: 31 tokens[nr_token].type = \u0026#39;+\u0026#39;; 32 nr_token++; 33 break; 34 35 // -, *, /, !, (, ) 与之类似 36 37 ... 38 39 default: 40 assert(0); 41 } 42 break; 43 } 44 } 45} 以其中一个为例：\n1case NUM: 2 // token的类型为NUM 3 tokens[nr_token].type = NUM; 4 // 将sub_strlen长度的值存储到tokens.str 5 strncpy(tokens[nr_token].str, \u0026amp;e[position - substr_len], substr_len); 6 // 开始读取下一个token 7 nr_token++; 8 // 跳出switch循环 9 break; 阶段2：表达式求值\n判断表达式括号匹配 1bool check_parentheses(int p, int q) { 2 int a = 0; // 记录表达式token下标 3 int i = 0, j = 0; // 分别记录左、右括号总数 4 5 // 检查表达式首尾是否为括号 6 if(tokens[p].type == \u0026#39;(\u0026#39; || tokens[q].type == \u0026#39;)\u0026#39;) { 7 for(a = p; a\u0026lt;=q; a++) { 8 if(tokens[a].type == \u0026#39;(\u0026#39;) { 9 i++; 10 } 11 if(tokens[a].type == \u0026#39;)\u0026#39;) { 12 j++; 13 } 14 if(a != q \u0026amp;\u0026amp; i == j) { 15 // 排除例如 (a+b)) 这种情况 16 return false; 17 } 18 } 19 20 if(i == j) { 21 // 左右括号数量相等，正确 22 return true; 23 } 24 else { 25 // 数量不等，错误 26 return false; 27 } 28 } 29 30 return false; 31} 寻找主操作符 dominant operator（主操作符）是表达式中最后参与运算的运算符，根据运算符优先级可知：\n非运算符的token不是dominant operator。 出现在一对括号中的token不是dominant operator。注意到这里不会出现有括号包围整个表达式的情况，因为这种情况已经在check_parentheses()相应的if块中被处理了。 dominant operator的优先级在表达式中是最低的。这是因为dominant operator是最后一步才进行的运算符。 当有多个运算符的优先级都是最低时，根据结合性，最后被结合的运算符才是dominant operator。一个例子是1 + 2 + 3，它的dominant operator应该是右边的+。 找到主操作符后，表达式的运算可归结为主操作符两侧数的运算。这也就意味着该问题满足了分治的基本条件：一个问题可分解为若干个与原问题结构相同的子问题。\n参阅此处：分治法 1int dominant_operator(int p, int q) { 2 int step = 0; 3 int op = -1; 4 int i = 0; // 记录token下标 5 int pri = 0; // 记录当前操作符优先级 6 7 for(i = p; i \u0026lt;= q; i++) { 8 if(tokens[i].type == \u0026#39;(\u0026#39;) { 9 step ++; 10 } 11 else if(tokens[i].type == \u0026#39;)\u0026#39;) { 12 step --; 13 } 14 15 if(step == 0) { 16 if(tokens[i].type == OR) { 17 if(pri \u0026lt; 51) { 18 op = i; 19 pri = 51; 20 } 21 } 22 else if(tokens[i].type == AND) { 23 if(pri \u0026lt; 50) { 24 op = i; 25 pri = 50; 26 } 27 } 28 else if(tokens[i].type == EQ || tokens[i].type == NOTEQ) { 29 if(pri \u0026lt; 49) { 30 op = i; 31 pri = 49; 32 } 33 } 34 else if(tokens[i].type == \u0026#39;+\u0026#39; || tokens[i].type == \u0026#39;-\u0026#39;) { 35 if(pri \u0026lt; 48) { 36 op = i; 37 pri = 48; 38 } 39 } 40 else if(tokens[i].type == \u0026#39;*\u0026#39; || tokens[i].type == \u0026#39;/\u0026#39;) { 41 if(pri \u0026lt; 46) { 42 op = i; 43 pri = 46; 44 } 45 }\t46 } 47 else if(step \u0026lt; 0) { 48 return -2; 49 } 50 } 51 return op; 52} 递归计算表达式的值 这里运用的就是分治算法。\n1uint32_t eval(int p, int q) { 2 int result = 0; 3 int op = 0; 4 int val1, val2; 5 6 // 表达式左侧超过右侧，错误 7 if (p \u0026gt; q) { 8 assert(0); 9 } 10 11 // 表达式左侧等于右侧，说明为单个数字 12 else if (p == q) { 13 // 处理10进制数 14 if (tokens[p].type == NUM) { 15 sscanf(tokens[p].str, \u0026#34;%d\u0026#34;, \u0026amp;result); 16 return result; 17 } 18 19 // 处理16进制数 20 else if (tokens[p].type == HEX) { 21 int i = 2; 22 while(tokens[p].str[i] != 0) { 23 result *= 16; 24 if (tokens[p].str[i] \u0026lt;= \u0026#39;9\u0026#39;) { 25 // 16进制为0-9 26 result += tokens[p].str[i] - \u0026#39;0\u0026#39;; 27 } 28 else { 29 // 16进制为a-f 30 result += tokens[p].str[i] - \u0026#39;a\u0026#39; + 10;\t31 } 32 i++; 33 } 34 return result; 35 } 36 37 // 处理寄存器 38 else if (tokens[p].type == REGISTER) { 39 if (!strcmp(tokens[p].str, \u0026#34;$eax\u0026#34;)) { 40 return cpu.eax; 41 } 42 43 // 剩下的寄存器使用相同的处理办法 44 45 ... 46 47 else { 48 return 0; 49 } 50 } 51 else { 52 assert(0); 53 } 54 } 55 56 // 表达式两侧不等，但是括号匹配，去掉括号 57 else if (check_parentheses(p, q) == true) { 58 return eval(p + 1, q - 1); 59 } 60 61 // 正常表达式 62 else { 63 // 寻找主操作符 64 op = dominant_operator(p, q); 65 66 if (op == -2) { 67 assert(0); 68 } 69 70 // 处理一元运算符 71 else if (op == -1) { 72 // 处理逻辑非运算，如 !1 73 if (tokens[p].type == \u0026#39;!\u0026#39;) { 74 sscanf(tokens[q].str, \u0026#34;%d\u0026#34;, \u0026amp;result); 75 return !result; 76 } 77 78 // 之后将在此处实现负数运算和指针解引用 79 80 } 81 82 // 计算主操作数两侧表达式值 83 84 val1 = eval(p, op - 1); // 计算主操作数左侧表达式 85 val2 = eval(op + 1, q); // 计算主操作数右侧表达式 86 87 switch (tokens[op].type) { 88 case \u0026#39;+\u0026#39; : 89 return val1 + val2;\t90 91 // -, *, / , OR, AND, EQ, NOTEQ运算以此类推 92 93 ... 94 95 default : 96 assert(0); 97 } 98 } 99 return 0; 100} 举例：\n分治法求表达式的值 expr函数 1uint32_t expr(char *e, bool *success) { 2 if(!make_token(e)) { 3 *success = false; 4 return 0; 5 } 6 7 /* TODO: Insert codes to evaluate the expression. */ 8 9 int i; 10 for (i = 0; i \u0026lt; nr_token; i++){ 11 if (tokens[i].type == \u0026#39;*\u0026#39; \u0026amp;\u0026amp; (i == 0 || (tokens[i - 1].type != NUM \u0026amp;\u0026amp; tokens[i - 1].type != HEX \u0026amp;\u0026amp; tokens[i - 1].type != \u0026#39;)\u0026#39;))){ 12 tokens[i].type = POINT; 13 } 14 if (tokens[i].type == \u0026#39;-\u0026#39; \u0026amp;\u0026amp; (i == 0 || (tokens[i - 1].type != NUM \u0026amp;\u0026amp; tokens[i - 1].type != HEX \u0026amp;\u0026amp; tokens[i - 1].type != \u0026#39;)\u0026#39;))){ 15 tokens[i].type = NEG; 16 } 17 } 18 return eval(0, nr_token - 1); 19 20 // panic(\u0026#34;please implement me\u0026#34;); 21 return 0; 22} 最终实现 在/nemu/src/monitor/debug/ui.c中写入cmd_p函数：\n1static int cmd_p(char *args) { 2 bool *success = false; 3 int result = 0; 4 result = expr(args, success); 5 if(!success) { 6 printf(\u0026#34;%d\\n\u0026#34;, result); 7 } 8 return 0; 9} 表达式求值功能正式实现。\n选做任务：实现负数运算和指针解引用\r在eval函数中加入以下内容：\n1uint32_t eval(int p, int q) { 2 3 ... 4 5 // 正常表达式 6 else { 7 // 处理一元运算符 8 else if (op == -1) { 9 10 ... 11 12 // 处理带负数的表达式，如 1+ -1 13 if (tokens[p].type == NEG) { 14 sscanf(tokens[q].str, \u0026#34;%d\u0026#34;, \u0026amp;result); 15 return -result; 16 } 17 18 // 实现指针解引用 19 else if (tokens[p].type == POINT) { 20 if (!strcmp(tokens[p + 2].str, \u0026#34;$eax\u0026#34;)){ 21 result = swaddr_read(cpu.eax, 4); 22 return result; 23 } 24 25 // 其余寄存器采用类似操作 26 27 ... 28 } 29 } 30 } 31} 监视点 新建监视点 在nemu/src/monitor/debug/watchpoint.c中，定义函数new_wp()：\n1// 从free_链表中返回一个空闲监视点 2WP* new_wp() { 3 WP *temp; 4 temp = free_; // free_链表的头节点作为返回值 5 free_ = free_-\u0026gt;next; // free_链表的下一个节点成为头节点 6 temp-\u0026gt;next = NULL; // 空闲监视点为head链表的尾节点 7 8 // 若head链表为空，返回的节点成为头节点 9 if(head == NULL) { 10 head = temp; 11 } 12 // head链表不为空，寻找其尾节点 13 else { 14 WP *p; 15 p = head; 16 // 将返回的节点插入head链表的尾部 17 while (p-\u0026gt;next != NULL) { 18 p = p-\u0026gt;next; 19 } 20 p-\u0026gt;next = temp; 21 } 22 return temp; 23} 示意图如下：\n监视点链表 释放监视点 同理，在nemu/src/monitor/debug/watchpoint.c中定义：\n1// 释放监视点至free_链表 2void free_wp(WP *wp) { 3 if(wp == NULL) { 4 assert(0); // 返回节点为空 5 } 6 else if (wp == head) { 7 head = head-\u0026gt;next; 8 } 9 else { 10 WP* temp = head; 11 // 找到head链表待删除节点的前一个节点 12 while(temp != NULL \u0026amp;\u0026amp; temp-\u0026gt;next != wp) { 13 temp = temp-\u0026gt;next; 14 } 15 // 取消待删除节点与其后节点的连接 16 temp-\u0026gt;next = wp-\u0026gt;next; 17 } 18 19 // 待删除节点成为free链表的头节点 20 wp-\u0026gt;next = free_; 21 free_ = wp; 22 23 // 清空待删除节点的内容 24 wp-\u0026gt;result = 0; 25 wp-\u0026gt;expr[0] = \u0026#39;\\0\u0026#39;; 26} 释放监视点实际上就是新建监视点的逆操作，换言之，就是将head链表待删除的节点变成free链表的头节点。\n判断监视点是否触发 在nemu/src/monitor/debug/watchpoint.c中定义：\n1// 判断监视点是否触发 2bool checkWP() { 3 bool check = false;\t// 最终返回值 4 5 bool *success = false; 6 WP *temp = head; // 从head链表的头节点开始遍历 7 int expr_temp; 8 9 while(temp != NULL) { 10 expr_temp = expr(temp-\u0026gt;expr, success); 11 if (expr_temp != temp-\u0026gt;result){ 12 check = true; 13 printf (\u0026#34;Hint watchpoint %d at address 0x%08x\\n\u0026#34;, temp-\u0026gt;NO, cpu.eip); 14 temp = temp-\u0026gt;next; 15 continue; 16 // 检测到监视点对应的值发生变化 17 } 18 temp-\u0026gt;result = expr_temp; 19 temp = temp-\u0026gt;next; 20 }\t21 return check; 22} 在/nemu/src/monitor/cpu-exec.c中加入以下内容：\n1/* TODO: check watchpoints here. */ 2 3// 链接外部函数 4extern bool checkWP(); 5bool change = checkWP(); 6if (change) { 7 nemu_state = STOP; 8} 打印监视点和删除监视点 1// 打印所有监视点 2void printf_wp(){ 3 WP *temp = head; 4 if (temp == NULL){ 5 printf(\u0026#34;No watchpoints\\n\u0026#34;); 6 } 7 while (temp != NULL){ 8 printf(\u0026#34;Watch point %d: %s\\n\u0026#34;, temp-\u0026gt;NO, temp-\u0026gt;expr); 9 temp = temp-\u0026gt;next; 10 } 11} 12 13// 删除监视点 14WP* delete_wp(int p, bool *key){ 15 WP *temp = head; 16 while (temp != NULL \u0026amp;\u0026amp; temp-\u0026gt;NO != p){ 17 temp = temp-\u0026gt;next; 18 } 19 if (temp == NULL){ 20 *key = false; 21 } 22 return temp; 23} 加入调试器指令 最后在/nemu/src/monitor/debug/ui.c中加入指令函数：\n1// 打印监视器的值 2static int cmd_info(char *args) { 3\tchar *arg = strtok(NULL, \u0026#34; \u0026#34;); // 获取第二个字符 4 5\t... 6 7\telse if(*arg == \u0026#39;w\u0026#39;) { 8\textern void printf_wp(); 9\tprintf_wp(); 10\t} 11 12\t... 13 14\treturn 0; 15} 16 17// 设置监视点 18static int cmd_w(char *args) { 19 20 extern WP* new_wp(); 21 WP* temp = new_wp(); 22 23 bool *success = false; 24 int result = 0; 25 result = expr(args, success); 26 27 if(!success) { 28 // 若表达式合法，将对应的值赋给temp这个新监视点 29 temp-\u0026gt;result = result; 30 strcpy(temp-\u0026gt;expr, args); 31 } 32 33 return 0; 34} 35 36// 删除监视点 37static int cmd_d(char *args) { 38 int p = 0; 39 bool key = true; 40 sscanf(args, \u0026#34;%d\u0026#34;, \u0026amp;p); 41 42 // 记得链接外部函数 43 extern WP* delete_wp(); 44 extern void free_wp(); 45 WP *q = delete_wp(p, \u0026amp;key); 46 47 if (key){ 48 printf(\u0026#34;Delete watchpoint %d: %s\\n\u0026#34;, q-\u0026gt;NO, q-\u0026gt;expr); 49 free_wp(q); 50 return 0; 51 } 52 else { 53 printf(\u0026#34;No found watchpoint %d\\n\u0026#34;, p); 54 return 0; 55 } 56 57 return 0; 58} 思考题 思考题1：opcode_table到底是一个什么类型的数组？\n解答\ropcode_table数组是一个函数指针数组。\n思考题2（1）：在cmd_c()函数中, 调用cpu_exec()的时候传入了参数-1 , 你知道为什么吗?\n解答\r-1是无符号类型最大的数字，所以函数里的for循环可以执行所有指令。\n思考题2（2）：框架代码中定义wp_pool等变量的时候使用了关键字static，static在此处 的含义是什么? 为什么要在此处使用它?\n解答\rstatic在此处的含义是静态全局变量，该变量只能被本文件中的函数调用，并且是全局变量，而不能被同一程序其他文件中的函数调用，使用static是为了避免它被误修改。\n思考题3-1：EFLAGS寄存器中的CF位是什么意思?\n解答\ri386手册里P34页中和参阅附录c提到，CF是进位标志。 EFLAGS寄存器 思考题3-2：ModR/M字节是什么?\n解答\rP241-243页。ModR/M 由 Mod，Reg/Opcode，R/M 三个部分组成。 Mod 是前两位，提供寄存器寻址和内存寻址， Reg/Opcode为3-5位，如果是Reg表示使用哪个寄存器，Opcode表示对group属性的Opcode进行补充； R/M为6-8位，与mod结合起来会得到8个寄存器和24个内存寻址。 ModR/M 思考题3-3：mov指令的具体格式是怎么样的?\n解答\rP345页，格式是DEST ← SRC。 mov指令 思考题3-4： 完成 PA1 的内容之后, nemu目录下的所有.c和.h和文件总共有多少行代码? 你是使用什么命令得到这个结果的？和框架代码相比, 你在PA1中编写了多少行代码？你可以把这条命令写入Makefile中, 随着实验进度的推进, 你可以很方便地统计工程的代码行数, 例如敲入 make count就会自动运行统计代码行数的命令。再来个难一点的, 除去空行之外, nemu目录下的所有.c和.h文件总共有多少行代码？\n解答\r通过find . -name \u0026quot;*[.h/.c]\u0026quot; | xargs wc -l命令，得到4376行。和框架代码4197行相比, 我在 PA1中编写了606行代码。\n通过find . -name \u0026quot;*[.h/.c]\u0026quot; | xargs grep \u0026quot;^.\u0026quot; | wc -l命令计算去除空行的所有.c .h文件得到了3900行代码。\nmake count指令如下：\nmake count\n​@find nemu/ -name “.c” -o -name “.h” | xargs cat | grep -v ^$$ | wc -l\n思考题3-5：打开工程目录下的Makefile文件, 你会在CFLAGS变量中看到 gcc 的一些编译选项。请解释 gcc 中的-Wall和-Werror有什么作用? 为什么要使用-Wall和-Werror？\n解答\r-Wall使GCC编译后显示所有的警告信息。-Werror会将将所有的警告当成错误进行处理，并且取消编译操作。使用-Wall和-Werror就是为了找出可能存在的错误，尽可能地避免程序运行出错，优化程序。\n至此，PA1全部完成\nPA2预备知识 ","date":"2025-09-08T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/cslab/nemu/part1/","title":"NEMU-PART I"},{"content":"以下由Hugo的stack主题演示，其他的可作为参考。\n修改方法来源：莱特雷-letere 引入APlayer 在Hugo工作文件夹的layouts/partials/footer文件夹中新建一个文件，命名为 aplayer.html。\n在 aplayer.html中输入以下内容：\n1\u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css\u0026#34;\u0026gt; 2\u0026lt;div id=\u0026#34;aplayer\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; 3\u0026lt;script src=\u0026#34;https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; 4 5\u0026lt;script\u0026gt; 6 const ap = new APlayer({ 7 container: document.getElementById(\u0026#39;aplayer\u0026#39;), 8 fixed: true, 9 listFolded: true, 10 lrcType: 3, 11 audio: [{ 12 name: \u0026#39;example\u0026#39;, 13 artist: \u0026#39;example\u0026#39;, 14 url: \u0026#39;https://example.mp3\u0026#39;, 15 lrc: \u0026#39;example.lrc\u0026#39;, 16 cover: \u0026#39;example.png\u0026#39; 17 }] 18 }); 19\u0026lt;/script\u0026gt; 在layouts/partials/footer中新建一个文件夹，命名为custom.html，在其中输入： 1{{ partialCached \u0026#34;footer/aplayer.html\u0026#34; . }} 这样，aplayer就成功导入到网页中了。\n修改APlayer样式 实现播放进度保存 1\u0026lt;script\u0026gt; 2 /** 3 * 页面销毁前监听 4 */ 5 window.onbeforeunload = () =\u0026gt; { 6 // 将播放信息用对象封装，并存入到localStorage中 7 const playInfo = { 8 index: ap.list.index, 9 currentTime: ap.audio.currentTime, 10 paused: ap.paused 11 }; 12 localStorage.setItem(\u0026#34;playInfo\u0026#34;, JSON.stringify(playInfo)); 13 }; 14 15 /** 16 * 页面加载后监听 17 */ 18 window.onload = () =\u0026gt; { 19 // 从localStorage取出播放信息 20 const playInfo = JSON.parse(localStorage.getItem(\u0026#34;playInfo\u0026#34;)); 21 if (!playInfo) { 22 return; 23 } 24 // 切换歌曲 25 ap.list.switch(playInfo.index); 26 // 等待500ms再执行下一步(切换歌曲需要点时间，不能立马调歌曲进度条) 27 setTimeout(() =\u0026gt; { 28 // 调整时长 29 ap.seek(playInfo.currentTime); 30 // 是否播放 31 if (!playInfo.paused) { 32 ap.play() 33 } 34 }, 500); 35 }; 36\u0026lt;/script\u0026gt; 实现隐藏播放器图标 1\u0026lt;style\u0026gt; 2 .aplayer-fixed.aplayer-narrow .aplayer-body { 3 left: -70px !important; 4 /* 默认情况下缩进左侧70px，只留一点箭头部分 */ 5 } 6 7 .aplayer-fixed.aplayer-narrow .aplayer-body:hover { 8 left: 0 !important; 9 /* 鼠标悬停是左侧缩进归零，完全显示按钮 */ 10 } 11\u0026lt;/style\u0026gt; 导入pjax实现音乐不间断播放 pjax是一项页面切换不加载技术，可实现切换网页后音乐不间断。\n导入pjax 在layouts/partials/footer中新建文件，命名为pjax.html.\n在文件中写入代码：\n1\u0026lt;script src=\u0026#34;https://cdn.jsdelivr.net/npm/pjax/pjax.min.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; 2\u0026lt;script\u0026gt; 3 var pjax = new Pjax({ 4 selectors: [ 5 \u0026#34;.main-container\u0026#34; 6 ] 7 }) 8\u0026lt;/script\u0026gt; 这样pjax就成功导入网页中了。\n修复网页样式 在pjax.html中加入以下内容：\n1\u0026lt;script\u0026gt; 2 pjax._handleResponse = pjax.handleResponse; 3 pjax.handleResponse = function(responseText, request, href, options) { 4 if (request.responseText.match(\u0026#34;\u0026lt;html\u0026#34;)) { 5 if (responseText) { 6 // 将新页面的html字符串解析成DOM对象 7 let newDom = new DOMParser().parseFromString(responseText, \u0026#39;text/html\u0026#39;); 8 // 获取新页面中body的className，并设置回当前页面 9 let bodyClass = newDom.body.className; 10 document.body.setAttribute(\u0026#34;class\u0026#34;, bodyClass) 11 // 放行，交给pjax自己处理 12 pjax._handleResponse(responseText, request, href, options); 13 } 14 } else { 15 // handle non-HTML response here 16 } 17 } 18\u0026lt;/script\u0026gt; 修复主题切换 在pjax.html中加入以下内容。\n1\u0026lt;script\u0026gt; 2 document.addEventListener(\u0026#39;pjax:complete\u0026#39;, () =\u0026gt; { 3 // Stack脚本初始化 4 window.Stack.init(); 5 }) 6\u0026lt;/script\u0026gt; 修复搜索 修改assets/ts/search.tsx代码，封装方法并export 1/** 2 * 记得把window.addEventListener(\u0026#39;load\u0026#39; ...这部分代码注释掉 3 * 初始化工作交给Stack.init()处理了，不需要这个了 4 */ 5... 6function searchInit() { 7 let search = document.querySelector(\u0026#39;.search-result\u0026#39;); 8 if (search) { 9 const searchForm = document.querySelector(\u0026#39;.search-form\u0026#39;) as HTMLFormElement, 10 searchInput = searchForm.querySelector(\u0026#39;input\u0026#39;) as HTMLInputElement, 11 searchResultList = document.querySelector(\u0026#39;.search-result--list\u0026#39;) as HTMLDivElement, 12 searchResultTitle = document.querySelector(\u0026#39;.search-result--title\u0026#39;) as HTMLHeadingElement; 13 14 new Search({ 15 form: searchForm, 16 input: searchInput, 17 list: searchResultList, 18 resultTitle: searchResultTitle, 19 resultTitleTemplate: window.searchResultTitleTemplate 20 }); 21 } 22} 23 24export { 25 searchInit 26} 修改assets/ts/main.ts，引入搜索初始化方法并调用 1... 2import { searchInit } from \u0026#34;ts/search\u0026#34;; 3let Stack = { 4 init: () =\u0026gt; { 5 ... 6 // 调用search脚本初始化方法 7 searchInit(); 8 } 9} tsx 类型的文件引入方式有点特殊，需要我们修改main.ts的引入方式，修改layouts/partials/footer/components/script.html，改法参考layouts/page/search.html，把JSXFactory，createElement补充上就好\n修改assets/ts/search.tsx，在动态渲染数据方法末尾让pjax重新解析文档\n1private async doSearch(keywords: string[]) { 2 ... 3 /* 4 方法末尾，让pjax重新解析文档数据，识别动态渲染的数据 5 虽然当前文件没有pjax对象，但最后静态页面会生成一个整体的js文件 6 pjax对象那时就能识别到，就可成功调用 7 */ 8 pjax.refresh(document); 9} 修复Latex 修改layouts/partials/article/components/math.html，添加一个元素标签，便于判断文档是否使用了KaTeX 1\u0026lt;div class=\u0026#34;math-katex\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; 在layouts/partials/footer/custom.html中引入以下代码： 1\u0026lt;script\u0026gt; 2 async function renderKaTeX() { 3 // 判断当前页面是否有KateX 4 let katex = document.querySelector(\u0026#34;.math-katex\u0026#34;); 5 if (!katex) { 6 return; 7 } 8 // 等待函数加载成功后，再执行渲染方法 9 while (typeof renderMathInElement !== \u0026#39;function\u0026#39;) { 10 await delay(500); 11 } 12 // KaTeX渲染方法 13 renderMathInElement(document.body, { 14 delimiters: [ 15 { left: \u0026#34;$$\u0026#34;, right: \u0026#34;$$\u0026#34;, display: true }, 16 { left: \u0026#34;$\u0026#34;, right: \u0026#34;$\u0026#34;, display: false }, 17 { left: \u0026#34;\\\\(\u0026#34;, right: \u0026#34;\\\\)\u0026#34;, display: false }, 18 { left: \u0026#34;\\\\[\u0026#34;, right: \u0026#34;\\\\]\u0026#34;, display: true } 19 ], 20 ignoredClasses: [\u0026#34;gist\u0026#34;] 21 }); 22 } 23 24 /** 25 * 同步延迟 26 */ 27 function delay(time) { 28 return new Promise(resolve =\u0026gt; { 29 setTimeout(resolve, time) 30 }) 31 } 32 33 document.addEventListener(\u0026#39;pjax:complete\u0026#39;, () =\u0026gt; { 34 renderKaTeX(); 35 }) 36\u0026lt;/script\u0026gt; 取消pjax的时间戳 pjax会默认给网页加上时间戳，具体为表现为?t=1724141234567的样式，这样会使页面间的跳转出现问题，建议关闭。\n在pjax.html中引入：\n1\u0026lt;script\u0026gt; 2 document.addEventListener(\u0026#39;DOMContentLoaded\u0026#39;, function () { 3 if (window.pjax) { 4 window.pjax.options.cacheBust = false; // 关闭时间戳参数 5 } 6 }); 7\u0026lt;/script\u0026gt; ","date":"2025-08-17T00:00:00Z","permalink":"https://rd806.github.io/passage/website/aplayer/","title":"APlayer"},{"content":"系统直接安装到U盘 在微软官网找到Windows系统下载 ，选择需要安装的系统。\n准备一个U盘（容量大于8GB），并插入电脑。\n选择“创建Windows10安装媒体”，点击立即下载，将下载启动文件。\n打开启动文件，同意用户协议后，选择“直接安装到U盘”，再选择安装位置，等待系统安装完成。这时系统就在U盘中，可直接启动。\n注意：安装到U盘会将U盘格式化。\n下载系统镜像 在上述方法的第4步，选择“下载系统镜像”，即可下载系统镜像文件。这样U盘不会格式化，仍可以储存其他文件。\n系统镜像文件不是完整系统，无法直接从U盘启动。但是通过Rufus烧录的镜像则可以选择直接从U盘启动。\n微PE工具箱 若只是进行系统修复而不需要重装系统，可选择使用PE系统U盘。这里推荐使用“微PE工具箱”。\n什么是PE？\nPE简单而言就是一个极简的Windows系统，通常无法联网，但保留了系统的基本操作功能。在PE模式下，原系统的所有文件都相当于普通硬盘的文件，可以任意删除（包括Windows\\System！）。\n在微PE工具箱官网 下载微PE工具箱。\n准备一个U盘（容量大于8GB），并插入电脑。\n打开微PE工具箱，选择右下角的安装到U盘，将打开设置界面。\n“格式化”如果勾选，则U盘会格式化。\n“U盘卷标”表示安装后U盘的名称。\n设置完成后点击安装，等待片刻后PE系统就会安装到U盘中。此时查看“此电脑”，通常会出现一个“EFI”和另一个空盘。“EFI”盘是PE系统，另一个空盘可以作为普通U盘使用，可以储存系统镜像文件。 参考视频：\n提示：为了获取更好的视频观看体验，请从PC端访问或在手机上开启电脑模式。\n安装系统\n微PE\n","date":"2025-08-17T00:00:00Z","permalink":"https://rd806.github.io/passage/system/windows/","title":"Windows系统安装与修复"},{"content":"一些简单的练习 → 尽量上课！ 课下完整看完一本书！ 做题！ 极限与函数 求极限的方法 等价无穷小 等价无穷小 $(x \\to 0)$ $ \\sin x \\sim x$ $ \\tan x \\sim x $ $\\arcsin x \\sim x$ $ \\arctan x \\sim x $ $\\displaystyle \\cos x \\sim 1-\\frac{1}{2}x^{2} $ $ \\mathrm{e}^{x}-1 \\sim x $ $ \\ln(1+x) \\sim x $ $ (1+x)^{\\alpha}-1 \\sim \\alpha x $ 重要极限 $\\displaystyle \\lim_{n \\to 0} \\frac{\\sin n}{n} = 1，\\lim_{x \\to 0} \\frac{\\sin x}{x} = 1$.\n$\\displaystyle \\lim_{n \\to \\infty} \\left(1+ \\frac{1}{n} \\right)^{n} = \\mathrm{e}，\\lim_{x \\to \\infty} \\left(1+ \\frac{1}{x} \\right)^{x} = \\mathrm{e}$\n$\\displaystyle \\lim_{x \\to +\\infty} a^{\\frac{1}{x}} = 1$\nCauchy命题：若 $\\displaystyle \\lim_{n \\to \\infty} a_n = a$，则 $\\displaystyle \\lim_{n \\to \\infty}\\frac{a_1+a_2+\\cdots+a_n}{n}=a$.\n泊松定理：$\\displaystyle \\lim_{n \\to \\infty} \\mathrm{C}_{n}^{k} p^k (1-p)^{n-k} = \\lim_{n \\to \\infty} \\frac{(np)^k \\mathrm{e}^{-np}}{k!} $\nStolz定理 Stolz 定理也称作离散形式的洛必达法则.\n设数列 $\\{y_n\\}$ 严格单调递增，且 $\\displaystyle \\lim_{n \\to \\infty} y_n = + \\infty$，若 $\\displaystyle \\lim_{n \\to \\infty} \\frac{x_n - x_{n-1}}{y_n - y_{n-1}}$ 存在或为无穷大，则 $$\\lim_{n \\to \\infty} \\frac{x_n}{y_n} = \\lim_{n \\to \\infty} \\frac{x_n - x_{n-1}}{y_n - y_{n-1}}$$泰勒公式 皮亚诺余项 $$ f(x) = \\sum_{k=0}^{n} \\frac{f^{(k)}(x_0)}{k!}(x - x_0)^k + o\\left((x - x_0)^n\\right), \\quad x \\to x_0 $$ 拉格朗日余项 $$ f(x) = \\sum_{k=0}^{n} \\frac{f^{(k)}(x_0)}{k!}(x - x_0)^k + \\frac{f^{(n+1)}(\\xi)}{(n+1)!}(x - x_0)^{n+1}, \\quad \\xi 介于 x 和 x_0 之间 $$麦克劳林公式 $\\displaystyle \\mathrm{e}^x = \\sum_{n=0}^{\\infty} \\frac{x^{n}}{n!} = 1 + x + \\frac{x^{2}}{2!} + \\frac{x^{3}}{3!} + \\cdots + \\frac{x^n}{n!} + o(x^{n})$\n$\\displaystyle \\sin x = \\sum_{n=0}^{\\infty} (-1)^{n}\\frac{x^{2n+1}}{(2n+1)!} = x - \\frac{x^{3}}{3!} + \\frac{x^{5}}{5!} - \\cdots + (-1)^{n}\\frac{x^{2n+1}}{(2n+1)!} + o(x^{2n+1})$\n$\\displaystyle \\cos x = \\sum_{n=0}^{\\infty} (-1)^{n}\\frac{x^{2n}}{(2n)!} = 1 - \\frac{x^{2}}{2!} + \\frac{x^{4}}{4!} - \\cdots + (-1)^{n}\\frac{x^{2n}}{(2n)!} + o(x^{2n})$\n$\\displaystyle \\ln(1+x) = \\sum_{n=1}^{\\infty} (-1)^{n-1} \\cdot \\frac{x^{n}}{n} = x - \\frac{x^{2}}{2} + \\frac{x^{3}}{3} - \\cdots + (-1)^{n-1} \\cdot \\frac{x^{n}}{n} + o(x^{n})，\\\\ (-1\u0026lt;x\\leqslant 1)$\n$\\displaystyle (1+x)^{\\alpha} = \\sum_{n=0}^{\\infty} \\mathrm{C}_\\alpha^n x^{n} = 1 + \\alpha x + \\frac{\\alpha(\\alpha-1)}{2!}x^{2} + \\cdots + \\mathrm{C}_{\\alpha}^{n} x^n + o(x^n)，(|x|\u0026lt;1)$\n参见：函数展开成幂级数 讨论极限的存在性 单调有界准则 单调递增且有上界的数列必收敛；单调递减且有下界的数列必收敛。\n利用海涅定理 如果能够选取数列 $\\{a_n\\}$，$\\{b_n\\}$，使得 $\\displaystyle \\lim_{n \\to \\infty} a_n = x_0$，$\\displaystyle \\lim_{n \\to \\infty} b_n = x_0$，并且 $\\displaystyle \\lim_{n \\to \\infty} f(a_n)$ 与 $\\displaystyle \\lim_{n \\to \\infty} f(b_n)$ 至少有一个不存在，或者都存在但不相等，那么极限 $\\displaystyle \\lim_{x \\to x_0} f(x)$ 不存在.\n柯西收敛准则 数列 $\\{u_n\\}$ 的极限存在 $\\Leftrightarrow$ $\\forall \\varepsilon \u0026gt; 0, \\exist N \u0026gt; 0$，使得当 $n \u0026gt; N(\\varepsilon)$ 时，对任意的正整数 $p$，有 $| u_{n+p}-u_{n} | \u0026lt; \\varepsilon$ 恒成立.\n一元函数微分学 求导方法 方法 公式 利用导数定义 $$\\displaystyle f'(x_{0}) = \\lim_{x \\to x_{0}} \\frac{f(x)-f(x_{0})}{x-x_{0}}$$ 隐函数求导 $$\\left[ f^{-1}(x) \\right]' = \\frac{1}{f'(y)} \\quad 或 \\quad \\frac{\\mathrm{d}y}{\\mathrm{d}x}= \\frac{1}{\\dfrac{\\mathrm{d}x}{\\mathrm{d}y}}$$ 莱布尼茨公式 对于函数$u=u(x)$和$v=v(x)$的乘积，有：$$(uv)^{(n)} = \\mathrm{C}_{n}^{0}u^{(n)}v + \\mathrm{C}_{n}^{1}u^{(n-1)}v'+\\cdots + \\mathrm{C}_{n}^{n-1}u'v^{(n-1)} + \\mathrm{C}_{n}^{n}uv^{(n)}.$$ 泰勒公式 由泰勒公式可知：$$f(x) = \\sum_{k=0}^{n} \\frac{f^{(k)}(0)}{k!} x^{k} + o(x^{n}).$$ 比较同次幂系数可得 $f^{(k)}(0) = k!a_{k}, k=0,1,2,\\cdots,n$. 常用求导公式：\n$(\\mathrm{e}^x) ^ {(n)} = \\mathrm{e}^x$；\n$\\displaystyle (\\sin x) ^ {(n)} = \\sin (x+n\\cdot\\frac{\\pi}{2})，(\\cos x) ^ {(n)} = \\cos (x+n\\cdot\\frac{\\pi}{2})$；\n$\\displaystyle (\\arcsin x)' = \\frac{1}{\\sqrt{1-x^{2}}}，(\\arccos x)' = -\\frac{1}{\\sqrt{1-x^{2}}}，\\\\ (\\arctan x)' = \\frac{1}{1+x^{2}}，(\\mathrm{arccot} x)' = -\\frac{1}{1+x^{2}}$\n$\\displaystyle [\\ln (1+x) ^ {(n)}] = (-1)^{(n-1)} \\frac{(n-1)!}{(1+x)^{n}}$；\n$(x^{\\alpha})^{(n)} = \\alpha (\\alpha-1) \\cdots (\\alpha-n+1)x^{\\alpha - n}$，（$\\alpha$是任意常数）\n微分中值定理 费马定理：如果 $f(x)$ 在点 $x_{0}$ 处取极值，且 $f'(x_{0})$ 存在，那么 $f'(x_{0})=0$.\n罗尔中值定理：如果 $f(x)$ 在$[a,b]$上连续，在 $(a,b)$ 内可导，且$f(a)=f(b)$，那么至少存在一点$\\xi \\in(a,b)$，使得$f'(\\xi) = 0$.\n拉格朗日中值定理：如果 $f(x)$ 在$[a,b]$上连续，在$(a,b)$内可导，那么至少存在一点$\\xi \\in(a,b)$，使得$f(b)-f(a)=f'(\\xi)(b-a)$.\n建立原函数与导函数的关系，关键在于构造辅助函数：\n函数 辅助函数 $ f(x) = 0 $ $ F(x) $ $ u'(x)v(x) + u(x)v'(x) = 0 $ $F(x) = u(x)v(x) $ $ u'(x)v(x) - u(x)v'(x) = 0 $ $\\displaystyle F(x) = \\frac{u(x)}{v(x)}，$ $v(x) \\ne 0 $ $ ku(x) + xu'(x) = 0 $ $ F(x) = x^{k}u(x) $ $ u'(x) + \\lambda u(x) = 0 $ $ F(x) = u(x)\\mathrm{e}^{\\lambda x} $ $ u'(x) + u(x)v'(x) = 0 $ $ F(x) = u(x)\\mathrm{e}^{v(x)} $ 柯西中值定理：如果$f(x)$和$g(x)$在$[a,b]$上连续，在 $(a,b)$ 内可导，且$g(x)\\ne 0$，那么至少存在一点 $\\xi \\in(a,b)$，使得 $\\displaystyle \\frac{f(b)-f(a)}{g(b)-g(a)} = \\frac{f'(\\xi)}{g'(\\xi)} $. 把 $x$ 当作参数，则 $\\displaystyle \\left\\{ \\begin{array}{c} u=f(x) \\\\ v=g(x) \\\\ \\end{array} \\right. $ 可以看作一个参数方程. 其中： ① $\\displaystyle \\frac{f(b)-f(a)}{g(b)-g(a)} $ 表示连接参数两端点弦的斜率. ② $\\displaystyle \\frac{f'(\\xi)}{g'(\\xi)}$ 表示曲线上某点切线的斜率.\n柯西中值定理可理解为：用参数方程表示的曲线上至少有一点，在这一点处的切线平行于连接两个端点的弦. 泰勒中值定理：如果函数 $f(x)$ 在含有 $x_0$ 的某个开区间 $(a,b)$ 内具有直到 $n+1$ 阶的导数，则当 $x \\in (a,b)$ 时，$f(x)$ 可表示为： $$f(x) = f(x_0) + f'(x_0)(x-x_0) + \\frac{1}{2!} f''(x_0)(x-x_0)^2 + \\cdots + \\frac{1}{n!}f^{(n)}(x_0)(x-x_0)^n + R_n(x)$$ 其中 $\\displaystyle R_n(x) = \\frac{f^{(n+1)}(\\xi)}{(n+1)!}(x-x_0)^{n+1}$，$\\xi$ 介于 $x_0$ 和 $x$ 之间. 出现二阶及以上导数时可考虑使用泰勒中值定理.\n导数的应用 曲线的切线与法线 （在$x_{0}$处）\n切线方程：$y-f(x_{0}) = f'(x_{0})(x-x_{0})$； 法线方程：$\\displaystyle y-f(x_{0}) = -\\frac{1}{f'(x_{0})}(x-x_{0})$.\n函数的单调性与极值 充分必要条件：\n设$f(x)$在$[a,b]$上连续，在$(a,b)$内可导，那么 (1) $\\forall x \\in (a,b)$，$f'(x)\u0026gt;0$，则$y=f(x)$在$[a,b]$上单调递增. (2) $\\forall x \\in (a,b)$，$f'(x)\u0026lt;0$，则$y=f(x)$在$[a,b]$上单调递减. 判定方法：\n若 $f(x)$在$x_{0}$处二阶可导，且$f'(x)=0$，$f''(x) \\ne 0$. 则当 $f''(x)\u0026gt;0$ 时，$f(x)$在$x_{0}$处取得极小值；当 $f''(x)\u0026lt;0$ 时，$f(x)$在$x_{0}$处取得极大值.\n曲线的凹凸性与拐点 设$f(x)$在$[a,b]$上连续，在$(a,b)$内二阶可导，那么\n若在$(a,b)$内$f''(x)\u0026gt;0$，则曲线$y=f(x)$在$[a,b]$上是凹函数； 若在$(a,b)$内$f''(x)\u0026lt;0$，则曲线$y=f(x)$在$[a,b]$上是凸函数. 曲线的渐近线 若 $\\displaystyle \\lim_{x \\to x_{0}} f(x) = \\infty$，则直线$x=x_{0}$是曲线的垂直渐近线； 若 $\\displaystyle \\lim_{x \\to \\infty} f(x) = A$，则直线$y=A$是曲线的水平渐近线； 若 $\\displaystyle \\lim_{x \\to \\infty} \\frac{f(x)}{x} = k$，$\\displaystyle \\lim_{x \\to \\infty} [f(x)-kx] = b$，则直线$y=kx+b$是曲线的斜渐近线. 曲率与曲率中心 参数方程 $\\left\\{ \\begin{array}{c} x = \\varphi(t) \\\\ y = \\psi(t) \\ \\end{array} \\right. t \\in [a,b]$ 确定的平面曲线的曲率 $$ K = \\frac{\\left| \\varphi'(t) \\psi''(t) - \\varphi''(t) \\psi'(t) \\right|}{[\\varphi'^{\\ 2}(t)+\\psi'^{\\ 2}(t)]^{\\frac{3}{2}}} $$曲线 $y=y(x)$ 的曲率中心 $$\\left\\{ \\begin{array}{c} \\begin{align*} \\xi \u0026= x - \\dfrac{y'(1+y'^{\\ 2})}{y''} \\\\ \\eta \u0026= y + \\dfrac{1+y'^{\\ 2}}{y''} \\end{align*} \\end{array} \\right.$$一元函数积分学 常规积分方法 凑微分法 基本凑微分法 $\\displaystyle \\mathrm{e}^{x} \\mathrm{d}x = \\mathrm{d} (\\mathrm{e}^{x})$ $\\displaystyle x^{n-1} \\mathrm{d}x = \\frac{1}{na} \\mathrm{d} (ax^{n}+b)$ $\\displaystyle \\frac{\\mathrm{d}x}{x} = \\mathrm{d}(\\ln x)$ $\\displaystyle \\frac{\\mathrm{d}x}{1+x^{2}} = \\mathrm{d} (\\arctan x)$ $\\displaystyle \\frac{\\mathrm{d}x}{\\cos ^{2}x} = \\mathrm{d} (\\tan x)$ $\\displaystyle \\sin x \\mathrm{d}x = - \\mathrm{d}(\\cos x)$ $\\displaystyle \\cos x \\mathrm{d}x = \\mathrm{d}(\\sin x)$ $\\displaystyle \\frac{\\mathrm{d}x}{\\sqrt{1-x^{2}}} = \\mathrm{d}(\\arcsin x)$ 特殊凑微分法 $\\displaystyle \\frac{1}{(1+x^2)^{\\frac{3}{2}}} \\mathrm{d}x = \\mathrm{d}\\left(\\frac{x}{\\sqrt{1+x^2}}\\right)$ $\\displaystyle \\frac{1}{\\sqrt{1+x^2}} = \\mathrm{d} \\ln \\left( x+\\sqrt{1+x^2} \\right)$ $\\displaystyle x\\mathrm{d}x + y\\mathrm{d}y = \\frac{1}{2} \\mathrm{d}\\left(x^2+y^2\\right)$ $\\displaystyle y\\mathrm{d}x - x\\mathrm{d}y = y^2 \\mathrm{d} \\left(\\frac{x}{y} \\right)$ 换元积分法 三角代换 形式 代换 含有 $\\sqrt{a^2-x^2}$ 设$x = a\\sin t$，$\\displaystyle t \\in \\left[-\\frac{\\pi}{2},\\frac{\\pi}{2} \\right]$ 含有 $\\sqrt{a^2+x^2}$ 设$x = a\\tan t$，$\\displaystyle t \\in \\left[-\\frac{\\pi}{2}，\\frac{\\pi}{2} \\right]$ 含有 $\\sqrt{x^2-a^2}$ 设$x = a\\sec t$，$\\displaystyle t \\in \\left[0,\\frac{\\pi}{2} \\right]$ 含有 $\\sqrt{ax^{2}+bx+c}$ 可先配方再设 $\\displaystyle \\int f(\\sin x, \\cos x) \\mathrm{d}x$，其中 $f(u,v)$是有理函数 利用代换 $\\displaystyle t = \\tan \\frac{x}{2}$ 可化为有理函数积分 根式代换 ① 含两个一次平方根式 $\\sqrt{x+\\alpha}$与$\\sqrt{x+\\beta}$ $(\\alpha \u0026lt; \\beta)$，可设 \\[ \\sqrt{x+\\beta} = \\lambda \\left(t+\\frac{1}{t}\\right)， \\sqrt{x+\\alpha} = \\lambda \\left(t-\\frac{1}{t}\\right) \\] 以上两式平方后相减，有$4\\lambda^{2} = \\beta - \\alpha$. ② 含两个一次根式 $\\sqrt[m]{x+a}$与$\\sqrt[n]{x+a}$的积分，可设 $t = \\sqrt[k]{x+a}$，这里$k$是$m$，$n$的最小公倍数. ③ 对于根式 $\\displaystyle \\sqrt[m]{\\frac{x+a}{x-a}}$，直接设 $\\displaystyle t = \\sqrt[m]{\\frac{x+a}{x-a}}$ 倒代换 令 $\\displaystyle t = \\frac{1}{x+a}$，当被积函数为$x$的有理式或无理式、分母次数较高时，往往可利用倒代换消去分母中所含的因子 $x + a$ 或 $(x + a)^{n}$。\n分部积分法 设 $u(x)$，$v(x)$ 具有连续导数，则有分部积分公式\n$$ \\int u(x)v'(x) \\mathrm{d}x = u(x)v(x) - \\int u'(x)v(x) \\mathrm{d}x $$或简记为：$\\displaystyle \\int u \\mathrm{d}v = uv - \\int v \\mathrm{d}u$\n分部积分法适用情境：\n函数乘积的积分。 含有对数、反三角函数的积分。 含有 $\\mathrm{e}^x \\sin x$ 函数的积分。 证明递推关系式。 特殊积分方法 区域可加性 对于部分函数，尤其是含有绝对值函数的定积分，适合拆分成多个定积分，分别计算最后求和.\n例如：$\\displaystyle \\int_{0}^{x} |\\cos t| \\mathrm{d}t = \\sum_{k=1}^{n} \\int_{(k-1)\\pi}^{k\\pi} |\\cos t| \\mathrm{d}t + \\int_{n\\pi}^{x} |\\cos t| \\mathrm{d}t $，其中 $ n\\pi \\leqslant x \u0026lt; (n+1)\\pi $\n区间再现法 对于周期函数，若知道其周期，可使用区间再现法求定积分。\n例如，若 $f(x+T)=f(x)$，则有\n$$\\int_{a}^{a+T} f(x) \\mathrm{d}x = \\int_{0}^{T} f(x) \\mathrm{d}x$$$$\\int_{0}^{nT} f(x) \\mathrm{d}x = n\\int_{0}^{T} f(x) \\mathrm{d}x$$组合积分法 如果积分式具有单对称性，可考虑构造另一个积分式，使两者的线性运算所得的积分容易求出，最后通过解方程求得原式的结果。\n反函数积分法 对于一些定积分，若被积函数较复杂，而其反函数较简单，可利用定积分的几何意义：用积分区间的面积减去被积函数反函数的定积分。\n常用积分 线性换元法 对于连续函数 $f(x)$： $$\\int_{a}^{b} f(x) \\mathrm{d}x = \\int_{a}^{b} f(a+b-x) \\mathrm{d}x = \\frac{1}{2} \\int_{a}^{b} [f(x) + f(a+b-x)] \\mathrm{d}x $$ 进一步，若 $f(x)$ 关于 $\\displaystyle x = \\frac{a+b}{2}$ 对称，则有： $$\\int_{a}^{b} xf(x) \\mathrm{d}x = \\frac{a+b}{2} \\int_{a}^{b} f(x) \\mathrm{d}x = (a+b) \\int_{a}^{\\frac{a+b}{2}} f(x) \\mathrm{d}x $$ 特别地，有：\n$$\\int_{0}^{\\pi} xf(\\sin x) \\mathrm{d}x = \\frac{\\pi}{2} \\int_{0}^{\\pi} f(\\sin x) \\mathrm{d}x $$沃利斯公式 $$I_n = \\int_{0}^{\\frac{\\pi}{2}} \\sin^{n}x \\mathrm{d}x = \\int_{0}^{\\frac{\\pi}{2}} \\cos^{n}x \\mathrm{d}x = \\left\\{ \\begin{array}{c} \\begin{align*} \u0026 \\displaystyle \\frac{(n-1)!!}{n!!} \u0026 n \u0026= 2k+1 \\\\ \\\\ \u0026 \\displaystyle \\frac{(n-1)!!}{n!!} \\cdot \\frac{\\pi}{2} \u0026 n\u0026=2k \\\\ \\end{align*} \\end{array} \\right.$$进一步：\n$$I(m,n) = \\int_{0}^{\\frac{\\pi}{2}} \\sin^{m}x \\cos^{n}x \\mathrm{d}x = \\left\\{ \\begin{array}{c} \\begin{align*} \u0026 \\displaystyle \\frac{(m-1)!! (n-1)!!}{(m+n)!!} \u0026 m,n 不全为偶 \\\\ \\\\ \u0026 \\displaystyle \\frac{(m-1)!! (n-1)!!}{(m+n)!!} \\cdot \\frac{\\pi}{2} \u0026 m,n 全偶 \\\\ \\end{align*} \\end{array} \\right.$$高斯积分 $$\\int_{0}^{+\\infty} \\mathrm{e}^{-x^{2}} \\mathrm{d}x = \\frac{\\sqrt{\\pi}}{2} $$傅汝兰尼积分公式 设 $f(x)$ 在 $[0,+\\infty)$ 上连续，且 $\\displaystyle \\int_{A}^{+\\infty} \\frac{f(x)}{x} \\mathrm{d}x$ 收敛，其中常数 $A \u0026gt; 0$，则有 $$\\int_{0}^{+\\infty} \\frac{f(ax)-f(bx)}{x} \\mathrm{d}x = f(0) \\ln \\frac{b}{a} \\quad (a \u003c b \u003c c) $$柯西积分不等式 $$\\left[ \\int_{a}^{b} f(x)g(x) \\mathrm{d}x \\right]^{2} \\leqslant \\int_{a}^{b} f^{2}(x) \\mathrm{d}x \\int_{a}^{b} g^{2}(x) \\mathrm{d}x $$ 其中 $f(x)$，$g(x)$ 均为 $[a,b]$ 上的连续函数.\n证明过程 定积分的应用 曲线的弧长 参数方程 $$\\left\\{ \\begin{array}{c} x = \\varphi(t) \\\\ y = \\psi(t) \\\\ \\end{array} \\right. t \\in [a,b]$$ 确定的平面曲线的弧长 $\\displaystyle s = \\int_{a}^{b} \\sqrt{\\varphi'^{\\ 2}(t) + \\psi'^{\\ 2}(t)} \\mathrm{d}t $\n极坐标方程 $$\\rho = \\rho(\\theta) \\quad \\theta \\in (\\alpha,\\beta) $$ 确定的平面曲线的弧长 $\\displaystyle s = \\int_{\\alpha}^{\\beta} \\sqrt{\\rho^{2}(\\theta) + \\rho'^{\\ 2}(\\theta)} \\mathrm{d}\\theta $\n旋转体的体积 截面法：曲线 $y=f(x)$ 在 $[c,d]$ 上的部分绕 $x$ 轴旋转一周所围立体的体积 $\\displaystyle V = \\pi \\int_{c}^{d} f^{2}(x) \\mathrm{d}x $\n柱壳法：曲线 $y=f(x)$ 在 $[c,d]$ 上的部分绕 $y$ 轴旋转一周所围立体的体积 $\\displaystyle V = 2\\pi \\int_{c}^{d} xf(x) \\mathrm{d}x $\n旋转曲面的面积 曲线 $y=f(x)$ 在 $[c,d]$ 上的部分绕 $x$ 轴旋转一周所得曲面的面积 $\\displaystyle S = 2\\pi \\int_{c}^{d} f(x)\\sqrt{1+f'^{\\ 2}(x)} \\mathrm{d}x $\n空间解析几何 向量的运算 数量积 $$\\bm{a} \\cdot \\bm{b} = x_1 x_2+y_1 y_2+z_1 z_2 $$ 向量积 $$ \\bm{a} \\times \\bm{b} = \\left| \\begin{matrix} \\bm{i} \u0026 \\bm{j} \u0026 \\bm{k} \\\\ x_1 \u0026 y_1 \u0026 z_1 \\\\ x_2 \u0026 y_2 \u0026 z_2 \\\\ \\end{matrix} \\right| $$ 混合积 $$ ( \\bm{a} \\times \\bm{b} ) \\cdot \\bm{c} = \\left| \\begin{matrix} x_1 \u0026 y_1 \u0026 z_1 \\\\ x_2 \u0026 y_2 \u0026 z_2 \\\\ x_3 \u0026 y_3 \u0026 z_3 \\\\ \\end{matrix} \\right| $$向量基本定理 已知点 $A，B，C$，对于另一点 $O$，若 $\\overrightarrow{OA} = \\lambda \\overrightarrow{OB} + (1-\\lambda) \\overrightarrow{OC}$，则点 $A，B，C$ 在同一条直线上.\n已知向量 $\\boldsymbol{a}，\\boldsymbol{b}$，则向量 $\\boldsymbol{c} = \\lambda \\boldsymbol{a} + \\mu \\boldsymbol{b}$ 与 $\\boldsymbol{a}$，$\\boldsymbol{b}$ 共面.\n对于 $n$ 维空间，至少存在一组包含 $n$ 个线性无关的向量，使得该空间内所有的向量都可以用这一组向量表示.\n用向量表示几何元素 角平分线：已知 $\\angle AOB$，则其角平分线向量 $\\displaystyle \\boldsymbol{a} = \\frac{\\overrightarrow{OA}}{\\left|\\overrightarrow{OA}\\right|} + \\frac{\\overrightarrow{OB}}{\\left|\\overrightarrow{OB}\\right|}$\n中线：已知 $\\triangle ABC$，则其 $BC$ 边中线向量 $\\displaystyle \\boldsymbol{a} = \\overrightarrow{AB} + \\overrightarrow{AC}$\n三角形的面积：已知三角形 $\\triangle ABC$，则其面积 $\\displaystyle S_{\\triangle ABC} = \\frac{1}{2} \\left( \\overrightarrow{AB} \\times \\overrightarrow{AC} \\right)$\n平行六面体的体积：已知平行六面体其中一个顶点所连的三条边对应的向量分别为 $\\boldsymbol{a}$，$\\boldsymbol{b}$，$\\boldsymbol{c}$， 则其体积 $V = \\left| (\\boldsymbol{a} \\times \\boldsymbol{b}) \\cdot \\boldsymbol{c} \\right|$\n此方法也可用于判断三个向量是否共面：三个向量共面 $\\Leftrightarrow$ 三个向量所张成的平行六面体的体积为0.\n向量的夹角：已知向量 $\\boldsymbol{a}$ 与 向量 $\\boldsymbol{b}$，则其夹角 $\\theta$ 满足 $\\displaystyle \\cos \\theta = \\frac{\\boldsymbol{a} \\cdot \\boldsymbol{b}}{\\left| \\boldsymbol{a}\\right| \\cdot \\left| \\boldsymbol{b}\\right|}$ 用方程表示几何元素 平面 类型 方程 点法式 $$A(x-x_0)+B(x-y_0)+C(z-z_0)=0$$ 截距式 $$\\frac{x}{a} + \\frac{y}{b} + \\frac{z}{c} = 1 $$ 参数式 $$\\left\\{ \\begin{array}{c} x=x_0+su_1+tv_1 \\\\ y=y_0+su_2+tv_2 \\\\ z=z_0+su_3+tv_3 \\end{array} \\right. $$ 一般式 $$ Ax+By+Cz+D=0 $$ 直线 类型 方程 对称式 $$\\frac{x-x_0}{a} = \\frac{y-y_0}{b} = \\frac{z-z_0}{c} $$ 参数式 $$\\left\\{ \\begin{array}{c} x=x_0+at \\\\ y=y_0+bt \\\\ z=z_0+ct \\end{array} \\right. $$ 一般式 $$\\left\\{ \\begin{array}{c} A_1x+B_1y+C_1z+D_1=0 \\\\ A_2x+B_2y+C_2z+D_2=0 \\end{array} \\right. $$ 平面束方程\n对于给出一般式方程的直线 $$l:\\left\\{ \\begin{array}{c} A_1x+B_1y+C_1z+D_1=0 \\\\ A_2x+B_2y+C_2z+D_2=0 \\end{array} \\right. $$ 过该直线的所有平面的方程可表示为 $$ \\lambda(A_1x+B_1y+C_1z+D_1) + \\mu (A_2x+B_2y+C_2z+D_2) = 0 $$ 称为平面束方程.\n二次曲面 类型 方程 柱面 $$x^{2}+y^{2}=r^{2} $$ 球面 $$x^{2}+y^{2}+z^{2}=R^{2}$$ 旋转抛物面 $$z=x^{2}+y^{2}$$ 圆锥面 $$z=\\sqrt{x^{2}+y^{2}}$$ 旋转曲面方程 坐标面上曲线 $\\displaystyle \\left\\{ \\begin{array}{c} F(y,z) = 0 \\\\ x = 0 \\end{array} \\right.$ 绕坐标轴（如 $z$ 轴）旋转一周而成的旋转曲面方程：$F(\\pm\\sqrt{x^2+y^2}, z) = 0$ 常见的空间几何问题 投影直线的方程 已知直线 $l: \\left\\{ \\begin{array}{c} A_1x+B_1y+C_1z+D_1=0 \\\\ A_2x+B_2y+C_2z+D_2=0 \\end{array} \\right.$，求其在平面 $\\varPi: Ax+By+Cz+D=0$ 上的投影直线的方程：\n投影直线 设平面束方程 $(A_1x+B_1y+C_1z+D_1) + \\mu (A_2x+B_2y+C_2z+D_2) = 0$，求出其方向向量 $\\bm{n}_1$. 由几何性质可知，过该投影直线的平面应与 $Ax+By+Cz+D=0$ 垂直. 而目标平面法向量为 $\\bm{n}_2$，由 $\\bm{n}_1 \\times \\bm{n_2} = 0$ 可解得参数 $\\mu$. 则 $$\\left\\{ \\begin{array}{c} \\begin{align*} \u0026 A_1x+B_1y+C_1z+D_1+\\mu(A_2x+B_2y+C_2z+D_2)=0 \\\\ \u0026 Ax+By+Cz+D=0 \\end{align*} \\end{array} \\right.$$ 即为所求投影直线的方程.\n空间中的距离 点到平面的距离 已知点 $M_0(x_0,y_0,z_0) \\notin \\varPi$，平面 $\\varPi: Ax+By+Cz+D=0$，则有：\n$$d = \\frac{| Ax_0 + By_0 + Cz_0 + D |}{\\sqrt{A^2 + B^2 + C^2}}$$ 点到直线的距离 已知点 $M_0(x_0,y_0,z_0)$ ，直线 $\\displaystyle L: \\frac{x-x_1}{m} + \\frac{y-y_1}{n} + \\frac{z-z_1}{p}$，$M_1(x_1,y_1,z_1) \\in L$，$\\bm{s}=(m,n,p)$，则有 $$d = \\frac{ |\\bm{s} \\times \\overrightarrow{M_0 M_1} |}{| \\bm{s} |}$$ 两条异面直线间的距离 已知直线 $\\displaystyle L_1: \\frac{x-x_1}{m_1} + \\frac{y-y_1}{n_1} + \\frac{z-z_1}{p_1}$，直线 $\\displaystyle L_2: \\frac{x-x_2}{m_2} + \\frac{y-y_2}{n_2} + \\frac{z-z_2}{p_2}$，且两直线为异面直线，$M_1(x_1,y_1,z_1) \\in L_1$，$M_2(x_2,y_2,z_2) \\in L_2$. $\\bm{s}_1=(m_1,n_1,p_1)$，$\\bm{s}_2=(m_2,n_2,p_2)$. 则有 $$d = \\frac{|(\\bm{s}_1 \\times \\bm{s}_2) \\cdot \\overrightarrow{M_1 M_2}|}{|\\bm{s}_1 \\times \\bm{s}_2|}$$ 多元函数微分学 二重极限 常用方法：\n四则运算法则和复合函数运算法则. 等价无穷小代换. 无穷小量与有界量之积为无穷小量. 迫敛准则. 重要极限. 全微分 定义：$ \\Delta z = f(x_0+\\Delta x, y_0+\\Delta y) - f(x_0,y_0) = A \\Delta x + B \\Delta y + o(\\rho) $\n判定：\n$ f'_x (x_0,y_0) $ 与 $ f'_y (x_0,y_0) $ 均存在. 证明： $$ \\lim_{\\substack{\\Delta x \\to 0 \\\\ \\Delta y \\to 0}} \\frac{\\Delta z - f'_x(x_0,y_0) \\Delta x - f'_y(x_0,y_0) \\Delta y}{\\sqrt{\\Delta x^{2} + \\Delta y^{2}}} = 0 $$ 判断函数可微的方法： 不连续 $\\Rightarrow$ 不可微. 偏导不存在 $\\Rightarrow$ 不可微. 偏导连续 $\\Rightarrow$ 可微. 充要条件：$$ \\lim_{\\substack{\\Delta x \\to 0 \\\\ \\Delta y \\to 0}} \\frac{f(x+\\Delta x,y+\\Delta y) - f(x,y) - f'_x(x,y) \\Delta x - f'_y(x,y) \\Delta y}{\\sqrt{\\Delta x^{2} + \\Delta y^{2}}} = 0 $$ 函数连续、偏导、可微的关系 函数连续与存在偏导数无关. 函数可微 $\\Rightarrow$ 连续，连续不一定可微. 函数可微 $\\Rightarrow$ 偏导数存在，偏导数存在不一定可微. 函数可微 $\\Leftrightarrow$ 函数偏导数连续. 多元函数求导 含参变量的变限积分求导 $$\\left[\\int_{a}^{x} f(u,t) \\mathrm{d}t \\right]'_{x} = \\int_{a}^{x} \\frac{\\partial f}{\\partial u} \\mathrm{d}t \\cdot \\frac{\\mathrm{d}u}{\\mathrm{d}x} + f(u,x)$$隐函数求导 由$F(x,y,z)=0$ 确定 $z=z(x,y)$.\n(1) 公式：$\\displaystyle \\frac{\\partial z}{\\partial x} = - \\frac{F'_x}{F'_z}$，$\\displaystyle \\frac{\\partial z}{\\partial y} = - \\frac{F'_y}{F'_z}$ (2) 两边同时求偏导 (3) 利用微分形式不变性：$F'_x \\mathrm{d}x + F'_y \\mathrm{d}y + F'_z \\mathrm{d}z = 0$\n由多个函数确定 $$\\left\\{ \\begin{array}{c} F(x,y,u,v) = 0 \\\\ G(x,y,u,v) = 0 \\end{array} \\right.$$ 分别对等式两边求偏导，解关于 $\\displaystyle \\frac{\\partial z}{\\partial x}$ 和 $\\displaystyle \\frac{\\partial z}{\\partial y}$ 的线性方程组.\n方向导数和梯度 方向导数 (1) 定义式：\n$$ \\frac{\\partial f}{\\partial \\bm{l}} \\Bigg|_{(x_0,y_0)} = \\lim_{(\\Delta x, \\Delta y) \\to (0,0)} \\frac{f(x_0+\\Delta x, y_0+\\Delta y) - f(x_0,y_0)}{\\sqrt{\\Delta x^{2} + \\Delta y^{2}}} $$ (2) 计算式：\n$$ \\frac{\\partial f}{\\partial \\bm{l}} \\Bigg|_{(x_0,y_0)} = \\frac{\\partial f}{\\partial x} \\cos \\alpha + \\frac{\\partial f}{\\partial y} \\cos \\beta $$ 其中 $\\displaystyle \\cos \\alpha = \\frac{x_0}{\\sqrt{x_0^{2}+y_0^{2}}}$，$\\displaystyle \\cos \\beta = \\frac{y_0}{\\sqrt{x_0^{2}+y_0^{2}}}$\n梯度 $$\\textbf{grad}z = \\left(\\frac{\\partial f}{\\partial x},\\frac{\\partial f}{\\partial y}\\right)$$ 应用 切平面和法线 已知曲面 $F(x,y,z)=0$，在点 $(x_0,y_0,z_0)$ 处的切平面方程为 $$F'_x(x-x_0)+F'_y(y-y_0)+F'_z(z-z_0) = 0$$已知曲线 $$\\left\\{ \\begin{array}{c} A_1x+B_1y+C_1z+D_1=0 \\\\ A_2x+B_2y+C_2z+D_2=0 \\end{array} \\right. $$ 在一点 $(x_0,y_0,z_0)$ 处的法向量 $\\bm{n} = (A_1,B_1,C_1) \\times (A_2,B_2,C_2)$\n极值与最值 无条件极值 对于稳定点 $x_0$ （满足 $f'(x_0) = 0$），有$Hesse$ 矩阵： $$H = \\left[ \\begin{matrix} \\dfrac{\\partial^{2}y}{\\partial x_1^{2}} \u0026 \\dfrac{\\partial^{2}y}{\\partial x_1 \\partial x_2} \u0026 \\cdots \u0026 \\dfrac{\\partial^{2}y}{\\partial x_1 \\partial x_n} \\\\ \\dfrac{\\partial^{2}y}{\\partial x_2 \\partial x_1} \u0026 \\dfrac{\\partial^{2}y}{\\partial x_2^{2}} \u0026 \\cdots \u0026 \\dfrac{\\partial^{2}y}{\\partial x_2 \\partial x_n} \\\\ \\vdots \u0026 \\vdots \u0026 \u0026 \\vdots \\\\ \\dfrac{\\partial^{2}y}{\\partial x_n \\partial x_1} \u0026 \\dfrac{\\partial^{2}y}{\\partial x_n \\partial x_2} \u0026 \\cdots \u0026 \\dfrac{\\partial^{2}y}{\\partial x_n^{2}} \\\\ \\end{matrix} \\right]$$ 若 $Hesse$ 矩阵是正定矩阵，则稳定点 $P_0$ 是极小值点. 若 $Hesse$ 矩阵是负定矩阵，则稳定点 $P_0$ 是极大值点. 若 $Hesse$ 矩阵是不定矩阵，则稳定点 $P_0$ 不是极值点. 条件极值与拉格朗日乘数法 已知函数 $F(x,y) = 0$，约束方程 $W(x,y) = 0$. 构造拉格朗日函数 $L(x,y,\\lambda) = F(x,y) + \\lambda W(x,y)$，求满足方程组 $$ \\left\\{\\begin{array}{c} \\begin{align*} L'_x \u0026= 0 \\\\ L'_y \u0026= 0 \\\\ L'_\\lambda \u0026= W(x,y) = 0 \\end{align*} \\end{array} \\right. $$的$x,y,\\lambda$，则 $F(x,y)$ 在所求的 $(x,y)$ 处存在极值.\n最值\n多元函数积分学 重积分 二重积分 积分换序\n坐标变换 一般坐标变换：令 $x = x(u,v)$，$y = y(u,v)$，则 $$\\iint\\limits_D f(x,y) \\mathrm{d}x \\mathrm{d}y = \\iint\\limits_D f(x(u,v),y(u,v)) \\left| \\frac{\\partial(x,y)}{\\partial(u,v)} \\right| \\mathrm{d}u \\mathrm{d}v $$ 其中 $$\\frac{\\partial(x,y)}{\\partial(u,v)} = \\left| \\begin{matrix} \\dfrac{\\partial x}{\\partial u} \u0026 \\dfrac{\\partial x}{\\partial v} \\\\ \\\\ \\dfrac{\\partial y}{\\partial u} \u0026 \\dfrac{\\partial y}{\\partial v} \\\\ \\end{matrix} \\right|$$ 特别的，有极坐标变换：\n令 $x = \\rho \\cos \\theta$，$y = \\rho \\sin \\theta$，则 $$\\iint\\limits_D f(x,y) \\mathrm{d}x\\mathrm{d}y = \\iint\\limits_D f(\\rho \\cos \\theta,\\rho \\sin \\theta) \\rho \\mathrm{d}\\rho \\mathrm{d}\\theta$$ 轮换对称性 若积分区域关于原点对称，则 $x$ 与 $y$ 交换位置后，积分值不变. 即 $$\\iint\\limits_D f(x,y) \\mathrm{d}x \\mathrm{d}y = \\frac{1}{2} \\left( \\iint\\limits_D f(x,y) \\mathrm{d}x \\mathrm{d}y + \\iint\\limits_D f(y,x) \\mathrm{d}y \\mathrm{d}x \\right)$$ 三重积分 先一后二： $\\displaystyle \\iiint\\limits_\\varOmega f(x,y,z) \\mathrm{d}V = \\iint\\limits_{D_{xy}} \\mathrm{d}x\\mathrm{d}y \\int_{z_1(x,y)}^{z_2(x,y)} f(x,y,z) \\mathrm{d}z $\n先二后一：$\\displaystyle \\iiint\\limits_\\varOmega f(x,y,z) \\mathrm{d}V = \\int_{c}^{d} \\mathrm{d}z \\iint\\limits_{D_{xy}} f(x,y,z) \\mathrm{d}\\sigma $\n球坐标变换 令 $$\\left\\{ \\begin{array}{c} \\begin{align*} x \u0026= \\rho \\cos \\theta \\sin \\varphi \\\\ y \u0026= \\rho \\sin \\theta \\sin \\varphi \\\\ z \u0026= \\rho \\cos \\varphi \\end{align*} \\end{array}\\right.$$ 则雅可比行列式的绝对值为 $\\rho^{2} \\sin \\theta$\n重积分的应用 物体的质心 设物体的密度函数为 $\\mu(x,y,z)$，则物体质心坐标为 $$\\begin{array}{c} \\displaystyle \\overline{x} = \\frac{1}{m}\\iiint\\limits_\\varOmega x \\mu(x,y,z) \\mathrm{d}V \\\\ \\\\ \\displaystyle \\overline{y} = \\frac{1}{m}\\iiint\\limits_\\varOmega y \\mu(x,y,z) \\mathrm{d}V \\\\ \\\\ \\displaystyle \\overline{z} = \\frac{1}{m}\\iiint\\limits_\\varOmega z \\mu(x,y,z) \\mathrm{d}V \\end{array}$$ 特别地，若物体质量均匀，即 $\\mu(x,y,z) = C$，则物体的质心即为物体的形心。\n$$\\begin{array}{c} \\displaystyle \\overline{x} = \\iiint\\limits_\\varOmega x \\mathrm{d}V ，\\displaystyle \\overline{y} = \\iiint\\limits_\\varOmega y \\mathrm{d}V ，\\displaystyle \\overline{z} = \\iiint\\limits_\\varOmega z \\mathrm{d}V \\end{array}$$ 物体的转动惯量 设物体的密度函数为 $\\mu(x,y,z)$，则物体对 $x,y,z$ 轴的转动惯量分别为 $$\\begin{array}{c} \\displaystyle I_x = \\iiint\\limits_\\varOmega (y^{2}+z^{2}) \\mu(x,y,z) \\mathrm{d}V \\\\ \\\\ \\displaystyle I_y = \\iiint\\limits_\\varOmega (x^{2}+z^{2}) \\mu(x,y,z) \\mathrm{d}V \\\\ \\\\ \\displaystyle I_z = \\iiint\\limits_\\varOmega (x^{2}+y^{2}) \\mu(x,y,z) \\mathrm{d}V \\end{array} $$ 线面积分 曲线积分 第一类曲线积分 对于由参数方程 $$\\left\\{ \\begin{array}{c} x=x(t) \\\\ y=y(t) \\\\ z=z(t) \\\\ \\end{array} \\right. t \\in [a,b] $$ 确定的曲线，有 $$\\int_{L} f(x,y,z) \\mathrm{d}s = \\int_{a}^{b} f(x(t),y(t),z(t))\\sqrt{x'^{\\ 2}(t) + y'^{\\ 2}(t) + z'^{\\ 2}(t)} \\mathrm{d}t$$ 利用第一类曲线积分求柱体侧面积\n母线平行于 $z$ 轴的柱面 $S: f(x,y) = 0$ 上介于两曲线弧 $$l_1: \\left\\{ \\begin{array}{c} z=z_1(x,y) \\\\ \\\\ f(x,y) = 0 \\end{array} \\right.，l_2: \\left\\{ \\begin{array}{c} z=z_2(x,y) \\\\ \\\\ f(x,y) = 0 \\end{array} \\right.，z_1(x,y) \\geqslant z_2(x,y)$$ 之间的曲面面积为 $$S = \\int_L [z_1(x,y)-z_2(x,y)] \\mathrm{d}l $$ 第二类曲线积分 对于由参数方程 $$\\left\\{ \\begin{array}{c} x=x(t) \\\\ y=y(t) \\\\ z=z(t) \\\\ \\end{array} \\right. t \\in [a,b] $$ 确定的曲线，向量值函数 $\\bm{A} = P(x,y,z)\\bm{i} + Q(x,y,z)\\bm{j} + R(x,y,z)\\bm{k} $， 有 $$\\begin{align*} \\int_{L} \\bm{A} \\cdot \\mathrm{d} \\bm{r} \u0026= \\int_{L} P(x,y,z) \\mathrm{d}x + \\int_{L} Q(x,y,z) \\mathrm{d}y + \\int_{L} R(x,y,z) \\mathrm{d}z \\\\ \u0026= \\int_{a}^{b} [P(x(t),y(t),z(t))x'(t) + Q(x(t),y(t),z(t))y'(t) \\\\ \u0026 \\qquad + R(x(t),y(t),z(t))z'(t)] \\mathrm{d}t \\end{align*}$$ 两类曲线积分之间的联系\n$$\\int_{L} P \\mathrm{d}x + Q \\mathrm{d}y + R \\mathrm{d}z = \\int_{L} [P\\cos \\alpha + Q\\cos \\beta + R\\cos \\gamma] \\mathrm{d}s $$ 格林公式 曲面积分 第一类曲面积分（一投二代三根号） 对于曲面 $z=z(x,y)$，有 $$\\iint\\limits_{\\varSigma} f(x,y,z) \\mathrm{d}S = \\iint\\limits_{D_{xy}} f(x,y,z(x,y)) \\sqrt{1+z_x^{'\\ 2}(x,y) + z_y^{'\\ 2}(x,y)} \\mathrm{d}\\sigma $$ 第二类曲面积分（一投二代三符号） 对于曲面 $z=z(x,y)$，有 $$\\begin{array}{c} \\displaystyle \\iint\\limits_{\\varSigma} R(x,y,z) \\mathrm{d}x\\mathrm{d}y = \\pm \\iint\\limits_{D_{xy}} R(x,y,z(x,y)) \\mathrm{d}\\sigma \\\\ \\\\ \\displaystyle \\iint\\limits_{\\varSigma} P(x,y,z) \\mathrm{d}y\\mathrm{d}z = \\pm \\iint\\limits_{D_{yz}} P(x(y,z),y,z) \\mathrm{d}\\sigma \\\\ \\\\ \\displaystyle \\iint\\limits_{\\varSigma} Q(x,y,z) \\mathrm{d}x\\mathrm{d}z = \\pm \\iint\\limits_{D_{xz}} Q(x,y(x,z),z) \\mathrm{d}\\sigma \\end{array}$$ 其中正负号由积分曲面的方向决定.\n高斯公式 三大公式 格林公式 $$\\oint_{L} P \\mathrm{d}x + Q \\mathrm{d}y = \\iint\\limits_{D} \\left( \\frac{\\partial Q}{\\partial x} - \\frac{\\partial P}{\\partial y} \\right) \\mathrm{d}\\sigma $$ 高斯公式 $$\\oiint\\limits_{\\varSigma} P \\mathrm{d}y\\mathrm{d}z + Q \\mathrm{d}x\\mathrm{d}z + R \\mathrm{d}x\\mathrm{d}y = \\iiint\\limits_{\\varOmega} \\left( \\frac{\\partial P}{\\partial x} + \\frac{\\partial Q}{\\partial y} + \\frac{\\partial R}{\\partial z} \\right) \\mathrm{d}V $$ 斯托克斯公式 $$\\begin{align*} \\oint_{\\varGamma} (P \\mathrm{d}x + Q \\mathrm{d}y + R \\mathrm{d}z) \u0026= \\iint\\limits_{\\varSigma} \\left[ \\left( \\frac{\\partial R}{\\partial y} - \\frac{\\partial Q}{\\partial z} \\right) \\mathrm{d}y\\mathrm{d}z + \\left( \\frac{\\partial P}{\\partial z} - \\frac{\\partial R}{\\partial x} \\right) \\mathrm{d}z\\mathrm{d}x + \\left( \\frac{\\partial Q}{\\partial x} - \\frac{\\partial P}{\\partial y} \\right) \\mathrm{d}x\\mathrm{d}y \\right] \\\\ \u0026= \\iint\\limits_{\\varSigma} \\left| \\begin{matrix} \\mathrm{d}y\\mathrm{d}z \u0026 \\mathrm{d}z\\mathrm{d}x \u0026 \\mathrm{d}x\\mathrm{d}y \\\\\\\\ \\dfrac{\\partial}{\\partial x} \u0026 \\dfrac{\\partial}{\\partial y} \u0026 \\dfrac{\\partial}{\\partial z} \\\\\\\\ P \u0026 Q \u0026 R \\end{matrix} \\right| \\end{align*}$$ 级数 数项级数 数项级数收敛的条件 若 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛，则 $\\displaystyle \\lim_{n \\to \\infty} a_n = 0$；反之，若 $\\displaystyle \\lim_{n \\to \\infty} a_n \\ne 0$，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n $ 发散，\n基本数项级数 级数 形式 收敛条件 几何级数 $\\displaystyle \\sum_{n=0}^{\\infty} q^{n} $ 当 $|q|\u0026lt;1$ 时收敛，和 $\\displaystyle S = \\frac{1}{1-q}$ $p$ 级数 $\\displaystyle \\sum_{n=0}^{\\infty} \\frac{1}{n^{p}} $ 当 $p\u0026gt;1$ 时收敛；当 $p \\leqslant 1$ 时发散 调和级数 $\\displaystyle \\sum_{n=1}^{\\infty} \\frac{1}{n}$ 发散 正项级数收敛的判断 比较判别法 设 $\\exists N$，当 $n\u0026gt;N$ 时，$0 \\leqslant a_n \\leqslant b_n$，若 $\\displaystyle \\sum_{n=1}^{\\infty} b_n$ 收敛，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛；若 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散，则 $\\displaystyle \\sum_{n=1}^{\\infty} b_n$ 发散. 极限形式：对两个正项级数 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 和 $\\displaystyle \\sum_{n=1}^{\\infty} b_n$，设 $\\displaystyle \\lim_{n \\to \\infty} \\frac{a_n}{b_n} = l$，若 $0\u0026lt;l\u0026lt;+\\infty$，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 和 $\\displaystyle \\sum_{n=1}^{\\infty} b_n$ 同敛散.\n推论：设 $a_n \\geqslant 0$，$b_n \\geqslant 0$，若 $n \\geqslant n_0$ 时有 $\\displaystyle \\frac{a_{n+1}}{a_{n}} \\leqslant \\frac{b_{n+1}}{b_{n}}$，则有：若$\\displaystyle \\sum_{n=1}^{\\infty} b_n$ 收敛，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛；若 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散，则 $\\displaystyle \\sum_{n=1}^{\\infty} b_n$ 发散.\n比值判别法 设 $a_n\u0026gt;0$，$n=1,2,\\cdots$. 当 $n \\geqslant n_0$ 时，若 $\\displaystyle \\frac{a_{n+1}}{a_n} \\leqslant q \u0026lt; 1$，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛；若 $\\displaystyle \\frac{a_{n+1}}{a_n} \\geqslant 1$，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散. 极限形式：若 $\\displaystyle \\lim_{n \\to \\infty} \\frac{a_{n+1}}{a_n} = q$，则当 $q\u0026lt;1$ 时，$\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛；当 $q\u0026gt;1$ 时，$\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散.\n根值判别法 设 $a_n \\geqslant 0$，若 $\\exists N \\in \\textbf{N}$，使得 $n\u0026gt;N$ 时，有 $\\sqrt[n]{a_n} \\leqslant q \u0026lt; 1$，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛；若对无穷多个 $n$，有 $\\sqrt[n]{a_n} \\geqslant 1$，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散. 极限形式：若 $\\displaystyle \\lim_{n \\to \\infty} \\sqrt[n]{a_n} = q$，则当 $q\u0026lt;1$ 时，$\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛；$q\u0026gt;1$ 时，$\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散.\n积分判别法 设 $x \\geqslant 1$ 时，$f(x) \\geqslant 0$ 且单调递减，则无穷级数 $\\displaystyle \\sum_{n=1}^{\\infty} f(n)$ 与无穷积分 $\\displaystyle \\int_{1}^{\\infty} f(x) \\mathrm{d}x $ 同敛散.\nRabbe判别法 设 $a_n \u0026gt; 0$，$n=1,2,\\cdots$. ①若 $n \u0026gt; n_0$ 时，$\\displaystyle n \\left( \\frac{a_n}{a_{n+1}} - 1 \\right) \\leqslant 1$，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散. ②若 $n \u0026gt; n_0$ 时，$\\displaystyle n \\left( \\frac{a_n}{a_{n+1}} - 1 \\right) \\geqslant r \u0026gt; 1$，则 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛.\n极限形式：若 $\\displaystyle \\lim_{n \\to \\infty} n \\left( \\frac{a_n}{a_{n+1}}-1 \\right) = l$，则当 $l\u0026gt;1$ 时，级数 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛；当 $l\u0026lt;1$ 时，级数 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散.\nGauss判别法 设 $a_n \u0026gt; 0$，满足 $$\\frac{a_n}{a_{n+1}} = 1 + \\frac{1}{n} + \\frac{\\beta}{n \\ln n} + o\\left( \\frac{1}{n \\ln n} \\right)，n \\to \\infty$$ 则当 $\\beta \u0026gt; 1$ 时 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛；当 $\\beta \u0026lt; 1$ 时 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散. 极限形式：若 $\\displaystyle \\lim_{n \\to \\infty} n \\ln n \\left( \\frac{a_n}{a_{n+1}}-1 - \\frac{1}{n} \\right) = \\beta$，则当 $\\beta\u0026gt;1$ 时，级数 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 收敛；当 $\\beta\u0026lt;1$ 时，级数 $\\displaystyle \\sum_{n=1}^{\\infty} a_n$ 发散.\n一般级数收敛的判断 莱布尼茨判别法 设交错级数 $\\displaystyle \\sum_{n=1}^{\\infty} (-1)^{n} a_n$，$a_n \u0026gt;0$，若 $\\{a_n\\}$ 递减趋于0，则 $\\displaystyle \\sum_{n=1}^{\\infty} (-1)^{n} a_n$ 收敛.\n阿贝尔和狄利克雷判别法 (1) 分部求和公式 设数列 $\\{ a_n \\}$和 $\\{ b_n \\}$，记 $\\displaystyle S_k = \\sum_{i=1}^{k} a_i$，$S_0 = 0$，则 $$\\sum_{k=1}^{n} a_k b_k = \\sum_{k=1}^{n-1}S_k(b_k-b_{k+1})+S_n b_n $$ (2) 阿贝尔引理 设数列 $\\{b_n \\}$ 单调，$\\displaystyle S_k = \\sum_{i=1}^{k} a_i$，若 $|S_k| \\leqslant M (k=1,2,\\cdots,n)$，则 $$\\left| \\sum_{k=1}^{n} a_k b_k \\right|\\leqslant M \\left(\\left| b_1 \\right| + 2 \\left| b_n \\right| \\right)$$ (3) 狄利克雷判别法 设数列 $\\{ a_n \\}$和 $\\{ b_n \\}$，记 $\\displaystyle S_k = \\sum_{i=1}^{k} a_i$，若它们满足：$\\{b_n\\}$ 单调且 $\\displaystyle b_n = 0$，$\\{S_k\\}$ 有界，则 $\\displaystyle \\sum_{n=0}^{\\infty} a_n b_n $ 收敛. (4) 阿贝尔判别法 设数列 $\\{ a_n \\}$和 $\\{ b_n \\}$ 满足：$\\{ b_n \\}$ 单调有界，且 $\\displaystyle \\sum_{n=0}^{\\infty} a_n$ 收敛，则 $\\displaystyle \\sum_{n=0}^{\\infty} a_n b_n $ 收敛.\n幂级数 幂级数的收敛半径 对幂级数 $\\displaystyle \\sum_{n=0}^{\\infty} a_n x^{n}$，\n阿贝尔定理 若在 $x_0 \\ne 0$ 处收敛，则它对一切 $\\left| x \\right| \u0026lt; \\left| x_0 \\right|$ 绝对收敛；\n若在 $x_1 \\ne 0$ 处发散，则它对一切 $\\left| x \\right| \u0026gt; \\left| x_1 \\right|$ 发散；\n$R = \\left| x_0 \\right|$ 称为幂级数 $\\displaystyle \\sum_{n=0}^{\\infty} a_n x^{n}$ 的收敛半径.\n幂级数收敛的性质 ① $0\u0026lt;R\u0026lt;+\\infty$，$\\left| x \\right| \u0026lt; R$ 时绝对收敛；$\\left| x \\right| \u0026gt; R$ 时发散. ② $R = +\\infty$，级数在整个数轴上都绝对收敛. ③ $R = 0$，仅在 $x=0$ 时收敛.\n收敛半径公式\n$$R = \\frac{1}{\\displaystyle \\lim_{n \\to \\infty} \\sqrt[n]{\\left| a_n \\right|}} = \\lim_{n \\to \\infty} \\left| \\frac{a_n}{a_{n+1}} \\right|$$函数展开成幂级数 泰勒系数 $\\displaystyle a_n = \\frac{f^{(n)}(x_0)}{n!}$\n参见：麦克劳林公式 傅里叶级数 傅里叶系数 $$\\left\\{ \\begin{array}{c} \\begin{align*} a_n \u0026= \\displaystyle \\frac{1}{\\pi} \\int_{-\\pi}^{\\pi} f(x) \\cos nx \\mathrm{d}x，(n=0,1,2,\\cdots) \\\\ \\\\ \\displaystyle b_n \u0026= \\frac{1}{\\pi} \\int_{-\\pi}^{\\pi} f(x) \\sin nx \\mathrm{d}x，(n=1,2,\\cdots) \\end{align*} \\end{array} \\right.$$傅里叶级数 $$f(x) \\sim \\frac{a_0}{2} + \\sum_{n=1}^{\\infty} \\left( a_n \\cos nx + b_n \\sin nx \\right) $$狄利克雷收敛定理 傅里叶级数的和函数 $S(x)$ 以 $2\\pi$ 为周期，\n$$ S(x) = \\left\\{ \\begin{array}{c} \\begin{align*} \u0026f(x)， x为f(x)的连续点 \\\\ \\\\ \u0026 \\displaystyle \\frac{f(x-0)+f(x+0)}{2}，x为f(x)的间断点 \\\\ \\\\ \u0026 \\displaystyle \\frac{f(-\\pi+0)+f(\\pi-0)}{2}，x=\\pm \\pi \\\\ \\end{align*} \\end{array} \\\\ \\right.$$微分方程 可分离变量微分方程 基本形式：\n$$u_1(x)v_1(y) \\mathrm{d}x + u_2(x)v_2(y) \\mathrm{d}y= 0$$求法：将含 $x$，$y$ 的方程分别移至等式两边，再同时求积分.\n一阶线性微分方程 基本形式：\n$$\\frac{\\mathrm{d}y}{\\mathrm{d}x} + P(x)y = Q(x)$$通解可表示为 $$y = \\mathrm{e}^{-\\int P(x) \\mathrm{d}x} \\left[ \\int Q(x) \\mathrm{e}^{\\int P(x) \\mathrm{d}x} \\mathrm{d}x + C \\right] $$全微分方程 基本形式：如果存在二元函数 $\\mathrm{d}\\varphi(x,y) = P(x,y) \\mathrm{d}x + Q(x,y) \\mathrm{d}y$，则称 $$P(x,y) \\mathrm{d}x + Q(x,y) \\mathrm{d}y = 0$$ 为全微分方程.\n$P(x,y) \\mathrm{d}x + Q(x,y) \\mathrm{d}y = 0$ 是全微分方程的充要条件为 $ \\displaystyle \\frac{\\partial P}{\\partial y} = \\frac{\\partial Q}{\\partial x} $\n求法：\n凑全微分法 不定积分法 曲线积分法 可降阶微分方程 形如 $y=f^{(n)}(x)$：积分 $n$ 次，每积分一次加一个常数.\n形如 $y'' = f(x,y')$：令 $\\displaystyle y' = p，y'' = \\frac{\\mathrm{d}p}{\\mathrm{d}x}$，即可降解为一阶微分方程 $\\displaystyle \\frac{\\mathrm{d}p}{\\mathrm{d}x} = f(x,p)$.\n形如 $y'' = f(y,y')$：令 $\\displaystyle y' = p，y'' = p \\frac{\\mathrm{d}p}{\\mathrm{d}y}$，即可降解为一阶微分方程 $\\displaystyle p \\frac{\\mathrm{d}p}{\\mathrm{d}y} = f(y,p)$.\n二阶常系数线性微分方程 基本形式：\n$$y'' + ay' + by = f(x)$$解法：\n解对应的特征方程 $$\\lambda^{2} + a\\lambda + b = 0$$ 得出 $\\lambda_1$，$\\lambda_2$ 两个根.\n得出齐次方程通解 $y(x)$：\n(1) 若 $\\lambda_1$，$\\lambda_2$ 是两个互异实根，则 $y(x)=C_1\\mathrm{e}^{\\lambda_1 x}+C_2\\mathrm{e}^{\\lambda_2 x} $ (2) 若 $\\lambda_1=\\lambda_2$，则 $y(x)=(C_1+C_2)\\mathrm{e}^{\\lambda_1 x} $ (3) 若 $\\lambda_1$，$\\lambda_2$ 是一对共轭复根，即 $\\lambda_{1,2} = \\alpha \\pm \\mathrm{i}\\beta $，则 $y(x)=\\mathrm{e}^{\\alpha x}(C_1 \\cos \\beta x+C_2\\sin \\beta x) $ 求出非齐次方程的特解 $y^{*}$\n写出方程的通解：$y=y(x)+y^{*}$\n小知识 三角公式 诱导公式 $\\sin(x+2k\\pi) = \\sin x$ $\\sin(\\pi \\pm x) = \\mp \\sin x $ $\\displaystyle \\sin \\left(\\frac{\\pi}{2} \\pm x \\right) = \\cos x $ $\\cos(x+2k\\pi) = \\cos x$ $\\cos(\\pi \\pm x) = -\\cos x $ $\\displaystyle \\cos \\left(\\frac{\\pi}{2} \\pm x \\right) = \\mp \\sin x $ $\\tan(x+k\\pi) = \\tan x$ $\\tan(\\pi \\pm x) = \\pm \\tan x$ $ \\displaystyle \\tan \\left(\\frac{\\pi}{2} \\pm x \\right) = \\mp \\cot x $ 两角和差与二倍角公式 $\\cos(\\alpha \\pm \\beta) = \\cos\\alpha\\cos\\beta \\mp \\sin\\alpha\\sin\\beta$ $\\cos(2\\alpha) = \\cos^2 \\alpha - \\sin^2 \\alpha = 2\\cos^2\\alpha-1$ $\\sin(\\alpha \\pm \\beta) = \\sin\\alpha\\cos\\beta \\pm \\cos\\alpha\\sin\\beta$ $\\sin(2\\alpha) = 2\\sin\\alpha\\cos\\alpha$ $\\displaystyle \\tan(\\alpha \\pm \\beta) = \\frac{\\tan\\alpha \\pm \\tan\\beta}{1 \\mp \\tan\\alpha\\tan\\beta}$ $\\displaystyle \\tan(2\\alpha) = \\frac{2\\tan\\alpha}{1-\\tan^2\\alpha}$ 和差化积与积化和差公式 $\\displaystyle \\sin\\alpha+\\sin\\beta = 2\\sin\\frac{\\alpha+\\beta}{2} \\cdot \\cos\\frac{\\alpha-\\beta}{2}$ $\\displaystyle \\sin\\alpha-\\sin\\beta = 2\\cos\\frac{\\alpha+\\beta}{2} \\cdot \\sin\\frac{\\alpha-\\beta}{2}$ $\\displaystyle \\cos\\alpha+\\cos\\beta = 2\\cos\\frac{\\alpha+\\beta}{2} \\cdot \\cos\\frac{\\alpha-\\beta}{2}$ $\\displaystyle \\cos\\alpha-\\cos\\beta = -2\\sin\\frac{\\alpha+\\beta}{2} \\cdot \\sin\\frac{\\alpha-\\beta}{2}$ $\\displaystyle \\sin\\alpha\\cos\\beta = \\frac{1}{2} \\left[\\sin(\\alpha+\\beta) + \\sin(\\alpha-\\beta) \\right] $ $\\displaystyle \\cos\\alpha\\sin\\beta = \\frac{1}{2} \\left[\\sin(\\alpha+\\beta) - \\sin(\\alpha-\\beta) \\right] $ $\\displaystyle \\cos\\alpha\\cos\\beta = \\frac{1}{2} \\left[\\cos(\\alpha+\\beta) + \\cos(\\alpha-\\beta) \\right] $ $\\displaystyle \\sin\\alpha\\sin\\beta = -\\frac{1}{2} \\left[\\cos(\\alpha+\\beta) - \\cos(\\alpha-\\beta) \\right] $ 斐波那契数列 递推公式：$F_{n} = F_{n-1} + F_{n-2}$，用矩阵表示为 $$\\left[\\begin{array}{c} F_{n+1} \\\\ F_{n} \\\\ \\end{array} \\right] = \\left[\\begin{matrix} 1\u0026 1 \\\\ 1\u0026 0 \\\\ \\end{matrix}\\right] \\left[\\begin{array}{c} F_{n} \\\\ F_{n-1} \\\\ \\end{array} \\right] $$记 $$\\bm{A} = \\left[\\begin{matrix} 1\u0026 1 \\\\ 1\u0026 0 \\\\\\end{matrix} \\right] ， \\bm{D}_{n} = \\left[\\begin{array}{c} F_{n+1} \\\\ F_{n} \\\\ \\end{array}\\right] $$则 $$\\bm{D}_{n} = \\bm{A} \\bm{D}_{n-1}$$递推得 $$\\bm{D}_{n} = \\bm{A}^{n} \\bm{D}_{0} $$下面计算 $\\bm{A}^{n}$.\n易知$\\bm{A}$的特征多项式为$f(\\lambda) = \\lambda ^ {2} - \\lambda - 1$，特征值为 $\\displaystyle \\lambda_{1} = \\frac{1-\\sqrt{5}}{2}$，$\\displaystyle\\lambda_{2} = \\frac{1+\\sqrt{5}}{2}$，相应的特征向量分别为 $$\\bm{\\xi}_{1} = \\left[\\begin{array}{c} 1 \\\\ -\\lambda_{2} \\end{array}\\right]， \\bm{\\xi}_{2} = \\left[\\begin{array}{c} 1 \\\\ -\\lambda_{1} \\\\ \\end{array}\\right]$$令 $\\bm{T} = \\left[\\bm{\\xi}_1, \\bm{\\xi}_2\\right]$，则\n$$\\bm{A} = \\bm{T} \\left[\\begin{matrix} \\lambda_1 \u0026 \\\\ \u0026 \\lambda_2 \\\\ \\end{matrix}\\right] \\bm{T}^{-1} $$于是 $$\\begin{align*} \\bm{A}^{n} \u0026= \\bm{T} \\left[\\begin{matrix} \\lambda_{1}^{n} \u0026 \\\\ \u0026 \\lambda_{2}^{n} \\\\ \\end{matrix}\\right] \\bm{T}^{-1} = \\left[\\begin{matrix} 1\u0026 1 \\\\ -\\lambda_{2}\u0026 -\\lambda_{1} \\\\ \\end{matrix}\\right] \\left[\\begin{matrix} \\lambda_{1}^{n}\u0026 \\\\ \u0026 \\lambda_{2}^{n} \\\\ \\end{matrix}\\right] \\left[\\begin{matrix} 1\u0026 1 \\\\ -\\lambda_{2}\u0026 -\\lambda_{1} \\\\ \\end{matrix}\\right]^{-1} \\\\ \u0026= \\frac{1}{\\sqrt{5}} \\left[\\begin{matrix} \\lambda_{2}^{n+1} - \\lambda_{1}^{n+1}\u0026 \\lambda_{2}^{n}- \\lambda_{1}^{n} \\\\ \\lambda_{2}^{n}- \\lambda_{1}^{n}\u0026 \\lambda_{2}^{n-1} - \\lambda_{1}^{n-1} \\\\ \\end{matrix}\\right] \\end{align*}$$最后将 $ \\bm{A}^{n} $ 代入 $\\boldsymbol{D}_n = \\boldsymbol{A}^{n} \\boldsymbol{D}_0$. 并注意到 $\\boldsymbol{D}_0 = [1,1]^{\\mathrm{T}} $ 且 $\\lambda_1$ 与 $\\lambda_2$ 是 $\\lambda^{2} = \\lambda + 1$ 的根，即得\n$$ F_{n} = \\frac{1}{\\sqrt{5}} \\left[\\left(\\frac{1+\\sqrt{5}}{2}\\right)^{n+1} - \\left(\\frac{1-\\sqrt{5}}{2}\\right)^{n+1} \\right] $$坐标旋转变换 空间直角坐标系如果其原点不动，绕着某一个轴旋转而构成新的坐标系，这个过程就叫做坐标旋转。新旧坐标之间存在一定的转换关系，可以用旋转矩阵表示。\n设坐标系 $Oxyz$ 绕 $z$ 轴逆时针（向着 $z$ 轴正方向看）旋转 $\\theta$ 角，新坐标为 $(x', y', z')$。易知 $z$ 分量不变，简化为在 $xOy$ 平面讨论：\n坐标旋转变换 点 $M_x$ 和点 $M_{x'}$ 分别是点 $M$ 在 $x$ 轴和 $x'$ 轴下的投影。则有：\n$$\\begin{align*} \u0026 \\left\\{ \\begin{array}{c} x = OM_x = OM \\cos \\angle MOM_x = OM \\cos(\\varphi-\\theta) \\\\ y = MM_x = OM \\sin \\angle MOM_x = OM \\sin(\\varphi-\\theta) \\end{array} \\right. \\tag{1} \\\\ \\\\ \u0026 \\left\\{ \\begin{array}{c} x' = OM_{x'} = OM \\cos \\angle MOM_{x'} = OM \\cos\\varphi \\\\ y' = MM_{x'} = OM \\sin \\angle MOM_{x'} = OM \\sin\\varphi \\end{array} \\right. \\tag{2} \\end{align*}$$把（1）式按照三角函数展开得：\n$$\\left\\{ \\begin{array}{c} x = OM \\cos\\varphi\\cos\\theta + OM \\sin\\varphi\\sin\\theta \\\\ y = OM \\sin\\varphi\\cos\\theta - OM \\cos\\varphi\\sin\\theta \\end{array} \\right.$$把（2）式代入（3）式得：\n$$\\left\\{ \\begin{align*} x \u0026= x'\\cos\\theta + y'\\sin\\theta \\\\ y \u0026= -x'\\sin\\theta + y'\\cos\\theta \\end{align*} \\right. $$坐标中的 $z$ 分量不变，即 $z=z'$。这样坐标变换可写成如下形式：\n$$\\left\\{ \\begin{align*} x \u0026= x'\\cos\\theta + y'\\sin\\theta \\\\ y \u0026= -x'\\sin\\theta + y'\\cos\\theta \\\\ z \u0026= z' \\end{align*} \\right.$$将其用矩阵表示为：\n$$\\left[ \\begin{array}{c} x \\\\ y \\\\ z \\end{array} \\right] = \\bm{R}_Z(\\bm{\\theta}) \\left[ \\begin{array}{c} x' \\\\ y' \\\\ z' \\end{array} \\right] $$其中 $$\\bm{R}_Z(\\bm{\\theta}) = \\left[ \\begin{matrix} \\cos\\theta \u0026 \\sin\\theta \u0026 0 \\\\ -\\sin\\theta \u0026 \\cos\\theta \u0026 0 \\\\ 0 \u0026 0 \u0026 1 \\end{matrix} \\right] $$同理可知 $$\\bm{R}_X(\\bm{\\theta}) = \\left[ \\begin{matrix} 1 \u0026 0 \u0026 0 \\\\ 0 \u0026 \\cos\\theta \u0026 \\sin\\theta \\\\ 0 \u0026 -\\sin\\theta \u0026 \\cos\\theta \\end{matrix} \\right]，\\bm{R}_Y(\\bm{\\theta}) = \\left[ \\begin{matrix} \\cos\\theta \u0026 0 \u0026 -\\sin\\theta \\\\ 0 \u0026 1 \u0026 0 \\\\ \\sin\\theta \u0026 0 \u0026 \\cos\\theta \\end{matrix} \\right]$$","date":"2025-08-12T00:00:00Z","permalink":"https://rd806.github.io/passage/math/tips/","title":"微积分"},{"content":"Termux简介 Termux是Android系统上的Linux终端模拟器，能够让用户在未获取root权限的情况下运行Linux虚拟机，并可以安装多个Linux发行版。\nTermux下载Linux发行版 方法1：使用TMOE工具 TMOE是GitHub的2moe大佬制作的容器一键安装脚本（目前不再更新，但仍可继续使用，最新支持Ubuntu 24.04 (LTS) 和Debian 13）\n输入curl -LO https://gitee.com/mo2/linux/raw/2/2.awk \u0026amp;\u0026amp; awk -f 2.awk下载TMOE工具，之后默认全输入Y。\n在语言选择界面使用小键盘的“↑”、“↓”键选择所需语言。\n语言选择界面 选择第一个proot容器，模拟root环境，按回车继续。 环境选择 选择终端配色和字体，看个人喜好。\n是否创建termux.properties，看个人喜好。\n选择DNS解析地址，建议选择阿里（Ali）\nDNS设置 是否需要启用“一言”，看个人喜好。 启用“一言”可以让终端界面出现颜文字、古诗句、名言警句等，很有意思，建议开启。\n选择时区，默认选“Yes”。\n选择共享sd目录，这个需要慎重考虑，它关系到你的Linux发行版的用户文件目录。尽量不要共享整个sd目录，建议选择自定义路径。\n共享sd目录 选择共享Home目录，选择默认选项。 到此为止，TMOE的配置工作全部结束，接下来就可以安装自己喜欢的Linux发行版了。\n方法2：古法装机 Termux启动SSH功能 Termux配置SSH功能后，可以搭配Serverbox软件实现监测Android系统运行状态的功能，还是挺有用的。\n安装并启动 SSH 服务 打开 Termux，依次执行以下命令： 1pkg update \u0026amp;\u0026amp; pkg upgrade -y # 更新软件包列表 2pkg install openssh -y # 安装 OpenSSH 3sshd # 启动 SSH 服务（默认端口为 8022） 注意：Termux 的 SSH 服务默认监听端口是 8022，不是常见的 22。\n查看用户名和 IP 地址 1whoami # 查看用户名（后续连接用） 2ifconfig # 查看本机 IP 地址（需在局域网内） 记下类似 192.168.x.x 的 IP 地址和用户名（如 u0_a123）。\n设置登录密码（可选） 1passwd 输入两次密码即可设置完成。\nTermux 默认仅支持密钥登录，密码登录需额外配置。\n接下来就可以使用SSH连接工具连接Termux了。\n","date":"2025-08-10T00:00:00Z","image":"https://rd806.github.io/passage/system/termux/termux_hu_8a034c697c3d0fc8.png","permalink":"https://rd806.github.io/passage/system/termux/","title":"Termux使用小技巧"},{"content":"回顾知识点 → 题目编号依据红宝书2023年版\n极限与函数 【例1.9】求 $\\displaystyle I=\\lim_{x \\to 1^-} \\frac{\\ln (1-x) + \\tan\\dfrac{\\pi}{2}x}{\\mathrm{cot}\\pi x}$\n点击展开解答 解：将原极限拆分成两项极限之和，则可得：\n$$I_1 = \\lim_{x \\to 1^-} \\frac{\\ln(1-x)}{\\mathrm{cot}\\pi x} = \\lim_{x \\to 1^-} \\frac{-\\dfrac{1}{1-x}}{-\\pi \\mathrm{csc}^2 \\pi x} = \\lim_{x \\to 1^-} \\frac{\\sin^2 \\pi x}{\\pi (1-x)} = \\lim_{x \\to 1^-} \\frac{2\\pi \\sin \\pi x \\cos \\pi x}{-\\pi} = 0 $$$$I_2 = \\lim_{x \\to 1^-} \\frac{\\sin \\pi x}{\\cos \\pi x} \\cdot \\lim_{x \\to 1^-} \\frac{\\sin \\dfrac{\\pi}{2}x}{\\cos \\dfrac{\\pi}{2}x} = (-1) \\cdot \\lim_{x \\to 1^-} \\frac{\\sin \\pi x}{\\cos \\dfrac{\\pi}{2}x} = (-1)\\lim_{x \\to 1^-} \\frac{\\pi \\cos \\pi x}{-\\dfrac{\\pi}{2} \\sin \\dfrac{\\pi}{2}x} = -2 $$则 $I=I_1+I_2=-2$\n① 本题如果想直接使用洛必达法则，还必须证明分子极限为无穷，这是困难的. 因此考虑将其拆分成两项分别计算. ② 使用洛必达法则时，每一次求导之后都应立即检查式子能否化简，例如 $\\displaystyle \\lim_{x \\to 1^-} \\frac{-\\dfrac{1}{1-x}}{-\\pi \\mathrm{csc}^2 \\pi x} = \\lim_{x \\to 1^-} \\frac{\\sin^2 \\pi x}{\\pi (1-x)} $，这样可以大幅降低运算量.\n【例1.13】求极限 $\\displaystyle I = \\lim_{\\varphi \\to 0} \\frac{1-\\cos\\varphi \\sqrt{\\cos 2\\varphi} \\cdots \\sqrt[n]{\\cos n\\varphi}}{\\varphi^2}\\quad (n \\in \\mathbf{N^*})$\n点击展开解答 解：记 $f(\\varphi) = \\cos\\varphi \\sqrt{\\cos 2\\varphi} \\cdots \\sqrt[n]{\\cos n\\varphi}$，则 $f(0)=1$，且 $$f'(\\varphi) = \\left[ \\mathrm{e}^{\\ln f(\\varphi)} \\right]' = \\mathrm{e}^{\\ln f(\\varphi)} [\\ln f(\\varphi)]' = f(\\varphi)\\left( \\sum_{k=1}^n \\frac{\\ln \\cos k\\varphi}{k} \\right)' = -f(\\varphi) \\sum_{k=1}^{n} \\tan k\\varphi $$ 则 $$\\begin{align*} I \u0026= \\lim_{\\varphi \\to 0} \\frac{1-f(\\varphi)}{\\varphi^2} = \\lim_{\\varphi \\to 0} \\frac{-f'(\\varphi)}{2\\varphi} = \\lim_{\\varphi \\to 0} \\frac{f(\\varphi)}{2} \\sum_{k=1}^{n} \\tan k\\varphi \\\\ \u0026= \\frac{f(0)}{2} \\sum_{k=1}^{n} \\left(\\lim_{\\varphi \\to 0} \\frac{\\tan k\\varphi}{\\varphi} \\right) = \\frac{1}{2} \\sum_{k=1}^{n} k = \\frac{1}{4} n(n+1) \\end{align*}$$ 【例1.16】求下列极限：\n（1）$\\displaystyle \\lim_{n \\to \\infty} n \\left[ \\left(1+\\frac{1}{n}\\right)^n - \\mathrm{e} \\right] $；\n（2）$\\displaystyle \\lim_{n \\to \\infty} \\left( \\frac{a^{\\frac{1}{n}}+b^{\\frac{1}{n}}+c^{\\frac{1}{n}}}{3} \\right)^n$，其中 $a \u0026gt; 0$，$b \u0026gt; 0$，$c \u0026gt; 0$\n点击展开解答 解：（1）由海涅定理可知，\n$$\\begin{align*} \\lim_{n \\to \\infty} n \\left[ \\left(1+\\frac{1}{n}\\right)^n - \\mathrm{e} \\right] \u0026= \\lim_{x \\to 0} \\frac{\\left(1+x\\right)^{\\frac{1}{x}} - \\mathrm{e}}{x} = \\mathrm{e} \\lim_{x \\to 0} \\frac{\\mathrm{e}^{\\frac{\\ln (1+x)}{x}-1}-1}{x} = \\mathrm{e}\\lim_{x \\to 0} \\frac{\\dfrac{\\ln (x+1)}{x}-1}{x} \\\\ \u0026= \\mathrm{e}\\lim_{x \\to 0}\\frac{\\ln (1+x)-x}{x^2} = \\mathrm{e} \\lim_{x \\to 0} \\frac{\\dfrac{1}{1+x}-1}{2x} = -\\frac{\\mathrm{e}}{2} \\lim_{x \\to 0} \\frac{1}{x+1} = -\\frac{\\mathrm{e}}{2} \\end{align*} $$（2）由海涅定理，令 $\\displaystyle f(x) = \\left( \\frac{a^x+b^x+c^x}{3} \\right)^{\\frac{1}{x}}$，则原式 $\\displaystyle = \\lim_{x \\to 0} f(x) $，而易知 $\\displaystyle \\ln f(x) = \\frac{\\ln(a^x+b^x+c^x)-\\ln 3}{x}$，则利用洛必达法则，$\\displaystyle \\lim_{x \\to 0} \\ln f(x) = \\lim_{x \\to 0} \\frac{a^x\\ln a+b^x\\ln b+c^x\\ln c}{a^x+b^x+c^x} = \\ln \\sqrt[3]{abc}$. 因此 $\\displaystyle \\lim_{x \\to 0} f(x) = \\sqrt[3]{abc}$，即所求极限为 $\\sqrt[3]{abc}$.\n求复杂的数列极限时，可考虑使用海涅定理，将数列极限转化为函数极限. 但是注意，必须强调“海涅定理”，不可直接对数列极限作“求导”操作.\n【例1.18】设函数 $f(x)$ 在 $x=0$ 的某领域内存在 $n$ 阶导数，$f(0)=f'(0)=\\cdots=f^{(n-1)}(0)=0$，而 $f^{(n)}(0) \\ne 0$，求极限 $\\displaystyle I=\\frac{\\displaystyle \\int_{0}^{x}(x-t)f(t)\\mathrm{d}t}{\\displaystyle x\\int_{0}^{x}f(x-t)\\mathrm{d}t}$\n点击展开解答 解：设 $u=x-t$，则有 $\\displaystyle \\int_{0}^{x} f(x-t) \\mathrm{d}t = \\int_{x}^{0} -f(u) \\mathrm{d}u = \\int_{0}^{x} f(u) \\mathrm{d}u = \\int_{0}^{x} f(t) \\mathrm{d}t $. 则有\n$$\\begin{align*} I \u0026= \\lim_{x \\to 0} \\frac{\\displaystyle x\\int_{0}^{x} f(t) \\mathrm{d}t - \\int_{0}^{x} tf(t) \\mathrm{d}t}{\\displaystyle x\\int_{0}^{x} f(u)\\mathrm{d}u } = 1 - \\lim_{x \\to 0} \\frac{\\displaystyle \\int_{0}^{x} tf(t) \\mathrm{d}t}{\\displaystyle x\\int_{0}^{x} f(t) \\mathrm{d}t} = 1 - \\lim_{x \\to 0} \\frac{\\displaystyle xf(x)}{\\displaystyle xf(x) + \\int_{0}^{x} f(t) \\mathrm{d}t} \\\\ \\\\ \u0026= 1 - \\frac{1}{1 + \\displaystyle \\lim_{x \\to 0} \\dfrac{\\displaystyle \\int_{0}^{x} f(t) \\mathrm{d}t }{xf(x)}} \\end{align*}$$而由泰勒公式，$\\displaystyle f(x) = \\frac{f^{(n)}(0)}{n!}x^n + o(x^n)$，即得 $\\displaystyle f'(x) = \\frac{f^{n}(0)}{(n-1)!}x^{n-1} + o(x^{n-1})$. 所以\n$$\\lim_{x \\to 0} \\frac{\\displaystyle \\int_{0}^{x} f(t) \\mathrm{d}t}{xf(x)} = \\lim_{x \\to 0} \\frac{f(x)}{f(x) + xf'(x)} = \\lim_{x \\to 0} \\frac{\\dfrac{f^{(n)}(0)}{n!}x^n + o(x^n)}{\\dfrac{f^{(n)}(0)}{n!}x^n + \\dfrac{f^{(n)}(0)}{(n-1)!}x^n + o(x^n)} = \\frac{1}{n+1}$$代入得 $\\displaystyle I = \\frac{1}{n+2}$\n【例1.58】设 $x_1=2021$，$x_n^2-2(x_n+1)x_{n+1}+2021=0 \\ (n \\geqslant 1)$. 证明数列 $\\{x_n\\}$ 收敛，并求极限 $\\displaystyle \\lim_{n \\to \\infty} x_n$.\n点击展开解答 解：构造函数 $\\displaystyle f(x) = \\frac{x}{2} + \\frac{a}{x} \\ (x\u0026gt;0)$，其中 $a=1011$. 再令 $y_n = 1+x_n$，则 $y_1=2a$，且当 $n \\geqslant 1$ 时，有 $y_{n+1}=f(y_n)$. 易知当 $x\u0026gt;\\sqrt{2a}$ 时有 $x\u0026gt;f(x)\u0026gt;\\sqrt{2a}$，所以 ${y_n}$ 单调递减且以 $\\sqrt{2021}$ 为下界. 由此可得 $\\{y_n\\}$ 收敛，可推知 $\\{x_n\\}$ 收敛.\n记 $\\displaystyle \\lim_{n \\to \\infty} y_n = A$， 由 $y_{n+1} = f(y_n)$ 得 $A=f(A)$，即 $A = \\sqrt{2A}$. 因此 $$\\lim_{n \\to \\infty} x_n = \\sqrt{2a}-1 = \\sqrt{2022}-1 $$ 为什么构造函数 $\\displaystyle f(x) = \\frac{x}{2} + \\frac{a}{x} \\ (x\u0026gt;0)$？\n题中所给方程中有 $2(x_n+1)x_{n+1}$，多出一个 $2x_{n+1}$.\n【例1.62】设函数 $f(x)$ 在 $x=0$ 的某领域内具有二阶连续导数，且 $f(0), f'(0), f''(x)$ 均不为零. 证明：存在唯一的一组实数 $k_1, k_2, k_3$，使得 $$\\lim_{h \\to 0} \\frac{k_1 f(h)+k_2 f(2h)+k_3 f(3h) - f(0)}{h^2} = 0$$ 点击展开解答 解：记分子为 $F(x)$. 由泰勒公式，可知当 $h \\to 0$ 时，有：\n$$f(h)=f(0)+f'(0)h+\\frac{1}{2}f''(0)h^2+o(h^2)$$ $$f(2h)=f(0)+2f'(0)h+2f''(0)h^2+o(h^2)$$ $$f(3h)=f(0)+3f'(0)h+\\frac{9}{2}f''(0)h^2+o(h^2)$$从而有：\n$$F(x) = (k_1+k_2+k_3)f(0)+(k_1+2k_2+3k_3)f'(0)+\\frac{1}{2}(k_1+4k_2+9k_3)f''(0) + o(h^2)$$若要使原极限值为0，则只需 $k_1, k_2, k_3$ 满足方程组 $$\\left\\{ \\begin{array}{c} k_1+k_2+k_3 = 0 \\\\ k_1+2k_2+3k_3 = 0 \\\\ k_1+4k_2+9k_3 = 0 \\end{array} \\right.$$易知此方程组的系数行列式 $$\\left| \\begin{matrix} 1 \u0026 1 \u0026 1 \\\\ 1 \u0026 2 \u0026 3 \\\\ 1 \u0026 4 \u0026 9 \\end{matrix} \\right| = 2 \\ne 0$$即方程组有解，故存在唯一的一组实数 $k_1, k_2, k_3$ 满足要求.\n注意到分母为 $h^2$，联想到二阶泰勒公式.\n【例1.65】设 $\\displaystyle A_n = \\frac{n}{n^2+1^2} + \\frac{n}{n^2+2^2} + \\cdots + \\frac{n}{n^2+n^2} $，求极限 $\\displaystyle \\lim_{n \\to \\infty} n \\left( \\frac{\\pi}{4}-A_n \\right)$\n点击展开解答 解：记 $\\displaystyle x_k = \\frac{k}{n}$，$\\displaystyle f(x)=\\frac{1}{1+x^2}$，易知 $\\displaystyle \\frac{\\pi}{4} = \\int_{0}^{1} \\frac{1}{1+x^2} \\mathrm{d}x = \\int_{0}^{1} f(x) \\mathrm{d}x $，从而有：\n$$\\frac{\\pi}{4}-A_n = \\int_{0}^{1}f(x)\\mathrm{d}x - \\frac{1}{n} \\sum_{k=1}^{n} \\frac{1}{1+x_k^2} = \\sum_{k=1}^{n} \\int_{x_{k-1}}^{x_k} [f(x)-f(x_k)] \\mathrm{d}x $$对 $f(x)$ 在区间 $[x,x_k]$ 上运用拉格朗日中值定理，则存在 $\\xi_k \\in [x,x_k]$，使得 $f(x)-f(x_k)=f'(\\xi_k)(x-x_k)$，所以\n$$n\\left(\\frac{\\pi}{4}-A_n\\right) = n \\sum_{k=1}^{n} \\int_{x_{k-1}}^{x_k} [f(x)-f(x_k)] \\mathrm{d}x = n \\sum_{k=1}^{n} \\int_{x_{k-1}}^{x_k} f'(\\xi_k)(x-x_k) \\mathrm{d}x $$设 $f'(x)$ 在 $[x,x_k]$ 上的最小值与最大值分别为 $m_k, M_k$，注意到 $\\displaystyle \\int_{x_{k-1}}^{x_k} (x-x_k) \\mathrm{d}x = -\\frac{1}{2n^2} $，所以\n$$m_k \\leqslant 2n^2 \\int_{x_{k-1}}^{x_k} f'(\\xi_k) (x_k-x) \\mathrm{d}x \\leqslant M_k$$对 $f'(x)$ 利用连续函数的介值定理，存在 $\\eta_k \\in [x_{k-1},x_k]$，使得\n$$f'(\\eta_k) = 2n^2 \\int_{x_{k-1}}^{x_k} f'(\\xi_k) (x_k-x) \\mathrm{d}x$$代入原式，得\n$$\\lim_{n \\to \\infty} n \\left( \\frac{\\pi}{4}-A_n \\right) = -\\frac{1}{2} \\lim_{n \\to \\infty} \\frac{1}{n} \\sum_{k=1}^{n}f'(\\eta_k)\\mathrm{d}x = -\\frac{1}{2} \\int_{0}^{1} f'(x)\\mathrm{d}x = -\\frac{1}{2}[f(1)-f(0)] = \\frac{1}{4}$$ 求极限：$\\displaystyle \\lim_{x \\to 0} \\left( \\frac{a^{x^{2}} + b^{x^{2}}}{a^{x} + b^{x}} \\right) ^ {\\frac{1}{x}}$\n点击展开解答 解：利用重要极限，变形得\n$$ \\lim_{x \\to 0} \\left( \\frac{a^{x^{2}} + b^{x^{2}}}{a^{x} + b^{x}} + 1 - 1 \\right) ^ {\\frac{1}{x}} = \\mathrm{exp}\\left\\{\\lim_{x \\to 0} \\frac{a^{x^{2}} + b^{x^{2}} - a^{x} - b^{x}}{a^{x} + b^{x}} \\cdot \\frac{1}{x}\\right\\} $$下面求 $\\displaystyle \\lim_{x \\to 0} \\frac{a^{x^{2}} + b^{x^{2}} - a^{x} - b^{x}}{a^{x} + b^{x}} \\cdot \\frac{1}{x} $，记为 $I$.\n$$\\begin{align*} \\displaystyle I \u0026= \\lim_{x \\to 0} \\frac{1}{a^{x}+b^{x}} \\left[\\frac{a^{x} \\left(a^{x(x-1)} -1\\right)}{x} + \\frac{b^{x} \\left(b^{x(x-1)}-1 \\right)}{x} \\right] \\\\ \u0026= \\lim_{x \\to 0} \\frac{1}{a^{x}+b^{x}} \\left[a^{x} \\frac{\\left(a^{x(x-1)} -1\\right)}{x(x-1)} \\cdot (x-1) + b^{x} \\frac{\\left(b^{x(x-1)}-1 \\right)}{x(x-1)} \\cdot (x-1) \\right] \\\\ \u0026= \\frac{1}{2} (-\\ln a - \\ln b) = \\ln \\frac{1}{\\sqrt{ab}} \\end{align*}$$故原式 $\\displaystyle = \\frac{1}{\\sqrt{ab}} $\n求极限：$\\displaystyle \\lim_{x \\to + \\infty} \\int_{0}^{\\pi} \\sin \\frac{\\pi}{x+t} \\mathrm{d}t$\n点击展开解答 解：由 $\\sin x$ 的泰勒展开式，当 $x$ 为正且 $x$ 充分小时，有\n$$ x - \\frac{x^{3}}{6} \u003c \\sin x \u003c x $$而 $x \\to + \\infty $ 时，$ \\displaystyle \\frac{\\pi}{x+t} \\to 0 $，故原式可放缩为\n$$ \\int_{0}^{x} \\frac{\\pi}{x+t} \\mathrm{d}t - \\frac{\\pi^{3}}{6} \\int_{0}^{x} \\frac{1}{(x+t)^{3}} \\mathrm{d}t \u003c \\int_{0}^{\\pi} \\sin \\frac{\\pi}{x+t} \\mathrm{d}t \u003c \\int_{0}^{\\pi} \\frac{\\pi}{x+t} \\mathrm{d}t $$而 $\\displaystyle \\int_{0}^{\\pi} \\frac{\\pi}{x+t} \\mathrm{d}t = \\pi \\ln 2 $，对 $\\displaystyle \\int_{0}^{x} \\frac{1}{(x+t)^{3}} \\mathrm{d}t $ 有\n$$ \\int_{0}^{x} \\frac{1}{(x+t)^{3}} \\mathrm{d}t = \\frac{1}{2} \\left( \\frac{1}{x^{2}}- \\frac{1}{4x^{2}} \\right) \\to 0 $$由迫敛准则知，原式 $ = \\pi \\ln 2 $.\n求极限：$\\displaystyle \\lim_{x \\to 0} \\frac{1}{n^{4}} \\prod_{i=1}^{2n} (n^{2} + i^{2}) ^{\\frac{1}{n}}$\n点击展开解答 解：由题意， $\\displaystyle \\frac{1}{n^{4}} \\prod_{i=1}^{2n} (n^{2} + i^{2}) ^{\\frac{1}{n}} = \\mathrm{exp} \\left\\{ \\ln \\frac{1}{n^{4}} \\prod_{i=1}^{2n} (n^{2} + i^{2}) ^{\\frac{1}{n}} \\right\\} = \\mathrm{exp} \\left\\{ \\sum_{i=1}^{2n} \\ln (n^{2} + i^{2})^{\\frac{1}{n}} - \\ln n^{4} \\right\\}$，对指数部分做变形，\n$\\displaystyle \\sum_{i=1}^{2n} \\ln (n^{2} + i^{2})^{\\frac{1}{n}} - \\ln n^{4} = \\sum_{i=1}^{2n} \\frac{\\ln n^{2}}{n} + \\sum_{i=1}^{2n} \\frac{\\ln [1+(\\frac{i}{n})^{2}]}{n} - 4 \\ln n = 2 \\ln n^{2} + \\sum_{i=1}^{2n} \\frac{\\ln [1+(\\frac{i}{n})^{2}]}{n}- 4 \\ln n = \\sum_{i=1}^{2n} \\frac{\\ln [1+(\\frac{i}{n})^{2}]}{n}$\n则原式 $\\displaystyle = \\lim_{x \\to \\infty} \\mathrm{exp} \\left\\{ \\sum_{i=1}^{2n} \\frac{\\ln [1+(\\frac{i}{n})^{2}]}{n} \\right\\} = \\mathrm{exp} \\left\\{ \\int_{0}^{2} \\ln (1+x^{2}) \\mathrm{d}x \\right\\} = 25\\mathrm{e}^{2\\arctan 2 - 4}$\n本题核心在于取对数，将连乘转换为连加，从而可以使用微积分的定义解决。\n微分中值定理 设 $f(x)$ 在$[0,1]$上连续，在$(0,1)$内可导，$f(1) = 2f(0)$. 试证明：至少存在一点$\\xi \\in (0,1)$，使得$ (1+\\xi)f'(\\xi) = f(\\xi) $.\n点击展开解答 解：构造函数 $\\displaystyle F(x) = \\frac{f(x)}{x+1} $，可知 $ F(0) = F(1) $. 由罗尔中值定理，存在 $\\xi \\in (a,b)$ 使得 $\\displaystyle F'(\\xi) = \\frac{f'(\\xi)(1+\\xi) - f(\\xi)}{(1+\\xi)^{2}} = 0 $，即 $ (1+\\xi)f'(\\xi) = f(\\xi)$.\n本题核心在于构造辅助函数 $ \\displaystyle F(x) = \\frac{f(x)}{x+1} $. 由相减的形式可考虑函数相除的形式.\n设 $f(x)$ 在 $ [0,1] $上连续，在 $(0,1)$内可导，$ f(0) = 0, f(1) = 1 $, $k_{1}, k_{2}, \\cdots ,k_{n} $为 $n$ 个正数，证明：在区间 $(0,1) $内至少存在一组互不相等的数 $x_{1}, x_{2}, \\cdots, x_{n}$，使得 $\\displaystyle \\sum_{i=1}^{n} \\frac{k_{i}}{f'(x_{i})} = \\sum_{i=1}^{n} k_{i} $.\n点击展开解答 证：记 $\\displaystyle m = \\sum_{i=1}^{n} k_{i} $，$\\displaystyle \\lambda_{i} = \\frac{k_{i}}{m} $，$i = 1, 2, \\cdots, n$，且 $0\u0026lt;\\lambda_{i}\u0026lt;1$, $\\displaystyle \\sum_{i=1}^{n} \\lambda_{i} = 1 $.\n因为 $f(0) = 0, f(1) = 1$，$f(x)$在 $[0,1]$上连续，由界值定理，存在点 $c_{1} \\in (0,1)$，使得 $f(c_{1}) = \\lambda_{1} $；点 $c_{2} \\in (c_{1},1)$，使得 $f(c_{2}) = \\lambda_{1} + \\lambda_{2} $，以此类推，找到点 $0\u0026lt;c_{1}\u0026lt;c_{2}\u0026lt;\\cdots \u0026lt;c_{i} $，使得 $\\displaystyle f(c_{i}) = \\sum_{j=1}^{i} \\lambda_{j} = \\frac{1}{m} \\sum_{j=1}^{i} k_{i}，(i = 1, 2, \\cdots, n-1)$. 记 $c_{0} = 0$，$c_{n} = 1$，则有 $f(c_{n}) = 1$.\n对$f(x)$ 在 $[c_{i-1},c_{i}]$上应用拉格朗日中值定理，存在 $x_{i} \\in (c_{i-1},c_{i})$，$\\displaystyle f'(x_{i}) = \\frac{f(c_{i}) - f(c_{i-1})}{c_{i} - c_{i-1}} = \\frac{\\lambda_{i}}{c_{i} - c_{i-1}}$，则 $\\displaystyle \\frac{\\lambda_{i}}{f'(x_{i})} = c_{i} - c_{i-1} $\n两边同时求和，得 $$\\sum_{i=1}^{n} \\frac{\\lambda_{i}}{f'(x_{i})} = \\sum_{i=1}^{n} (c_{i} - c_{i-1}) = c_{n} - c_{0} = 1 $$代入 $\\displaystyle \\lambda_{i} = \\frac{k_{i}}{m} $，得 $\\displaystyle \\sum_{i=1}^{n} \\frac{k_{i}}{f'(x_{i})} = m = \\sum_{i=1}^{n} k_{i} $\n设函数 $\\varphi(x)$可导，且满足 $\\varphi(x) = 0 $，又设 $\\varphi'(x)$单调递减.\n(1) 证明：对 $x \\in (0,1)$，有 $\\varphi(1)x \u0026lt; \\varphi(x) \u0026lt; \\varphi'(0)x$；\n(2) 若 $ \\varphi(1) \\geqslant 0$，$\\varphi'(0) \\leqslant 1$，任取 $x_{0} \\in (0,1)$，令 $x_{n} = \\varphi(x_{n-1}), (n=1,2,\\cdots)$. 证明：$\\displaystyle \\lim_{n \\to \\infty} x_{n} $ 存在，并求出该极限值.\n点击展开解答 证：\n一元函数积分学 求积分：$\\displaystyle \\int \\frac{\\cos ^{3} x}{1 + \\cos x \\sin x} \\mathrm{d}x$\n点击展开解答 解：令 $\\displaystyle I = \\int \\frac{\\cos ^{3} x}{1 + \\cos x \\sin x} \\mathrm{d}x$，$\\displaystyle J = \\int \\frac{\\sin ^{3} x}{1 + \\cos x \\sin x} \\mathrm{d}x$，则\n$$I-J = \\int \\frac{\\cos^{3} x - \\sin^{3} x}{1 + \\cos x \\sin x} \\mathrm{d}x = \\int (\\cos x - \\sin x)\\mathrm{d}x = \\sin x + \\cos x + C_{1}$$$$\\begin{align*} I+J \u0026= \\int \\frac{\\cos^{3} x + \\sin^{3} x}{1 + \\cos x \\sin x} \\mathrm{d}x = \\int \\frac{(\\cos x + \\sin x)(1-\\sin x \\cos x)}{1+\\sin x \\cos x}\\mathrm{d}x \\\\ \u0026= \\int \\frac{1+(\\sin x + \\cos x)^{2}}{3-(\\sin x - \\cos x)^{2}} \\mathrm{d}(\\sin x - \\cos x) \\xlongequal{t = \\sin x - \\cos x} \\int \\frac{1+t^{2}}{3-t^{2}} \\mathrm{d}t \\\\ \u0026= \\int \\left(\\frac{4}{3-t^{2}} - 1\\right)\\mathrm{d}t = \\frac{2}{\\sqrt{3}} \\ln \\left|\\frac{\\sqrt{3}+t}{\\sqrt{3}-t}\\right| - t + C_{2} \\\\ \u0026= \\frac{2}{\\sqrt{3}} \\ln \\left|\\frac{\\sqrt{3}+\\sin x - \\cos x}{\\sqrt{3}-\\sin x + \\cos x}\\right| - \\sin x + \\cos x + C_{2} \\end{align*}$$解上述方程得：$\\displaystyle I = \\frac{1}{\\sqrt{3}} \\ln \\left|\\frac{\\sqrt{3}+\\sin x - \\cos x}{\\sqrt{3}-\\sin x + \\cos x}\\right| + \\cos x + C$\n求积分： $$I =\\int_{0}^{7} \\left( \\sqrt[3]{x-\\sqrt{x^{2}-1}}+\\sqrt[3]{x+\\sqrt{x^{2}+1}}\\right) \\mathrm{d}x$$ 点击展开解答 解：令 $\\displaystyle f(x) = \\left( \\sqrt[3]{x-\\sqrt{x^{2}-1}}+\\sqrt[3]{x+\\sqrt{x^{2}+1}}\\right)$，考虑它的反函数：\n$\\displaystyle y^{3} = x-\\sqrt{x^{2}-1}+x+\\sqrt{x^{2}+1} + 3 \\sqrt[3]{\\left( x-\\sqrt{x^{2}+1}\\right)^{2} \\left(x+\\sqrt{x^{2}+1}\\right) } + 3 \\sqrt[3]{\\left( x+\\sqrt{x^{2}+1} \\right)^{2} \\left(x-\\sqrt{x^{2}+1}\\right)} = 2x - 3 \\sqrt[3]{x-\\sqrt{x^{2}+1}} - 3 \\sqrt[3]{x+\\sqrt{x^{2}+1}} = 2x - 3y$\n解得 $\\displaystyle x = \\frac{y^{3}+3y}{2}$，则令 $ x = 7$，得 $ y^{3} + 3y = 14$，解得 $y = 2$. 则：\n$$ I = 2 \\cdot 7 - \\int_{0}^{2} \\frac{x^{3}+3x}{2} \\mathrm{d}x = 14 - \\left( \\frac{x^{4}}{8} + \\frac{3x^{2}}{4} \\right) \\Bigg|_{0}^{2} = 9$$ 【例3.79】证明柯西积分不等式 $$\\left[ \\int_{a}^{b} f(x)g(x) \\mathrm{d}x \\right]^{2} \\leqslant \\int_{a}^{b} f^{2}(x) \\mathrm{d}x \\int_{a}^{b} g^{2}(x) \\mathrm{d}x $$ 其中 $f(x)$，$g(x)$ 均为 $[a,b]$ 上的连续函数.\n点击展开解答 证：设$D$：$a \\leqslant x \\leqslant b, a \\leqslant y \\leqslant b$，则\n$$\\begin{array}{c} \\begin{align*} \u0026 \\quad \\left[\\int_{a}^{b} f(x)g(x) \\mathrm{d}x \\right]^{2} \\\\ \u0026= \\int_{a}^{b} f(x)g(x) \\mathrm{d}x \\int_{a}^{b} f(y)g(y) \\mathrm{d}y \\\\ \u0026= \\iint\\limits_{D} f(x)g(y) \\cdot f(y)g(x) \\mathrm{d}x\\mathrm{d}y \\\\ \u0026 \\leqslant \\iint\\limits_{D} \\frac{1}{2} \\left[ f^{2}(x)g^{2}(y) + f^{2}(y)g^{2}(x) \\right] \\mathrm{d}x\\mathrm{d}y \\\\ \u0026= \\frac{1}{2} \\iint\\limits_{D} f^{2}(x)g^{2}(y) \\mathrm{d}x\\mathrm{d}y + \\frac{1}{2} \\iint\\limits_{D}f^{2}(y)g^{2}(x) \\mathrm{d}x\\mathrm{d}y \\\\ \u0026= \\frac{1}{2} \\int_{a}^{b} f^{2}(x) \\mathrm{d}x \\int_{a}^{b} g^{2}(y) \\mathrm{d}y + \\frac{1}{2} \\int_{a}^{b} f^{2}(y) \\mathrm{d}y \\int_{a}^{b} g^{2}(x) \\mathrm{d}x \\\\ \u0026= \\frac{1}{2} \\int_{a}^{b} f^{2}(x) \\mathrm{d}x \\int_{a}^{b} g^{2}(x) \\mathrm{d}x + \\frac{1}{2} \\int_{a}^{b} f^{2}(x) \\mathrm{d}x \\int_{a}^{b} g^{2}(x) \\mathrm{d}x \\\\ \u0026= \\int_{a}^{b} f^{2}(x) \\mathrm{d}x \\int_{a}^{b} g^{2}(x) \\mathrm{d}x \\\\ \\end{align*} \\end{array}$$ 多元函数积分学 【例7.26】计算三重积分：$\\displaystyle I=\\iiint\\limits_{\\varOmega} \\frac{\\mathrm{d}x\\mathrm{d}y\\mathrm{d}z}{(1+x^2+y^2+z^2)^2} $，其中 $\\varOmega: 0 \\leqslant x \\leqslant 1, 0 \\leqslant y \\leqslant 1, 0 \\leqslant z \\leqslant 1$\n点击展开解答 解：利用重积分的轮换对称性，有：\n$$\\begin{align*} I \u0026= 2\\int_{0}^{1} \\mathrm{d}z \\iint\\limits_{D} \\frac{\\mathrm{d}x\\mathrm{d}y}{(1+x^2+y^2+z^2)^2} = 2\\int_{0}^{1} \\mathrm{d}z \\int_{0}^{\\frac{\\pi}{4}} \\mathrm{d}\\theta \\int_{0}^{\\mathrm{sec}\\theta} \\frac{r\\mathrm{d}r}{(1+r^2+z^2)^2} \\\\ \u0026= \\int_{0}^{1} \\mathrm{d}z \\int_{0}^{\\frac{\\pi}{4}} \\left( \\frac{1}{1+z^2}-\\frac{1}{1+\\mathrm{sec}^2 \\theta+z^2} \\right) \\mathrm{d}\\theta \\\\ \u0026= \\frac{\\pi}{4}\\int_{0}^{1} \\frac{\\mathrm{d}z}{1+z^2} - \\int_{0}^{\\frac{\\pi}{4}} \\mathrm{d}\\theta \\int_{0}^{1} \\frac{\\mathrm{d}z}{1+\\mathrm{sec}^2 \\theta +z^2} = \\frac{\\pi^2}{16}-I_1 \\end{align*}$$下面计算 $I_1$，作变量代换 $z=\\tan t$，利用对称性，有\n$$\\begin{align*} I_1 \u0026= \\int_{0}^{\\frac{\\pi}{4}} \\mathrm{d}\\theta \\int_{0}^{1} \\frac{\\mathrm{d}z}{1+\\mathrm{sec}^2 \\theta +z^2} \\\\ \u0026= \\int_{0}^{\\frac{\\pi}{4}} \\mathrm{d}\\theta \\int_{0}^{\\frac{\\pi}{4}} \\frac{\\mathrm{sec}^2 t}{\\mathrm{sec}^2 \\theta +\\mathrm{sec}^2 t} \\mathrm{d}t = \\int_{0}^{\\frac{\\pi}{4}} \\mathrm{d}t \\int_{0}^{\\frac{\\pi}{4}} \\frac{\\mathrm{sec}^2 \\theta}{\\mathrm{sec}^2 \\theta + \\mathrm{sec}^2 t} \\mathrm{d}\\theta \\\\ \u0026= \\frac{1}{2} \\int_{0}^{\\frac{\\pi}{4}} \\mathrm{d}\\theta \\int_{0}^{\\frac{\\pi}{4}} \\frac{\\mathrm{sec}^2 t+\\mathrm{sec}^2\\theta}{\\mathrm{sec}^2 \\theta+\\mathrm{sec}^2 t} \\mathrm{d}t = \\frac{\\pi^{2}}{32} \\end{align*}$$故 $\\displaystyle I=\\frac{\\pi^2}{16}-\\frac{\\pi^2}{32} = \\frac{\\pi^2}{32}$.\n【例7.28】 计算：$\\displaystyle I=\\iint\\limits_{D}\\mathrm{sgn} (x+y)\\mathrm{e}^{x^2+y^2} \\mathrm{d}x \\mathrm{d}y$，$D: x^2 \\leqslant y \\leqslant \\sqrt{1-x^2}$，其中 $\\mathrm{sgn}(x)$ 为符号函数.\n点击展开解答 解：如图，作出积分区域 $D$，构造两条辅助线 $y=x$，$y=-x$ 将积分区域分成三部分.\n易知在区域 $D_1$ 上有 $\\mathrm{sgn}(x+y) = -1$，区域 $D_2, D_3$ 上有 $\\mathrm{sgn}(x+y) = 1$.\n由重积分的对称性可得 $$\\iint\\limits_{D_1} \\mathrm{sgn}(x+y) \\mathrm{e}^{x^2+y^2} \\mathrm{d}x\\mathrm{d}y = -\\iint\\limits_{D_3} \\mathrm{sgn}(x+y) \\mathrm{e}^{x^2+y^2} \\mathrm{d}x\\mathrm{d}y $$因此 $\\displaystyle I = \\iint\\limits_{D_2} \\mathrm{sgn}(x+y) \\mathrm{e}^{x^2+y^2} \\mathrm{d}x\\mathrm{d}y = 2 \\int_{\\frac{\\pi}{4}}^{\\frac{\\pi}{2}} \\mathrm{d}\\theta \\int_{0}^{1} r\\mathrm{e}^{r^2} \\mathrm{d}r = \\frac{\\pi}{4} (\\mathrm{e}-1) $\n本题通过构造辅助线 $y = x$，利用重积分的对称性，将积分区域转换成易于计算的扇形.\n【例7.30】 计算：$\\displaystyle I = \\iint\\limits_{D} \\left| \\frac{x+y}{\\sqrt{2}}-x^2-y^2 \\right| \\mathrm{d}x\\mathrm{d}y$，其中 $D: x^2+y^2 \\leqslant 1$.\n点击展开解答 方法1：令 $x=r\\cos \\theta, y=r\\sin \\theta$，则 $\\displaystyle I = \\int_{0}^{2\\pi} \\mathrm{d}\\theta \\int_{0}^{1} \\left| r \\sin (\\theta+\\frac{\\pi}{4}) - r^2 \\right| \\mathrm{d}r$，记 $\\displaystyle \\varphi = \\theta+\\frac{\\pi}{4}$，则 $\\displaystyle I=\\int_{0}^{2\\pi} \\mathrm{d}\\varphi \\int_{0}^{1} \\left| J(\\sin \\varphi) \\right| \\mathrm{d}r$\n① 当 $\\sin \\varphi \u0026gt; 0$，即 $\\varphi \\in [0,\\pi]$ 时，有：\n$$I_1 = \\int_{0}^{\\pi} \\mathrm{d}\\varphi \\int_{0}^{\\sin \\varphi} \\left(r^2 \\sin \\varphi - r^3 \\right) \\mathrm{d}r = \\frac{1}{12} \\int_{0}^{\\pi} \\sin^{4} \\varphi \\mathrm{d}\\varphi $$$$I_2 = \\int_{0}^{\\pi} \\mathrm{d}\\varphi \\int_{\\sin \\varphi}^{1} \\left(r^3 - r^2 \\sin \\varphi \\right) \\mathrm{d}r = \\int_{0}^{\\pi} \\left( \\frac{1}{4} - \\frac{\\sin \\varphi}{3} + \\frac{1}{12} \\sin^{4} \\varphi \\right) \\mathrm{d}\\varphi$$② 当 $\\sin \\varphi \u0026lt; 0$，即 $\\varphi \\in [\\pi,2\\pi]$ 时，有：\n$$I_3 = \\int_{\\pi}^{2\\pi} \\mathrm{d}\\varphi \\int_{0}^{1} \\left(r^3 - r^2 \\sin \\varphi \\right) \\mathrm{d}r = \\int_{\\pi}^{2\\pi} \\left( \\frac{1}{4} - \\frac{\\sin \\varphi}{3} \\right) \\mathrm{d}\\varphi $$则 $\\displaystyle I=I_1+I_2+I_3=\\int_{0}^{\\pi} \\frac{\\sin^{4}\\varphi}{6} \\mathrm{d}\\varphi + \\int_{0}^{2\\pi} \\left( \\frac{1}{4}-\\frac{\\sin \\varphi}{3} \\right) \\mathrm{d}\\varphi = \\frac{9\\pi}{16}$\n方法2：由题意，$\\displaystyle f(x,y) = \\frac{x+y}{2}-x^2-y^2 = \\frac{1}{4}-\\left( x-\\frac{1}{2\\sqrt{2}} \\right)^2-\\left( y-\\frac{1}{2\\sqrt{2}} \\right)^2$.\n故单位圆 $D: x^2+y^2 \\leqslant 1$ 被分成两部分：$D_1=\\{(x,y)| f(x,y) \\geqslant 0 \\}, D_2=D-D_1$，因此\n$$\\begin{align*} I \u0026=\\iint\\limits_{D} \\left| f(x,y) \\right| \\mathrm{d}x\\mathrm{d}y = \\iint\\limits_{D_1} f(x,y) \\mathrm{d}x\\mathrm{d}y - \\iint\\limits_{D_2} f(x,y) \\mathrm{d}x\\mathrm{d}y \\\\ \u0026= 2\\iint\\limits_{D_1} f(x,y) \\mathrm{d}x\\mathrm{d}y -\\iint\\limits_{D_1+D_2} f(x,y) \\mathrm{d}x\\mathrm{d}y = 2 \\iint\\limits_{D_1} f(x,y) \\mathrm{d}x\\mathrm{d}y - \\iint\\limits_{D} f(x,y) \\mathrm{d}x\\mathrm{d}y \\\\ \u0026= 2 \\iint\\limits_{D_1} \\left[ \\frac{1}{4}-\\left( x-\\frac{1}{2\\sqrt{2}} \\right)^2-\\left( y-\\frac{1}{2\\sqrt{2}} \\right)^2 \\right] \\mathrm{d}x\\mathrm{d}y - \\iint\\limits_{D} \\left( \\frac{x+y}{2}-x^2-y^2 \\right) \\mathrm{d}x\\mathrm{d}y \\\\ \u0026= 2 \\int_{0}^{2\\pi} \\mathrm{d}\\theta \\int_{0}^{\\frac{1}{2}} \\left( \\frac{1}{4} - \\rho^2 \\right) \\rho \\mathrm{d}\\rho + \\int_{0}^{2\\pi} \\mathrm{d} \\theta \\int_{0}^{1} \\rho^3 \\mathrm{d}\\rho = 4\\pi \\left( \\frac{1}{32}-\\frac{1}{64} \\right) + \\frac{\\pi}{2} = \\frac{9\\pi}{16} \\end{align*}$$ 【例7.37】设 $\\displaystyle f(x)=\\int_{0}^{x} \\frac{\\sin t}{\\pi-t} \\mathrm{d}t$，计算：$\\displaystyle I=\\int_{0}^{\\pi} f(x) \\mathrm{d}x$\n点击展开解答 解法1：\n$$I=xf(x) \\Big|_{0}^{\\pi} - \\int_{0}^{\\pi} x\\mathrm{d}[f(x)]=\\pi f(\\pi) - \\int_{0}^{\\pi} \\frac{x \\sin x}{\\pi-x} \\mathrm{d}x$$ 注意到 $\\displaystyle \\pi f(\\pi) = \\pi \\int_{0}^{\\pi} \\frac{\\sin t}{\\pi-t} \\mathrm{d}t = \\int_{0}^{\\pi} \\frac{\\pi \\sin x}{\\pi-x} \\mathrm{d}x$，则 $$I=\\int_{0}^{\\pi} \\frac{(\\pi-x) \\sin x}{\\pi -x} \\mathrm{d}x = 2$$解法2：\n$$\\begin{align*} I \u0026= \\int_{0}^{\\pi}f(x) \\mathrm{d}x = \\int_{0}^{\\pi} \\left( \\int_{0}^{x} \\frac{\\sin t}{\\pi-t} \\mathrm{d}t \\right)\\mathrm{d}x \\\\ \u0026= \\int_{0}^{\\pi} \\mathrm{d}t \\int_{t}^{\\pi} \\frac{\\sin t}{\\pi-t} \\mathrm{d}x = \\int_{0}^{\\pi} \\frac{\\sin t}{\\pi-t} \\cdot (\\pi-t) \\mathrm{d}t = \\int_{0}^{\\pi} \\sin t \\mathrm{d}t = 2 \\end{align*}$$ 设 $f(x,y) \\geqslant 0$，在 $D: x^2+y^2 \\leqslant a^2$ 上有连续一阶偏导数，边界上取值为0. 证明：\n$$ \\left| \\iint\\limits_{D} f(x,y) \\mathrm{d}x\\mathrm{d}y \\right| \\leqslant \\frac{1}{3} \\pi a^3 \\cdot \\underset{(x,y)\\in D}{\\mathrm{max}} \\sqrt{\\left( f'_x \\right)^2 + \\left( f'_y \\right)^2} $$ 点击展开解答 证：由 $f(x,y)$ 存在连续一阶偏导数可知，对于任意边界点 $(x_0,y_0)$，存在：\n$$f(x,y) = f(x_0,y_0) + f'_x(x_0,y_0)(x-x_0) + f'_y(x_0,y_0) = f'_x(x_0,y_0)(x-x_0) + f'_y(x_0,y_0) $$由柯西不等式，\n$$f'_x(x_0,y_0)(x-x_0) + f'_y(x_0,y_0)(y-y_0) \\leqslant \\sqrt{\\left( f'_x \\right)^2 + \\left( f'_y \\right)^2} \\cdot \\sqrt{(x-x_0)^2 + (y-y_0)^2}$$因此 $$\\left| \\iint\\limits_{D} f(x,y) \\mathrm{d}x\\mathrm{d}y \\right| \\leqslant \\iint\\limits_{D} \\left| f(x,y) \\right| \\mathrm{d}x\\mathrm{d}y \\leqslant \\underset{(x,y)\\in D}{\\mathrm{max}} \\sqrt{\\left( f'_x \\right)^2 + \\left( f'_y \\right)^2} \\cdot \\iint\\limits_{D} (a-r) \\mathrm{d}\\sigma $$而又因为 $$\\iint\\limits_{D} (a-r) \\mathrm{d}\\sigma = \\int_{0}^{2\\pi} \\mathrm{d}\\theta \\int_{0}^{a} r(a-r) \\mathrm{d}r = \\frac{1}{3} \\pi a^3 $$故 $$ \\left| \\iint\\limits_{D} f(x,y) \\mathrm{d}x\\mathrm{d}y \\right| \\leqslant \\frac{1}{3} \\pi a^3 \\cdot \\underset{(x,y)\\in D}{\\mathrm{max}} \\sqrt{\\left( f'_x \\right)^2 + \\left( f'_y \\right)^2} $$ 真题 第十五届非数A 设 $\\displaystyle I_n = n \\int_{1}^{a} \\frac{\\mathrm{d}x}{1+x^n}$，其中 $a\u0026gt;1$. 求极限 $\\displaystyle \\lim_{n \\to \\infty} I_n$\n点击展开解答 解：设 $\\displaystyle t = \\frac{1}{x}$，记 $b=\\frac{1}{a}$，代入原式得： $$\\begin{align*} I_n \u0026= n \\int_{1}^{b} - \\frac{t^{n-2}}{t^n+1} \\mathrm{d}t = \\int_{b}^{1} \\frac{\\mathrm{d}(\\ln (1+t^n))}{t} = \\frac{t^n+1}{t}\\Big|_{b}^{1} + \\int_{b}^{1} \\frac{\\ln(1+t^n)}{t^2} \\mathrm{d}t \\\\ \u0026= \\ln 2 - \\frac{\\ln(1+b^n)}{b} + \\int_{b}^{1} \\frac{\\ln(1+t^n)}{t^2} \\mathrm{d}t \\end{align*}$$ 当 $n \\to \\infty$ 时，$\\displaystyle \\frac{\\ln(1+b^n)}{b} \\to 0$，下面计算 $\\displaystyle \\lim_{n \\to \\infty} \\int_{b}^{1} \\frac{\\ln(1+t^n)}{t^2} \\mathrm{d}t$.\n易知当 $t \\in (b,1)$ 时，$\\ln(1+t^n) \u0026lt; t^n$，则有 $$0 \u003c \\frac{\\ln(1+t^n)}{t^2} \u003c t^{n-2}$$ 即 $$0 \u003c \\int_{b}^{1} \\frac{\\ln(1+t^n)}{t^2} \\mathrm{d}t \u003c \\int_{b}^{1} t^{n-2} = \\frac{1-b^{n-1}}{n-1}$$ 当 $n \\to \\infty$ 时，$\\displaystyle \\lim_{n \\to \\infty} = \\frac{1-b^{n-1}}{n-1} = 0$，则由迫敛准则可知 $\\displaystyle \\lim_{n \\to \\infty} \\int_{b}^{1} \\frac{\\ln(1+t^n)}{t^2} \\mathrm{d}t = 0$，故 $\\displaystyle \\lim_{n \\to \\infty} I_n = \\ln 2$\n第十六届非数A 设 $f(x)$ 是 $(-\\infty,+\\infty)$ 上具有连续导数的非负函数，且存在 $M\u0026gt;0$ 使得对任意的 $x,y \\in (-\\infty,+\\infty)$，有 $|f'(x)-f'(y)| \\leqslant M|x-y|$. 证明：对任意实数 $x$，恒有 $(f'(x))^2 \\leqslant 2Mf(x)$.\n点击展开解答 证：$\\forall x \\in (-\\infty,+\\infty)$，对 $\\forall h \\in (-\\infty,+\\infty)$ 且 $h \\ne 0$，则有： $$ 0 \\leqslant f(h+x) = f(x) + \\int_{0}^{h} f'(x+t) \\mathrm{d}t = f(x) + \\int_{0}^{h} [f'(x+t)-f'(x)] \\mathrm{d}t + f'(x)h $$ 取 $h$ 使得 $hf'(x) \\leqslant 0$，则 $$ -hf'(x) \\leqslant f(x) + \\int_{0}^{h} [f'(x+t)-f'(x)] \\mathrm{d}t \\leqslant f(x) + M \\frac{h^2}{2} $$ 两边同时取绝对值，则有 $$|f'(x)| \\leqslant \\frac{f(x)}{|h|} + M \\cdot \\frac{|h|}{2} \\leqslant 2 \\sqrt{\\frac{f(x)}{|h|} \\cdot M \\cdot \\frac{|h|}{2}} = \\sqrt{2Mf(x)} $$ 当且仅当 $\\displaystyle |h| = \\sqrt{\\frac{2f(x)}{M}}$ 时等号成立. 两边平方可得 $(f'(x))^2 \\leqslant 2Mf(x)$.\n","date":"2025-08-07T00:00:00Z","permalink":"https://rd806.github.io/passage/math/quiz/","title":"微积分：题目"},{"content":"Linux发行版 发行版名称 基础系统 特点 适用场景 推荐用户群体 Ubuntu Debian 易用性高、软件生态丰富、社区支持强大 桌面、服务器 初学者、开发者、企业用户 Linux Mint Ubuntu/Debian 界面友好、预装丰富软件、高度易用 桌面 从 Windows 转过来的新用户 Fedora 独立开发 新技术前沿、更新频繁、适合尝鲜 桌面、服务器 开发者、技术爱好者 Zorin OS Ubuntu 类似 Windows 的 UI、预装丰富软件 桌面 初学者、Windows 迁移用户 Debian 独立开发 稳定性高、自由软件精神、适合服务器 服务器、桌面 高级用户、企业用户 AlmaLinux RHEL 免费、与 RHEL 高度兼容 服务器 企业用户、开发者 Ubuntu LTS Debian 长期支持、稳定性高 服务器、桌面 企业用户、个人用户 Kali Linux Debian 安全测试、渗透测试、内置大量安全工具 安全测试、渗透测试 安全专家、渗透测试人员 Raspberry Pi OS Debian 针对 Raspberry Pi 优化、适合嵌入式设备 教育、DIY、物联网 学生、爱好者 Arch Linux 独立开发 滚动更新、高度定制、适合高级用户 桌面、服务器 高级用户、开发者 Manjaro Arch Linux 滚动更新、优化安装和配置 桌面 中级用户、开发者 Linux系统命令 文件操作 命令 作用 示例 ls 列出目录内容 ls -l（详细信息） cd 切换目录 cd /home/user pwd 显示当前路径 pwd mkdir 创建目录 mkdir new_folder touch 创建空文件 touch file.txt cp 复制文件/目录 cp file.txt backup.txt mv 移动或重命名 mv old.txt new.txt rm 删除文件/目录 rm -r folder（递归删除） cat 查看文件内容 cat file.txt less/more 分页查看文件 less file.txt head/tail 查看文件开头/结尾 tail -n 50 file.log 搜索与查找 命令 作用 示例 find 查找文件 find / -name \u0026quot;*.conf\u0026quot; grep 文本搜索 grep \u0026quot;error\u0026quot; log.txt which 查找命令路径 which python3 locate 快速查找文件（需updatedb） locate bashrc 系统信息 命令 作用 示例 top/htop 实时进程监控 htop（需安装） ps aux 查看进程 `ps aux grep nginx` df -h 磁盘空间 df -h free -h 内存使用 free -h uname -a 内核信息 uname -a uptime 系统运行时间 uptime 权限与用户 命令 作用 示例 chmod 修改权限 chmod +x script.sh chown 修改所有者 chown user:group file sudo 以管理员权限运行 sudo apt update adduser 添加用户 sudo adduser alice passwd 修改密码 passwd 网络操作 命令 作用 示例 ping 测试网络连通性 ping google.com curl 发送HTTP请求 curl -I https://example.com wget 下载文件 wget https://file.tar.gz ssh 远程登录 ssh user@192.168.1.100 scp 远程复制文件 scp file.txt user@host:/path netstat/ss 查看网络连接 ss -tuln 软件包管理（根据发行版选择） 系统 命令 示例 Debian/Ubuntu apt sudo apt install nginx CentOS/RHEL yum/dnf sudo dnf install nginx Arch Linux pacman sudo pacman -S nginx 其他实用命令 命令 作用 示例 tar 压缩/解压 tar -xzf file.tar.gz zip ZIP格式压缩 unzip archive.zip unzip -d 解压到指定目录 unzip archive.zip history 查看命令历史 history grep ssh alias 设置命令别名 alias ll='ls -la' wc 统计行数/单词数 wc -l file.txt diff 比较文件差异 diff file1.txt file2.txt 文本编辑器 Nano 功能 命令 说明 启动 Nano nano [文件名] 打开一个新文件或已存在的文件。如果文件不存在，将创建一个新文件。 保存文件 Ctrl + O 保存当前文件，按 Enter 确认保存路径和文件名。 退出 Nano Ctrl + X 退出 Nano。如果文件有未保存的更改，会提示是否保存。 撤销更改 Ctrl + U 撤销最近的更改。 跳到文件顶部 Ctrl + _ 跳到文件的第一行。 跳到文件底部 Ctrl + Shift + _ 跳到文件的最后一行。 跳到指定行 Ctrl + _，输入行号，Enter 跳到指定的行号。 删除字符 Backspace 删除光标所在位置的字符。 删除光标前字符 Ctrl + Backspace 删除光标前的字符。 剪切到行尾 Ctrl + K 剪切从光标位置到行尾的内容。 粘贴 Ctrl + U 粘贴剪切的内容。 查找文本 Ctrl + W 查找文本，输入要查找的内容后按 Enter。 替换文本 Ctrl + \\ 替换文本，输入要查找的内容，按 Enter，再输入要替换的内容，按 Enter。 自动缩进 Ctrl + I 在新的一行中自动缩进。 显示帮助菜单 Ctrl + G 显示 Nano 的帮助菜单。 切换拼写检查 Ctrl + T 切换拼写检查功能（需要安装拼写检查工具）。 显示行号 nano -l [文件名] 或 Ctrl + C 启动时加上 -l 参数显示行号，或在编辑时按 Ctrl + C 显示当前行号和列号。 Vim 功能 命令模式 说明 启动 Vim vim [文件名] 打开一个新文件或已存在的文件。如果文件不存在，将创建一个新文件。 模式切换 i 切换到插入模式（可以输入文本）。 Esc 从插入模式返回到命令模式。 v 切换到可视模式（逐字符选择）。 V 切换到可视行模式（逐行选择）。 Ctrl + v 切换到可视块模式（逐列选择）。 保存和退出 :w 保存文件。 :wq 或 ZZ 保存并退出 Vim。 :q 退出 Vim（如果文件有未保存的更改，会提示）。 :q! 或 ZQ 强制退出 Vim，不保存更改。 光标移动 h、j、k、l 左、下、上、右移动光标。 gg 跳到文件顶部。 G 跳到文件底部。 :行号 跳到指定行号。 Ctrl + f 向下翻页。 Ctrl + b 向上翻页。 编辑操作 x 或 Del 删除光标所在位置的字符。 dd 删除光标所在的整行。 yy 或 Ctrl + y 复制光标所在的整行。 p 粘贴复制的内容（粘贴到光标下方）。 P 粘贴复制的内容（粘贴到光标上方）。 u 撤销最近的更改。 Ctrl + r 重做撤销的更改。 查找和替换 /搜索内容 向下查找指定的文本。 ?搜索内容 向上查找指定的文本。 n 查找下一个匹配项。 N 查找上一个匹配项。 :%s/旧内容/新内容/g 替换文件中所有匹配的文本。 其他功能 :help 显示帮助文档。 :set number 或 :set nu 显示行号。 :set nonumber 或 :set nonu 隐藏行号。 :set ignorecase 或 :set ic 在查找时忽略大小写。 :set noignorecase 或 :set noci 在查找时区分大小写。 SSH连接Linux系统 参见：SSH配置简介 ","date":"2025-08-04T00:00:00Z","image":"https://rd806.github.io/passage/system/linux/Linux-tips_hu_79f01dab15780611.png","permalink":"https://rd806.github.io/passage/system/linux/","title":"Linux系统小技巧"},{"content":"基本原理 Hugo的stack主题提供了自定义样式的接口，主要在layouts/partials/footer/custom.html和assets/scss/custom.scss中 Hugo的文件可以实现文件覆盖。只要文件位置与themes文件夹中的相同，就会先加载自定义文件。 页面布局 首页文章样式 在/assets/scss/custom.scss加入\n1/*主页文章图片样式*/ 2$image-scale: 1.2; 3.article-list article .article-image img { 4 width: 100%; 5 height: 150px; 6 object-fit: cover; 7 //不同显示器（手机，小屏幕电脑，大屏幕电脑）显示的图片高度大小 8 @include respond(sm) { 9 height: 305px; 10 } 11 12 @include respond(md) { 13 height: 305px; 14 } 15 @include respond(xl) { 16 height: 325px; 17 } 18} 19 20/*主页文章图片圆角*/ 21.article-list article { 22 --card-border-radius: 24px; 23} 24 25/*文章标签圆角*/ 26.article-category a, .article-tags a { 27 border-radius: 11px; 28} 29 30 31/*鼠标移动到文章图片放大*/ 32.article-list article .article-image { 33 position: relative; 34 overflow: hidden; //不显示超出的部分 35} 36 37.article-list article .article-image img:hover { 38 transform: scale($image-scale); //放大尺寸 39} 40 41.article-list article .article-image img { 42 transition: transform 0.85s ease-in-out;//持续时间 43} 修改归档和友链界面 修改assets/scss/custom.scss文件，引入以下css样式代码：\n1@media (min-width: 1024px) { 2 .article-list--compact { 3 display: grid; 4 // 目前是两列，如需三列，则后面再加一个1fr，以此类推 5 grid-template-columns: 1fr 1fr; 6 background: none; 7 box-shadow: none; 8 gap: 1rem; 9 10 article { 11 background: var(--card-background); 12 border: none; 13 box-shadow: var(--shadow-l2); 14 margin-bottom: 8px; 15 margin-right: 8px; 16 border-radius: 16px; 17 } 18 } 19} 代码块样式 代码块行标设置 在config.yaml中找到highlight部分：\n1highlight: 2 noClasses: false 3 codeFences: true 4 guessSyntax: true 5 lineNoStart: 1 6 lineNos: true # 是否显示行号 7 lineNumbersInTable: false # 行号是否独立成列 8 tabWidth: 4 MacOS风格图标 准备一张macOS代码块的红绿灯图片放到static/icons文件夹下，或者将以下代码写入code-header.svg文件中： 1\u0026lt;svg xmlns=\u0026#34;http://www.w3.org/2000/svg\u0026#34; version=\u0026#34;1.1\u0026#34; x=\u0026#34;0px\u0026#34; y=\u0026#34;0px\u0026#34; width=\u0026#34;450px\u0026#34; height=\u0026#34;130px\u0026#34;\u0026gt; 2 \u0026lt;ellipse cx=\u0026#34;65\u0026#34; cy=\u0026#34;65\u0026#34; rx=\u0026#34;50\u0026#34; ry=\u0026#34;52\u0026#34; stroke=\u0026#34;rgb(220,60,54)\u0026#34; stroke-width=\u0026#34;2\u0026#34; fill=\u0026#34;rgb(237,108,96)\u0026#34;/\u0026gt; 3 \u0026lt;ellipse cx=\u0026#34;225\u0026#34; cy=\u0026#34;65\u0026#34; rx=\u0026#34;50\u0026#34; ry=\u0026#34;52\u0026#34; stroke=\u0026#34;rgb(218,151,33)\u0026#34; stroke-width=\u0026#34;2\u0026#34; fill=\u0026#34;rgb(247,193,81)\u0026#34;/\u0026gt; 4 \u0026lt;ellipse cx=\u0026#34;385\u0026#34; cy=\u0026#34;65\u0026#34; rx=\u0026#34;50\u0026#34; ry=\u0026#34;52\u0026#34; stroke=\u0026#34;rgb(27,161,37)\u0026#34; stroke-width=\u0026#34;2\u0026#34; fill=\u0026#34;rgb(100,200,86)\u0026#34;/\u0026gt; 5\u0026lt;/svg\u0026gt; 将以下代码复制进assets/scss/custom.scss文件中。 1.highlight { 2 border-radius: var(--card-border-radius); 3 max-width: 100% !important; 4 margin: 0 !important; 5 box-shadow: var(--shadow-l1) !important; 6} 7 8.highlight:before { 9 content: \u0026#34;\u0026#34;; 10 display: block; 11 // 这里填图片地址 12 background: url(../icons/macOS-code-header.svg) no-repeat 0; 13 background-size: contain; 14 height: 18px; 15 margin-top: -10px; 16 margin-bottom: 10px; 17} 复制不显示行号 在assets/ts/main.ts中找到copyButton项，修改为以下内容：\n1copyButton.addEventListener(\u0026#39;click\u0026#39;, () =\u0026gt; { 2 // 创建一个临时容器来克隆代码块的内容 3 const tempCodeBlock = codeBlock.cloneNode(true) as HTMLElement; 4 5 // 删除行号，行号的元素是 \u0026lt;span class=\u0026#34;ln\u0026#34;\u0026gt; 6 const lineNumbers = tempCodeBlock.querySelectorAll(\u0026#39;.ln\u0026#39;); 7 lineNumbers.forEach(lineNumber =\u0026gt; lineNumber.remove()); 8 9 // 获取没有行号的纯文本内容 10 const codeText = tempCodeBlock.textContent; 11 12 navigator.clipboard.writeText(codeText || \u0026#39;\u0026#39;) 13 // navigator.clipboard.writeText(codeBlock.textContent) 14 .then(() =\u0026gt; { 15 copyButton.textContent = copiedText; 16 17 setTimeout(() =\u0026gt; { 18 copyButton.textContent = copyText; 19 }, 1000); 20 }) 21 .catch(err =\u0026gt; { 22 alert(err) 23 console.log(\u0026#39;Something went wrong\u0026#39;, err); 24 }); 25}); 可视化加载条 下载【文件 】，并将压缩包中的topbar.min.js移动至assets/js中。\n在layouts/partials/footer/custom中加入以下代码：\n1{{ with resources.Get \u0026#34;js/topbar.min.js\u0026#34; }} 2 \u0026lt;!-- 引入本地JS脚本 --\u0026gt; 3 \u0026lt;script src={{ .Permalink }}\u0026gt;\u0026lt;/script\u0026gt; 4{{ end }} 5\u0026lt;script\u0026gt; 6 // 修改进度条颜色 7 topbar.config({ 8 barColors: { 9 \u0026#39;0\u0026#39;: \u0026#39;rgba(255, 255, 255, 1)\u0026#39;, // 进度0%白色 10 \u0026#39;1.0\u0026#39;: \u0026#39;rgba(0, 149, 234, 1)\u0026#39; // 进度100%蓝色 11 } 12 }) 13\t14 document.addEventListener(\u0026#39;pjax:send\u0026#39;, () =\u0026gt; { 15 // 显示顶部进度条 16 topbar.show(); 17 }) 18\t19 document.addEventListener(\u0026#39;pjax:complete\u0026#39;, () =\u0026gt; { 20 // 隐藏顶部进度条 21 topbar.hide(); 22 }) 23\u0026lt;/script\u0026gt; 网页组件 若想在网页中加入自定义内容，一种方法是在模版中写入.html源码；另一种方法是将代码封装成组件（widget），再以链接的方式引入模板中。\n后者可以方便地实现代码复用，对原模版的改动也最小。实际上，每个组件本质上就是一个网页文件（.html），然后放入模版文件中即可实现在网页上加载。\n以下提供了几个示例，供您参考。\n首页欢迎栏 在/layouts/partial/widget/中新建文件welcome-bar.html，写入以下内容： 1\u0026lt;!-- 首页欢迎字幅 --\u0026gt; 2\u0026lt;div class=\u0026#34;welcome\u0026#34;\u0026gt; 3 \u0026lt;p style=\u0026#34;font-size: 2rem; text-align: center; font-weight: bold\u0026#34;\u0026gt; 4 \u0026lt;span class=\u0026#34;shake\u0026#34;\u0026gt;👋\u0026lt;/span\u0026gt; 5 \u0026lt;span class=\u0026#34;jump-text1\u0026#34; \u0026gt; Welcome\u0026lt;/span\u0026gt; 6 \u0026lt;span class=\u0026#34;jump-text2\u0026#34;\u0026gt; To \u0026lt;/span\u0026gt; 7 \u0026lt;span class=\u0026#34;jump-text3\u0026#34; style=\u0026#34;color:#e99312\u0026#34;\u0026gt;Wei Qi\u0026lt;/span\u0026gt; 8 \u0026lt;span class=\u0026#34;jump-text9\u0026#34; style=\u0026#34;color:#e99312\u0026#34;\u0026gt;Blog\u0026lt;/span\u0026gt; 9 \u0026lt;/p\u0026gt; 10\u0026lt;/div\u0026gt; 11\u0026lt;!-- 首页欢迎字幅 --\u0026gt; 在/assets/scss/custom.scss里加入： 1//首页欢迎板块样式 2.welcome { 3 color: var(--card-text-color-main); 4 background: var(--card-background); 5 box-shadow: var(--shadow-l2); 6 border-radius: 30px; 7 display: inline-block; 8} 9 10// 👋emoji实现摆动效果 11.shake { 12 display: inline-block; 13 animation: shake 1s; 14 animation-duration: 1s; 15 animation-timing-function: ease; 16 animation-delay: 0s; 17 animation-iteration-count: 1; 18 animation-direction: normal; 19 animation-fill-mode: none; 20 animation-play-state: running; 21 animation-name: shake; 22 animation-timeline: auto; 23 animation-range-start: normal; 24 animation-range-end: normal; 25 animation-delay: 2s; 26 @keyframes shake { 27 0% { 28 transform: rotate(0); 29 } 30 25% { 31 transform: rotate(45deg) scale(1.2); 32 } 33 50% { 34 transform: rotate(0) scale(1.2); 35 } 36 75% { 37 transform: rotate(45deg) scale(1.2); 38 } 39 100% { 40 transform: rotate(0); 41 } 42 } 43} 44 45// 实现字符跳动动画 46.jump-text1 { 47 display: inline-block; 48 animation: jump 0.5s 1; 49} 50.jump-text2 { 51 display: inline-block; 52 animation: jump 0.5s 1; 53 animation-delay: 0.1s; 54} 55.jump-text3 { 56 display: inline-block; 57 animation: jump 0.5s 1; 58 animation-delay: 0.2s; 59} 60.jump-text9 { 61 display: inline-block; 62 animation: jump 0.5s 1; 63 animation-delay: 0.9s; 64} 65 66@keyframes jump { 67 0% { 68 transform: translateY(0); 69 } 70 50% { 71 transform: translateY(-20px); 72 } 73 100% { 74 transform: translateY(0); 75 } 76} 实际上，这些css代码也可以直接写在welcome-bar.html的\u0026lt;style\u0026gt;\u0026lt;/style\u0026gt;标签中，在以下组件中同理。\n随机文字卡片 随机效果 随机效果依赖javascript脚本：\n1// 获取并展示文字内容 2function showQuotes() { 3 // 随机文字 4 index = Math.floor(Math.random() * quotes.length); 5 const quote = quotes[index]; 6 7 // 获取文字和作者信息 8 const textElement = document.querySelector(\u0026#34;.quote-text\u0026#34;); 9 const authorElement = document.querySelector(\u0026#34;.quote-author\u0026#34;); 10 11 textElement.innerText = quote.quote; 12 authorElement.innerText = `—— ${quote.author}`; 13 14 // 渲染数学公式（可选） 15 renderMathInElement(textElement, { 16 delimiters: [ 17 {left: \u0026#39;$$\u0026#39;, right: \u0026#39;$$\u0026#39;, display: true}, 18 {left: \u0026#39;$\u0026#39;, right: \u0026#39;$\u0026#39;, display: false}, 19 {left: \u0026#39;\\\\[\u0026#39;, right: \u0026#39;\\\\]\u0026#39;, display: true}, 20 {left: \u0026#39;\\\\(\u0026#39;, right: \u0026#39;\\\\)\u0026#39;, display: false} 21 ] 22 }); 23}; 完善实现事件还需要增加一个按钮，实现点击就能随机显示文字。\n1\u0026lt;button id=\u0026#34;new-quote\u0026#34;\u0026gt;Random\u0026lt;/button\u0026gt; 然后赋予其点击事件：\n1\u0026lt;script\u0026gt; 2 document.querySelector(\u0026#34;#new-quote\u0026#34;).addEventListener(\u0026#34;click\u0026#34;, showQuotes); 3\u0026lt;/script\u0026gt; 设置配置文件 如果将文字内容写在.html文件内部，可配置性不佳，而且会使代码臃肿。因此，可以将随机文字的内容写入json文件并放入static/文件夹中。\n为什么放入static文件夹？\nstatic文件夹存放网页的静态内容，通俗点就是其中的内容就在站点目录之下。例如站点名为https://www.example.com，那么static/quotes.json就在https://www.example.com/quote.json处，在寻找时可以直接输入/quotes.json。\n密码栏 在网页中显示组件 主页显示 在index.html中加入：\n1\u0026lt;section class=\u0026#34;article-list\u0026#34;\u0026gt; 2 ... 3 {{ partial \u0026#34;widget/你的组件名.html\u0026#34; . }} 4 ... 5\u0026lt;/section\u0026gt; 侧边栏 1page: 2 - type: toc 3 - type: 你的组件名 ","date":"2025-08-02T00:00:00Z","image":"https://rd806.github.io/passage/website/decorate/patrick-perkins-3wylDrjxH-E-unsplash_hu_ed6391603487a5de.jpg","permalink":"https://rd806.github.io/passage/website/decorate/","title":"Hugo-stack主题装饰"},{"content":"Hugo环境配置 点击进入Hugo下载地址 ，下载最新的release文件。\n创建博客网站 准备步骤 在hugo对应的文件夹内打开cmd，输入hugo new site 你的文件夹名，可以看到多出一个新的空文件夹。\n进入空文件夹，在cmd中输入hugo service build。可以看到网站在localhost:1313转发，在浏览器中输入该网址即可看到当前网站的内容。\n下载Hugo主题 在Hugo官网上进入Theme，下载需要的主题文件，解压后放入网站文件夹的theme子文件夹。\n接着在下载的主题文件夹中复制content文件夹和hugo.yaml（或hugo.toml）文件，粘贴到你的网站文件夹中。\n打开主题的配置文件，找到theme: hugo-theme-stack一行，这里标明所使用主题的名称，须保持名称与主题文件夹的名称相同，否则要修改其一。再次执行hugo service build，即可看到使用了主题的网站。\n创建自定义内容 Hugo网站的文章内容均在content文件夹中，每篇文章对应一个子文件夹。\n每篇文章均采用Markdown语法书写，通常在文章开头有类似的配置文字：\n1--- 2title: xxxxx # 文章的标题 3description: xxxxx # 文章的副标题 4date: xxxxx # 文章的日期 5slug: xxxxx # 文章在静态页面所属的文件夹 6categories: 7 - xxxxx # 文章所属类别 8--- 必须包含这些内容网站才会显示对应文章。\n文章正文参照Markdown语法规则。\nHugo构建命令 完成网页的编辑后，需执行Hugo的构建命令，方能生成网页文件。\n1hugo server -D #构建本地网页 2hugo #构建在线网页 3hugo --cleanDestinationDir #清理构建文件夹 注意事项\n使用hugo server -D命令构建的是本地网页，遇到超链接时会重定向到localhost:1313/xxx，不能直接部署到GitHub等服务器上，必须再执行一次hugo命令清除本地链接的内容之后，才能正确部署。\n参考视频：\r在Github上托管网页 Github网站提供了“Github Pages”功能，允许用户为自己的项目部署一个静态网页。\n创建网站仓库 注册Github账号，并创建一个新仓库，命名为你的用户名.github.io。\n为什么命名为你的用户名.github.io？\nGithub的Pages分为两种，一种为用户Pages，另一种为项目Pages。用户Pages每个账号只能拥有一个，域名为https://你的用户名.github.io；项目Pages数目不限，域名为https://你的用户名.github.io/你的项目名.\n因此，设置仓库名为你的用户名.github.io可以使网站地址更简洁。\n生成静态网页文件 在命令行中执行\n1hugo 执行完成后会在工作区文件夹中出现一个public文件夹，进入该文件夹。\n上传文件至Github 参见：玩转Github 参考视频：\r插入其他资源 插入图片 1{{\u0026lt; figure src=\u0026#34;图片路径\u0026#34; width=\u0026#34;宽度\u0026#34; height=\u0026#34;高度\u0026#34; title=\u0026#34;图片标题\u0026#34; \u0026gt;}} 插入视频 1\u0026lt;!-- 插入Bilibili视频 --\u0026gt; 2{{/* \u0026lt; bilibili bv号 分p(可选) */\u0026gt;}} Hugo网站搭建内部链接 使用相对路径链接 相对路径是根据当前页面的位置来定位目标页面的路径。这是最简单且常用的方式之一。\n假设你的网站目录结构如下：\n1content/ 2├── about.md 3├── blog/ 4│ ├── post1.md 5│ └── post2.md 6└── projects.md 在about.md中链接到 blog/post1.md：\n1[访问博客文章](blog/post1) 在 blog/post1.md 中链接到projects.md：\n1[查看项目](../projects) 在 blog/post1.md 中链接到同级的post2.md：\n1[查看另一篇文章](post2) 使用绝对路径链接 绝对路径是从网站的根目录开始的完整路径。这种方式的好处是不受当前页面位置的影响。\n假设你的网站根目录是 https://example.com ，目录结构同上。\n在about.md中链接到 blog/post1.md：\n1[访问博客文章](/blog/post1) 在 blog/post1.md 中链接到projects.md：\n1[查看项目](/projects) 使用 Hugo 的 ref 和 relref 短代码 Hugo 提供了 ref 和 relref 短代码，可以更智能地处理内部链接。这些短代码会根据页面的路径自动解析链接。\nref 短代码：生成绝对路径链接。\n1[访问博客文章]({{\u0026lt; ref \u0026#34;blog/post1.md\u0026#34; \u0026gt;}}) relref 短代码：生成相对路径链接。\n1[访问博客文章]({{\u0026lt; relref \u0026#34;blog/post1.md\u0026#34; \u0026gt;}}) 链接到页面的特定部分 如果你希望链接到页面的某个特定部分（例如某个标题），可以通过锚点（anchor）来实现。\n假设post1.md中有一个标题：\n1## 我的博客文章内容 {#my-section} 你可以通过以下方式链接到这个部分：\n1[查看博客文章的特定部分](/blog/post1#my-section) 链接到页面的别名 如果某些页面有别名（例如在 frontmatter 中定义了 aliases），你可以直接使用别名来链接。\n假设post1.md的 frontmatter 中定义了别名：\n1--- 2title: \u0026#34;我的博客文章\u0026#34; 3aliases: 4 - \u0026#34;/old-post1\u0026#34; 5--- 你可以通过以下方式链接到它：\n1[访问旧的博客文章](/old-post1) ","date":"2025-08-02T00:00:00Z","image":"https://rd806.github.io/passage/website/hugo/Hugo_hu_5131b2a8a7ed6789.png","permalink":"https://rd806.github.io/passage/website/hugo/","title":"使用Hugo搭建网站"},{"content":"我从2025年2月初开始学习搭建MC服务器，到现在也学到了不少知识。以下是我的开服历程，若能对各位有所帮助，实在是我的荣幸。\n服务端搭建 常见的服务端 目前MC服务端主要包括：原版、插件端、模组端和混合端四类。\n类别 特点 原版 就和MC原版一样，没有特殊功能 插件端 能加插件，不能加模组 模组端 能加模组，不能加插件 混合端 既能加模组，也能加插件 似乎混合端功能更强大，但实际上它的兼容性更差，所以如果想开整合包服务器的话最好还是用模组端。\n由于我目前没找到合适的模组代替插件，因此只能用混合端了。\n以下是常见的服务端：\n服务端 类别 支持 Spigot 插件端 全版本 Paper 插件端 全版本 Forge/Fabric/NeoForge 模组端 全版本 Catserver（猫端） 混合端 1.12.2/1.16.5/1.18.2 Mohist（墨端） 混合端 全版本 安装 Java 环境 Java环境是MC服务器必备的运行环境。Java有多个发行版，不同的MC服务端对应不同的Java。\nMC版本 支持 1.12 - 1.16 Java 8 1.17 - 1.20 Java 17 1.21 以上 Java 21 Java可从Oracle官网 下载（最新版需要注册账号才可下载）。如果不在意，也可从镜像站例如Adoptium 下载。\n使用.exe或.msi文件安装的Java一般自动配置好了环境变量，如果使用.zip安装Java则需手动配置。\n服务端启动流程 首先在网络上下载对应的服务端，通常是一个.jar文件。然后新建一个文件夹，将服务端核心放在文件夹内。\n然后新建一个文本文档，在文档内输入java -jar 你的服务端核心名.jar，保存后将文件扩展名改为.bat。之后双击.bat文件，服务端将会运行并且在终端实时输出。这时通常会出现是否同意eula协议，此时须在文件夹内找到eula开头的文件，将其中的false改为true。最后再次启动.bat文件，服务端开启成功。\n网络配置 搭建服务器最重要的是配置好网络，核心是确定服务器的IP地址和端口号。\n局域网联机 局域网联机最简单，只需知道服务器运行的主机的IP地址即可。\nWindows平台：win+r打开cmd，输入ipconfig，查看Wifi（无线连接）或以太网（有线连接）下的IP地址。\nLinux平台：命令行输入 ip a 。\n通俗来说，通过同一个Wifi相连的设备都处于同一个局域网下。连接在同一个局域网下的设备，它们的设备IP地址仅最后一位不同。在同一个局域网下的设备可通过IP地址互相连接。\n内网穿透 请在网络上自行查找相关内容。\n内网穿透是通过特定技术，将你的内网（如局域网）地址经服务器映射到公网上的过程。此时一个公网IP地址，如：frp-xxx.com:xxxxx就等同于你的局域网地址192.168.x.x。\nIPv6连接 这是目前成本最低，效果最好的连接方式。\n首先必须确保你和你的伙伴都有IPv6访问，然后win+r打开cmd，输入ipconfig，这时应该可以看到一串240e:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx（必须为240e开头，这样才是公网IPv6），这时[IPV6地址]:端口号的形式就是服务器的IP地址。\n目前IP技术分为IPv4和IPv6两种。IPv4地址为12个十进制数，每3个数字用“ : ”隔开；IPv6地址为28个16进制数，每4个数字用“ : ”隔开。由此可见，IPv6地址比IPv4多得多，所以每个IPv6地址都可以作为公网使用。\n服务器进阶 修改服务器配置 依据服务端核心的不同，修改方法也有所区别。\n启动文件 示例：\n1#!/bin/bash 2set -e 3 4# 1. 如果 MySQL 没装，就装（可选） 5# sudo apt update \u0026amp;\u0026amp; sudo apt install -y mysql-server 6 7# 2. 确保 MySQL 服务已启动 8sudo service mysql start 9# sudo systemctl is-active --quiet mysql || { echo \u0026#34;MySQL 启动失败\u0026#34;; exit 1; } 10 11# 3. 等待 3306 真正响应 12until nc -z 127.0.0.1 3306; do 13 echo \u0026#34;等待 MySQL 端口 3306 …\u0026#34; 14 sleep 1 15done 16 17# 4. 启动 MC（stop正常退出，崩溃自动重启） 18cd {\u0026#34;服务器所在目录\u0026#34;} 19while true; do 20 java -Xms4G -Xmx8G -jar mohist-1.20.1.jar 21 EXIT_CODE=$? 22 23 # 退出码 0 = 正常停止 (stop命令) 24 if [ $EXIT_CODE -eq 0 ]; then 25 echo \u0026#34;服务器正常关闭，退出脚本\u0026#34; 26 break 27 fi 28 29 echo \u0026#34;服务器异常终止 (退出码: $EXIT_CODE)，5秒后自动重启...\u0026#34; 30 sleep 5 31done 在java -jar 你的服务端核心名.jar中，可在-jar之后加上-XmsAG -XmxBG表示给服务器至少分配A个G的内存，至多分配B个G的内存。\n特别的，java可以替换为具体的Java/bin路径。若未指明，默认为最新版的Java。\nserver.properties 这是所有服务器都具备的配置文件。\n1allow-flight=true #是否启用飞行 2allow-nether=true #是否生成下界 3broadcast-console-to-ops=true #是否向管理员发送控制台消息 4broadcast-rcon-to-ops=true 5debug=false #是否开启调试模式 6difficulty=normal #难度设置 7enable-command-block=true #是否启用命令方块 8enable-jmx-monitoring=false 9enable-query=false 10enable-rcon=false 11enable-status=true 12enforce-secure-profile=true 13enforce-whitelist=false 14entity-broadcast-range-percentage=100 15force-gamemode=false #是否强制设置玩家的游戏模式 16function-permission-level=4 #命令等级设置，最高为4，最低为0 17gamemode=survival #游戏模式设置 18generate-structures=true 19generator-settings={} 20hardcore=false 21hide-online-players=false 22initial-disabled-packs= 23initial-enabled-packs=vanilla 24level-name=play #游戏主世界存档名称 25level-seed= #游戏主世界地图种子 26level-type=minecraft\\:normal #主世界地图类型 27max-chained-neighbor-updates=1000000 28max-players=40 #服务器允许的最多人数 29max-tick-time=60000 30max-world-size=29999984 31motd=智算11班公益养老服(1.4) 32network-compression-threshold=256 33online-mode=false #是否启用在线模式 34op-permission-level=4 #管理员命令等级 35player-idle-timeout=0 36prevent-proxy-connections=false #是否阻止代理连接 37pvp=true #是否允许玩家互相攻击 38query.port=25565 39rate-limit=0 40rcon.password= 41rcon.port=25575 42require-resource-pack=false #是否强制使用资源包 43resource-pack= #资源包链接 44resource-pack-prompt= 45resource-pack-sha1= 46server-ip= #服务器运行的IP地址，默认留空为127.0.0.1 47server-port=30067 #服务器运行的端口 48simulation-distance=10 #服务器模拟距离，建议设置为4~6 49spawn-animals=true 50spawn-monsters=true 51spawn-npcs=true 52spawn-protection=0 #出生点保护范围 53sync-chunk-writes=true 54text-filtering-config= 55use-native-transport=true 56view-distance=10 #服务器视野距离，建议设置为4~6 57white-list=false #是否启用白名单 bukkit.yml spiogt.yml 安装插件和模组 使用SSH远程连接服务器主机 参见：SSH配置简介 使用MySQL管理玩家数据 对于多个服务器，如果想不同服务器之间共享玩家数据（如权限、经验等），可以使用MySQL数据库。\n下面以服务端插件PowerRanks为例进行说明。\n打开PowerRanks的配置文件，找到关于数据来源的配置。 将type改为mysql，并配置好端口、用户名和密码。这样在启动时，插件会自动从127.0.0.1:3306端口的root用户读入数据。 1... 2storage: 3 type: mysql 4 mysql: 5 host: 127.0.0.1 6 port: 3306 7 database: powerranks 8 username: root 9 password: ******* 10 ssl: false 11 verbose: false 12... 在MySQL的表中创建新表，命名为powerranks，此处名称应与配置文件中的database后的名称相同。\n启动MC服务器，这样Powerranks插件就会自动在MySQL中创建数据表，可以对其进行相关操作。\n注意：使用MySQL的数据时，每次启动服务器前应当先启动MySQL客户端，否则插件会报错。\n可以使用命令：sudo service mysql start\n开发者选项 制作自己的服务端插件 ","date":"2025-07-31T00:00:00Z","image":"https://rd806.github.io/passage/minecraft/server/helena-hertz-wWZzXlDpMog-unsplash_hu_2307260c751d0e0b.jpg","permalink":"https://rd806.github.io/passage/minecraft/server/","title":"Minecraft服务器"},{"content":"选择SSH应用程序 Visual Studio Code 这是目前为止最强大的SSH应用，只需下载VScode并安装Remote-ssh插件，写好配置文件后就能连接。\n全程免费，而且附带端口转发、文件编辑、下载等功能，绝对好用！\nTabby Tabby是一款现代的终端应用，界面简洁。\nTabby的Github仓库 ServerBox ServerBox是一款国产的远程服务器监控和操作应用，支持Windows、Linux、Android、MacOS等操作系统。优点是可以监测服务器实时运行状态（包括CPU、内存、温度、网络、硬盘等）。\n注意，Serverbox自带的脚本只支持监控Linux系统的运行数据，对于WSL系统，只能监控部分数据。\nServerBox的Github仓库 以下是各ssh应用程序的功能比较：\n应用 特点 平台 VScode 功能最强大 Windows/Linux/MacOs Tabby 界面简洁美观 Windows/Linux/MacOS Serverbox 可以监控服务端的运行 Windows/Android 配置 SSH 连接到远程主机的原理与连接MC服务器类似，关键在于确定远程主机的IP地址和端口。\nWindows系统 安装 SSH 服务 首先在要连接的主机上打开设置，搜索“可选功能”，在“添加可选功能”中搜索“OpenSSH服务器”，下载该功能。\n启动并配置 SSH 服务 管理员权限打开Powershell，输入：\n1Start-Service sshd 2Set-Service -Name sshd -StartupType \u0026#39;Automatic\u0026#39; 然后开放防火墙端口（默认22）：\n1New-NetFirewallRule -Name sshd -DisplayName \u0026#39;OpenSSH Server\u0026#39; -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 2 3# 其中\u0026#39;OpenSSH Server\u0026#39;是协议的名称，可自行修改 4# 这样默认同时开启IPV4和IPV6的端口，即“127.0.0.1:22”和“[0:0:0:0]:22” 还可以通过以下方法实现：\n步骤 操作 ① 打开防火墙高级设置：控制面板 \u0026gt; Windows Defender 防火墙 \u0026gt; 高级设置（或win+R输入wf.msc） ② 新建入站规则：右键“入站规则” \u0026gt; 新建规则。 ③ 选择规则类型：选择“端口” \u0026gt; 下一步。 ④ 指定端口和协议：协议类型：选择 TCP（或 UDP，视应用而定）；特定本地端口：输入 22 \u0026gt; 下一步。 ⑤ 选择操作：选择“允许连接” \u0026gt; 下一步。 ⑥ 选择配置文件：默认全选（域、专用、公用）\u0026gt; 下一步。 ⑦ 指定规则名称：如“允许 IPv6 22222 端口” \u0026gt; 完成。 如果有时开放了防火墙但仍无法连接，可尝试重启电脑（我就是这样解决的……）\nLinux系统 安装 OpenSSH Server 1sudo apt update 2sudo apt install openssh-server 启动 SSH 服务 1sudo systemctl start ssh 2sudo systemctl enable ssh # 设置开机自启 3sudo systemctl status ssh # 检查ssh运行状态 输出中应显示active (running)。\n配置防火墙 允许 SSH 默认端口（22）：\n1sudo ufw enable # 如果防火墙未启用 2sudo ufw allow ssh 获取服务器的IP地址 1ip a # 或 hostname -I 找到类似 192.168.x.x 的局域网 IP 或公网 IP（如果适用）。\nWSL系统 安装 OpenSSH Server 打开 WSL 中的 Ubuntu 终端，执行：\n1sudo apt update 2sudo apt install openssh-server 配置 SSH 编辑配置文件：\n1sudo nano /etc/ssh/sshd_config 确保以下配置项存在且未被注释：\n1... 2Port 22 3... 4PasswordAuthentication yes 5PermitRootLogin yes 如果要启用IPV6的SSH连接，还应该保持以下内容未被注释：\n1Port 22 2AddressFamily any 3ListenAddress 0.0.0.0 4ListenAddress :: 启动 SSH 服务 在 WSL 中，不能使用 systemctl，请使用：\n1sudo service ssh start 验证服务是否运行：\n1sudo service ssh status 2# 或使用 3ps aux | grep sshd 注意事项:\n必须保证Windows防火墙的22端口已被放行；\nWSL系统是Windows的子系统，在Windows开机时，WSL的ssh功能默认并不能开启，此时需要将WSL的ssh注册为系统服务实现Windows开机时启用WSL的ssh功能。\n下面给出使用任务计划程序（无需第三方程序）的方法：点击展开 打开任务计划程序 Win+R → taskschd.msc\n创建任务：\n选项 操作 名称 StartWSL 触发器 选择「计算机启动时」 操作 新建 →程序/脚本：wsl.exe，参数：-d Ubuntu-22.04 -u root /usr/sbin/service ssh start（或 -d Ubuntu-22.04 true 单纯启动实例） 设置 勾选「允许任务按需运行」 保存时输入管理员密码。重启测试即可。\nTermux 参见：Termux启动SSH功能 连接 SSH 在 Windows 本地测试： 1ssh 用户名@localhost 从局域网其他设备连接： 1ssh 用户名@\u0026lt;Windows主机IP\u0026gt; VScode的SSH配置文件: 1Host xxxx # Host的名称，可自定义 2 HostName xxx.xxx.xxx.xxx # SSH服务端的IP地址 3 User xxxxx # 登录的用户名 4 Port xxxxx # SSH服务端的IP端口 注意：VScode的Host名会绑定远程主机的操作系统（Windows、Linux、MacOS）。如果使用同一个Host名连接不同操作系统的主机，需要在设置中修改，否则会报错。（就因为这个，让我花了近1小时）\n修改方法：打开设置 → 搜索Remote Platform → 修改相应项的值\n","date":"2025-07-31T00:00:00Z","image":"https://rd806.github.io/passage/guide/ssh/SSH_hu_a128d6c974ddc0a1.png","permalink":"https://rd806.github.io/passage/guide/ssh/","title":"SSH配置简介"},{"content":"鸿蒙项目结构 1entry 2├── preview 3├── src 4 ├── main 5 ├── ets # 存放代码文件 6 ├── entryability 7 ├── entrybackupability 8 ├── pages 9 ├── Index.ets 10 ├── resources # 存放资源文件 示例文件Index.ets\n1@Entry // Index文件入口 2@Component // 声明以下为组件 3struct Index { 4 @State message: string = \u0026#39;Hello World\u0026#39;; 5 6 build() { 7 RelativeContainer() { 8 Text(this.message) // 系统组件 9 .id(\u0026#39;HelloWorld\u0026#39;) 10 .fontSize($r(\u0026#39;app.float.page_text_font_size\u0026#39;)) 11 .fontWeight(FontWeight.Bold) 12 .alignRules({ 13 center: { anchor: \u0026#39;__container__\u0026#39;, align: VerticalAlign.Center }, 14 middle: { anchor: \u0026#39;__container__\u0026#39;, align: HorizontalAlign.Center } 15 }) 16 .onClick(() =\u0026gt; { 17 this.message = \u0026#39;Welcome\u0026#39;; 18 }) 19 } 20 .height(\u0026#39;100%\u0026#39;) 21 .width(\u0026#39;100%\u0026#39;) 22 } 23} 变量和数据类型 一般变量 信息类型 数据类型 文字信息 字符串类型（string） 数字信息 数字类型（number） 状态信息 布尔类型（boolean） 声明变量：\n1let parameter: type = value 数组 数组是一种容器，用来存储多个同类型数据。数组中元素的索引从0开始。\n声明数组：\n1let array: type[] = [data1,data2,data3,...] 对象 对象可以一次性存储多个不同类型的数据。在HarmonyOS中，使用接口约定对象的结构和类型。\n声明对象：\n1interface Interface { 2 parameter1: type1 3 parameter2: type2 4 ... 5 parametern: typen 6} 7 8// 约定接口后相应对象中应包含接口中的所有数据类型 9let object: Interface = { 10 parameter1: data1, 11 parameter2: data2, 12 ... 13 parametern: datan 14} 15 16// 访问方法 17fun(object.data1) 函数 普通函数 定义函数 1function fun (parameter1: type1, parameter2: type2,...) { 2 ... 3 return value 4} 调用函数 1fun(parameter1, parameter2,...) 2 3//可以使用变量接收函数返回值 4let text: string = fun() 箭头函数 1// 定义函数 2let fun = (parameter1: type1, parameter2: type2, ...) =\u0026gt; { 3 ... 4 return value 5} 6 7// 调用函数 8fun(parameter1, parameter2) 自定义构建函数 可以将组件的构建函数封装到@Builder中。\n1@Entry 2@Component 3struct Index { 4 // 定义自定义构建函数 5 @Builder 6 name (parameterList) { 7 component 8 } 9 10 build() { 11 Column() { 12 // 使用自定义构建函数 13 this.name(parameterList) 14 } 15 } 16} 组件 ArkUI（方舟开发框架）：构建鸿蒙应用界面的框架\n组件：界面构建与显示的最小单位\n两类基本组件 容器组件：控制布局\n1// 写法：组件名() {} 2 3Cloumn() {} // 内容竖排 4Row() {} // 内容横排 build() {} 中只允许存在一个根组件，但组件允许嵌套使用。\n内容组件：内容\n1// 写法：组件名() 2 3Text(\u0026#39;内容\u0026#39;) // 文本组件 4Button() // 按钮组件 5Image(url) // 图像组件 6List() // 可滚动组件 通用属性 属性名 作用 属性值 width 宽度 数值（默认单位vp） height 高度 数值（默认单位vp） backgroundColor 背景色 色值（内置颜色或16进制色值） 给组件添加属性：\n1struct Index { 2 build() { 3 Column() { 4 Text(\u0026#39;text\u0026#39;) 5 .width(100) // 宽度设为100vp 6 .height(50) // 高度设为50vp 7 .backgroundColor(Color.Orange) // 背景色设为橙色 8 /* 9 HarmonyOS的满屏尺寸： 10 .width(360) 11 .width(\u0026#39;100%\u0026#39;) 12 */ 13 } 14 } 15} 文本属性 属性名 作用 属性值 fontsize 字体大小 数值（默认单位fp） fontColor 文本颜色 色值（内置颜色或16进制色值） fontWeight 字体粗细 100~900 示例：\n1struct Index { 2 build() { 3 Column() { 4 Text(\u0026#39;text\u0026#39;) 5 .fontSize(30) 6 .fontColor(Color.Red) 7 .fontWeight(400) // 默认粗细为400 8 } 9 } 10} 图像属性 图片路径 1// 本地路径：设图片在entry/src/main/resource/media文件夹中 2Image($r(\u0026#39;app.media.xx\u0026#39;)) 3 4// 网络路径 5Image(www.example.com) 图片样式 可使用通用属性。\n内外边距属性 内边距：padding，拉开内容与组件边缘的距离。\n外边距：margin，拉开两个组件之间的距离。\n1// 四个方向间距相同 2component() 3 .padding(10) 4 .margin(10) 5 6// 间距不同 7component() 8 .padding({top: 10, bottom: 20, left: 30, right: 40}) 9 .margin({top: 10, bottom: 20, left: 30, right: 40}) 示例：\n1struct Index { 2 build() { 3 Column() { 4 Button(\u0026#39;登录\u0026#39;) 5 .width(\u0026#39;100%\u0026#39;) 6 .margin(10) 7 Button(\u0026#39;注册\u0026#39;) 8 .width(\u0026#39;100%\u0026#39;) 9 } 10 .backgroundColor(\u0026#39;#DDDDDD\u0026#39;) 11 .padding({ 12 top: 10, 13 bottom: 20, 14 left: 30, 15 right: 30 16 }) 17 } 18} 边框属性 1component() 2 .border({ 3 width: // 粗细 4 color: // 颜色 5 style: // 线条样式 6 radius: // 圆角 7 }) 实例：歌曲列表 1@Entry 2@Component 3 4struct Index { 5 build() { 6 Column() { 7 Text(\u0026#39;猜你喜欢\u0026#39;) 8 .fontColor(\u0026#39;#fff\u0026#39;) 9 .width(\u0026#39;100%\u0026#39;) 10 .margin({bottom: 10}) 11 12 List() { 13 // 音乐卡片1 14 ListItem() { 15 Row() { 16 // 音乐封面 17 Image($r(\u0026#39;app.media.1\u0026#39;)) 18 .width(80) 19 .border({radius: 8}) 20 .margin({right: 10}) 21 22 // 音乐信息 23 Column() { 24 Text(\u0026#39;xxx\u0026#39;) 25 .fontColor(\u0026#39;#F3F3F3\u0026#39;) 26 .width(\u0026#39;100%\u0026#39;) 27 .fontWeight(700) 28 .margin({bottom: 15}) 29 Row() { 30 Text(\u0026#39;VIP\u0026#39;) 31 .fontColor(\u0026#39;#9ABE28\u0026#39;) 32 .border({ 33 width: 1, color: \u0026#39;#9ABE28\u0026#39;, radius: 12 34 }) 35 .padding({ 36 left: 5, right: 5, top: 3, bottom: 3 37 }) 38 .margin({right: 10}) 39 40 Text(\u0026#39;Singer\u0026#39;) 41 } 42 .width(\u0026#39;100%\u0026#39;) 43 } 44 .layoutWeight(1) // 占用所有剩余空间 45 46 // 更多信息 47 Image($r(\u0026#39;app.media.ic_more\u0026#39;)) 48 .width(24) 49 .fillColor(\u0026#39;#FEFEFE\u0026#39;) 50 51 } 52 .width(\u0026#39;100%\u0026#39;) 53 .height(80) 54 .backgroundColor(Color.Pink) 55 .margin({bottom: 10}) 56 } 57 } 58 } 59 .width(\u0026#39;100%\u0026#39;) 60 .height(\u0026#39;100%\u0026#39;) 61 .backgroundColor(\u0026#39;#131313\u0026#39;) 62 .padding({left: 10, right: 10}) 63 /* 扩充安全区 64 .expandSafeArea( 65 [SafeAreaType.SYSTEM], 66 [SafeAreaType.TOP, SafeAreaType.BOTTOM] 67 ) 68 */ 69 } 70} 控制结构 分支语句 if分支语句 1if (condition1) { 2 code 3} else if (condition2) { 4 code 5} else { 6 code 7} 条件表达式 1condition ? code1 : code2 2 3/* 等价于 4if (condition) { 5 code1 6} else { 7 code2 8} 9 10可用变量接收：let num: number = a\u0026gt;b ? a : b 11*/ 条件渲染 实现满足某个条件再渲染组件的功能。\n1if (condition1) { 2 component1() 3} else if (condition2) { 4 component2() 5} else { 6 component3() 7} 循环渲染 1ForEach(array, (item: type, index: number) =\u0026gt; { 2 component 3}) 4 5// item为数组中的元素，index为数组元素下标 示例：\n1let name: string[] = [\u0026#39;text1\u0026#39;, \u0026#39;text2\u0026#39;, \u0026#39;text3\u0026#39;] 2 3@Entry 4@Component 5 6struct Index { 7 build() { 8 Column() { 9 ForEach(name, (item: string, index: number) =\u0026gt; { 10 Text(item) 11 }) 12 } 13 } 14} 状态管理 应用的运行时状态是参数，当参数改变时，UI渲染刷新。\n状态变量：使用装饰器修饰，状态变量数据改变会引起UI的渲染刷新。\n1component 2 // 为组件添加事件 3 .event(() =\u0026gt; { 4 code 5 }) 示例：\n1// 启用HarmonyOS的V2状态管理 2@ComponentV2 3 4struct Index { 5 @Local num: number = 1 6 // 状态必须设置数据类型 7 // 状态必须设置初始值 8 ... 9 // 定义事件 10 Text(this.num.toString()) 11 // 添加点击事件 12 .onClick(() =\u0026gt; { 13 this.num ++ 14 }) 15 ... 16} ","date":"2025-07-14T00:00:00Z","image":"https://rd806.github.io/passage/software/harmonyos/HarmonyOS_hu_d6e435dba41fea6b.png","permalink":"https://rd806.github.io/passage/software/harmonyos/","title":"HarmonyOS入门"},{"content":"排序是将一个数据元素的任意序列，重新排列成一个按关键字有序的序列的过程。\n所有排序算法均使用以下结构：\n1#define MAXSIZE 100 2typedef int KeyType； 3 4struct Data { 5 KeyType key; 6}; 7 8struct SqList { 9 Data r[MAXSIZE+1]; // 通常 r[0] 用作辅助空间，也称作“哨兵位” 10 int length; 11}; 定义函数LT()为元素比较函数：\n1// 将元素从小到大排列 2bool LT(int a, int b) { 3 return a\u0026gt;b; 4} 5 6// 将元素从大到小排列 7bool LT(int a, int b) { 8 return a\u0026lt;b; 9} 插入排序 直接插入排序 核心是将一个待排序的数据插入到已排好序的有序表中，从而完成排序。\n1void InsertSort(SqList \u0026amp;L) { 2 for (int i = 2; i\u0026lt;=L.length; i++) { 3 if(LT(L.r[i].key, L.r[i-1].key)) { // 将L.r[i]插入有序子表 4 L.r[0] = L.r[i]; // 复制到“哨兵”位 5 L.r[i] = L.r[i-1]; 6 } 7 for (int j = i-2; LT(L.r[0].key, L.r[j].key); j--) { 8 L.r[j+1] = L.r[j]; // 记录后移 9 } 10 L.r[j+1] = L.r[0]; // 插入到正确位置 11 } 12} 希尔排序 步骤：\n设待排序对象序列有 $n$ 个对象，首先取一个整数gap \u0026lt; n作为间隔，将全部对象分为gap个子序列，所有距离为gap的对象放在同一个子序列中 在每一个子序列中分别施行直接插入排序； 然后缩小间隔gap，重复上述的子序列划分和排序工作； 直到最后取gap = 1，将所有对象放在同一个序列中排序为止。 1void ShellSort(SqList \u0026amp;L) { 2 int i, j = 0; 3 int gap = L.length / 2; 4 while (gap \u0026gt;= 1) { 5 // 直接插入排序 6 for (i = gap + 1; i \u0026lt;= L.length; i++) {\t7 L.r[0] = L.r[i]; 8 for (j = i - gap; j \u0026gt; 0 \u0026amp;\u0026amp; LT(L.r[0].key, L.r[j].key); j -= gap) { 9 L.r[j+gap] = L.r[j]; 10 } 11 L.r[j+gap] = L.r[0]; 12 } 13 gap /= 2; 14 } 15} 希尔排序的特点：\n开始时gap的值较大，但子序列中的对象较少，排序速度较快；随着gap逐渐变小，子序列中对象个数逐渐变多，但大多数对象已基本有序，所以排序速度仍然很快。时间复杂度取决于gap的取法（或称“增量”序列函数）； 对特定待排序对象序列，可准确估算比较次数和移动次数。希尔排序所需的比较次数和移动次数约为 $n^{1.3}$，当n趋于无穷时可减少到 $n(\\log n)^2$； 希尔排序是一种不稳定的排序方法。 交换排序 基本思想：两两比较待排序对象的关键字，若为逆序，则交换之，直到所有对象都排好序为止。\n冒泡排序 冒泡排序的原理是每次都将最大（或最小）的元素转移至最右侧，类似于水中的气泡不断上升的过程。\n步骤：\n设待排序对象个数为n； 一般地，第i趟冒泡排序从1到n-i+1依次比较相邻两个记录的关键字，若为逆序，则交换之。 在一趟排序过程中没有进行过交换记录的操作，则结束，最多作n-1趟排序。 1void BubbleSort(SqList \u0026amp;L) { 2 // 设置交换标记 3 bool exchange = true; 4 for(int i = 1; i \u0026lt; L.length \u0026amp;\u0026amp; exchange; i++) { 5 // 假设未交换 6 exchange = false; 7 for(int j = 1; j \u0026lt; L.length-i+1; j++) { 8 if(LT(L.r[j].key, L.r[j+1].key)) { 9 // 若满足交换条件，则设置交换标记为真 10 swap(L.r[j].key, L.r[j+1].key); 11 exchange = true; 12 } 13 } 14 } 15} 冒泡排序分析：\n最好情况：若初始序列为正序，则只执行一趟排序，做n-1次比较，不移动记录； 最坏情形：若初始序列为逆序，则需执行n-1趟排序，第i趟 $(1 \\leqslant i \\leqslant n)$ 做n-i次比较和交换； 时间复杂度为 $O(n^2)$； 冒泡排序是一个稳定的排序方法。 快速排序 基本思想：\n选取一个记录作基准，通过一趟排序将待排记录划分为左右两个子序列，使得：左侧子序列中所有关键字都小于基准关键字，右侧子序列中所有关键字都大于或等于基准关键字； 基准对象则排在这两个子序列中间（这也是该对象最终应安放的位置），称为枢轴（支点）； 然后分别对这两个子序列重复施行上述方法，直到所有的对象都排在相应位置为止。 一趟快速排序的过程：\n设两个指针low和high，设枢轴记录的关键字为pivotkey； 首先从high所指位置起向前搜索找到第一个关键字小于pivotkey的记录，并和枢轴记录互相交换 然后从low所指位置起向后搜索，找到第一个关键字大于pivotkey的记录，和枢轴记录互相交换 重复2, 3两步直至low == high为止。 1/* ----- 一趟快速排序 ----- */ 2int Partition(SqList \u0026amp;L, int low, int high) { 3 L.r[0] = L.r[low];\t// 第一个记录作基准对象 4 KeyType pivotkey = L.r[low].key;\t// 枢轴记录关键字 5 while (low \u0026lt; high) { 6 while(low \u0026lt; high \u0026amp;\u0026amp; L.r[high].key \u0026gt;= pivotkey) { 7 high-- ; 8 } 9 L.r[low] = L.r[high];\t// 小于基准对象的移到区间的左侧 10 11 while(low \u0026lt; high \u0026amp;\u0026amp;\tL.r[low].key \u0026lt;= pivotkey) { 12 low++ ; 13 } 14 L.r[high] = L.r[low];\t// 大于基准对象的移到区间的右侧 15 } 16 L.r[low] = L.r[0]; 17 return low; 18} 19 20/* ----- 在序列 low-high 中递归地进行快速排序 ----- */ 21void Qsort(SqList \u0026amp;L, int low, int high) { 22 if (low \u0026lt; high) { 23 pivotloc = Partition(L, low, high);\t// 划分 24 QSort(L, low, pivotloc-1); // 左序列同样处理 25 QSort(L, pivotloc+1, high);\t// 右序列同样处理 26 } 27} 28 29/* ----- 主函数 ----- */ 30void QuickSort(SqList \u0026amp;L) { 31 Qsort(L, 1, L.length); 32} 快速排序分析：\n快速排序的平均计算时间为 $O(n\\log n)$。实验结果表明：就平均计算时间而言，快速排序是所有内排序方法中最好的一个。 快速排序是一种不稳定的排序方法。 在C++中，快速排序可使用algorithm库中的sort函数，时间复杂度为 $O(n\\log n)$。\n1#include \u0026lt;algorithm\u0026gt; 2 3// 长度为n的数组 4sort(a,a+n); 5// vector容器 6sort(vector.begin(), vector.end()); 基于比较的排序，其复杂度不会低于 $O(n\\log n)$\n选择排序 基本思想：进行n–1趟排序，每一趟在n–i+1 $(i=1,2,\\cdots,n-1)$ 个记录中选取关键字最小的记录作为有序序列中第i个记录。\n直接选择排序 基本步骤：\n每一步，在L.r[i]～L.r[n]中选择关键字最小记录； 若它不是该组第一个记录，则将它与该组中的第一个记录对调； 在剩下的记录L.r[i+1]～L.r[n]中重复执行第1、2步，直到循环结束。 1void SelectSort(SqList \u0026amp;L) { 2 for (int i = 1; i \u0026lt; L.length; i++) { 3 int k = i;\t// 选择具有最小的关键字 4 for(int j = i+1; j \u0026lt;= L.length; j++) { 5 if(L.r[j].key \u0026lt; L.r[k].key) { 6 k = j; // 当前最小关键字 7 } 8 } 9 if( k != i ) { 10 // 对换到第 i 个位置 11 swap(L.r[i], L.r[k]); 12 }\t13 } 14} 堆排序 堆的定义：设有一个关键字集合，按完全二叉树的顺序存储方式存储在一维数组中。对它们从根开始，自顶向下，同一层自左向右从1开始连续编号。若满足 $$K_i \\leqslant K_{2i} \\ \\\u0026\\\u0026\\ K_i \\leqslant K_{2i+1}$$ 或 $$K_i \\geqslant K_{2i} \\ \\\u0026\\\u0026\\ K_i \\geqslant K_{2i+1}$$ 则称该关键字集合构成一个堆。前者称为小顶堆（最小堆），后者称为大顶堆（最大堆）。\n堆调整：将一无序序列看成完全二叉树，则最后一个非终端结点是第 $\\displaystyle \\left\\lfloor \\frac{n}{2} \\right\\rfloor$ 个元素，则从该元素开始自下向上逐步调整为大顶堆（小顶堆）。\n使用堆排序实现由小到大排列：\n建立一个大顶堆，则可以交换第一和最后一个对象，最后一个对象就位； 而前n–1个元素使用一次调整算法，又可成为一个大顶堆，则再交换第一和倒数第二个元素，再调整； 依此类推可得最终序列。 1typedef SqList HeapType; 2 3/* ----- 堆调整算法 ----- */ 4// 设大顶堆为 H.r[s..m]，且 H.r[s] 需要调整 5void HeapAdjust(HeapType \u0026amp;H, int s, int m) { 6 Data rc = H.r[s]; 7 for(int j = 2*s; j \u0026lt;= m; j *= 2) { 8 if(j \u0026lt; m \u0026amp;\u0026amp; H.r[j].key \u0026lt; H.r[j+1].key)\t{ 9 j++; 10 } 11 if(rc.key \u0026gt;= H.r[j].key) { 12 break; 13 } 14 H.r[s] = H.r[j]; 15 s = j; 16 } 17 H.r[s] = rc; 18} 19 20/* ----- 堆排序 ----- */ 21void HeapSort(HeapType \u0026amp;H) { 22 // 建立堆 23 for(int i = H.length/2; i \u0026gt; 0; i--) {\t24 HeapAdjust(H, i, H.length); 25 } 26 // 排序 27 for(int i = H.length; i \u0026gt; 1; i--) {\t28 swap(H.r[1], H.r[i]); 29 HeapAdjust(H, 1, i–1); 30 } 31} 归并排序 定义：不断将两个或两个以上的有序表合并成一个新的有序表的排序方法。\n常用的归并排序方法为2-路归并排序。\n步骤：\n设初始序列有 $n$ 个对象，首先把它看成是 $n$ 个长度为 $1$ 的有序子序列； 然后两两归并，得到 $\\displaystyle \\left\\lceil \\frac{n}{2} \\right\\rceil$ 个长度为 $2$ 的有序子序列（如果 $n$ 为奇数，则最后一个有序子序列的长度为 $1$）； 再做两两归并，如此重复，最后得到一个长度为 $n$ 的有序序列。 1// 将有序的 SR[l..m] 和 SR[m+1..r] 归并为有序的 TR[l..r] 2void Merge(RcdType SR[], RcdType TR[], int l, int m, int r) { 3 int i = l, j = m + 1, k = l; 4 while (i \u0026lt;= m \u0026amp;\u0026amp; j \u0026lt;= r) {\t// 归并 5 if (SR[i].key \u0026lt;= SR[j].key) { 6 TR[k] = SR[i++]; 7 } 8 else { 9 TR[k] = SR[j++]; 10 } 11 k++; 12 } 13 if (i \u0026lt;= m) { 14 TR[k..r] = SR[i..m];\t// 整体复制 15 } 16 if (j \u0026lt;= r) { 17 TR[k..r] = SR[j..r]; // 整体复制 18 } 19} 20 21// 一趟归并排序 22void MSort (RcdType SR[], RcdType TR[], int len, int n) { 23 int i = 1; // 序列从1开始两两归并 24 while (i + 2*len – 1 \u0026lt;= n) { 25 Merge(SR, TR, i, i+len–1, i+2*len–1); 26 i += 2*len; // 循环两两归并 27 } 28 if (i + len \u0026lt;= n) { // 仍可再进行一次归并 29 Merge(SR, TR, i, i + len – 1, n); 30 } 31 else { 32 TR[i..n] = SR[i..n]; // 整体复制 33 } 34} 35 36// 2-路归并排序主程序 37void MergeSort(SqList \u0026amp;L) { 38 RcdType TR[L.length]; 39 int len = 1; 40 while (len \u0026lt; L.length) { 41 MSort(L.r, TR, len, L.length); 42 L.r = TR;\t// 表示将TR整体复制到原序列L.r 43 len *= 2; 44 } 45} 递归形式的归并排序：\n1void MSort(RcdType SR[], RcdType \u0026amp;TR[], int l, int r) { 2 if(l == r) { 3 TR[l] = SR[l]; 4 } 5 else { 6 int m = (l+r) / 2;\t// 平分SR[l..r] 7 MSort(SR, TR1, l, m); // 对左侧进行归并排序 8 MSort(SR, TR1, m+1, r); // 对右侧进行归并排序 9 Merge(TR1, TR, l, m, r); // 合并左右两个有序序列 10 } 11} 12 13// 对顺序表L作归并排序 14void MergeSort(SqList \u0026amp;L) {\t15 MSort(L.r, L.r, 1, L.length); 16} 桶排序 桶排序的时间复杂度为 $O(n)$，适用于数据范围较小且已知、数据容量大的排序场景。它利用值域小的特点，可以用一个数组（桶）记录各类数据出现的次数，然后下标就可以自动排序了。\n1int n,m; // n为数据的个数，m为数据的种数 2int a[n], bucket[m]; 3 4void bucket_sort(int a[], int bucket[], int n, int m) { 5 for(int i = 0; i \u0026lt; n; i++) { 6 bucket[a[i]]++ ; // 记录元素a[i]出现的次数，放进编号为a[i]的桶中 7 } 8 9 for(int i = 0; i \u0026lt; m; i++) { 10 // 遍历每个桶，第i个桶中的元素代表对应的i元素出现的次数 11 for(int j = 0; j \u0026lt; bukket[i]; j++) { 12 cout \u0026lt;\u0026lt; i \u0026lt;\u0026lt; \u0026#39; \u0026#39;; 13 } 14 } 15} 各种排序的复杂度比较：\n排序方法 比较次数 移动次数 稳定性 额外存储空间 直接插入排序 $O(n) \\sim O(n^2)$ $0 \\sim O(n^2)$ 稳定 $1$ 折半插入排序 $O(n\\log n)$ $0 \\sim O(n^2)$ 稳定 $1$ 冒泡排序 $O(n) \\sim O(n^2)$ $0 \\sim O(n^2)$ 稳定 $1$ 快速排序 $O(n\\log n) \\sim O(n^2)$ $O(n\\log n) \\sim O(n^2)$ 不稳定 $\\log n \\sim n^2$ 直接选择排序 $O(n^2)$ $0 \\sim O(n)$ 不稳定 $1$ 堆排序 $O(n\\log n)$ $O(n\\log n)$ 不稳定 $1$ 归并排序 $O(n\\log n)$ $O(n\\log n)$ 稳定 $n$ ","date":"2025-07-06T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/sort/","title":"排序"},{"content":"程序 = 数据结构 + 算法\n本文主要用来应付我的数据结构课程期末考试，所以写得比较粗糙，很多细节都忽略掉了，还请各位 dalao 谅解 🥰。\n以后如果有时间我可能会新建页面具体分析相关内容，所以可以把本文看作一篇索引（一个页表？）。\n索引 当前已更新索引，原内容拆分为五个部分\n数据结构：线性表\r数据结构：树与二叉树\r数据结构：图\r查找\r排序\rC语言补充知识 typedef typedef可以给变量起一个别名，例如：\n1typedef int ElemType 此后可以用ElemType代替int。\n输入输出函数 一般而言，C语言的输入输出函数比cin，cout更高效。\n1int num; 2float fnum; 3double dnum; 4char str[10]; 5 6int main() { 7 // 输入 8 scanf(\u0026#34;%d\u0026#34;, \u0026amp;num); // 整数 9 scanf(\u0026#34;%f\u0026#34;, \u0026amp;fnum); // float类型浮点数 10 scanf(\u0026#34;%lf\u0026#34;, \u0026amp;dnum); // double类型浮点数 11 scanf(\u0026#34;%s\u0026#34;, str); // 字符串 12 13 //输出 14 printf(\u0026#34;%d\u0026#34;, num); 15 printf(\u0026#34;%f\u0026#34;, fnum); 16 17 return 0; 18} C语言的格式符：\n格式符 含义 示例代码 输出示例 %d 十进制整数 printf(\u0026quot;%d\u0026quot;, 123); 123 %f 浮点数 printf(\u0026quot;%f\u0026quot;, 3.14); 3.140000 %c 字符 printf(\u0026quot;%c\u0026quot;, 'A'); A %s 字符串 printf(\u0026quot;%s\u0026quot;, \u0026quot;hello\u0026quot;); hello %x 十六进制整数（小写） printf(\u0026quot;%x\u0026quot;, 255); ff %X 十六进制整数（大写） printf(\u0026quot;%X\u0026quot;, 255); FF %o 八进制整数 printf(\u0026quot;%o\u0026quot;, 8); 10 %p 指针地址 printf(\u0026quot;%p\u0026quot;, ptr); 0x7ffeefbff5a0 %e 科学计数法（小写e） printf(\u0026quot;%e\u0026quot;, 1234.5); 1.234500e+03 %E 科学计数法（大写E） printf(\u0026quot;%E\u0026quot;, 1234.5); 1.234500E+03 %g 自动选 %f 或 %e（更短） printf(\u0026quot;%g\u0026quot;, 0.00001); 1e-05 %u 无符号十进制整数 printf(\u0026quot;%u\u0026quot;, -1); 4294967295 动态内存分配 函数 作用 返回 malloc 申请未初始化的连续字节 void *（成功）或 NULL（失败） calloc 申请已清零的连续元素 同上 realloc 扩容/缩容已申请的块 同上 free 归还内存 void 申请要判空，用完必释放，扩容用临时，释放后置 NULL。\n","date":"2025-07-06T00:00:00Z","image":"https://rd806.github.io/passage/cs/data-structure/guerrillabuzz-7hA2wqBcSF8-unsplash_hu_609e21f5d4048b9f.jpg","permalink":"https://rd806.github.io/passage/cs/data-structure/","title":"熟练掌握数据结构"},{"content":"阅读 阅读Ⅰ 阅读下面的文字，完成1~5题。（本题共5小题，19分）\n材料一：\n教育是强国建设、民族复兴之基。党的十八大以来，我们坚持把教育作为国之大计、党之大计，全面贯彻党的教育方针，作出深入实施科教兴国战略、加快教育现代化的重大决策，确立到2035年建成教育强国的奋斗目标，加强党对教育工作的全面领导，不断推进教育体制机制改革，推动新时代教育事业取得历史性成就、发生格局性变化，教育强国建设迈出坚实步伐。\n我们要建成的教育强国，是中国特色社会主义教育强国，应当具有强大的思政引领力、人才竞争力、科技支撑力、民生保障力、社会协同力、国际影响力，为以中国式现代化全面推进强国建设、民族复兴伟业提供有力支撑。\n建设教育强国是一项复杂的系统工程，需要我们紧紧围绕立德树人这个根本任务，着眼于培养德智体美劳全面发展的社会主义建设者和接班人，坚持社会主义办学方向，坚持和运用系统观念，正确处理支撑国家战略和满足民生需求、知识学习和全面发展、培养人才和满足社会需要、规范有序和激发活力、扎根中国大地和借鉴国际经验等重大关系。\n要坚持不懈用新时代中国特色社会主义思想铸魂育人，实施新时代立德树人工程。不断加强和改进新时代学校思想政治教育，教育引导青少年学生坚定马克思主义信仰、中国特色社会主义信念、中华民族伟大复兴信心，立报国强国大志向、做挺膺担当奋斗者。注重运用新时代伟大变革成功案例，充分发挥红色资源育人功能，不断拓展实践育人和网络育人的空间和阵地。加大国家通用语言文字推广力度，促进铸牢中华民族共同体意识。\n要统筹实施科教兴国战略、人才强国战略、创新驱动发展战略，一体推进教育发展、科技创新、人才培养。以科技发展、国家战略需求为牵引，着眼提高创新能力，优化高等教育布局，完善高校学科设置调整机制和人才培养模式，加强基础学科、新兴学科、交叉学科建设和拔尖人才培养。强化校企科研合作，让更多科技成果尽快转化为现实生产力。构建职普融通、产教融合的职业教育体系，大力培养大国工匠、能工巧匠、高技能人才。\n要坚持以人民为中心，不断提升教育公共服务的普惠性、可及性、便捷性，让教育改革发展成果更多更公平惠及全体人民。优化区域教育资源配置，推动义务教育优质均衡发展，逐步缩小城乡、区域、校际、群体差距。持续巩固“双减”成果，全面提升课堂教学水平，提高课后服务质量。深入实施国家教育数字化战略，扩大优质教育资源受益面，提升终身学习公共服务水平。\n要实施教育家精神铸魂强师行动，加强师德师风建设，提高教师培养培训质量，培养造就新时代高水平教师队伍。提高教师政治地位、社会地位、职业地位，加强教师待遇保障，维护教师职业尊严和合法权益，让教师享有崇高社会声望、成为最受社会尊重的职业之一。\n要深入推动教育对外开放，统筹“引进来”和“走出去”，不断提升我国教育的国际影响力、竞争力和话语权。扩大国际学术交流和教育科研合作，积极参与全球教育治理，为推动全球教育事业发展贡献更多中国力量。\n——习近平《在二〇二四年全国教育大会上的讲话》（节选） 材料二：\n这学期，天津大学新开的一门“人工智能导论”课受到学生热捧。这门课由该校人工智能学院教授胡清华领衔，8位人工智能及交叉学科领域教授齐心打造，13个学院的30位教师共同授课；4000余名大一新生在智慧教室内通过裸眼3D、全景智能板书等智能教具与教授互动……这是天津大学以新工科建设为契机，积极推动学科交叉及新兴学科布局，创新拔尖人才培养模式的一个缩影。\n树立“从未来到未来”的人才培养理念，把培养国家重大战略急需人才摆在突出位置；聚焦国家重大战略需求优化学科布局，壮大新兴学科，培育未来学科，促进学科交叉融合，这是天津大学在迈入办学第130个年头之际的思考与实践。\n“我们可以在大型振动台台面上1∶1等比例还原一栋7层楼高的建筑物，复现地震作用下建筑结构的破坏形式，进而分析研究建筑的抗震性能。”不久前，在天津大学地震大装置实验中心现场，地震大装置学生宣讲团成员虞永博在为学弟学妹们上一堂沉浸式思政课。他生动讲述了地震大装置的建设背景、师生攻坚克难的建设过程、“人造地震”的工作原理等，在场师生无不动容。\n位于天津大学北洋园校区西南隅正在建设中的“天津大学国家大型地震工程模拟研究设施”，被师生们亲切地称为“大装置”，它不仅是科研大平台，更是学校教育引导青年学子发扬科学家精神、理解国家需求与所学专业关系的生动教材。每年，数百名“智能制造与建造”类专业的大学新生，正是从这里开始将头脑中原本抽象的“国家需求”“攻坚克难”等词汇变成鲜活的现实案例。\n作为新工科建设的引领者，近年来，天津大学按照“强工、厚理、振文、兴医、交叉（融合）”的学科发展思路，新增了18个本科专业，其中大多是像“合成生物学”“智能制造工程”“智能感知工程”这样具有明显学科交叉特征的新专业；还在全国率先设立了“救援医学”“非物质文化遗产学”“地球系统科学”等交叉学科硕博士授权点。同时，天大实施了“人工智能+传统工科”的“天智计划”，推动传统工科优势专业与新兴学科交叉融合，增设大数据、云计算、智能电网、水下机器人等领域方向，组建了跨学科、跨行业、国际化的团队，构建了人工智能核心课程、关联课程、普及课程相结合的模块化课程体系，推动人工智能为传统工科“添智”“赋能”，全面推进校级层面的学科交叉融合。\n在天津大学，如果拔尖创新人才培养是一张宏大的棋盘，那么推动传统工科迭代更新、发展壮大新兴学科、提前布局未来学科就是学校落下的一枚枚闪闪发光的棋子，稳扎稳打、步步为营，完成学习方式、育人模式等方面的深层次变革，最终实现为祖国培养堪当重任的卓越工程师这一终极目标。\n“天津大学将持续以新工科建设推动学校人才培养模式改革，带动新文科、新医科建设，着力提升拔尖创新人才自主培养能力；紧密对接国家战略和行业产业发展需求，增强关键核心技术的攻关和供给能力，着力打通束缚新质生产力发展的堵点卡点；要在深化教育综合改革方面敢迈步、先迈步，持续推动新工科‘天大方案’迭代更新，以昂扬状态投入到教育强国建设中，努力为推进中国式现代化、实现中华民族伟大复兴贡献积极力量。”天津大学党委书记杨贤金说。（本报记者 陈欣然 通讯员 刘晓艳）\n——节选自2024年11月1日《中国教育报》 下列对材料相关内容的理解和分析，不正确的一项是（3分）\nA.\t教育作为强国建设和民族复兴之基，要求我们坚持把教育作为国之大计、党之大计，全面贯彻党的教育方针。\nB.\t我们的教育强国应当具有思政引领力、人才竞争力、科技支撑力等六大特点，反映中国特色社会主义的特征。\nC.\t壮大新兴学科、培育未来学科、促进学科交叉融合等措施，体现天津大学“从未来到未来”的人才培养理念。\nD.\t将持续以新工科建设推动学校人才培养模式改革，是天津大学以昂扬状态投入到教育强国建设中的重要举措。\n结合材料，下列说法不正确的一项是（3分）\nA.\t教育强国建设是一项庞大的系统工程，需要协调各方，综合考虑人才与社会、国内与国际形势等诸多方面。\nB.\t为了加强教师的待遇保障，维护教师职业尊严和合法权益，我们需要培养和造就新时代的高水平教师队伍。\nC.\t虞永博在地震大装置为学弟学妹们上的一堂沉浸式思政课，是天津大学在推进教育强国建设上的生动实践。\nD.\t天津大学正在逐步探索出一条创新人才培养模式和学科融合的新路径、新范式，持续推动教育高质量发展。\n根据材料内容，下列选项不是体现天津大学推进新工科建设的是（3分）\nA.\t培养胸怀祖国和勇担使命的卓越工程师。\nB.\t打造适应产业发展需求的拔尖创新人才。\nC.\t探索校级学科间创新融合发展的新路径。\nD.\t实现我国教育的“引进来”和“走出去”。\n材料二第6段中“棋盘”和“棋子”的比喻生动形象、蕴含深意，请简要分析其表达效果。（4分）\n新工科建设是应对我国经济形势的新挑战，从服务国家战略、满足产业需求和面向未来发展的高度，提出的一项重大教育改革行动计划。请结合两则材料，分析新工科建设对于推进我国建设教育强国的深远意义。（6分）\n阅读Ⅱ 阅读下面的文字，完成6~9题。（本题共4小题，16分）\n花开在大山之间 周笑瑜 在甘肃宕昌的一年支教经历已经过半，看过了大山盛夏耀眼的日光、温柔秋天里红树间疏黄，也曾抚过冬季水墨画里的冰瀑雾凇、琼花玉树。在内陆群山里生活了175天，已经习惯刀砍斧凿的粗犷景色。现在，又重新踏上空荡辽远的平原，心头却多一分陌生、局促与空落。 那最柔软的一部分，还牵挂在陇南内陆群山深处，映着朝阳月色。 那里有心如花木的孩子们。 他们是我的花儿。 我总是想起我的花儿们。 在山间种一朵花 宕昌是座夹在两山之间、狭长分布的小小城镇，地处西北，却是长江流域。在这样山连山、山环山的县城里，我们8个从天津大学来的支教老师堪称麟角凤毛。与各自班级第一次见面的时候，站上讲台的那一瞬就能赢得无数尖叫。\n我所支教的宕昌县第一中学，是当地最好的高中。每间教室内墙上贴着“2018全国大学排行榜前100名”，给这些鲜少了解外界的孩子们一些自我激励的目标导向。第一堂课我介绍自己从哪里来，“天津大学”四字一出，给墙上的排行榜引来无数伸长脖颈、眼含热望的小圆脑袋，接着又是一声整整齐齐的“哇哦！”几十双发光的眼睛盯着我，焕发熠熠神采。\n我带的文科班里女孩子居多，名字也相似。名册上常见十几个“芳”“红”“兰”“梅”“蓉”……都是花朵一样的名字。我认认真真记下“桂兰”和“爱兰”的长相、“雪梅”和“淑梅”的个性差别……像园丁记下花园里的每一朵花。\n山里的花开得迟些，孩子们也成熟得晚。十多岁的少年看起来仍像是未长开的样子，表达他们的喜欢，也用最简单纯粹的方式。一节晚自习过去，兜里常常莫名多出几个还带着温度的糖块；一旦课上表扬了某个同学，第二天课上就有纸条夹在作业本里被收上来，是加粗书写的“谢谢”；简简单单两行英文作文评语，会被学生描黑红字、在下面模仿着一行又一行。\n一片渴望改变的绿叶 那个反复模仿评语的男孩子，是文科班里少见的“万花丛中一点绿”。他喜欢写文章，高一就是学校文学社的副社长，我和同学们一起，叫他“马副社长”。\n马副社长是班里最喜欢和我交流的同学之一。其他人表达想法时会偷偷塞给我一张纸条，他是塞给我一篇800字起步、讲述少年心事的文章。他人很聪明，也追求完美主义，总要一张张撕掉已经写好的作业重来，只为了把字写得更加漂亮。我拿着被他撕得薄薄的作业本找他谈话，想劝他把这种“精益求精”放宽一些，节省时间也节约纸张。\n他没有拒绝我的建议，但是晚上又偷偷塞了一篇题目是“我命由我不由天”的文章给我。\n“小学的时候从大城市来的表弟到我家做客。表弟能熟背唐诗三百首，看过《十万个为什么》，我大他两岁，但知识和眼界都远远不如他。我相信总有改变命运的机会。怎么改变我还不懂，但是我能把字写好。”\n收到文章的第二周，我安排了“马副社长”所在的班级去听那一周的“智慧空间站”云课堂。这是支教团与母校天津大学为孩子们共同准备的网络直播远程课程。他坐在屏幕前面第一排，眼睛里闪着光。\n在那节主题为“清洁供暖”的科普课后，马副社长又递给我他的新文章。\n他写道：“今天我有了新梦想，我想要考上天大，去学清洁供暖。”\n眼里有光的孩子 相比天津，山上的宕昌是距离阳光更近的地方。正午时分，课桌上跳动的碎金颜色总是轻易抓走我昏昏欲睡的学生们的注意力。就像向日葵追逐太阳，他们的眼睛常常投向窗外，悄悄留意树枝摇晃的影子。支教团的老师们戏称，这是我们的“花儿们”在进行“光合作用”。\n但佳怡是不同的，是这群向阳花儿里的例外。她的大眼睛里总是盛着盈盈的光。第一节英语课上我就注意到佳怡眼里的神采，蓝天可爱一样的、带着求知的光芒。从清晨的第一节早读，到夜晚的最后一节晚自习，一直发着光，定定地看着我。\n作为一个初上讲台的支教老师，心里难免忐忑，因此这份光芒就理所当然地成为我在课上重点关注的信号。一旦那神采黯淡下来，多半是大部分同学都对课堂知识有所迷惑。我就会停下来，中英结合、“手舞足蹈”地重复解释一番，直到熟悉的光芒再次亮起。这个活泼明朗又一心求知的小姑娘，已经成为我课堂上的一盏“白日灯光”。\n可惜这盏灯偶尔也有不愿放光彩的日子。\n期中考试结束的第二天一大早，被极低的考试分数警醒的少年们难得从“向阳花儿”变成了孜孜求知的爬山虎，我熟悉的“小灯笼”却低迷起来，神色怏怏地趴在桌上。\n我不明所以，但为了保护少女的小巧心思，没有当面询问，而是在当天给佳怡的作业评语中悄悄添了一句：“为何今日神色不振？”第二天的作业本里佳怡回复：“我喜欢英语，但它好像不喜欢我。”后面缀上一个神色夸张的哭脸。\n我把哭脸向下的嘴角擦掉，改成眉眼弯弯。评语里写：“分数不要过于在意，英语老师很喜欢你。”\n第二天的课堂上，我一进门就看到佳怡偷偷举着作业本对我挤眉弄眼，模仿我画的那个拙劣笑脸。她的大眼睛又神采奕奕起来。\n老师，你笑起来花都开了 从平原走进大山，走出象牙塔站上三尺讲台，至今已逾半载的支教生活里，山间教室里我茁壮生长的花儿们，为日升月落的平凡生活增添了多少动人的细节。\n夏天太阳晒晕眼睛，秋天落叶调皮地粘到发上，当树上的冰挂引来冬天……，只是在不经意之间，我已经陪伴你们度过了三季。在这“夏耘秋收冬藏”的175天里，你们有没有做好开花的准备呢？\n喜欢科技的少年们，3D打印已经搬进了深山，你们曾亲手做出过自己的成品；向往天体物理的孩子，天大支教老师用日食眼镜陪伴你们观看了“10年代”最后一场日食；也有从未踏出过岷山、眼界有限的同学，但你也曾推开屏幕走进了天大老师的课堂——机器人、智慧城市、人工智能……相信你也已经确知了自己的兴趣所在。\n待到寒假返校后，支教生活剩余的那半载，是守护你们花开的时候了。\n假期离校前，佳怡追上来塞给我一张纸条。“老师，悄悄跟你讲哦，你笑起来，让我感觉整个世界花都开了。”\n我本是长相并不出众的女孩子，谢谢我的花儿们，也把我当做仙女一样的宝贝。\n一年时间不长，我不敢用“园丁”的身份标榜自己，但想努力成为你们成长过程中的一束光，用如同慢火锻造精钢、流水打磨璞玉的耐心，照亮每一株植物开出绚烂的花。\n——选自2020年3月31日《中国青年报》 下列对文章内容的理解，不正确的一项是（3分）\nA.\t作者踏上辽远的平原心情却感到空落，是因为她仍挂念着支教生活中遇到的孩子们。\nB.\t马副社长看了网络远程直播课后就想学“清洁供暖”，可见他朝秦暮楚，缺乏主见。\nC.\t作者与孩子们独特的沟通方式既保护了他们的隐私，又在默默呵护稚嫩心灵的成长。\nD.\t在半年的支教生活中，作者不但收获了精神的慰藉，而且为山区的孩子们带来光明。\n下列对文章艺术特色的鉴赏，不正确的一项是（3分）\nA.\t通过插叙方式回忆作者支教生活的点点滴滴。\nB.\t小标题结构使文章内容层次分明又浑然一体。\nC.\t全文语言朴实细腻，将真挚的情感娓娓道来。\nD.\t运用对比手法丰富人物形象，凸显文章主旨。\n文章中“花”的意象出现多次，请简要分析其作用。（4分）\n2024年，天津大学为每位本科新生都准备了一份由宕昌县特产“当归”制作而成的精美礼物，取“当你学成，归家报国”之意。请结合文章，谈谈天津大学这样做的原因。（6分）\n阅读Ⅲ 阅读下面的文言文，完成10~14题。\n材料一：\n甲午战后，杏荪①奏曰：“自强首在储才，储才必先兴学。臣观津门之地，富野千里，通衢八方，自当创办新学，以期强兵富国。”帝曰：“善。”乃于光绪廿一年御批：“该衙门知道。”始立天津北洋西学堂，杏荪权督办。越明年，更名北洋大学堂，尊西学为上，辟工程、矿务、机器、律例四科，后增铁路，以济当世之需，开中国近代高等教育之先河。历辛亥革命，易名国立北洋大学，后为北洋工学院，“北洋”之称遂传于世。初，赵天麟首倡校训“实事求是”。赵天麟者，时任北洋大学校长也，专精法务。既立此训，以为端正学风之策。民国廿六，天津陷于日寇铁蹄，院西迁至陕西固县七星寺，组“国立西北联合大学”。当是时办学境艰乏屋舍师生乃于寺挑灯夜读，彻夜不息，时称“七星灯火”。抗战胜利，还迁原址，复其旧名。公元一九四九元月，天津解放，举城欢庆。同年，北洋大学划属中央教育部，增其旧制，设理、工二院，凡共十一系。适一九五一年九月廿二，始更名“天津大学”，沿用至今。至新世纪，已入“985”“211”“双一流”之列。建校百余年，谨记“兴学强国”使命，成果颇丰，培养各界人才逾卅万，享誉寰球。\n——佚名《天津大学校史》 材料二：\n花堤霭霭，北运滔滔，巍巍学府北洋高。悠长称历史，建设为同胞。不从纸上逞空谈，要实地把中华改造。穷学理，振科工，重实验，薄雕虫。望前驱之英华卓荦，应后起之努力追踪；念过去之艰难缔造，愿一心一德共扬校誉于无穷。\n——廖辅叔《天津大学校歌》 注：①杏荪：盛宣怀，字杏荪。\n文中画波浪线的部分有三处需要断句，请用铅笔将答题卡上相应位置的答案标号涂黑。每涂对一处给1分，涂黑超过三处不给分。（3分）\n当是时A办学B境艰C乏D屋舍E师生F乃于寺G挑灯H夜读\n下列对文中材料中加点词语及相关内容的解说，不正确的一项是（3分）\nA. “廿”，数目字，读作niàn。人们常用“廿”代表二十，“卅”代表三十。\nB. “权”，文中指代理，与《孟子》中“权，然后知轻重”的“权”意思不同。\nC. “以为”，文中指认为，与贾谊《过秦论》中“以为固”中的“以为”意思相同。\nD. “双一流”，指建设世界一流大学和一流学科，意在提升中国高等教育综合实力。\n下列对材料有关内容的概述，不正确的一项是（3分）\nA. 甲午中日战争战败后，为了挽救危局，盛宣怀上书提议在天津建立新式学校。\nB. 北洋大学堂完全教授西方先进科技知识，是中国高等教育探索道路上的先驱。\nC. 建国以来，天津大学位列“985”“211”“双一流”之列，是我国的著名学府。\nD. 天津大学以“兴学强国”为使命，提倡“实事求是”，脚踏实地投身祖国建设。\n把文中画横线的句子翻译成现代汉语。（8分）\n（1）臣观津门之地，富野千里，通衢八方，自当创办新学，以期强兵富国。\n（2）穷学理，振科工，重实验，薄雕虫。\n结合材料，说明天津大学是如何实践“实事求是”校训的。（5分）\n阅读Ⅳ 阅读下面这首古诗，完成15~16题。（本题共2小题，9分）\n初到津门 元好问 潞卫交流入海平，丁沽风物久闻名。 京南花月无双地，蓟北繁华第一城。 柳外楼台明雨后，水边鱼蟹逐潮轻。 分明小幅吴江画，我欲移家过此生。 下列对这首诗的理解和赏析，不正确的一项是（3分）。\nA.\t开篇介绍天津的地理位置，“久闻名”流露作者的期待之情。\nB.\t颔联对仗工整，作者在反衬中高度赞扬了天津的美丽富饶。\nC.\t尾联中作者直抒胸臆，赞叹天津的景致着实令人流连忘返。\nD.\t全诗语言简明直白，生动地表达作者对天津的喜爱和赞美。\n本诗的颈联独具特色，请简要赏析。（6分）\n名篇名句默写 补写出下列句子中的空缺部分。（6分）\n海小棠漫步在天津大学卫津路校区。正值秋季，看到青年湖旁落叶纷飞，她不禁想起杜甫《登高》中的 “ ， ”。夜晚，皓月当空，苏轼《念奴娇·赤壁怀古》中“ ， ”又涌上她的心头。乘坐615快线，她来到北洋园校区。在郑东图书馆前，她吟诵出“ ， ”，激励自己努力学习，奋发图强。 语言文字运用 阅读下面的文字，完成18~22题。（18分）\n2009年以来，以混合推进技术为特征的新一代水下滑翔机成为国际研究新趋势，它集能耗小、成本低、航程大、运动可控、部署便捷等优点于一身，具备独立在水下全天候工作的能力， \u0026nbsp;\u0026nbsp;\u0026nbsp;①\u0026nbsp;\u0026nbsp;\u0026nbsp;。世界海洋强国把滑翔机先进研究成果应用到军事装备设计中，相关技术和产品不向中国提供，中国亟需（ A ）。 2014年5月，按照国家高技术研究发展计划“深海滑翔机研制及海上实验研究”项目安排，天津大学“海燕”参加了规范化海上试验中期评估。在第三方全程监督下，“海燕”圆满完成了单周期、多周期及长航程……等一系列任务，是在南海测试的诸多各型滑翔机中一家全程无故障完成所有项目。\n2018年，“海燕”创下8213米的潜深世界纪录。2020年7月16日，“海燕”谱系中的“海燕-X”万米级水下滑翔机，最大下潜深度首次达到10619米， \u0026nbsp;\u0026nbsp;\u0026nbsp;②\u0026nbsp;\u0026nbsp;\u0026nbsp; 。\n“海燕”创造了中国水下滑翔机无故障航程最远、时间最长、剖面运动最多、工作深度最大等诸多纪录， \u0026nbsp;\u0026nbsp;\u0026nbsp;③\u0026nbsp;\u0026nbsp;\u0026nbsp;。“海燕” 以可靠性设计与质量管理为核心，实现了水下滑翔机整体水动力优化设计、大深度滑翔、新型驱动融合设计、多任务观测模块集成研究等关键技术的自主创新，在推进我国水下滑翔机的实用化进程中立下（ B ）。\n深潜，到万米海渊；远航，至天海无疆。“海燕”就如它的名字，是茫茫大海中勇敢欢乐的“战斗者”。\n在文中括号处填写合适的成语。（2分）\n文中画波浪线的句子有语病，请进行修改，可少量增删词语，但不得改变原意。（3分）\n在文中横线处补写恰当的语句，使整段文字语意完整连贯，内容贴切，逻辑严密，每处不超过15个字。（6分）\n天津大学为何要将水下滑翔机取名“海燕”？请谈谈你的理解。（3分）\n结合材料，请你给“海燕”滑翔机下一个定义，不超过50字。（4分）\n写作 阅读下面的材料，根据要求写作。（60分）\n2024年，不少人“吐槽”天津大学招生办的宣传工作不尽人意，尤其是在各大短视频平台“出镜率”较低，导致知名度不高；也有人认为，天津大学历来尊崇“实事求是”，作为新工科建设的“领头羊”，是金子总会发光。\n这引发了你怎样的联想与思考？请结合以上材料，写一篇文章。\n要求：选准角度、确定立意，明确文体，自拟标题；不要套作，不得抄袭，不得泄露个人信息；不少于800字。\n整体预览：\n","date":"2025-01-09T00:00:00Z","permalink":"https://rd806.github.io/passage/interesting/tju/","title":"有意思的玩意"},{"content":"git简介 git 是一个开源的分布式版本控制系统（VCS），用于高效、快速地处理从小型到大型项目的所有内容管理。它由 Linus Torvalds（Linux 之父）于 2005 年创建，最初是为了更好地管理 Linux 内核开发。\ngit基本概念 术语 含义 仓库（Repository） 存储项目所有文件和历史记录的地方 工作区（Working Directory） 你电脑上实际看到的项目文件夹 暂存区（Index/Stage） 准备提交的更改区域，介于工作区和仓库之间 提交（Commit） 保存项目当前状态为一个版本 分支（Branch） 从主线上分出来的独立开发线，不影响主线 合并（Merge） 将分支的更改整合到另一个分支 远程仓库（Remote） 托管在网络上的仓库，如 GitHub、GitLab git基本操作 克隆（clone） 远程仓库到本地 1git clone https://github.com/user/repo.git 在工作区中修改文件。\n暂存（add） 更改到暂存区\n1git add . 提交（commit） 更改到本地仓库 1git commit -m \u0026#34;描述信息\u0026#34; 2 3# 若提交时无文件更改 4git commit -m \u0026#34;描述信息\u0026#34; --allow-empty 推送（push） 到远程仓库 1git push 分支名 拉取（pull） 获取他人更新 1git pull origin main 变更分支 若更改未push到远程仓库中，默认保存在本地工作文件夹的.git文件夹中，此时可以对分支进行任意的修改操作。\n进入工程文件夹，在终端中输入 1git log 此命令可以查看当前所有提交的具体信息，包括提交时间、作者、提交ID等。可以使用键盘的“↑”、“↓”键滚动，按q键退出。\n选择需要更改的提交，复制它的ID。\n退出log，在终端中输入\n1git rebase -i 复制的提交ID 这样会打开一个Nano编辑器（Linux环境下），在要删除的提交前加上#，然后Ctrl+O写入、回车、Ctrl+X保存。系统会自动变更分支结构。\n继续提交新的更改，变更完成。 若要更改的提交已经push到远程仓库，则只需在最后push时输入\n1git pull \u0026lt;分支名\u0026gt; --force 强制变更。\n注意：强制变更时应保证此时没有其他人员的提交，否则会导致分支出错。\nGithub使用教程 Github是当前世界最大的开源网站库，使用git操作管理所有文件。\n注册一个Github账号后即可在Github上免费创建和使用仓库，也可以加入其他开源项目的开发。\n添加 SSH 密钥 一些情况下，使用git push时会提示网络连接超时。这时可以尝试使用SSH协议，为你的Github账户添加 SSH 密钥。\n以下操作均在Linux系统下进行。\n生成SSH密钥（如果尚未生成）： 1ssh-keygen -t rsa -b 4096 -C \u0026#34;your_email@example.com\u0026#34; 2# 引号中填写注册Github时的邮箱地址。 将公钥添加到GitHub账户： 复制公钥内容：\n1cat ~/.ssh/id_rsa.pub 登录GitHub，进入Settings → SSH and GPG keys → New SSH key，粘贴公钥并保存。\n更新Git远程仓库地址为SSH格式： 1git remote set-url origin git@github.com:USERNAME/REPOSITORY.git 替换USERNAME和REPOSITORY为你的GitHub用户名和仓库名。\n如果是Windows系统，则需要首先安装Git Bash，然后在Git Bash中执行上述操作。\n","date":"2024-11-04T00:00:00Z","image":"https://rd806.github.io/passage/guide/git/git_hu_7f4169e3778dd430.jpg","permalink":"https://rd806.github.io/passage/guide/git/","title":"玩转Github"},{"content":" ","date":"2024-10-10T00:00:00Z","permalink":"https://rd806.github.io/passage/cs/regular_expression/","title":"正则表达式"},{"content":"下载C/C++编译器 当前主流的C/C++编译器是gcc/g++，可以通过MinGW下载。\nMinGW有32位和64位版本，推荐使用64位版，因为32位的gcc/g++版本较低，且会在VScode的调试界面出现bug。\n在MinGW-64下载地址 查找符合自己版本的MinGW下载（默认是Linux系统）。\n对于Windows系统，推荐在对应的Github页面 下载x86_64-15.2.0-release-win32-seh-ucrt-rt_v13-rev0.7z版本。下载完成后解压。\n另一种获取编译器的方法是先下载一个IDE，如Dev-C++，小熊猫C++等。在其程序目录下通常会有编译器文件，可之后直接使用。\nIDE附赠的编译器 配置环境变量 环境变量是计算机中的一个重要参数，它指明了在终端中输入命令的来源和功能。若缺少对应的环境变量，一些命令会显示“无法识别”。\n找到并记住g++.exe文件所在目录，通常为.\\mingw64\\bin。 g\u0026#43;\u0026#43;.exe文件地址 Win11系统下打开 设置→系统→系统信息，在“相关信息”中打开“高级系统设置”\n在弹出窗口中选择“环境变量”，在新窗口中选择系统变量→Path→编辑，再在新窗口中选择新建，粘贴g++.exe文件所在的地址。之后一直点击“确定”关闭所有窗口。\n在cmd窗口中输入g++ --version，若显示版本等信息则表示环境变量配置成功。\n环境变量 注意：配置完 Windows 中的环境变量之后，必须重启 cmd 之后才会在 cmd 中生效。\n配置VScode 了解配置原理 这部分会比较抽象，省时间可以跳过。\nVScode默认有3套配置文件，均位于文件夹.vscode下。\n可以通过打开设置看到：用户区、工作区、SSH。\n区域 特点 用户区 可看作“全局配置”，在整个用户计算机（就是你的电脑上）均生效 工作区 仅在当前打开的文件夹内有效 SSH 当且仅当连接到SSH远程计算机时才会出现，实际上就是远程计算机的用户区配置文件 因此，若要配置运行环境，应当先创建一个文件夹作为“工作区”，然后将配置文件、源代码等文件全部放入。此后写代码和调试时都应在此文件夹中进行。\n配置运行环境 创建新文件夹workspace作为工作区，在workspace文件夹内再创建文件夹.vscode和bin\n在.vscode文件夹内再创建文件，分别命名为tasks.json和launch.json\n文件名 作用 tasks.json 终端任务文件，定义在终端执行的任务。在这里用于C/C++可执行文件的构建和运行 launch.json 运行任务文件，定义按F5调试时的任务。在这里用于C/C++可执行文件的调试 也就是说，如果只是要构建和运行C/C++程序，可以只用写tasks.json。\ntasks.json文件写入以下内容：\n1{ 2 \u0026#34;version\u0026#34;: \u0026#34;2.0.0\u0026#34;, // 版本号，建议保持不变 3 \u0026#34;tasks\u0026#34;: [ 4 { 5 \u0026#34;label\u0026#34;: \u0026#34;构建C/C++文件\u0026#34;, // 任务名称，选择任务时将会看到 6 \u0026#34;type\u0026#34;: \u0026#34;shell\u0026#34;, // 任务类别，shell表示在终端运行 7 \u0026#34;command\u0026#34;: \u0026#34;g++\u0026#34;, // 命令名称 8 \u0026#34;args\u0026#34;: [ // 命令参数（可自行修改） 9 // 表示将会被替换为所操作的.cpp文件 10 \u0026#34;${file}\u0026#34;, 11 \u0026#34;-o\u0026#34;, 12 // 可执行文件生成的位置 13 \u0026#34;${workspaceFolder}\\\\bin\\\\${fileBasenameNoExtension}.exe\u0026#34;, 14 \u0026#34;-g\u0026#34;, 15 \u0026#34;-Wall\u0026#34;, 16 \u0026#34;-static-libgcc\u0026#34;, 17 // 编码，默认为UTF-8 18 \u0026#34;-fexec-charset=UTF-8\u0026#34;, 19 // 构建的C++标准 20 \u0026#34;-std=c++14\u0026#34; 21 ], 22 \u0026#34;group\u0026#34;: \u0026#34;build\u0026#34;, 23 \u0026#34;presentation\u0026#34;: { 24 \u0026#34;echo\u0026#34;: true, 25 \u0026#34;reveal\u0026#34;: \u0026#34;always\u0026#34;, 26 \u0026#34;focus\u0026#34;: false, 27 \u0026#34;panel\u0026#34;: \u0026#34;new\u0026#34; 28 }, 29 \u0026#34;detail\u0026#34;: \u0026#34;生成可执行文件\u0026#34;, // 任务注释，显示为任务名称的下行小字 30 \u0026#34;problemMatcher\u0026#34;: \u0026#34;$gcc\u0026#34; 31 }, 32 33 { 34 \u0026#34;label\u0026#34;: \u0026#34;构建并运行C/C++文件\u0026#34;, 35 \u0026#34;type\u0026#34;: \u0026#34;shell\u0026#34;, 36 \u0026#34;dependsOn\u0026#34;: \u0026#34;构建C/C++文件\u0026#34;, 37 \u0026#34;command\u0026#34;: \u0026#34;${workspaceFolder}\\\\bin\\\\${fileBasenameNoExtension}.exe\u0026#34;, 38 \u0026#34;group\u0026#34;: { 39 \u0026#34;kind\u0026#34;: \u0026#34;build\u0026#34;, 40 \u0026#34;isDefault\u0026#34;: true // 设置为默认操作 41 }, 42 \u0026#34;presentation\u0026#34;: { 43 \u0026#34;echo\u0026#34;: true, 44 \u0026#34;reveal\u0026#34;: \u0026#34;always\u0026#34;, 45 \u0026#34;focus\u0026#34;: true, 46 \u0026#34;panel\u0026#34;: \u0026#34;new\u0026#34; 47 }, 48 \u0026#34;detail\u0026#34;: \u0026#34;调试器生成的任务\u0026#34;, 49 \u0026#34;problemMatcher\u0026#34;: [] 50 } 51 ] 52} 在.json文件中，所有的\\都应输入成\\\\，这一过程称为转译。\n配置完成后，点击 终端→运行任务→选择所需的任务 即可构建或运行程序。或直接按Ctrl+Shift+B运行默认任务，上例中为\u0026quot;构建并运行C/C++文件\u0026quot;，相当于在终端中执行命令：\n1g++ file.cpp -o file.exe -g -Wall -static-libgcc -fexec-charset=UTF-8 -std=c++14 2file.exe 构建并运行C\u0026#43;\u0026#43;程序 launch.json文件（可选）写入以下内容：\n1{ 2 \u0026#34;version\u0026#34;: \u0026#34;0.2.0\u0026#34;, 3 \u0026#34;configurations\u0026#34;: [ 4 { 5 // 单文件调试 6 \u0026#34;name\u0026#34;: \u0026#34;Debug for one file\u0026#34;, 7 \u0026#34;type\u0026#34;: \u0026#34;cppdbg\u0026#34;, // cppdbg对应cpptools提供的调试功能；只能是cppdbg 8 \u0026#34;request\u0026#34;: \u0026#34;launch\u0026#34;, 9 // 这里program指编译好的exe可执行文件的路径，与tasks中要对应 10 \u0026#34;program\u0026#34;: \u0026#34;${workspaceFolder}\\\\bin\\\\${fileBasenameNoExtension}.exe\u0026#34;, 11 \u0026#34;args\u0026#34;: [], 12 \u0026#34;stopAtEntry\u0026#34;: false, // 是否在main处打断点 13 \u0026#34;cwd\u0026#34;: \u0026#34;${fileDirname}\u0026#34;, // 调试程序时的工作目录 14 \u0026#34;environment\u0026#34;: [], 15 \u0026#34;externalConsole\u0026#34;: false, // 改为true时为使用cmd终端 16 \u0026#34;internalConsoleOptions\u0026#34;: \u0026#34;neverOpen\u0026#34;, // 设为true为调试时聚焦调试控制台 17 \u0026#34;MIMode\u0026#34;: \u0026#34;gdb\u0026#34;, 18 // 指定调试器所在路径，注意间隔是\\\\，请修改为你的路径 19 \u0026#34;miDebuggerPath\u0026#34;: \u0026#34;D:\\\\Developer\\\\mingw64\\\\bin\\\\gdb.exe\u0026#34;, 20 // 调试开始前执行的任务，必须与tasks.json的label相对应 21 \u0026#34;preLaunchTask\u0026#34;: \u0026#34;构建C/C++文件\u0026#34; 22 } 23 ] 24} 配置完成后，点击 运行→启动调试 即可开始调试。或直接按F5运行。\n之后，所有新建的C++文件都应在有配置文件的工作区中，这样可以直接在VScode中测试。 如果按照以上方法配置，工作区的文件结构应该如下所示：\n1workspace/ 2├── .vscode/ # 存放配置文件 3│ ├── launch.json 4│ └── tasks.json 5│ 6├── bin/ # 存放构建的exe文件 7│ ├── HelloWorld.exe 8│ ├── Number.exe 9│ └── {name}.exe 10│ 11├── HelloWorld.cpp # 存放源代码 12├── Number.cpp 13└── {name}.cpp ","date":"2024-09-16T00:00:00Z","permalink":"https://rd806.github.io/passage/guide/c_for_vscode/","title":"VScode配置C/C++运行环境"},{"content":"认识Minecraft Minecraft（简称MC），作为全球销量第一的游戏，深受众多玩家喜爱。\nMC分为Java版、基岩版、主机板（Xbox版）和网易版。\n下载Minecraft 正版和离线版 MC的正版与否取决于你的微软账号上有没有MC。换句话说，无论是否购买正版，你都可以下载到MC的游戏文件并启动游玩。唯一的区别在于非正版玩家无法进入开启了正版验证的服务器，因此MC中的“非正版”也被称之为“离线版”。\n离线版依然可以进入未开启正版验证的服务器\nMC Java版启动器 MC Java版本身没有.exe之类的文件，必须得有一个启动程序才能运行。\n启动器 支持系统 Minecraft Launcher （官方启动器） Windows/MacOS Plain Craft Launcher 2（PCL2） Windows Hello Minecraft Launcher （HMCL） Windows/Linux 也有部分发烧友喜欢在Android平台上启动MC Java版。目前，Android系统流行的启动器主要是Fold Craft Launcher和ZalitLauncher\n注意：千万不要指望Android平台上MC Java版的表现和Windows系统的一样。\n启动器的原理就是整合了启动游戏核心 .jar文件的功能。因此如果愿意，也可以使用IntelliJ IDEA启动。\nMC基岩版 MC基岩版则相对简单很多。只需要在相应的平台里下载MC基岩版即可。\n平台 下载地点 Windows Microsoft Store Android Google Play iOS Apple Store 鉴于国内通常无法打开Google网站，如果想体验Minecraft基岩版，可以在苦力怕论坛 下载。\n注意，论坛中下载的并非正版，请于下载体验后24小时内删除！\nMinecraft Java版进阶 Java版游戏文件 Minecraft Java版对玩家文件管理的要求较高，因此需先了解其文件结构。\n1.minecraft # 游戏文件根目录 2├── assets # 游戏资源文件夹 3├── global # 全局配置 4├── libraries # 加载库文件 5├── versions # 版本文件夹（开启版本隔离后生效） 6├── … 其中versions文件夹是我们进行操作的主要位置。\n版本隔离\n版本隔离是MC Java版独特的功能，它使得每个Java游戏版本都相互独立，互不影响。\n注意：版本隔离选项默认是关闭的，第一次使用应当在启动器设置内将“版本隔离”设置成“各版本相互独立”。\n安装 MOD Java版的优势之一就是能方便自由地安装mod、材质和光影等。\n安装mod的前提是安装mod加载器，这是绝大多数mod的加载环境。常用mod加载器如下：\n名称 版本支持 特点 Forge 1.5.2 - 最新 最流行，支持大量模组 Fabric 1.14 - 最新 轻量加载器，提供快照版本 NeoForge 1.20.1 - 最新 新兴加载器，由Forge发展而来，极具潜力 mod加载器一般互不兼容，只能选择其中一个。\n当安装了mod加载器后，下载适配当前加载器的模组并放到对应游戏版本的/versions/你的游戏版本/mods文件夹中，启动游戏即可畅玩！\n以下提供mod加载器的安装方法。\n启动器内安装 PCL2、HMCL等第三方启动器内置了mod加载器下载方式，在安装新版本时即可选择是否安装mod加载器。\n通用安装方法 在mod加载器相应的官网下载文件，并按说明安装。\n以Forge为例进行说明：\n进入Forge官网 ，选择需要下载的MC版本。 点击Installer，此时将跳转到广告界面。若你的网络状况较好，应当会在界面右上角出现“SKIP”按钮，点击“SKIP”即可下载Forge文件。 定位到文件所在位置，双击打开.jar文件，稍等一会儿就会打开安装界面，选择“Install client”，再选择安装位置，点击确定即可安装成功。 Forge 此时打开启动器，应当能在版本列表中看到刚安装的Forge版本。 安装材质和光影 安装材质的方法较为简单，直接下载好需要的材质文件（通常是压缩包的形式），将其放入/versions/你的游戏版本/resourcepacks文件夹即可。\n安装光影则需要MOD的前置支持，安装好对应MOD后，将下载的光影文件放入/versions/你的游戏版本/shaderpacks文件夹。\n模组加载器 对应MOD Forge 1.12.2 以下：Optifine；1.16.5 以上：Oculus Fabric Iris 导入地图 地图（实际上就是一个存档）的导入就是将该地图文件夹全部放入/versions/你的游戏版本/saves文件夹中即可。\nMC联机 MC的联机是一项复杂且具有挑战性的操作。学习MC的联机，您将了解并掌握《计算机网络》50% 以上的内容！\n局域网联机 这是最简单的联机方式，需要房主和玩家在同一个局域网下，也就是连接同一个Wifi。\n遗憾的是，校园网等大型局域网可能不支持这种方式。因为即使连接到同一个Wifi，ipv4地址的第3个十进制数（也就是网关）可能不相同，这样就无法通过 ipv4:端口号的方式联机。\n幸运的是，现在一些大型局域网已经支持了ipv6。这时，可以使用[ipv6]:端口号的方式启动局域网联机。\n选做：使用Radmin VPN创建虚拟局域网 不过，使用Radmin VPN创建虚拟局域网可以解决ipv4地址网关不同的问题。只需要双方同时下载Radmin VPN，由其中一方创建虚拟局域网，然后同时连接到该局域网下，即可联机成功。\n之所以称之为局域网联机，是因为在这种联机操作下，服务端就是房主的客户端（也就是房主的电脑就是服务器，所以房主必须上线）。与之相对应的就是服务器联机。\n服务器联机 详见：“Minecraft服务器——开服经历回顾” 常见问题 微软账号无法登录 有时网络运营商的 DNS 可能无法很好地解析微软的验证服务器地址，导致微软账号的登录界面无法进入，无法与小伙伴愉快游玩Hypixel。解决方法为更换更可靠的公共 DNS。\n进入 设置 \u0026gt; 网络和 Internet，点击正在连接的 Wi-Fi 或以太网的 “属性”。 找到 “DNS 服务器分配”，点击“编辑”。 将其更改为“手动”，然后打开 IPv4 开关。在“首选 DNS”中输入 8.8.8.8，在“备用 DNS”中输入 8.8.4.4。（这是 Google 的公共 DNS，非常稳定）。 保存设置，重新登录。 以上解决办法来源此处 更改DNS服务器后可能会影响其他网站的访问速度。当登录微软账号成功后，最好立即切换回自动DNS。\n链接网站 网站 内容 MC百科 下载MC Java版mod，整合包等资源。 苦力怕论坛 下载MC基岩版资源包、行为包、材质、光影、地图等。 LittleSkin皮肤站 托管MC皮肤文件。 Minecraft捆绑包商店 购买Minecraft正版。 Modrinth 下载MC和MC服务器资源。 ","date":"2024-08-10T00:00:00Z","image":"https://rd806.github.io/passage/minecraft/help/minecraft_hu_a15661c29bb9eac3.jpeg","permalink":"https://rd806.github.io/passage/minecraft/help/","title":"Minecraft教程"},{"content":"总序 金鸡峰下，银蝶湖畔，钟灵毓秀，人才辈出。有黄山松石铸精魂，蕴陶公知行明己身。时维九月，序属三秋，吾班初建，朝气蓬勃。所属虽异，团结如一；群贤毕至，共话宏图。\n忆开学之初，历历在目。虽相识不甚明，终同舟以共济。既立班委，又树新规。外出鸣、陆二帅 擎班旗，内命熙、蕾双将 督学风。已有各科班委司其职，更兼班之众生共进步。越明年，政通人和，百业俱兴。立学习小组 ，开制度先河。\n吾班凡五十有六，均性情殊异，各具风格，如若毂之共辐，屋之砖瓦。昔日成就，非独几人之功；尔后传奇，而赖众人合作。所以撰此《列传》，以记班人之名；作本短序，聊表敬佩之心。能得相聚，实乃佳缘。共事之日不足年。真挚情谊实可贵。敢竭鄙怀，恭疏短引；传世之作，仍待众才。请洒潘江，各倾陆海。\n文虽短小，情尤真切。倘成众之回忆，余当不胜感激。\n本传编写组\n二〇二四年六月作于屯溪一中\n朱天鸣传 朱天鸣者，安徽屯溪人也，任屯溪一中2024届14班班长。盖因其父为军，鸣自幼尚武，好军事，亦勤勉于学，世人赞云：“鸣文武双全，当世公瑾也。”\n时二〇二一年，鸣始任班长。因其善治，班主任甚厚之，遂连任至今。鸣性情豁达，待人宽厚，心系班级，与同窗交往甚洽，无不待之如亲朋，爱之如兄弟。久之，人皆心悦诚服，积极于世事矣。\n“鸣”者，一鸣惊人也。鸣于每次考试，皆蓄力，尚未见其大功大名。然于二〇二三年“江南” 联考，鸣之厚积薄发尽显，进步数十名，夺班之探花如探囊取物。未数月，于一、二模再展雄姿 ，是可谓“一鸣惊人”也乎。\t徐陆传 徐陆者，安徽黄山区人也，任屯溪一中2024届14班副班长，兼“超能陆战队”组长，后至领航班 。\n陆素以才思敏捷、文理兼通闻名于校。高一，深为师长重 ，至于高二三，更是然也。陆为副班长，行事之果断，办公之严明，首屈一指。陆亦善书，班之文字皆出其手，体有颜筋柳骨，迹可入木三分。\n陆尝谓同学曰：“吾名之‘陆’者，‘六’也，吾父肇锡余以此名，求平安顺遂之意。”言毕，众人相视而笑。再思之，确乎其理也。陆成绩优异，每逢大考定名列前茅。或问，必具以答，众人皆敬服之，结友甚广。于竞赛亦颇有深究，尤好物、生，并多取佳绩 。至于体育文艺，更是然也。\n昔人言：陆全面发展，诸多领域皆有建树。今观之，确为此乎哉！\n陈敬旻传 陈敬旻者，安徽屯溪人也，任屯溪一中2024届14班团支部书记，权化学课代表。\n旻身量虽小，志气尤高。凡遇展演，旻略无怯意，侃侃而谈。其文纵论古今，横贯中外；其音铿锵且美，众人无不陶醉称奇。旻之笑语声甚锐，尝引龙 驻足以学其声。旻性情爽朗，好交游，友朋遍全校。倘遇活动，必出力极多，常获称赞。\n时公元二〇二三六月一日，适儿童节，旻以黄庭坚之《登快阁》抒人生之志，说理透彻，语句隽永。既毕，掌声如雷鸣不绝。徐陆赞云：“旻之讲演，赋深意于黄诗也。广诗情，开诗境，以古人之志抒己心，借先辈之情砺后生。甚善，吾实为敬服。”\n旻之气度不凡，令人惊异，可造之才也。\n王扬熙传 王扬熙者，安徽屯溪人也，任屯溪一中2024届14班学习委员，分管竞赛事务，兼“名扬都城”组长，后至领航班。\n熙专精化竞 ，无机之变幻莫测，有机之繁复原理，结构之精细工巧，众皆迷惘不知，唯熙善拨云见日，解之易如反掌。陈雨尝与之试，竟甘拜下风。\n熙性憨厚，为人不拘小节。人尝云：“熙甚疏懒。虽见菜汤沾其衣，置之不理，仍行其道；或食饼，碎末近半遗地，竟不察也。”然瑕不掩瑜，熙众科皆强，化、英二者尤是。虽有如此成绩，熙不以为然，每日但见其之憨笑不止。熙亦通音律，明晓琴术，已谱成班歌一首，然曲高和寡，至今尚未得词。\n熙，实乃高人也。\n涂子航传 涂子航者，安徽屯溪人也，任屯溪一中2024届14班纪律委员。航之竞选演讲，文辞之恳切，声情之并茂，言语之铿锵，令众人动容。\n航深谙纪律之要，无规矩不可成方圆，班守班规方能戮力同心，行稳致远。是故课前之纪律维持，航贡献颇多，尤以眼保健操为要。凡遇碎言，必斥之，其声如洪钟，闻者虽无所过，尚胆战心惊，不敢出一言以复。\n航既司纪律，尤好学习。近几考，尽皆进步可观。假以时日，必成大器也。\n张雨乐传 张雨乐者，安徽黄山 人也，任屯溪一中2024届14班体育委员。乐名当其职，凡遇运动会，必于赛场驰骋，斩金摘银实繁，为班级总分贡献甚多，获二〇二三年校“体育之星”，众望所归也。\n然乐若在课堂，其弊则见。不知何故，嗜睡，尤以化学课为甚。坤校 讲至动情处，忽停，众不解其因。尔后惊闻“张雨乐”三字，皆知乐又睡矣。\n嗟夫！乐有过人之才，却困于嗜睡之症。倘能克其短，则又可获一栋梁哉！\n程建卓传 程建卓者，安徽屯溪人也，曾任屯溪一中2024届14班劳动委员 。卓视此职甚重，虽未得校“劳动之星”，仍为众人所敬。\n卓尝于语文演讲饰曹公。其言语行为，莫不神似，有英雄之风，故世人呼之以“曹孟德”。卓闻之，欣然曰：“甚善，名我固当。”卓恪尽职守，每逢劳动，事必躬亲，管理甚苛。凡值日者皆惧卓之盛威。或曰：“尝闻卓之怒斥值日生玩忽职守，冷气直冲天门，两股战战，不敢直视。”卓之威可于此一窥矣。\n二〇二三年五月廿三，适吾班足球赛。卓以一人之力连取六球，众人无不惊叹万分，传为佳话。世人慨叹曰：“得建卓者，近可扫一屋，远能平天下。”\t朱敏浩传 朱敏浩者，安徽休宁人也。初虽未序屯溪一中2024届14班班委之列 ，班主任视如心腹，常委以重任 ，甚得用也。\n浩为人朴实敦厚，行事不遗余力。凡为班级事务，皆不辞辛苦，身体力行。其诚恳坚韧，有目共睹。然二〇二三年五月十二，浩罹患新冠，身婴疾病。症之重，前人未见有也。而浩终不为所困，每日勤入网课而学，不曾废离。浩于生竞 缺席一事，未尝不慨叹惋惜。然天道轮回，此番缺憾，必有喜讯相报。\n浩立志入年纪前十。古人云：“有志者，事竟成。”以浩之力，定能成矣。语未毕，浩于2023年A10开年考取年级第八。\t陈雨传 陈雨者，安徽黄山区人也，任屯溪一中2024届14班数学课代表，兼“数学再爱一次我”组长，后至领航班。与徐陆交往甚厚，情同手足。其聪敏异常，解数学如有神助，龙因厚遇之。\n雨嗜数学竟成魔。凡遇，皆怀一数学题册。视题面数秒，稍思，即得解于众惑之际，人常奇之。雨亦身怀转物奇功，手中物皆可转，其速之迅，平衡之巧，无人能及。人常笑曰：“雨可转其子也 。”\n雨既为理学之圣，然略拙于语文，尤以古诗文背诵为甚。班主任常劝之，收效甚微。如其能于语文稍下苦功，则功成名就之时，指日可待与。\t江子恒传 江子恒者，安徽屯溪人也，任屯溪一中2024届14班物理课代表，迁领航班。甚聪慧，好音游，班主任寄以厚望。\n初入学，恒即崭露头角。然高二上之期中，恒仅取年级三十余名。班主任甚怒，叱之，恒默听而不言。尔后，恒暗自发奋，及期末，进步数十名，皆刮目相待。虽然，恒日益勤奋，至课下视之，苦读积分学兼概率论。适二〇二三年四月A10联盟，已入年级前十。未盈月，于“江南十校”再创佳绩。至于高三，则势如破竹，凡遇大小测试，不出年级前十，且获2023年高中数学联赛省三。\n恒学习之刻苦，进取心之坚定，可为众人之楷模乎！\n李奕冉传 李奕冉者，李家村人氏。初入平行班，以其刻苦有功，高一获“校园之星”，高二得晋。\n冉身形健美，思维灵活，素好锻炼刷卷。高二暑假未逾二十日，刷卷四十张，人皆谓之“自律哥”，冉笑而不语。视冉之卷，工整清晰，如阅珍品，他学者虽窥伺效慕，莫能如也。高三以来，冉逢考必进，“最后一卷”已入年级二十，传为佳话。\n冉通晓军事，各式兵器，如数家珍。世界大事亦了然于胸，或问之，纵横捭阖，有将帅之风。冉，李家之高人哉。\t","date":"2024-06-14T00:00:00Z","permalink":"https://rd806.github.io/passage/interesting/senior_high/","title":"十四班学生列传"},{"content":"本文提供了可用于 Hugo 内容文件的基本 Markdown 语法示例，还显示了 Hugo 主题中的基本 HTML 元素是否使用 CSS 进行修饰。\n标题 如下的 \u0026lt;h1\u0026gt;—\u0026lt;h6\u0026gt; 显示了标题的6个级别， \u0026lt;h1\u0026gt; 级别最高， \u0026lt;h6\u0026gt; 级别最低.\n1# H1 2## H2 3### H3 4#### H4 5##### H5 6###### H6 文本类型 加粗与斜体 加粗：**文本** → 文本\n斜体：*文本* → 文本\n下划线 \u0026lt;span style=\u0026quot;text-decoration: wavy underline;\u0026quot;\u0026gt; 天津大学是中国第一所现代大学。 \u0026lt;/span\u0026gt; → 天津大学是中国第一所现代大学。 \u0026lt;u\u0026gt; 2025年将迎来天津大学130周年校庆。 \u0026lt;/u\u0026gt; → 2025年将迎来天津大学130周年校庆。 上下标 H\u0026lt;sub\u0026gt;2\u0026lt;/sub\u0026gt;O → H2O\nX\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; + Y\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; = Z\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; → Xn + Yn = Zn\n方框与高亮显示 按下 \u0026lt;kbd\u0026gt;CTRL\u0026lt;/kbd\u0026gt; + \u0026lt;kbd\u0026gt;ALT\u0026lt;/kbd\u0026gt; + \u0026lt;kbd\u0026gt;Delete\u0026lt;/kbd\u0026gt; 以结束段落。 → 按下 CTRL + ALT + Delete 以结束段落。\n\u0026lt;mark\u0026gt;兴学强国\u0026lt;/mark\u0026gt;的使命，\u0026lt;mark\u0026gt;实事求是\u0026lt;/mark\u0026gt;的校训，\u0026lt;mark\u0026gt;严谨治学\u0026lt;/mark\u0026gt;的校风，\u0026lt;mark\u0026gt;矢志创新\u0026lt;/mark\u0026gt;的追求。 → 兴学强国的使命，实事求是的校训，严谨治学的校风，矢志创新的追求。\n段落 普通段落 马克思主义者认为，只有人们的社会实践，才是人们对于外界认识真理性的标准。实际的情形是这样的，只有在社会实践过程中（物质生产过程中，阶级斗争过程中，科学实验过程中），人们达到了思想中所预想的结果时，人们的认识才被证实了。人们要想得到工作的胜利即得到预想的结果，一定要使自己的思想合于客观外界的规律性，如果不合，就会在实践中失败。人们经过失败之后，也就从失败取得教训，改正自己的思想使之适合于外界的规律性，人们就能变失败为胜利，所谓“失败是成功之母”，“吃一堑长一智”，就是这个道理。\n段落类型 首行缩进：\u0026lt;p style=\u0026quot;text-indent: 2em;margin-top: 0;margin-bottom: 0;\u0026quot;\u0026gt; 文本 \u0026lt;/p\u0026gt;，其中margin-top: 0表示忽略段前空行，margin-bottom: 0表示忽略段后空行。 示例：\n君子曰：学不可以已。 青，取之于蓝而青于蓝；冰，水为之而寒于水。木直中绳，輮以为轮，其曲中规。虽有槁暴，不复挺者，輮使之然也。故木受绳则直，金就砺则利，君子博学而日参省乎己，则知明而行无过矣。 吾尝终日而思矣，不如须臾之所学也；吾尝跂而望矣，不如登高之博见也。登高而招，臂非加长也，而见者远；顺风而呼，声非加疾也，而闻者彰。假舆马者，非利足也，而致千里；假舟楫者，非能水也，而绝江河。君子生非异也，善假于物也。\n积土成山，风雨兴焉；积水成渊，蛟龙生焉；积善成德，而神明自得，圣心备焉。故不积跬步，无以至千里；不积小流，无以成江海。骐骥一跃，不能十步；驽马十驾，功在不舍。锲而舍之，朽木不折；锲而不舍，金石可镂。蚓无爪牙之利，筋骨之强，上食埃土，下饮黄泉，用心一也。蟹六跪而二螯，非蛇鳝之穴无可寄托者，用心躁也。\n居中：\u0026lt;div style=\u0026quot;text-align: center;\u0026quot;\u0026gt; 文本 \u0026lt;/div\u0026gt;或\u0026lt;center\u0026gt; 文本 \u0026lt;/center\u0026gt;\n左对齐：默认\n右对齐：\u0026lt;div style=\u0026quot;text-align: right;\u0026quot;\u0026gt; 文本 \u0026lt;/div\u0026gt;\n引用 引用元素表示从另一个来源引用的内容，可以选择引用必须在footer或cite元素内，也可以选择内联更改，如注释和缩写。\n不含注解的引用 Tiam, ad mint andaepu dandae nostion secatur sequo quae. Note that you can use Markdown syntax within a blockquote.\n包含注解的引用 不积跬步，无以至千里；不积小流，无以成江海。\n——— 荀子1\n表格 表格不是Markdown语法的核心功能，但是Hugo同样为其提供了支持。\n姓名 年级 专业 张三 2024级 计算机科学与技术 李四 2023级 软件工程 行内列表 斜体 加粗 代码 italics bold code A B C D E F Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ultricies, sapien non euismod aliquam, dui ligula tincidunt odio, at accumsan nulla sapien eget ex. Proin eleifend dictum ipsum, non euismod ipsum pulvinar et. Vivamus sollicitudin, quam in pulvinar aliquam, metus elit pretium purus Proin sit amet velit nec enim imperdiet vehicula. Ut bibendum vestibulum quam, eu egestas turpis gravida nec Sed scelerisque nec turpis vel viverra. Vivamus vitae pretium sapien 代码块 使用三个竖撇号包裹 1\u0026lt;!doctype html\u0026gt; 2\u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; 3\u0026lt;head\u0026gt; 4 \u0026lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; 5 \u0026lt;title\u0026gt;Example HTML5 Document\u0026lt;/title\u0026gt; 6\u0026lt;/head\u0026gt; 7\u0026lt;body\u0026gt; 8 \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt; 9\u0026lt;/body\u0026gt; 10\u0026lt;/html\u0026gt; 使用Tab缩进表示 \u0026lt;!doctype html\u0026gt; \u0026lt;html lang=\u0026quot;en\u0026quot;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026quot;utf-8\u0026quot;\u0026gt; \u0026lt;title\u0026gt;Example HTML5 Document\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; 自动代码高亮 1\u0026lt;!doctype html\u0026gt; 2\u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; 3\u0026lt;head\u0026gt; 4 \u0026lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; 5 \u0026lt;title\u0026gt;Example HTML5 Document\u0026lt;/title\u0026gt; 6\u0026lt;/head\u0026gt; 7\u0026lt;body\u0026gt; 8 \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt; 9\u0026lt;/body\u0026gt; 10\u0026lt;/html\u0026gt; 代码比较 1[dependencies.bevy] 2git = \u0026#34;https://github.com/bevyengine/bevy\u0026#34; 3rev = \u0026#34;11f52b8c72fc3a568e8bb4a4cd1f3eb025ac2e13\u0026#34; 4- features = [\u0026#34;dynamic\u0026#34;] 5+ features = [\u0026#34;jpeg\u0026#34;, \u0026#34;dynamic\u0026#34;] 列举类 有序列举 11. 项目一 22. 项目二 33. 项目三 效果：\n项目一 项目二 项目三 无序列举 1* 项目 2* 另一个项目 3* 再一个项目 效果：\n项目 另一个项目 再一个项目 嵌套列举 1* Fruit 2 * Apple 3 * Orange 4 * Banana 5* Dairy 6 * Milk 7 * Cheese 效果：\nFruit Apple Orange Banana Dairy Milk Cheese 在Markdown中使用Tex 在Markdown文件中，Tex文本须使用$…$（行内文本）或$$…$$（行间文本）包裹.\n注意：若要在行内文本中显示行间文本的样式，须加上\\displaystyle.\n数学符号 符号 语法 示例 空格 a\\ b $a\\ b$ 小于 a \u0026lt; b 空格不能少 $a \u0026lt; b$ 大于 a \u0026lt; b 空格不能少 $a \u0026gt; b$ 小于等于 \\leqslant $a \\leqslant b$ 大于等于 \\geqslant $a \\geqslant b$ 点乘 \\cdot $A \\cdot B$ 叉乘 \\times $ A \\times B $ 正负号 \\pm $ \\pm a $ 角 \\angle $\\angle ABC $ 三角形 \\triangle $\\triangle ABC $ 向量 \\overrightarrow{} $\\overrightarrow{AB}$ 推出 \\Rightarrow $A \\Rightarrow B$ 等价于 \\Leftrightarrow $ A \\Leftrightarrow B $ 粗体 \\boldsymbol{} $\\boldsymbol{a}$ 正体 \\mathrm{} $\\mathrm{d}x$ 字母 LaTeX 命令 字母 LaTeX 命令 字母 LaTeX 命令 字母 LaTeX 命令 α \\alpha ν \\nu Α \\Alpha Ν \\Nu β \\beta ξ \\xi Β \\Beta Ξ \\Xi γ \\gamma ο \\omicron Γ \\Gamma Ο \\Omicron δ \\delta π \\pi Δ \\Delta Π \\Pi ε \\epsilon ρ \\rho Ε \\Epsilon Ρ \\Rho ζ \\zeta σ \\sigma Ζ \\Zeta Σ \\Sigma η \\eta τ \\tau Η \\Eta Τ \\Tau θ \\theta υ \\upsilon Θ \\Theta Υ \\Upsilon ι \\iota φ \\phi Ι \\Iota Φ \\Phi κ \\kappa χ \\chi Κ \\Kappa Χ \\Chi λ \\lambda ψ \\psi Λ \\Lambda Ψ \\Psi μ \\mu ω \\omega Μ \\Mu Ω \\Omega 公式 语法 示例 分式 \\frac{a}{b} $\\displaystyle \\frac{a}{b}$ 幂 a^{m} $ a^{m} $ 根式 \\sqrt{2} $\\sqrt{2}$ 高次根式 \\sqrt[n]{m} $\\sqrt[n]{m}$ 下标 a_{n} $ a_{n} $ 方程组 \\left\\{ \\begin{array}{c} \\end{array} \\right. $$\\left\\{ \\begin{array}{c} F(x,y,u,v) = 0 \\\\ G(x,y,u,v) = 0 \\end{array} \\right.$$ 导数与微分 公式 语法 示例 极限 \\lim_{x \\to 0} $\\displaystyle \\lim_{x \\to 0}$ 二重极限 \\lim_{\\substack{\\Delta x \\to 0 \\\\ \\Delta y \\to 0}} $$\\lim_{\\substack{\\Delta x \\to 0 \\\\ \\Delta y \\to 0}} f(x,y)$$ 导数 f \\'(x) $ f'(x) $ \\frac{\\mathrm{d}y}{\\mathrm{d}x} $\\displaystyle \\frac{\\mathrm{d}y}{\\mathrm{d}x} $ f^{(n)}(x) $f^{(n)}(x)$ 偏导 \\partial $\\displaystyle \\frac{\\partial z}{\\partial x}$ 求和与积分 公式 语法 示例 求和 \\sum_{i=0}^{n} $\\displaystyle \\sum_{i=0}^{n} a_i$ 求积 \\prod_{i=0}^{n} $\\displaystyle \\prod_{i=0}^{n} a_i $ 积分 \\int_{a}^{b} $\\displaystyle \\int_{a}^{b} f(x) \\mathrm{d}x$ \\iint\\limits_D $\\displaystyle \\iint\\limits_D f(x,y) \\mathrm{d}x \\mathrm{d}y$ \\oint_{L} $\\displaystyle \\oint_{L} f(x,y,z) \\mathrm{d}l$ \\oiint\\limits_{\\varSigma} $\\displaystyle \\oiint\\limits_{\\varSigma} f(x,y,z) \\mathrm{d}S$ 行列式与矩阵 矩阵：\n1\\left[ 2\\begin{matrix} 3a \u0026amp; a+b \\\\ # \u0026#39;\u0026amp;\u0026#39;是占位符，\u0026#39;\\\\\u0026#39;是换行符 4c+d \u0026amp; d \\\\ 5\\end{matrix} 6\\right] 效果：\n$$\\left[\\begin{matrix} a \u0026 a+b \\\\ c+d \u0026 d \\\\ \\end{matrix} \\right]$$在等号处对齐 使用{align*}环境，在每一行公式后加上\\\\；在要对齐的等号前加上\u0026amp;。\n1$$ 2\\begin{align*} 3x_1+x_2 \u0026amp;= \\frac{-b+\\sqrt{b^{2}-4ac}}{2a} + \\frac{-b-\\sqrt{b^{2}-4ac}}{2a} \\\\ \u0026amp;= -\\frac{b}{a} 4\\end{align*} 5$$ 效果：\n$$ \\begin{align*} x_1+x_2 \u0026= \\frac{-b+\\sqrt{b^{2}-4ac}}{2a} + \\frac{-b-\\sqrt{b^{2}-4ac}}{2a} \\\\ \u0026= -\\frac{b}{a} \\end{align*}$$其他 隐藏内容 1\u0026lt;details\u0026gt; 2 \u0026lt;summary\u0026gt;点击展开隐藏内容\u0026lt;/summary\u0026gt; 3 4隐藏内容 5\u0026lt;/details\u0026gt; 效果：\n点击展开隐藏内容 隐藏内容\n参考资料 1[图片文件](网址) → 荀子，中国古代哲学家。\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2019-03-11T00:00:00Z","image":"https://rd806.github.io/passage/guide/markdown/pawel-czerwinski-8uZPynIu-rQ-unsplash_hu_e95a4276bf860a84.jpg","permalink":"https://rd806.github.io/passage/guide/markdown/","title":"Markdown语法"},{"content":"Hugo项目中的数学符号可以通过使用第三方JavaScript库来启用。\n这个例子中将会使用 KaTeX 如何使用 在 /layouts/partials/math.html 下创建文件。 使用在线JS库： Auto-render Extension 或在本地创建。 在文件中使用以下字段: 1{{ if or .Params.math .Site.Params.math }} 2{{ partial \u0026#34;math.html\u0026#34; . }} 3{{ end }} 若要在全局文件中使用KaTex，请在配置文件中将 math 设为 true . 若只在单个文件中使用KaTex，请在文件开头设置 math: true . Note: 查询在线帮助： Supported TeX Functions 1{{\u0026lt; math.inline \u0026gt;}} 2{{ if or .Page.Params.math .Site.Params.math }} 3\u0026lt;!-- KaTeX --\u0026gt; 4\u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css\u0026#34; integrity=\u0026#34;sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV\u0026#34; crossorigin=\u0026#34;anonymous\u0026#34;\u0026gt; 5\u0026lt;script defer src=\u0026#34;https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js\u0026#34; integrity=\u0026#34;sha384-XjKyOOlGwcjNTAIQHIpgOno0Hl1YQqzUOEleOLALmuqehneUG+vnGctmUb0ZY0l8\u0026#34; crossorigin=\u0026#34;anonymous\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; 6\u0026lt;script defer src=\u0026#34;https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js\u0026#34; integrity=\u0026#34;sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05\u0026#34; crossorigin=\u0026#34;anonymous\u0026#34; onload=\u0026#34;renderMathInElement(document.body);\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; 7{{ end }} 8{{\u0026lt;/ math.inline \u0026gt;}} 举例 行内公式: $\\varphi = \\dfrac{1+\\sqrt5}{2}= 1.6180339887…$\n行间公式: $$ \\varphi = 1+\\frac{1} {1+\\frac{1} {1+\\frac{1} {1+\\cdots} } } $$","date":"2019-03-08T00:00:00Z","permalink":"https://rd806.github.io/passage/math/typesetting/","title":"数学公式输入"},{"content":"Hugo 构建的网页中，有多种方式使用表情。\nThe emojify function can be called directly in templates or Inline Shortcodes .\nTo enable emoji globally, set enableEmoji to true in your site\u0026rsquo;s configuration and then you can type emoji shorthand codes directly in content files; e.g.\n🙈 :see_no_evil: 🙉 :hear_no_evil: 🙊 :speak_no_evil:\nThe Emoji cheat sheet is a useful reference for emoji shorthand codes.\nN.B. The above steps enable Unicode Standard emoji characters and sequences in Hugo, however the rendering of these glyphs depends on the browser and the platform. To style the emoji you can either use a third party emoji font or a font stack; e.g.\n1.emoji { 2 font-family: Apple Color Emoji, Segoe UI Emoji, NotoColorEmoji, Segoe UI Symbol, Android Emoji, EmojiSymbols; 3} I :heart: Hugo!\n","date":"2019-03-05T00:00:00Z","image":"https://rd806.github.io/passage/website/emoji/the-creative-exchange-d2zvqp3fpro-unsplash_hu_27b8954607cdb515.jpg","permalink":"https://rd806.github.io/passage/website/emoji/","title":"Emoji Support"}]