try ai
科普
编辑
分享
反馈
  • 伪随机数的悖论:用秩序模拟混沌

伪随机数的悖论:用秩序模拟混沌

SciencePedia玻尔百科
关键要点
  • 伪随机数由确定性算法生成,其中“种子”决定了整个可复现的序列。
  • 高质量的生成器至关重要,其定义包括长周期、均匀分布以及无高维相关性。
  • 有缺陷的伪随机性会破坏科学模拟、损害密码学安全并使金融模型失效。
  • 现代并行计算需要如块分割或基于计数器的生成器等复杂技术,以确保随机流的独立性。

引言

一台建立在逻辑和可预测性之上的机器,如何能产生像随机性这样混乱和不羁的东西?这个问题位于现代计算的核心,将我们带入​​伪随机数​​的悖论世界。这些数字并非真正的随机,而是确定性算法的产物——一种“虚假的”随机性,但矛盾的是,它支撑着从科学发现到数字安全的方方面面。本文的核心挑战和焦点,是理解是什么让这种对机遇的模仿“足够好”,以及当它不够好时会带来怎样的灾难性后果。接下来的章节将首先深入探讨伪随机数生成的​​原理与机制​​,探索如何定义一个高质量的生成器、如何测试它们,以及在并行系统中使用它们的复杂性。随后,我们将遍览其多样化的​​应用与跨学科联系​​,揭示这些确定性序列如何充当科学家的骰子、工程师的蓝图和密码学家的盾牌,并阐明为何这种“对机遇的模仿”的质量是至关重要的。

原理与机制

美丽的矛盾:确定性随机性

一台作为逻辑和可预测性典范的计算机,如何能产生像随机性这样狂野和不羁的东西?如果你让计算机给你一个“随机”数,它不会去参考蝴蝶翅膀的混沌扇动或电子的量子抖动。它运行的是一个算法。而算法的本质就是一个配方——一套固定的指令,给定相同的起点,总会产生相同的结果。

这就把我们带到了我们主题核心的美丽矛盾:​​伪随机数​​。“伪”(pseudo)意为“假的”,这是对这种确定性事实的谦逊承认。让我们看看这在实践中意味着什么。

想象一下,两名学生 Chloe 和 David,在完全相同的计算机上运行完全相同的科学模拟。他们在模拟液体中分子的行为,这个过程依赖于无数次的“随机”抖动和移动。当他们比较结果时,发现了一些奇怪的事情:他们最终计算出的能量不同。然而,每当 Chloe 重新运行她的模拟时,她都会得到完全相同的数字,精确到最后一位小数。David 的情况也是如此。他们各自的结果都是完全可复现的,但彼此之间却不一致。

这是怎么回事?是不是有什么幽灵般的变量潜入了机器?完全不是。答案在于算法的起始点,一个我们称之为​​种子​​的数字。伪随机数生成器(PRNG)就像一台极其复杂的机器,它接受一个数字(种子),然后确定性地生成一长串复杂的其他数字。改变种子,你会得到一个完全不同的序列。使用相同的种子,你每次都会得到完全相同的序列。Chloe 和 David 纯属偶然地使用了不同的种子启动他们的程序,这些种子很可能是由他们点击“运行”那一刻的系统时钟值提供的。

事实上,这种确定性是一个特性,而非一个缺陷。对于模拟复杂系统(如新药与蛋白质的相互作用或新的金融模型)的科学家来说,可复现性至关重要。如果发现了一个错误或需要验证一个结果,必须能够复现导致该结果的精确“随机”序列。因此,关键就在于简单地记录下种子。

所以,PRNG 是一种确定性的、离散状态的机器。从理论角度看,它像时钟一样可预测。然而,在实际应用中,当我们不知道种子时,它的输出看起来就像一个随机过程——一次真正的随机抽取。我们利用这种确定性的混沌,这种可预测的不可预测性,来为我们的模拟提供动力。

怎样才算好的“伪装”?高质量的标志

如果所有的 PRNG 都只是确定性序列,那么它们都是生而平等的吗?绝对不是。创建一个能够良好伪装成真正随机的序列是一门深刻而微妙的艺术。一个劣质的 PRNG 能够——而且已经——导致了极其错误的科学结论。一个高质量的生成器必须具备几个关键属性。

1. 庞大的“记忆”:周期

