1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! A package for handling quantities with uncertainties.
//!
//! The [`ValUnc`] type represents a quantity with a mean value `val` and
//! uncertainties `unc`. It is designed to be used with [newtypes] that wrap a
//! basic numeric type, e.g. `f64`. This allows for the type to define how
//! uncertainties should be propagated, with minimal confusion.
//!
//! [newtypes]: https://doc.rust-lang.org/1.0.0/style/features/types/newtype.html
//!
//! The [`traits`] module defines some traits that are necessary for
//! uncertainty types to be implemented in order for the related type to be
//! implemented for `ValUnc`. For example, in order to implement `Add` for
//! `ValUnc`, all of the uncertainty types used must implement [`UncAdd`].
//! These are opt-in and only the traits used need to be implemented.
//!
//! An example implementation of an uncertainty type is provided in [`unc`]. It
//! uses standard error propagation rules (see [this][uncertainty]), and
//! hopefully can be used if it fits your use case.
//!
//! [uncertainty]: https://en.wikipedia.org/wiki/Propagation_of_uncertainty
//!
//! # Features
//!
//! The `serde` feature can be enabled for use with [`serde`]. A `ValUnc<V, U>`
//! is (de)serialized as a `(V, U)` or if `unc` is zero, according to
//! [`num-traits::Zero`], just a `V`.
//!
//! [`serde`]: https://serde.rs
//! [`num-traits::Zero`]: https://docs.rs/num-traits/*/num_traits/identities/trait.Zero.html
//!
//! # Examples
//!
//! The following demonstrates how one would go about creating uncertainty
//! types and implementing the traits necessary for doing math with `ValUnc`
//! (only `Add`, in this case). Notably, the implementations of `UncAdd` are
//! different. The two uncertainties, though, can be used together in one
//! `ValUnc`.
//!
//! ```
//! use val_unc::{ValUnc, UncAdd};
//!
//! // This is a type for statistical uncertainties.
//! // The result of adding two `StatUnc`s is the square root of the sum of the squares.
//! #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
//! struct StatUnc(pub f64);
//!
//! impl<T> UncAdd<T> for StatUnc {
//! fn unc_add(self, _self_val: T, other: Self, _other_val: T) -> Self {
//! Self(f64::sqrt(f64::powi(self.0, 2) + f64::powi(other.0, 2)))
//! }
//! }
//!
//! // This is a type for systematic uncertainties.
//! // The result of adding two `SysUnc`s is the sum of the two.
//! #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
//! struct SysUnc(pub f64);
//!
//! impl<T> UncAdd<T> for SysUnc {
//! fn unc_add(self, _self_val: T, other: Self, _other_val: T) -> Self {
//! Self(self.0 + other.0)
//! }
//! }
//!
//! // Create two values and add them together
//! let v1 = ValUnc::new(10.2, (StatUnc(4.0), SysUnc(1.25)));
//! let v2 = ValUnc::new(8.5, (StatUnc(3.0), SysUnc(1.25)));
//! // You can use destructuring to unpack the results
//! let ValUnc { val, unc: (stat, sys) } = v1 + v2;
//!
//! assert!(f64::abs(val - 18.7) <= std::f64::EPSILON);
//! assert!(f64::abs(stat.0 - 5.0) <= std::f64::EPSILON);
//! assert!(f64::abs(sys.0 - 2.5) <= std::f64::EPSILON);
//! ```
pub use ;