This library is inspired by the excellent Measurements.jl and can, for all intents and purposes, be considered a port of it (even if it doesn’t yet support some of its features).
The basic gist is that one constructs Measurement
objects for one’s
measurement values, which include uncertainties. This is done via one
of two ways:
import measuremancer
let x = 1.0 ± 0.1 # via unicode operator
let y = measurement(2.0, 0.5)
Printing either of these yields a string representation using the ±
unicode operator:
1.0 ± 0.1
What makes this library actually useful however, is the ability to perform error propagation for the user.
import measuremancer
let x = 1.0 ± 0.1
let y = 2.0 ± 0.5
print x + y
print x * y
print x - y
print x / y
(print
is a helper defined to print the expression in addition to
the measurement. You may use echo
as usual for regular printing).
yields:
x + y: 3.0 ± 0.51 x * y: 2.0 ± 0.54 x - y: -1.0 ± 0.51 x / y: 0.50 ± 0.13
Error propagation is performed according to linear error propagation theory (or sometimes called “Gaussian error propagation”): https://en.wikipedia.org/wiki/Propagation_of_uncertainty
The library handles dependent variables correctly. This means things like:
import measuremancer
let x = 1.0 ± 0.1
print x - x
# and
print x / x
are handled correctly, resulting in:
x - x: 0.0 ± 0.0
x / x: 1.0 ± 0.0
meaning the resulting variable has no error associated to it.
We can also include more complicated expressions of course:
import measuremancer
proc gaus[T](x, μ, σ: T): T =
result = 1.0 / sqrt(2 * PI) * exp(- ((x - μ)^2) / (2 * (σ^2)))
let x = 1.0 ± 0.1
let μ = 0.5 ± 0.05
let σ = 1.2 ± 0.2
print gaus(x, μ, σ)
Note: Be very careful using ^
or **
for exponentiation. Notice
the extra parenthesis around the (x - μ)^2
term (and σ^2). That is, because at
least as of Nim devel 1.7 it otherwise includes the -
in the square!
gaus(x, μ, σ): 0.366 ± 0.0177
Of course, we wouldn’t be Nim if we couldn’t also apply the whole
logic to types other than float
!
Feel free to perform error propagation on unchained
types for
example:
import unchained, measuremancer
let m = 1.0.kg ± 0.1.kg
let a = 9.81.m•s⁻² ± 0.05.m•s⁻²
print m * a
which yields:
m * a: 9.81 ± 0.982 KiloGram•Meter•Second⁻²
NOTE: With units as complicated as unchained's
types, there is
still a chance of things breaking. Basic math (*
, /
, +
and -
)
should work correctly now though.
As of Nim version 1.6 any code using this library has to be compiled with:
--experimental:unicodeOperators
Feel free to create a nim.cfg
in the directory of your program to
avoid having to set this setting manually every time.
NOTE: This flag was not available in Nim 1.4 yet. Unicode operators
simply weren’t a thing. If you wish to use this library anyway, you
can do so, simply by constructing Measurements
using the
measurement
procedure. Further, in Nim >= 2.0, unicode operators are
allowed by default. So, special compilation options are unneeded.
If compiled with -d:useCligen
, uncertain number pair formatting is
the default ~cligen/strUt.fmtUncertain~. That uses the uncertainty to
limit precision of both value & uncertainty to the same decimal place
(3 decimals of the uncertainty by default, as per one common
convention, but you can compile with -d:mmErrPrec=N
to use N
places).