Skip to content

Verifying with Python

  • Follow one equation from its SymPy derivation to the page and to the tests.
  • Compare two computations by their relative difference, and choose a tolerance that rounding cannot fail and a real mistake cannot pass.
  • Run the site’s checks on your own machine.

Every equation on the site lives once, in packages/pe-core/equations/equations.yaml, as a SymPy expression with its symbols, its tests and its citation. The Python package python/pe_core works from it:

  • Where it can, a script in python/pe_core/derive/ derives the equation from first principles, solving the circuit’s balance equations with SymPy step by step. The derivations page shows those steps as the code computes them, and pytest checks that each result equals the catalogue’s expression.
  • python scripts/gen_equations.py writes the LaTeX the pages show and the test vectors: each equation’s own tests, and random inputs evaluated by SymPy. CI runs it again and fails on any difference.

The TypeScript engine behind the pages and the tools has its own evaluators, written by hand rather than generated from the same file, so that a mistake in one is not copied into the other. vitest checks every evaluator against the vectors.

Two computations are compared by their relative difference:

δ=∣x−xref∣∣xref∣\delta = \frac{\left|{x - x_\mathrm{ref}}\right|}{\left|{x_\mathrm{ref}}\right|}
δ\delta
relative difference
xrefx_\mathrm{ref}
reference value
xx
value under test
Relative difference of a value from its reference✓ verified by 8 tests
Assumptions, convention and source
Assumptions
  • definition
Notes
it does not change when the quantity is scaled, as by a change of unit from volts to millivolts, so one tolerance serves every quantity (a unit whose zero moves, such as degrees Celsius against kelvins, is the exception); at a zero reference it is undefined, and near one a small absolute difference becomes a large relative one. The site asks 1e-9 of the TypeScript and Python evaluations of the same equation, and 1 % or 2 % of a simulation against its equation
Source
Higham 2002, Sec. 1.2 (Relative Error and Significant Digits)
Equation id
num.rel_diff · equations.yaml entry

It does not change when the quantity is scaled, as by a change of unit from volts to millivolts, so one tolerance serves every quantity. At a zero reference it is undefined [Higham 2002, Sec. 1.2], and near zero it exaggerates a small difference, so compare against a scale there. Two correct programs need not produce the same bits: each operation rounds its result, and the result depends on the order of the operations. One rounding changes a number by at most the unit roundoff of the format, relative to its size:

u=β1−p2u = \frac{\beta^{1 - p}}{2}
uu
unit roundoff
β\beta
base (2 for binary)
pp
precision (significand digits)
Unit roundoff of a floating-point format✓ verified by 8 tests
Assumptions, convention and source
Assumptions
  • rounding to the nearest number of the format, IEEE 754's default
Notes
rounding a real number to the nearest number of the format changes it by at most this fraction of itself (in the normal range). For binary64, the IEEE 754 double precision of JavaScript's numbers and Python's floats, the base is 2 and the precision 53 digits, so u=2−53≈1.1×10−16u = 2^{-53} \approx 1.1 \times 10^{-16}. Higham writes the precision as tt
Source
Higham 2002, Ch. 2 (Floating Point Arithmetic: the unit roundoff, Sec. 2.1, and its value in IEEE double precision)
Equation id
num.unit_roundoff · equations.yaml entry

The site requires the TypeScript and the Python evaluations of an equation to agree within one part in a billion. That is millions of times the unit roundoff, so rounding passes as long as the evaluation does not magnify its errors, as subtracting nearly equal numbers does (cancellation) [Higham 2002, Sec. 1.7]; yet it lies far below any real mistake, such as a wrong constant or a missing factor. A simulation compared with its equation gets a looser tolerance, because the equation idealizes the circuit: it takes the ripple as small [Erickson & Maksimović 2020, Ch. 2], and the SPICE library’s switch and diodes are only nearly ideal. The SPICE library’s values must lie within one percent of the ideal equations, measured against each quantity’s largest magnitude over the period, and the in-browser simulator’s conversion ratio and ripple within two percent.

scripts/spice_crosscheck.py writes the in-browser simulator’s circuits again as netlists, from their schematics rather than from the simulator’s equations, and runs them in ngspice [ngspice – open source SPICE simulator]. CI compares the simulator with ngspice’s results: each value within half a percent of the quantity’s largest magnitude over the period, with a small allowance for what the SPICE parts add, and each peak-to-peak swing within two percent.