由于 PRNG 在一个有限的内部状态集上运行,它最终必然会自我重复。一旦某个状态被重复,生成器就陷入了一个循环,其输出的数字序列将永远重复下去。这个重复周期的长度被称为​​周期​​。

为了使模拟有效,其所需的随机数数量(假设为 NNN)必须远小于生成器的周期 PPP。如果 PPP 太短,模拟将无意中开始重复使用相同的“随机”数。想象一个蛋白质折叠的模拟。如果 PRNG 重复,蛋白质可能会被锁定在一系列重复的移动中,从而无法探索其他可能的形状。这破坏了正确采样所需的一个基本属性,即​​遍历性​​(ergodicity)——系统在足够长的时间内能够遍历其所有可能构型的能力。

一个鲜明的例子揭示了这种危险。考虑一个简单的模拟,其中一个粒子可以根据 PRNG 的输出向左、右移动或保持不动。一个设计良好的模拟应该允许该粒子最终访问所有可能的位置。但如果我们使用一个有缺陷的、周期仅为二的 PRNG,它可能会生成一个序列,永远只告诉粒子“向左移动”然后“向右移动”。粒子将被困住,永远在两个位置之间振荡,永远无法访问其他可用的状态。模拟的结果将是无稽之谈,只报告了现实中一个微小且不具代表性的片段。这就是为什么现代 PRNG 都被设计成具有天文数字般巨大的周期,例如 Mersenne Twister 的周期为 219937−12^{19937}-1219937−1,这是一个超过 6000 位的数字。

2. 填满画布:均匀性

PRNG 产生的数字应该在其可能的范围内均匀分布。如果我们在 0 和 1 之间生成数字,我们期望在 0.1 和 0.2 之间看到的数字数量与在 0.8 和 0.9 之间看到的数量大致相同。这个属性被称为​​均等分布​​(equidistribution)或均匀性。

缺乏均匀性会引入微妙但严重的偏差。在许多物理模拟中,如 Metropolis 算法,随机数被用来决定是否接受一个系统状态的提议变化。“上坡”移动——即那些增加系统能量的移动——以一定的概率被接受,该概率计算为 exp⁡(−βΔE)\exp(-\beta \Delta E)exp(−βΔE)。为了实现这一点,我们从 PRNG 中抽取一个随机数 uuu,如果 uexp⁡(−βΔE)u \exp(-\beta \Delta E)uexp(−βΔE),则接受该移动。如果我们的 PRNG 存在偏差,产生了过多的小数,我们接受这些能量上不利的移动的频率就会高于应有的水平。这将导致我们的模拟错误地偏爱高能量状态,从而得到一幅关于系统平衡行为的完全错误的图像。这个本应是随机的过程被系统性偏差所污染。

3. 晶格的诅咒:高维均匀性

这可能是 PRNG 最深刻、最隐蔽的失效模式。一个数字序列在一维上可能看起来完全均匀,但当你观察连续的数对、三元组或 k-元组时,一个惊人的结构可能会浮现出来。

想象一下将这些数字绘制在一条线上——它们可能看起来分布均匀。现在,将连续的数对 (Un,Un+1)(U_n, U_{n+1})(Un​,Un+1​) 作为点绘制在一个正方形中。一个好的生成器会用均匀的点云填满这个正方形。而一个坏的生成器可能会产生全部落在少数几条直线上的点。在三维空间中,绘制三元组 (Un,Un+1,Un+2)(U_n, U_{n+1}, U_{n+2})(Un​,Un+1​,Un+2​),这些点可能被限制在一组平行平面上,形成一种类似晶体的​​晶格结构​​。

这不是一个假设性的恐惧。这是最简单、最常见的生成器家族之一——线性同余生成器(LCGs)——的一个已被证明的数学特性。著名(且臭名昭著)的 RANDU 生成器,在科学计算中被使用了几十年,后来被发现在三维空间中存在灾难性的相关性。它的所有三元组都落在了单位立方体中的仅仅 15 个平行平面上。任何依赖三维随机性并使用 RANDU 的模拟,其产生的结果都来自一个随机点只能存在于这少数几个平面上的宇宙——这是一个巨大而隐藏的缺陷。

因此,拥有良好的​​k维均等分布​​至关重要。我们模拟的有效性取决于连续的随机数是独立的,而不是被一种看不见的几何结构秘密地捆绑在一起。

