Statistics Lab / Appendix
The parity ledger
A port is only useful if it computes the same thing. Every number in this table was written down in the 2020 submission; the right-hand column is the TypeScript port recomputing it from the original inputs and printing it at the same precision. The comparison runs in the test suite on every push.
- Printed R outputs reproduced exactly
- 34 / 34
- Hand calculations agreeing to their rounding
- 6 / 6
- Closed-form derivations evaluated
- 2 / 2
- Reference implementation
- R 4.6.1
42 values in all: 34 printed R outputs, 6 hand calculations and 2 symbolic derivations. marks an identical string, ≈ agreement to the table rounding the hand working used, and = a closed form evaluated numerically.
How it was checked
Reference values. A script in the repository (scripts/r_reference.R) re-runs the original computations in R — the same functions, data and seeds as the 2020 notebooks — and writes the results to a test fixture: summaries, quantiles, intervals, test statistics, the full lm fit with its diagnostics, and a grid of distribution functions.
Two levels of comparison. Internally every quantity must agree with R to about nine significant figures. The ledger then checks the stricter, human-facing claim: formatted at the precision printed in 2020, the port’s value is the same string. Even the full summary(lm) printout is reproduced character for character.
Hand calculations used rounded table values (for example t₉ = 2.262), so they agree to the last digit or two, not exactly; the ledger shows both.
Reproducing R’s random numbers
The midrange-versus-mean simulation (A1 Q4) depends on set.seed(2529). To replay it, the port re-implements R’s default generator: the seed-scrambling LCG, the Mersenne-Twister state, R’s guard against 0 and 1, and normal draws by inversion from two uniforms (2²⁷u₁ + u₂ fed to Wichura’s AS241). The first three uniforms to 17 significant digits (the port’s column is computed when this page is built):
The uniform stream is bit-identical to R’s over 100,000 draws. Normal and exponential draws can differ from R 4.6 on Apple silicon in the last bit or two (at most 4 and 1 units in the last place), because R’s build fuses multiply-adds inside qnorm and JavaScript cannot. That is far below any printed precision, so every 2020 value still matches.
- 1R 0.9589315231423825TS0.9589315231423825
- 2R 0.75501735182479024TS0.75501735182479024
- 3R 0.017361181322485209TS0.017361181322485209
# R
> set.seed(2529); sprintf("%.17g", runif(3))
// TypeScript (src/lib/rng.ts)
new RRandom(2529).runif(3)Assignment 1 — estimation
- Median plant heightQ1(a)
- 2020
- 68.95
- Port
- 68.95
- Mean plant heightQ1(a)
- 2020
- 98.17
- Port
- 98.17
- 2020
- 133.57
- Port
- 133.57
- Interquartile rangeQ1(a)
- 2020
- 113.55
- Port
- 113.55
- 2020
- 98.16667
- Port
- 98.16667
- Standard error of λ̂Q2(c)i
- 2020
- 0.788583
- Port
- 0.788583
- 95% CI for λQ2(c)ii
- 2020
- (1.118327, 5.189367)
- Port
- (1.118327, 5.189367)
- 2020
- 0.043088
- Port
- 0.043088
- 2020
- -0.020101
- Port
- -0.020101
- 2020
- 0.158578
- Port
- 0.158578
- 2020
- 0.069188
- Port
- 0.069188
Assignment 2 — intervals, regression and testing
- X-squared statisticQ1(b)
- 2020
- 4.7269
- Port
- 4.7269
- p-valueQ1(b)
- 2020
- 0.02969
- Port
- 0.02969
- 95% CI for p₁ − p₂Q1(c)
- 2020
- (0.005118323, 0.094881677)
- Port
- (0.005118323, 0.094881677)
- 2020
- (12.7897, 17.3303)
- Port
- (12.7895, 17.3305)agrees to table rounding
- 2020
- 35
- Port
- 35
- 95% CI for μX − μYQ2(c)
- 2020
- (-7.71898, -2.81102)
- Port
- (-7.71884, -2.81116)agrees to table rounding
- F statisticQ2(e)
- 2020
- 15.28
- Port
- 15.28
- F test p-valueQ2(e)
- 2020
- 0.00163
- Port
- 0.00163
- 95% CI for σ²X / σ²YQ2(e)
- 2020
- (3.167976, 64.130185)
- Port
- (3.167976, 64.130185)
- Intercept estimateQ3(a)
- 2020
- -32.3442
- Port
- -32.3442
- 2020
- 6.4005
- Port
- 6.4005
- Slope standard errorQ3(a)
- 2020
- 0.6345
- Port
- 0.6345
- 2020
- 64.6
- Port
- 64.6
- Multiple R-squaredQ3(a)
- 2020
- 0.8497
- Port
- 0.8497
- 2020
- 101.7
- Port
- 101.7
- Overall p-valueQ3(a)
- 2020
- 7.816e-09
- Port
- 7.816e-09
- 2020
- (-163.027250, 98.338933)
- Port
- (-163.027250, 98.338933)
- 95% CI for the slopeQ3(b)
- 2020
- (5.067368, 7.733558)
- Port
- (5.067368, 7.733558)
- 2020
- 607.7022 (576.7281, 638.6762)
- Port
- 607.7022 (576.7281, 638.6762)
- 2020
- 607.7022 (468.4949, 746.9094)
- Port
- 607.7022 (468.4949, 746.9094)
- Type I error e⁻²Q5(a)
- 2020
- e^-2
- Port
- 0.1353closed form evaluated numerically
- Power e^(−4/5)Q5(c)
- 2020
- e^-0.8
- Port
- 0.4493closed form evaluated numerically
- 2020
- 5.991
- Port
- 5.991
Assignment 3 — nonparametric and likelihood methods
- Days with cases ≥ 15Q1(a)
- 2020
- 14
- Port
- 14
- Sign test p-valueQ1(a)
- 2020
- 0.9608231
- Port
- 0.9608231
- Wilcoxon WQ1(b)
- 2020
- 38
- Port
- 38
- Wilcoxon p-valueQ1(b)
- 2020
- 0.04798
- Port
- 0.04798
- 2020
- 1.855
- Port
- 1.855
- 2020
- 0.706
- Port
- 0.706
- 2020
- 37.11096
- Port
- 37.11096
- 2020
- 64.7806
- Port
- 64.7806
The ledger is generated by src/lib/__tests__/parity.test.ts in the web app; the original files are in coursework/ of the project repository (private for now).