units
Use physical dimensions at compile-time or run-time.
dim.hpp
Go to the documentation of this file.
1 /// @file vnix/units/dim.hpp
2 /// @brief Definition of vnix::units::dim.
3 /// @copyright 2019 Thomas E. Vaughan; all rights reserved.
4 /// @license BSD Three-Clause; see LICENSE.
5 
6 #ifndef VNIX_UNITS_DIM_HPP
7 #define VNIX_UNITS_DIM_HPP
8 
9 #include <array> // for array
10 #include <vnix/rat.hpp> // for rational
11 #include <vnix/units/dim-base-off.hpp> // for dim_base_off
12 
13 namespace vnix {
14 namespace units {
15 
16 
17 /// Rational exponent for each basis-element of dimension.
18 ///
19 /// The template-type parameter DBO is of type dim_base_offset, which is
20 /// automatically generated from YAML and ERB before the header-only library is
21 /// installed.
22 ///
23 /// @tparam DBO Type of offset of basis-element of dimension.
24 template <typename DBO> class basic_dim {
25 public:
26  using rat = rational<4, 2>; ///< Type of rational for dimensioned values.
27  using off = DBO; ///< Type of offset for each base-element.
28 
29  enum {
30  NUM_BASES = DBO::num_offs, ///< Number of bases for dimension.
31  NUM_BITS = NUM_BASES * rat::BITS ///< Number of bits in instance of dim.
32  };
33 
34  /// Type of unsigned word in which dimensions are encoded.
35  using word = typename int_types<NUM_BITS>::US;
36 
37 private:
38  static_assert(NUM_BITS <= 64, "too many bits for bases");
39  word e_; ///< Storage for exponents.
40 
41  enum {
42  /// Maximum number of bits to shift an encoding of a rational exponent.
43  MAX_SHIFT = (NUM_BASES - 1) * rat::BITS
44  };
45 
46  /// Encode exponent associated with highest DBO at highest bit-offsets.
47  /// @tparam T Type that is convertible rat.
48  /// @tparam t Exponent to be encoded.
49  template <typename T> constexpr static word encode(T t) {
50  return rat::encode(t) << MAX_SHIFT;
51  }
52 
53 #if 1
54  /// Encode exponents, with higher DBO at higher bit-offsets.
55  /// @tparam T Type that is convertible to rat.
56  /// @tparam U List of types, each convertible to rat.
57  /// @param t Exponent to be encoded at lowest bit-offsets.
58  /// @param us Exponents to be encoded at higher bit-offsets.
59  template <typename T, typename... U>
60  constexpr static word encode(T t, U... us) {
61  constexpr auto N = sizeof...(us);
62  static_assert(N < NUM_BASES, "too many exponents");
63  constexpr auto SHIFT = MAX_SHIFT - N * rat::BITS;
64  constexpr word MASK = bit_range<word>(0, rat::BITS - 1) << SHIFT;
65  word const e = rat::encode(t) << SHIFT;
66  return (e & MASK) | (encode(us...) & ~MASK);
67  }
68 #endif
69 
70  constexpr static word encode(std::array<rat, NUM_BASES> const &a) {
71  word es = 0;
72  for (uint_fast8_t i = 0; i < NUM_BASES; ++i) {
73  auto const SHIFT = i * rat::BITS;
74  word const MASK = bit_range<word>(0, rat::BITS - 1) << SHIFT;
75  word const e = rat::encode(a[i]) << SHIFT;
76  es |= (e & MASK);
77  }
78  return es;
79  }
80 
81 public:
82  constexpr basic_dim() : e_(0) {}
83 
84  /// Initialize from dim that has been encoded into a word.
85  /// By default, initialize null (dimensionless) dim.
86  /// @param u Encoded data for dim.
87  constexpr explicit basic_dim(word u) : e_(u) {}
88 
89 #if 1
90  /// Initialize exponents, one for each base quantity.
91  ///
92  /// @tparam T List of types, one for each initializer in list for
93  /// rat_array. Each type should be rat.
94  ///
95  /// @param ts List of initializers for rat_array.
96  template <typename... T> constexpr basic_dim(T... ts) : e_(encode(ts...)) {
97  static_assert(sizeof...(ts) == NUM_BASES, "illegal number of bases");
98  }
99 #endif
100 
101  constexpr basic_dim(std::array<rat, NUM_BASES> const &a) : e_(encode(a)) {}
102 
103  /// Encode data for this dim into a word.
104  constexpr word encode() const { return e_; }
105 
106  /// Rational exponent at specified offset.
107  /// @param off Offset of exponent.
108  constexpr rat exp(DBO off) const {
109  constexpr auto mask = bit_range<word>(0, rat::BITS - 1);
110  return rat::decode((e_ >> (off * rat::BITS)) & mask);
111  }
112 
113  /// Rational exponent at specified offset.
114  /// @param off Offset of exponent.
115  constexpr rat operator[](DBO off) const { return exp(off); }
116 
117  /// Set rational exponent at specified offset.
118  /// @param off Offset of exponent.
119  /// @param r Rational exponent.
120  constexpr void set(DBO off, rat r) {
121  unsigned const bit_off = off * rat::BITS;
122  word const expon = rat::encode(r) << bit_off;
123  auto const mask = bit_range<word>(0, rat::BITS - 1) << bit_off;
124  e_ = (e_ & ~mask) | (expon & mask);
125  }
126 
127  /// Combine each exponent with corresponding other exponent via function.
128  /// @tparam F Type of function for combining two rationals to make third.
129  /// @param d Other rational exponents.
130  /// @param f Function operating on pair of rationals.
131  /// @return New rational exponents.
132  template <typename F>
133  constexpr basic_dim combine(basic_dim const &d, F f) const {
134  basic_dim r(word(0));
135  for (auto b : off::array) {
136  auto const os = DBO(b);
137  r.set(os, f(exp(os), d.exp(os)));
138  }
139  return r;
140  }
141 
142  /// Transform each exponent according to a function.
143  /// @tparam F Type of function.
144  /// @param f Unary function operating on rational.
145  /// @return New exponents.
146  template <typename F> constexpr basic_dim transform(F f) const {
147  basic_dim r(word(0));
148  for (auto b : off::array) {
149  auto const os = DBO(b);
150  r.set(os, f(exp(os)));
151  }
152  return r;
153  }
154 
155  /// Function used to add corresponding exponents.
156  constexpr static rat add(rat x, rat y) { return x + y; }
157 
158  /// Function used to subtract corresponding exponents.
159  constexpr static rat sbtrct(rat x, rat y) { return x - y; }
160 
161  /// Function object used for multiplying every exponent by a single factor.
162  struct mult {
163  rat f; ///< Factor by which to multiply exponents.
164 
165  /// Initialize from factor by which to multiply exponents.
166  /// @param ff Factor.
167  constexpr mult(rat ff) : f(ff) {}
168 
169  /// Multiply an exponent by the factor.
170  /// @param x Input exponent.
171  /// @return Output exponent.
172  constexpr rat operator()(rat x) const { return x * f; }
173  };
174 
175  /// Function object used for dividing every exponent by a single factor.
176  struct divd {
177  rat f; ///< Factor by which to divide exponents.
178 
179  /// Initialize from factor by which to divide exponents.
180  /// @param ff Factor.
181  constexpr divd(rat ff) : f(ff) {}
182 
183  /// Divide an exponent by the factor.
184  /// @param x Input exponent.
185  /// @return output exponent.
186  constexpr rat operator()(rat x) const { return x / f; }
187  };
188 
189  /// Add corresponding exponents.
190  /// This is called when two physical quantities are multiplied.
191  /// Passing lambda in constexpr function requires C++17.
192  /// @param a Addends.
193  /// @return Sums.
194  constexpr basic_dim operator+(basic_dim const &a) const {
195  return combine(a, add);
196  }
197 
198  /// Subtract corresponding exponents.
199  /// This is called when one physical quantity is divided by another.
200  /// Passing lambda in constexpr function requires C++17.
201  /// @param s Subtrahends.
202  /// @return Differences.
203  constexpr basic_dim operator-(basic_dim const &s) const {
204  return combine(s, sbtrct);
205  }
206 
207  /// Multiply exponents by rational factor.
208  /// This is called when a physical quantity is raised to a power.
209  /// @param f Factor.
210  /// @return Products.
211  constexpr basic_dim operator*(rat f) const { return transform(mult(f)); }
212 
213  /// Divide exponents by rational factor.
214  /// This is called when a physical quantity is raised to a power.
215  /// @param f Factor.
216  /// @return Products.
217  constexpr basic_dim operator/(rat f) const { return transform(divd(f)); }
218 
219  /// Divide exponents by rational factor.
220  /// This is called when a physical quantity is raised to a power.
221  /// @param f Factor.
222  /// @return Products.
223  constexpr basic_dim operator/(rat::stype f) const {
224  return transform(divd(f));
225  }
226 
227  constexpr bool operator==(basic_dim const &d) const { return e_ == d.e_; }
228 
229  constexpr bool operator!=(basic_dim const &d) const { return e_ != d.e_; }
230 
231  /// Print to output stream the symbolic contribution from a given unit.
232  /// @param s Output stream.
233  /// @param u Abbreviation for unit.
234  /// @param e Exponent of unit.
235  static std::ostream &print_unit(std::ostream &s, char const *u, rat e) {
236  if (e.to_bool()) {
237  s << " " << u;
238  if (e != rat(1)) {
239  s << "^";
240  if (e.d() != 1) { s << "["; }
241  s << e;
242  if (e.d() != 1) { s << "]"; }
243  }
244  }
245  return s;
246  }
247 
248  /// Print to to output stream.
249  /// @param s Reference to stream.
250  /// @param d Dimension to print.
252  for (auto i : DBO::array) { print_unit(s, DBO::sym[i], d[i]); }
253  return s;
254  }
255 };
256 
257 
258 /// Define dim as specification of basic_dim by way of YAML- and ERB-generated
259 /// type dim_base_off.
260 using dim = basic_dim<dim_base_off>;
261 
262 
263 constexpr static dim nul_dim; ///< Null dimension.
264 
265 
266 } // namespace units
267 } // namespace vnix
268 
269 #endif // ndef VNIX_DIM_HPP
static constexpr utype encode(rational r)
Encoding from rational number.
Definition: rational.hpp:113
constexpr auto operator-(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Difference between two rational numbers.
Definition: rational.hpp:255
Maximum number of bits to shift an encoding of a rational exponent.
Definition: dim.hpp:43
constexpr basic_dim(std::array< rat, NUM_BASES > const &a)
Definition: dim.hpp:101
constexpr word encode() const
Encode data for this dim into a word.
Definition: dim.hpp:104
static constexpr rat sbtrct(rat x, rat y)
Function used to subtract corresponding exponents.
Definition: dim.hpp:159
constexpr basic_dim combine(basic_dim const &d, F f) const
Combine each exponent with corresponding other exponent via function.
Definition: dim.hpp:133
static constexpr rational decode(utype u)
Rational number from encoding.
Definition: rational.hpp:116
constexpr rat operator()(rat x) const
Divide an exponent by the factor.
Definition: dim.hpp:186
constexpr int_types< DNM_BITS >::UF d() const
Normalized denominator.
Definition: encoding.hpp:68
Function object used for dividing every exponent by a single factor.
Definition: dim.hpp:176
static constexpr word encode(T t)
Encode exponent associated with highest DBO at highest bit-offsets.
Definition: dim.hpp:49
constexpr basic_dim operator+(basic_dim const &a) const
Add corresponding exponents.
Definition: dim.hpp:194
rat f
Factor by which to divide exponents.
Definition: dim.hpp:177
constexpr basic_dim(word u)
Initialize from dim that has been encoded into a word.
Definition: dim.hpp:87
constexpr basic_dim transform(F f) const
Transform each exponent according to a function.
Definition: dim.hpp:146
static constexpr word encode(std::array< rat, NUM_BASES > const &a)
Definition: dim.hpp:70
rat f
Factor by which to multiply exponents.
Definition: dim.hpp:163
constexpr auto operator+(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Sum of two rational numbers.
Definition: rational.hpp:231
constexpr void set(DBO off, rat r)
Set rational exponent at specified offset.
Definition: dim.hpp:120
constexpr rational(stype n=0, stype d=1)
Initialize from numerator and denominator.
Definition: rational.hpp:47
constexpr basic_dim operator-(basic_dim const &s) const
Subtract corresponding exponents.
Definition: dim.hpp:203
Smallest integer types for holding certain number of bits.
Definition: int-types.hpp:21
static constexpr dim nul_dim
Null dimension.
Definition: dim.hpp:263
static constexpr word encode(T t, U...us)
Encode exponents, with higher DBO at higher bit-offsets.
Definition: dim.hpp:60
Rational exponent for each basis-element of dimension.
Definition: dim.hpp:24
friend std::ostream & operator<<(std::ostream &s, basic_dim d)
Print to to output stream.
Definition: dim.hpp:251
constexpr rat exp(DBO off) const
Rational exponent at specified offset.
Definition: dim.hpp:108
constexpr rat operator[](DBO off) const
Rational exponent at specified offset.
Definition: dim.hpp:115
constexpr bool operator!=(rational< NB1, DB1 > r1, rational< NB2, DB2 > r2)
Compare rationals for inequality.
Definition: rational.hpp:141
static std::ostream & print_unit(std::ostream &s, char const *u, rat e)
Print to output stream the symbolic contribution from a given unit.
Definition: dim.hpp:235
constexpr mult(rat ff)
Initialize from factor by which to multiply exponents.
Definition: dim.hpp:167
constexpr bool to_bool() const
Automatically convert to boolean.
Definition: rational.hpp:65
constexpr bool operator==(basic_dim const &d) const
Definition: dim.hpp:227
constexpr basic_dim operator*(rat f) const
Multiply exponents by rational factor.
Definition: dim.hpp:211
constexpr basic_dim operator/(rat::stype f) const
Divide exponents by rational factor.
Definition: dim.hpp:223
Number of bits in instance of dim.
Definition: dim.hpp:31
Thomas E. Vaughan&#39;s public software.
Definition: rational.hpp:13
static constexpr rat add(rat x, rat y)
Function used to add corresponding exponents.
Definition: dim.hpp:156
Classes and functions supporting a model of physically dimensioned quantities.
Number of bases for dimension.
Definition: dim.hpp:30
word e_
Storage for exponents.
Definition: dim.hpp:38
Function object used for multiplying every exponent by a single factor.
Definition: dim.hpp:162
constexpr basic_dim()
Definition: dim.hpp:82
constexpr divd(rat ff)
Initialize from factor by which to divide exponents.
Definition: dim.hpp:181
constexpr bool operator!=(basic_dim const &d) const
Definition: dim.hpp:229
constexpr rat operator()(rat x) const
Multiply an exponent by the factor.
Definition: dim.hpp:172
constexpr basic_dim operator/(rat f) const
Divide exponents by rational factor.
Definition: dim.hpp:217
constexpr basic_dim(T...ts)
Initialize exponents, one for each base quantity.
Definition: dim.hpp:96