公正的法官:随机性测试

我们如何确信一个 PRNG 具备这些理想的属性?我们将其送上“审判席”。一整套统计测试,如名为“Diehard”和“TestU01”的测试包,已经被开发出来,用以探查任何与理想随机性的偏差。

基本思想很简单。我们构建一个零假设——例如,“此 PRNG 生成的每个数的最后一位数字在 0 到 9 之间均匀分布”。然后,我们生成数百万个数字,并统计每个数字出现的次数。​​卡方检验​​(chi-square test)为我们提供了一种方法,来衡量我们观察到的计数与期望计数(在我们的假设下,所有数字的期望计数应相等)之间的偏差。这个偏差是一个单一的数值,即检验统计量。。

根据这个统计量,我们计算出一个 ​​p值​​(p-value),它表示在零假设为真的情况下,纯粹由于偶然性而观察到至少这么大偏差的概率。按照惯例,一个非常小的 p值(例如,小于 0.05)被视为反对该假设的有力证据,表明生成器未能通过测试。

这引出了一个非常微妙的观点。如果我们在一个真正完美的生成器上运行许多不同的测试,p值的分布应该是什么样的?一个天真的猜测可能是所有的 p值都应该很高,接近 1,表示“强势通过”。这是错误的。统计学的一个基本结果表明,如果零假设为真,那么 p值本身必须在 0 和 1 之间均匀分布。这意味着我们应该预期,纯粹出于偶然,大约 5% 的测试会有小于 0.05 的 p值,10% 的测试会有小于 0.1 的 p值!一个产生过多高 p值的生成器与一个产生过多低 p值的生成器同样可疑;这表明生成器“过于完美”,而这是另一种形式的非随机性。

并行中的随机性:一个现代前沿

现代科学是一项大规模并行的事业。超级计算机将问题同时分配给数千个处理器。这就产生了一个新的挑战:我们如何为每个并行工作单元提供高质量、独立的随机数流?如果做错了,可能会使一项耗资数百万美元的计算完全无效。

天真的方法充满了危险:

  • ​​一个生成器,无锁:​​让所有线程在没有任何协调的情况下访问单个 PRNG 会导致混乱。线程会相互覆盖对生成器内部状态的更新,这是一种“数据竞争”,会彻底破坏输出序列。
  • ​​一个生成器,有锁:​​用锁保护单个生成器可以确保正确性——输出与串行运行相同。但这会造成巨大的瓶颈。每个线程都必须排队等待获取其随机数,这违背了并行的初衷。
  • ​​相邻种子:​​一个常见的错误是给每个线程自己的 PRNG 实例,并使用彼此接近的种子(例如,工作单元 1 使用种子 1,工作单元 2 使用种子 2,等等)。对于许多 PRNG 家族,特别是 LCGs,从相邻种子开始的流是高度相关的。你没有创造出独立的助手;你创造了一群“阴谋家”,他们的“随机”选择被秘密地联系在一起。

幸运的是,存在有原则的解决方案。关键是确保给予不同工作单元的流是可验证地独立的。两种强大的策略在现代实践中占主导地位:

  1. ​​块分割(Block-Splitting)与蛙跳法(Leapfrogging):​​其思想是获取一个极长的高质量流并将其分区。在块分割中,我们从主数据流中为每个工作单元提供一个大的、连续的数字块。在蛙跳法中,工作单元 iii 从流中获取第 iii 个、第 (i+P)(i+P)(i+P) 个、第 (i+2P)(i+2P)(i+2P) 个等数字。只要底层的 PRNG 具有高效的“向前跳跃”功能,可以快速跳转到任何给定块或子序列的起点,这两种方法都非常有效。

  2. ​​基于计数器的生成器(Counter-Based Generators):​​这是一种更为优雅的现代设计,以像 Random123 这样的库为代表。这些生成器不像 PRNG 那样被看作一个演变的状态(sn+1=T(sn)s_{n+1} = T(s_n)sn+1​=T(sn​)),而是像一个数学函数一样工作:output = f(key, counter)。“密钥”(key)就像一个主种子,定义了整个数字家族,而“计数器”(counter)只是你想要的数字的索引(第1个,第2个,第10亿个等)。函数 fff 是一个极其复杂的“混合”函数,其设计旨在表现得像一个随机排列。并行化变得轻而易举:要么给每个工作单元一个不同的密钥,要么给它们都使用相同的密钥,但为每个工作单元分配一个唯一的、不重叠的计数器值范围。没有需要管理的状态,也没有流重叠的风险。

