跳转到内容

用 Python 验证

  • 跟踪一个公式从 SymPy 推导到页面、再到测试的全过程。
  • 用相对差(relative difference)比较两个计算结果,并选择一个容差(tolerance),使舍入不会导致失败,而真正的错误无法通过。
  • 在自己的计算机上运行本站的检查。

本站的每个公式都只在 packages/pe-core/equations/equations.yaml 中出现一次,以 SymPy 表达式的形式存放,并附有其符号、测试和引用。Python 包 python/pe_core 以该文件为基础工作:

  • 在可能的情况下,python/pe_core/derive/ 中的脚本从基本原理推导公式,用 SymPy 逐步求解电路的平衡方程(balance equation)。推导页面按代码的计算过程展示这些步骤,pytest 则检查每个结果是否等于公式目录中的表达式。
  • python scripts/gen_equations.py 生成页面上显示的 LaTeX 和测试向量(test vector),测试向量包括每个公式自身的测试,以及由 SymPy 计算的随机输入。CI 会重新运行它,只要有任何差异就失败。

页面和工具背后的 TypeScript 引擎有自己的求值函数,它们是手工编写的,而不是从同一文件生成的,这样一方的错误就不会被复制到另一方。vitest 用测试向量检查每个求值函数。

两个计算结果用它们的相对差来比较:

δ=∣x−xref∣∣xref∣\delta = \frac{\left|{x - x_\mathrm{ref}}\right|}{\left|{x_\mathrm{ref}}\right|}
δ\delta
相对差
xrefx_\mathrm{ref}
参考值
xx
被检验的值
数值相对于参考值的相对差✓ 经 8 项测试验证
假设、约定与出处
假设
  • 定义
备注
物理量按比例缩放(例如单位从伏特换成毫伏)时,相对差不变,因此同一个容差适用于所有物理量(零点会移动的单位是例外,例如摄氏度相对于开尔文);参考值为零时相对差无定义,参考值接近零时,很小的绝对差也会变成很大的相对差。本站对同一公式的 TypeScript 与 Python 计算结果要求 1e-9,对仿真与其公式的比较要求 1 % 或 2 %
出处
Higham 2002, Sec. 1.2 (Relative Error and Significant Digits)
公式 id
num.rel_diff · equations.yaml 条目

物理量按比例缩放时(例如单位从伏特换成毫伏),相对差不变,因此同一个容差适用于所有物理量。参考值为零时相对差无定义 [Higham 2002, Sec. 1.2],参考值接近零时它会夸大很小的差异,因此在那里应与一个尺度比较。两个正确的程序不一定产生逐位相同的结果:每次运算都对其结果舍入,而结果取决于运算的顺序。一次舍入使一个数改变的量,相对于其大小,至多为该格式的单位舍入误差(unit roundoff):

u=β1−p2u = \frac{\beta^{1 - p}}{2}
uu
单位舍入误差(unit roundoff)
β\beta
基数(二进制为 2)
pp
精度(尾数位数)
浮点格式的单位舍入误差✓ 经 8 项测试验证
假设、约定与出处
假设
  • 舍入到该格式中最接近的数,即 IEEE 754 的默认方式
备注
将实数舍入到该格式中最接近的数,所引起的变化至多为其自身的这一比例(在规格化数范围内)。对于 binary64,即 JavaScript 的数值和 Python 的 float 所采用的 IEEE 754 双精度,基数为 2,精度为 53 位,因此 u=2−53≈1.1×10−16u = 2^{-53} \approx 1.1 \times 10^{-16}。Higham 将精度记为 tt
出处
Higham 2002, Ch. 2 (Floating Point Arithmetic: the unit roundoff, Sec. 2.1, and its value in IEEE double precision)
公式 id
num.unit_roundoff · equations.yaml 条目

本站要求同一公式的 TypeScript 计算结果与 Python 计算结果相差在十亿分之一以内。这是单位舍入误差的数百万倍,因此只要计算过程不像相消(cancellation)即几乎相等的两数相减那样放大误差 [Higham 2002, Sec. 1.7],舍入就能通过;同时它又远低于任何真正的错误,例如常数错误或漏掉一个因子。仿真与其公式比较时采用较宽松的容差,因为公式把电路理想化了:它假定纹波很小 [Erickson & Maksimović 2020, Ch. 2],而 SPICE 库中的开关管和二极管只是接近理想。SPICE 库的各个值与理想公式之差必须在 1 % 以内(以各物理量在一个周期内的最大绝对值为基准),浏览器内仿真器的电压变换比和纹波则须在 2 % 以内。

scripts/spice_crosscheck.py 根据电路原理图,而不是仿真器的方程,把浏览器内仿真器的电路重新写成网表,并在 ngspice 中运行 [ngspice – open source SPICE simulator]。CI 将仿真器与 ngspice 的结果比较:每个值之差都不得超过该物理量在一个周期内最大绝对值的 0.5 %,并为 SPICE 元件引入的影响留出少量余量;每个峰峰值摆幅之差须在 2 % 以内。

