Helper conversion to have the same API for Unchained types as well as regular numbers.Comparison operators. For two Measurements, only equal if that holds for value and uncertainty. TODO: should we use almostEqual here? Or is that too imprecise for the purpose?A "type safe" solution required for unchained could be achieved with something like this. However, it shows the problem of getting a squared type as the resder argumentDo we want the following? It forces any FloatLike to generate a Measurement[float]!propagation based plainly on operator overload?mutable assign/additionmutable assign/subtractionThe following two dirty (!) templates help us with the assignment of the result procedure calls, taking care of deducing the types and performing the conversions so that we don't need to manually convert them all the time. assign1 is used for the call to procRes with a single argument and assign2 for the procRes with two arguments.Overloads for literals that force same type as Measurement hasmutable assign/multiplicationOverloads for literals that force same type as Measurement hasNOTE: Using any of the following exponentiation functions is dangerous. The Nim parser might include an additional prefix into the argument to ^ instead of keeping it as a, well, prefix. So -(x - μ)^2 is parsed as (-(x - μ))^2!-> for static exponents-> for explicit float exponents
Now generate single argument (mostly trigonometric) functions They all follow the following structure
proc exp*(m: Measurement): Measurement = result = procRes(exp(m.val), exp(m.val), m)where the derivatives are taken from the 'lookup table' below. NOTE: some of the following functions are not implemented in Nim atm, hence they are commented out. This is based on the same in astgrad, which itself took the map from somewhere else. Need to look up where that was, oops.
Types
FloatLikeCanBePowExp = concept xtypeof(T)typeof(U) x is FloatLike pow(1.0, x).toFloat is float
- Source Edit
FloatLikeNotInt = concept xtypeof(T)typeof(U) x is FloatLike not (x is SomeInteger)
- Source Edit
FloatLikeSupportsPow = concept xtypeof(T)typeof(U) x is FloatLike pow(x, 1.0).toFloat is float
- Source Edit
FloatLikeUnchangedUnderPow = concept xtypeof(T) x is FloatLike (x ^ 2) is T
- Note: this does not actually check for a runtime integer, but for reasons that elude me, it does the right thing. And doing the "correct" thing here does _not work. So uhh. Source Edit
Measurement[T] = object val*: T uncer*: T
- Source Edit
Procs
proc `$`[T: FloatLike](m: Measurement[T]): string
- Source Edit
proc `*`[T: FloatLike; U: FloatLike](a: Measurement[T]; b: Measurement[U]): auto
- Source Edit
proc `*`[T: FloatLike; U: FloatLike](x: T{lit}; m: Measurement[U]): Measurement[ U]
- Source Edit
proc `*`[U: FloatLike; T: FloatLike](m: Measurement[U]; x: T{lit}): Measurement[ U]
- Source Edit
proc `**`[T: FloatLike](m: Measurement[T]; p: static SomeInteger): auto
- Source Edit
proc `**`[T: FloatLikeSupportsPow; U: FloatLikeCanBePowExp](a: Measurement[T]; b: Measurement[U]): Measurement[T]
-
NOTE: Both types must be compatible FloatLike in such a way that T can be the base argument to pow and U the exponent argument. Note that the operation is destructive, i.e. the return type of pow(T, U) is forced to be T.
This is done so that we don't need to rely on returning auto. If the destructive nature is a problem for your use case, open an issue and we can adjust the logic.
Source Edit proc `**`[T: FloatLikeSupportsPow; U: FloatLikeNotInt](m: Measurement[T]; p: U): Measurement[ T]
- Source Edit
proc `**`[T: FloatLikeUnchangedUnderPow](m: Measurement[T]; p: SomeInteger): Measurement[ T]
- Exponentiation for RT natural exponents, or technically for any type T for which calculating x ^ N does not change the type. Source Edit
proc `*=`[T: FloatLike](a: var Measurement[T]; b: Measurement[T])
- Source Edit
proc `*=`[T: FloatLike](a: var Measurement[T]; b: T)
- Source Edit
proc `+`[T: FloatLike; U: FloatLike](x`gensym7: `{}`(T, lit); m`gensym7: Measurement[U]): Measurement[U]
- Source Edit
proc `+`[T: FloatLike](a, b: Measurement[T]): Measurement[T]
- Source Edit
proc `+`[T: FloatLike](m`gensym7: Measurement[T]; x`gensym7: T): Measurement[T]
- Source Edit
proc `+`[T: FloatLike](x`gensym7: T; m`gensym7: Measurement[T]): Measurement[T]
- Source Edit
proc `+`[U: FloatLike; T: FloatLike](m`gensym7: Measurement[U]; x`gensym7: `{}`(T, lit)): Measurement[U]
- Source Edit
proc `+-`[T: FloatLike](val, uncer: T): Measurement[T]
- noUnicode-mode makes output like this which users may want to re-use as input without edit. Nim 2/--experimental:unicodeOperators allows it. Source Edit
proc `+/`[F](x, y: Measurement[F]): Measurement[F]
- en.wikipedia.org/wiki/Weighted_arithmetic_mean#Variance-defined_weights suggests inverse-variance weights via max.likelihood over normal distros theory which also makes sense from "variance linearity" perspective. This binary operator does this for a pair of measurements. Source Edit
proc `+=`[T: FloatLike](a: var Measurement[T]; b: Measurement[T])
- Source Edit
proc `-`[T: FloatLike; U: FloatLike](x`gensym8: `{}`(T, lit); m`gensym8: Measurement[U]): Measurement[U]
- Source Edit
proc `-`[T: FloatLike](a, b: Measurement[T]): Measurement[T]
- Source Edit
proc `-`[T: FloatLike](m: Measurement[T]): Measurement[T]
- Source Edit
proc `-`[T: FloatLike](m`gensym8: Measurement[T]; x`gensym8: T): Measurement[T]
- Source Edit
proc `-`[T: FloatLike](x`gensym8: T; m`gensym8: Measurement[T]): Measurement[T]
- Source Edit
proc `-`[U: FloatLike; T: FloatLike](m`gensym8: Measurement[U]; x`gensym8: `{}`(T, lit)): Measurement[U]
- Source Edit
proc `-=`[T: FloatLike](a: var Measurement[T]; b: Measurement[T])
- Source Edit
proc `/`[T: FloatLike; U: FloatLike](a: Measurement[T]; b: Measurement[U]): auto
- Source Edit
proc `/`[U: FloatLike; T: FloatLike](m: Measurement[U]; x: T{lit}): Measurement[ U]
- Source Edit
proc `<`[T: FloatLike; U: FloatLike](a`gensym105: `{}`(U, lit); b`gensym105: Measurement[T]): bool
- Source Edit
proc `<`[T: FloatLike; U: FloatLike](a`gensym105: Measurement[T]; b`gensym105: `{}`(U, lit)): bool
- Source Edit
proc `<`[T: FloatLike](a`gensym105, b`gensym105: Measurement[T]): bool
- Source Edit
proc `<`[T: FloatLike](a`gensym105: Measurement[T]; b`gensym105: T): bool
- Source Edit
proc `<`[T: FloatLike](a`gensym105: T; b`gensym105: Measurement[T]): bool
- Source Edit
proc `<=`[T: FloatLike; U: FloatLike](a`gensym106: `{}`(U, lit); b`gensym106: Measurement[T]): bool
- Source Edit
proc `<=`[T: FloatLike; U: FloatLike](a`gensym106: Measurement[T]; b`gensym106: `{}`(U, lit)): bool
- Source Edit
proc `<=`[T: FloatLike](a`gensym106, b`gensym106: Measurement[T]): bool
- Source Edit
proc `<=`[T: FloatLike](a`gensym106: Measurement[T]; b`gensym106: T): bool
- Source Edit
proc `<=`[T: FloatLike](a`gensym106: T; b`gensym106: Measurement[T]): bool
- Source Edit
proc `==`[T: FloatLike; U: FloatLike](m1: Measurement[T]; m2: Measurement[U]): bool
- NOTE: This is a bit hacky, but it checks if two types are simply aliases based on their names being equal. In unchained this can happen if a local type is redefined and the two measurements have different "type instances". Source Edit
proc `==`[T: FloatLike](m1, m2: Measurement[T]): bool
- comparison of two measurements does not need to take into account the type, as we require same type anyway. Hence use toFloat to compare as float Source Edit
proc `==`[T: FloatLike](m: Measurement[T]; x: T): bool
- Source Edit
proc `==`[T: FloatLike](x: T; m: Measurement[T]): bool
- Source Edit
proc `^`[T: FloatLike](m: Measurement[T]; p: static SomeInteger): auto
- NOTE: If you import unchained, this version is not actually used, as unchained defines a macro ^ for static integer exponents, which simply rewrites the AST to an infix (or trivial) node! Source Edit
proc `^`[T: FloatLikeSupportsPow; U: FloatLikeCanBePowExp](a: Measurement[T]; b: Measurement[U]): Measurement[T]
- Source Edit
proc `^`[T: FloatLikeSupportsPow; U: FloatLikeNotInt](m: Measurement[T]; p: U): Measurement[ T]
- Source Edit
proc `^`[T: FloatLikeUnchangedUnderPow](m: Measurement[T]; p: SomeInteger): Measurement[ T]
- Source Edit
proc abs[T: FloatLike](m: Measurement[T]): Measurement[T]
- Source Edit
proc abs2[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arccos[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arccosh[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arccot[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arccoth[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arccsc[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arccsch[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arcsec[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arcsech[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arcsin[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arcsinh[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arctan[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc arctanh[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc cbrt[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc copysign[T: FloatLike; U: FloatLike](a: Measurement[T]; b: U): Measurement[ T]
- Source Edit
proc copysign[T: FloatLike](a, b: Measurement[T]): Measurement[T]
- Source Edit
proc cos[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc cosh[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc cot[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc coth[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc csc[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc csch[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc deg2rad[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc erf[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc erfc[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc erfcinv[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc erfi[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc erfinv[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
func error[T: FloatLike](m: Measurement[T]): T {.inline.}
- Source Edit
proc exp[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc exp2[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc expm1[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc inv[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc isInf[T: FloatLike](m: Measurement[T]): bool
- Source Edit
proc isNegInf[T: FloatLike](m: Measurement[T]): bool
- Source Edit
proc ln[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc log[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc log1p[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc log2[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc log10[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc mean[F](x: varargs[Measurement[F]]): Measurement[F]
- Average however many uncertain values in x into an overall estimate using the binary +/ operator. x can also be any openArray[Measurement[F]]. Source Edit
proc measurement[T: FloatLike](val, uncer: T{lit}): Measurement[float]
- Source Edit
proc measurement[T: FloatLike](value, uncertainty: T): Measurement[T]
- Source Edit
proc pretty[T: FloatLike](m: Measurement[T]; precision: int; merge = false): string
- On the regular printing backend merge is ignored. Source Edit
proc rad2deg[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc sec[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc sech[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
func signbit[T: FloatLike](m: Measurement[T]): bool
- Source Edit
proc sin[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc sinh[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc sqrt[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc tan[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc tanh[T](m: Measurement[T]): auto
- letStmt contains the definition of x, let x = m.val Source Edit
proc to[T: FloatLike; U](m: Measurement[T]; dtype: typedesc[U]): Measurement[U]
- Source Edit
func uncertainty[T: FloatLike](m: Measurement[T]): T {.inline.}
- Source Edit
func value[T: FloatLike](m: Measurement[T]): T {.inline.}
- Source Edit
proc ±[T: FloatLike](val, uncer: T): Measurement[T]
- Source Edit
proc ±[T: FloatLike](val, uncer: T{lit}): Measurement[float]
- Source Edit