从简单的线性递推到这些复杂的基于计数器的设计的历程,证明了数学家和计算机科学家的独创性。这一历程是由对更多、更好、更快“随机性”的不懈需求所驱动的——这种本质而又矛盾的成分,使确定性的计算世界成为探索我们所居住的复杂、随机宇宙的强大工具。

应用与跨学科联系

我们已经花了一些时间拆解这些“伪随机”数生成器的内部构造,观察它们的齿轮和弹簧。我们窥探了它们确定性的核心,看到了一个简单的数学规则如何能纺出一串在所有意图和目的上都看似随机的数字序列。但是,一台机器的趣味性取决于它能完成的工作。一个公式在一无所成之前只是一串符号。那么,这些数字去向何方?它们是何等宏伟设计的一部分?

令人惊讶的答案是,它们几乎无处不在。它们是我们数字世界中看不见的建筑师。它们是我们模拟中的幽灵,是数字诸神的骰子,是我们一些最强大的计算工具中的秘密成分。从核反应堆的设计到区块链的安全,从金融崩溃的预测到人工智能的训练,处处都有它们的指纹。

本章是一次穿越这些应用的旅程。我们将看到,这种对机遇的模仿的质量并非学术上的小事。一个好的生成器和一个坏的生成器之间的差别,可能就是一次科学突破和一次巨大失误、一个安全系统和一扇敞开大门之间的差别。

科学家的骰子:模拟与建模

伪随机数最深远的应用或许是在模拟艺术中——通常被称为蒙特卡罗方法。其思想非常简单:如果一个系统过于复杂以至于无法直接计算,我们可以通过反复玩一个机会游戏来感受它的行为。我们让伪随机数生成器为我们掷骰子,通过观察许多次游戏的结果,我们可以推断出庄家的规则。

想象一下试图理解一个盒子里的气体行为。数以万亿计的分子在其中呼啸穿梭,相互碰撞,并与盒壁碰撞,进行着一场混乱、不可预测的舞蹈。追踪每一个分子是一项不可能完成的任务。但我们并不需要这么做。我们可以在计算机中创建一个虚拟盒子,并使用 PRNG 来模拟一些代表性分子的随机踢动和翻滚。通过对许多此类模拟进行平均,我们可以准确地预测真实气体的压力、温度和其他属性。

这个思想正是一些科学和工程领域最关键模拟的核心。考虑为核反应堆设计屏蔽层的挑战。屏蔽层必须阻挡大量高能中子。每个中子穿过屏蔽材料的旅程都是一次随机的漫游。它行进一段随机的距离,然后与一个原子碰撞。在碰撞中,它可能被吸收,也可能向一个新的随机方向散射。我们怎么可能知道屏蔽层是否足够厚?我们通过模拟来解决。

一个计算机程序追踪一个虚拟中子。它从一端开始。第一个问题是:“在撞到东西之前它能走多远?”物理学告诉我们,路径长度 sss 服从指数分布,我们可以使用来自 PRNG 的一个均匀随机数 u1u_1u1​ 来采样:s=−ln⁡(u1)/Σts = -\ln(u_1) / \Sigma_ts=−ln(u1​)/Σt​,其中 Σt\Sigma_tΣt​ 是材料的一个属性。移动中子后,下一个问题是:“碰撞时发生了什么?”它以一定的概率 pap_apa​ 被吸收,或者散射。我们向 PRNG 请求另一个数字 u2u_2u2​。如果 u2pau_2 p_au2​pa​,中子的故事就结束了。如果不是,它就散射,我们使用第三个数字 u3u_3u3​ 来选择一个新的随机方向。然后这个过程重复进行。在模拟了数百万个这样的中子历史之后,最终穿过的中子比例给了我们一个关于屏蔽层泄漏率的精确估计。