将仿真所得的电压变换比与理想值比较,并计算 binary64,即 JavaScript 的数值和 Python 的 float 所采用的 IEEE 754 双精度的单位舍入误差:

交叉校验示例
符号数值求法
xx 被检验的值0.496已知
xrefx_\mathrm{ref} 参考值0.5已知
β\beta 基数(二进制为 2)2已知
pp 精度(尾数位数)53已知
δ\delta 相对差0.008数值相对于参考值的相对差
uu 单位舍入误差(unit roundoff)1.11e-16浮点格式的单位舍入误差

该变换比与理想值相差 0.008,在库的 1 % 以内。单位舍入误差为 1.11e-16:十亿分之一的容差可以容纳数百万次舍入。

▶ 在公式浏览器中打开:数值相对于参考值的相对差
预设取自例题 num-parity

扫描被测值:相对差在参考值两侧线性增大,只在参考值本身处为零。

在实验台上用万用表测量变换器的输入电压和输出电压,用 Python 计算两者之比相对于理想值的相对差,并列出可能造成这一差异的因素:二极管压降、开关管和绕组的电阻、纹波。然后改变负载,观察其中哪些因素随电流增大。

  • 参考值接近零时,相对差失去意义;应像库的检查那样,与一个尺度比较,例如该物理量在一个周期内的最大值。
  • 共用代码的两种实现也共有其中的错误。生成的求值函数即使在源文件出错的地方,也会与该文件一致。
  • 浮点数(floating-point)不作相等比较。在 binary64 中,0.1 + 0.1 + 0.1 不等于 0.3:应在容差范围内比较(单位舍入误差)。
  • 工具 SymPy: Solve Equations — the SymPy development team · 访问于 2026-09-25
    SymPy 如何针对某个符号求解方程或方程组;本站的推导脚本就是这样求解平衡方程的。
  • 技术文章 Floating-Point Arithmetic: Issues and Limitations — the Python documentation (the tutorial) · 访问于 2026-09-25
    为什么在计算机中 0.1 + 0.1 + 0.1 不等于 0.3,为什么每次运算都可能引入最多 2**53 分之一的舍入误差,以及为什么比较结果时看其是否在容差之内,而不是看是否相等。
  1. 本站显示的公式来自哪里?

    1. 手工输入到各页面中的 LaTeX
    2. equations.yaml 中的一个条目:附有符号、测试和引用的 SymPy 表达式
    3. TypeScript 引擎
    4. 测验文件
    答案与解析

    正确答案:B 生成器根据该条目生成 LaTeX 和测试向量;若已提交的文件与生成结果不同,CI 就会失败。

  2. 为什么 TypeScript 求值函数是手工编写的,而不是从 equations.yaml 生成的?

    1. 为了使一方的错误不会被复制到另一方:两个独立的实现必须彼此一致
    2. 因为 TypeScript 无法读取 YAML
    3. 为了让页面加载得更快
    4. 因为 SymPy 无法进行数值计算
    答案与解析

    正确答案:A 生成的代码即使在源文件出错的地方也会与之一致;独立的实现则必须凭自身与测试向量一致。

  3. 将仿真得到的电压变换比 0.495 与理想值 0.5 比较。相对差是多少?

    1. 0.5 %
    2. 0.005 %
    3. 10 %
    4. 1 %
    答案与解析

    正确答案:D 差值 0.005 除以参考值 0.5 得 0.01,即 1 %。

  4. binary64 的单位舍入误差约为 1.1e-16。为什么一致性检查的容差是十亿分之一,而不是单位舍入误差?

    1. 因为 JavaScript 的精度低于 Python
    2. 两个正确的计算在每次运算中的舍入不同,结果可能相差若干个单位舍入误差;十亿分之一既为此留出余地,又仍能发现真正的错误
    3. 因为公式只精确到十亿分之一
    4. 因为 YAML 无法存放更小的数
    答案与解析

    正确答案:B 十亿分之一是单位舍入误差的数百万倍,因此在不放大舍入误差的计算中,舍入能够通过;而错误的常数或因子造成的差异要大得多。

  5. 为什么参考值接近零时相对差会失效?

    1. 除以接近零的参考值,会使极小的绝对差看起来很大
    2. 因为零没有单位
    3. 因为在那里它总是为零
    4. 不会失效
    答案与解析

    正确答案:A 在这种情况下,应像库的检查那样,与一个尺度比较,例如该物理量在一个周期内的最大值。

  6. 在 Python 中,0.1 + 0.1 + 0.1 == 0.3 的计算结果是:

    1. True
    2. 报错
    3. False:其和被舍入为一个不同于 0.3 的双精度数
    4. 仅在某些计算机上为 True
    答案与解析

    正确答案:C 0.1 无法用二进制精确表示,三者之和经舍入后为 0.30000000000000004,是与 0.3 相邻的双精度数;应在容差范围内比较。

本站例题、预设和练习中的数值均为合成值:为教学而凑整的数值,并非来自任何实际设计的数据。