In a physics lab every measurement has an uncertainty: a rod is 2.00 ± 0.01 m long, a swing takes 2.84 ± 0.02 s. When measurements are combined in a formula, their uncertainties combine too, and students keep getting that bookkeeping wrong. A number type that does it automatically lets them write the formula as it is.
Write a class Measured(value, error), where error >= 0 (a negative error raises ValueError). The attributes value and error can be read. Treat every operand as an independent measurement and use these rules, where a and b are measurements with errors ea and eb:
a + banda - b: errorsqrt(ea**2 + eb**2);a * b: errorsqrt((b * ea)**2 + (a * eb)**2)(using the values ofaandb);a / b: errorsqrt((ea / b)**2 + (a * eb / b**2)**2);a ** nfor a plain numbern: errorabs(n * a**(n - 1)) * ea;-akeeps the error.
A plain number (int or float) is an exact value with error 0, and may appear on either side of +, -, * and / (so 2 * a, 1 - a and 1 / a work). sum(list_of_measurements) must work. Anything else raises TypeError.
Also write:
a.relative, the relative errorerror / abs(value), read without brackets;a.agrees(b, k=2): whetherabs(a.value - b.value) <= k * sqrt(ea**2 + eb**2);repr(a):Measured(2.0, 0.01)(both numbers asreprshows them);str(a): withd = max(0, 1 - floor(log10(error)))decimals (two significant figures of the error),f"{value:.{d}f} ± {error:.{d}f}"; with an error of0, juststr(value).
The setup's helper ve(m) returns (m.value, m.error), pendulum_runs(n, seed) generates timing measurements, and raises(fn, *args) returns the name of the exception a call raises (or None).
Examples
Input: L, T = Measured(2.0, 0.01), Measured(2.84, 0.02)
g = 4 * math.pi ** 2 * L / T ** 2
str(g), ve(L + T), repr(-L), str(1 / T)
Output: ('9.79 ± 0.15', (4.84, 0.022360679774997897), 'Measured(-2.0, 0.01)', '0.3521 ± 0.0025')
Constraints
- Values and errors are floats or integers; divisors are not zero, and a value raised to a power is positive.
- Floats are compared with a tolerance of
1e-6.
Goals
- Write the arithmetic special methods, including the reflected ones, for a numeric value type
- Let plain numbers and your objects mix on either side of an operator
- Carry a derived quantity (the error) through every operation automatically