但正是在这里,一个深刻而美妙的微妙之处出现了。如果我们的 PRNG 有一个看似无害的缺陷会怎么样?假设它是一个“懒惰的”生成器,有时会连续两次给我们相同的数字:u2=u1u_2 = u_1u2​=u1​。现在,路径长度的随机性和相互作用类型的随机性不再独立。一个小的 u1u_1u1​ 值意味着一个长的飞行路径,但它也意味着条件 u2pau_2 p_au2​pa​ 更可能为真(假设 pap_apa​ 不小)。于是,我们的模拟创造了一种人为的、非物理的相关性:行进得远的中子现在更有可能被吸收!模拟从根本上被破坏了,不是因为我们物理代码中的错误,而是因为我们“对机遇的模仿”中的缺陷。这强调了一个关键点:我们的模拟的好坏取决于我们喂给它的随机性。我们不仅要生成具有正确分布的数字,还必须确保它们没有被隐藏相关性的微妙网络所束缚。

当然,并非所有模拟都如此戏剧性。一个更常见的任务是为现实世界中固有的混乱建模。当天文学家测量恒星的亮度或生物学家测量细胞培养物的生长时,总会有一些随机的测量误差。我们可以用 PRNG 来模拟这种“噪声”。通常,这种噪声遵循钟形曲线,即正态分布。我们可以使用像 Box-Muller 变换这样优雅的数学技巧,从均匀分布的 PRNG 输出中创建正态分布的数字,这种变换能将一对均匀数转换为一对独立的标准正态数。

通过将这种模拟噪声添加到完美的理论模型中,我们可以进行数千次“虚拟实验”。我们可以测试我们的数据分析方法,看它们是否能穿透噪声并恢复真实的信号。考虑到望远镜测量中的抖动,我们对行星轨道的估计有多准确?通过运行蒙特卡罗模拟,我们可以找出答案中的预期误差。这就是现代科学如何建立对其结论的信心的方式,即通过使用伪随机性来应对宇宙本身的随机性。

偶然性工程:从裂缝到人群

如果说科学使用 PRNG 来理解世界,那么工程学则用它们来建造世界。随机性不仅仅是要克服的障碍;它是一个需要理解的特性和可以运用的工具。

想象一下一块陶瓷板的破裂。裂缝并非沿完美的直线扩展。它蜿蜒曲折,沿着材料中微观的薄弱点前进。我们可以在计算机上模拟这个过程。我们可以说,裂纹尖端试图沿着应力方向前进,但在每一步,它都会受到一个小的随机侧向“抖动”。这个抖动由我们的 PRNG 提供。如果生成器是好的,抖动就是对称的,裂纹路径的统计数据将与现实相符。但如果生成器有偏见——比如,它偏爱较小的数字——抖动就会不对称。裂缝将以一种不反映真实物理情况的方式系统性地漂移。我们的模拟可能会预测一个组件比它实际更强或更弱,这是一个源于 PRNG 微妙偏见的危险错误。

工程师使用的“材料”并不总是物理的。考虑一下复杂且相互关联的金融世界。银行的稳定性取决于其储户的集体行为。是什么引发了银行挤兑?这可以看作是由个人焦虑和社会恐慌共同影响下的一系列决策的连锁反应。我们可以建立一个“基于主体的模型”(agent-based model),其中我们成千上万的虚拟储户中的每一个都被分配一个“恐慌倾向”——一个来自 PRNG 的随机数。模型中编程了一个反馈循环:随着越来越多的人取款,普遍的恐惧水平上升,使得即使是不那么恐慌的储户也更可能冲向出口。

银行会倒闭吗?通过用不同的随机数运行这个模拟数千次,我们可以估计灾难性连锁反应发生的概率。这是评估系统性风险不可或缺的工具。但同样,随机性的质量至关重要。早期在经济学和其他领域的计算机模拟经常使用像 RANDU 这样有缺陷的生成器,它因其在三维空间中产生的数字落在有限数量的平面上而臭名昭著。使用这样的生成器来模拟一个复杂的社会系统,可能会产生人为的羊群行为,或者相反,抑制它们,从而导致关于经济稳定性的根本性错误结论。

数字幽灵:信息、安全与智能

在纯粹数字化的信息领域,伪随机性扮演着一个全新且至关重要的角色。在这里,它最宝贵的特性是不可预测性。