A simulated conversion ratio against the ideal one, and the unit roundoff of binary64, the IEEE 754 double precision of JavaScript’s numbers and Python’s floats:

Cross-check example
SymbolValueHow it is obtained
xx value under test0.496given
xrefx_\mathrm{ref} reference value0.5given
β\beta base (2 for binary)2given
pp precision (significand digits)53given
δ\delta relative difference0.008Relative difference of a value from its reference
uu unit roundoff1.11e-16Unit roundoff of a floating-point format

The ratio differs from the ideal one by 0.008, within the library’s one percent. The unit roundoff is 1.11e-16: a tolerance of one part in a billion leaves room for millions of roundings.

▶ Open in the equation explorer: Relative difference of a value from its reference
Preset from the example num-parity

Sweep the value under test: the relative difference grows linearly on each side of the reference and reaches zero only at the reference itself.

Measure a converter’s input and output voltages on the bench with a multimeter, compute the relative difference of their ratio from the ideal one in Python, and list what can account for it: the diode’s drop, the switch’s and the winding’s resistances, the ripple. Then change the load and see which of them grows with the current.

  • A reference near zero makes the relative difference meaningless; compare against a scale, such as the quantity’s largest value over the period, as the library’s checks do.
  • Two implementations that share code share its mistakes. Generated evaluators would agree with the file they come from even where it is wrong.
  • Floating-point numbers are not compared for equality. In binary64, 0.1 + 0.1 + 0.1 is not 0.3: compare within a tolerance (unit roundoff).
  • Tool SymPy: Solve Equations — the SymPy development team · retrieved 2026-09-25
    How SymPy solves an equation or a system for a symbol, as the site's derivation scripts solve the balance equations.
  • Technical article Floating-Point Arithmetic: Issues and Limitations — the Python documentation (the tutorial) · retrieved 2026-09-25
    Why 0.1 + 0.1 + 0.1 is not 0.3 in a computer, why each operation can add a rounding error of up to one part in 2**53, and why results are compared within a tolerance, not for equality.
  1. Where does an equation shown on this site come from?

    1. LaTeX typed into each page
    2. One entry in equations.yaml: a SymPy expression with its symbols, tests and citation
    3. The TypeScript engine
    4. The quiz files
    Answer and explanation

    Correct answer: B The generator writes the LaTeX and the test vectors from that entry, and CI fails if the committed files differ from what it writes.

  2. Why are the TypeScript evaluators written by hand instead of generated from equations.yaml?

    1. So that a mistake in one is not copied into the other: two independent implementations must agree
    2. Because TypeScript cannot read YAML
    3. To make the pages load faster
    4. Because SymPy cannot evaluate numbers
    Answer and explanation

    Correct answer: A Generated code would agree with its source even where the source is wrong; an independent implementation has to agree with the vectors on its own.

  3. A simulated conversion ratio of 0.495 is compared with the ideal 0.5. What is the relative difference?

    1. 0.5 %
    2. 0.005 %
    3. 10 %
    4. 1 %
    Answer and explanation

    Correct answer: D The difference, 0.005, over the reference, 0.5, is 0.01: one percent.

  4. The unit roundoff of binary64 is about 1.1e-16. Why is the parity tolerance one part in a billion and not the unit roundoff?

    1. Because JavaScript has less precision than Python
    2. Two correct evaluations round differently at each operation and may differ by several units of roundoff; a billionth leaves room for that and still catches a real mistake
    3. Because the equations are only known to a billionth
    4. Because YAML cannot hold smaller numbers
    Answer and explanation

    Correct answer: B A billionth is millions of times the unit roundoff, so rounding passes in an evaluation that does not magnify it, while a wrong constant or factor is far larger.

  5. Why does the relative difference fail near a zero reference?

    1. Dividing by a reference near zero makes a tiny absolute difference look huge
    2. Because zero has no unit
    3. Because it is always zero there
    4. It does not fail
    Answer and explanation

    Correct answer: A Compare against a scale there, such as the quantity's largest value over the period, as the library's checks do.

  6. In Python, 0.1 + 0.1 + 0.1 == 0.3 evaluates to:

    1. True
    2. An error
    3. False: the sum rounds to a different double than 0.3
    4. True on some machines only
    Answer and explanation

    Correct answer: C 0.1 is not exact in binary, and the rounded sum of three of them, 0.30000000000000004, is the double next to 0.3; compare within a tolerance.

The numbers in the examples, presets and exercises on this site are synthetic: round teaching values, not data from any real design.