这是现代密码学的基石。你如何发送一条秘密消息?一种经典技术,称为一次性密码本(one-time pad),是将你的消息转换成一个比特序列 MMM,然后将其与一个等长的、秘密的、随机的比特密钥流 RRR 相结合。这种结合是通过一种称为异或(XOR,记为 ⊕\oplus⊕)的操作完成的。传输的密文是 C=M⊕RC = M \oplus RC=M⊕R。要解密,拥有相同密钥 RRR 的接收者只需计算 C⊕R=(M⊕R)⊕R=MC \oplus R = (M \oplus R) \oplus R = MC⊕R=(M⊕R)⊕R=M。如果密钥流 RRR 是真正随机且保密的,那么密文 CCC 也是完全随机的,该系统就是不可破解的。

但是这个长的随机密钥流从何而来?在实践中,它通常由 PRNG 生成。而危险就潜藏于此。考虑隐写术(steganography),这是一种将消息隐藏在显而易见之处的艺术——例如,隐藏在图像像素或音频文件样本的最低有效位(LSBs)中。其思想是用你加密消息的比特替换掉这些“嘈杂的”LSB。如果做得对,这种改变是难以察觉的。

但假设你使用了一个臭名昭著的劣质 LCG,其生成器状态的 LSB 只是简单地交替出现:0, 1, 0, 1, 0, 1, ... 你的“随机”密钥流现在变成了可以想象到的最可预测的模式!一个分析你文件 LSB 的分析师看到的将不是随机噪声,而是一个完美结构化的信号。一个简单的自相关统计检验就会大声警告说有问题。你的秘密被揭露,不是因为敌人破解了你的密码,而是因为你的“随机性”是一个昭然若揭的赝品。

同样的不可预测性原则对于分析像区块链这样的现代系统的安全性也至关重要。“双花”攻击可以被建模为攻击者与诚实网络之间的一场竞赛。在每一步,一方或另一方会找到一个“区块”,就像一次有偏的抛硬币。我们可以使用由 PRNG 驱动的蒙特卡罗模拟,来估计攻击者在各种条件下赢得这场竞赛的概率。这使我们能够量化系统的安全性,并确定安全的参数,例如商家在接受一笔交易前应该等待多少个“确认”。

最后,旅程将我们带到人工智能的前沿。许多学习算法都融入了随机性以提高其性能。随机性帮助它们探索新的可能性,并避免陷入糟糕的解决方案。考虑一个试图学习简单模式的单个“随机神经元”(stochastic neuron)。它的激活是概率性的:它接收一个输入,计算一个激活概率,然后使用一个随机数来决定是否激活。

现在,想象我们使用那个有缺陷的、LSB交替的 LCG 来做这个激活决定。再想象我们巧妙地构建训练过程,连续两次向神经元呈现相同的输入。在第一次呈现时,PRNG 提供了一个 0,而在第二次时,它提供了一个 1。神经元实际上被告知了相互矛盾的信息:对于完全相同的输入,它先被告知正确的输出是 1,紧接着又被告知正确的输出是 0。通过根据错误调整其参数来工作的学习算法,会完全陷入困惑。相互冲突的信号可能会相互抵消,导致神经元无法学习。这就像试图教一个孩子,而他听的老师却在不断地自相矛盾。随机性的质量是学习环境的一个基本属性。一个坏掉的 PRNG 会创造一个破碎的世界,而从一个破碎的世界中,不可能涌现出真正的智能。

结论

我们的巡礼至此结束。我们已经看到,伪随机数并非一个枯燥的数学奇珍,而是一股充满活力、至关重要的力量,它促成了现代科学技术的诸多成就。我们在反应堆的核心,在钢板的断裂处,在人群的恐慌中,以及在机器初生的心智中,都发现了它们的身影。

我们还学到了一个关键且反复出现的教训:“伪”字至关重要。创造这些数字的艺术是一场高风险的游戏。一个微妙的缺陷、一个隐藏的相关性、一个轻微的偏差,都可能在一个复杂的模拟或安全协议中级联放大,带来毁灭性的后果。对更好、更快的 PRNG 的不懈追求并非仅仅是完美主义;它是进步的先决条件。

这其中有某种诗意。我们,作为确定性的存在,编写确定性的配方——算法——来创造一种对宇宙最神秘、最基本方面之一——机遇——的近乎完美的模仿。通过用秩序来模拟混沌,我们为自己找到了一把强大的钥匙,用以解开世界的秘密,并在其中创造奇迹。