Line data Source code
1 : /** @file scaled_unit2.hpp
2 : *
3 : * Author: Roland Conybeare
4 : **/
5 :
6 : #pragma once
7 :
8 : #include "natural_unit.hpp"
9 :
10 : namespace xo {
11 : namespace qty {
12 : /** @class bpu2_array_rescale_result
13 : * @brief Represents the product sqrt(outer_scale_sq) * outer_scale_exact * nat_unit
14 : **/
15 : template <typename Int>
16 : struct scaled_unit {
17 22 : constexpr scaled_unit(const natural_unit<Int> & nat_unit,
18 : ratio::ratio<Int> outer_scale_exact,
19 : double outer_scale_sq)
20 22 : : natural_unit_{nat_unit},
21 22 : outer_scale_exact_{outer_scale_exact},
22 22 : outer_scale_sq_{outer_scale_sq}
23 : {}
24 :
25 : constexpr scaled_unit reciprocal() const {
26 : return scaled_unit(nu_reciprocal(natural_unit_,
27 : outer_scale_exact_.reciprocal(),
28 : 1.0 / outer_scale_sq_));
29 : }
30 :
31 : natural_unit<Int> natural_unit_;
32 : ratio::ratio<Int> outer_scale_exact_;
33 : double outer_scale_sq_;
34 : };
35 :
36 : namespace detail {
37 : template <typename Int>
38 : constexpr auto make_unit_rescale_result(const natural_unit<Int> & bpuv) {
39 : return scaled_unit<Int>(bpuv,
40 : ratio::ratio<Int>(1, 1),
41 : 1.0);
42 : }
43 : }
44 :
45 : namespace su2 {
46 : constexpr auto nanogram = detail::make_unit_rescale_result<std::int64_t>(nu2::nanogram);
47 : constexpr auto microgram = detail::make_unit_rescale_result<std::int64_t>(nu2::microgram);
48 : }
49 :
50 : namespace detail {
51 : template <typename Int>
52 : constexpr
53 : detail::bpu2_rescale_result<Int>
54 : bpu2_product(const bpu<Int> & lhs_bpu,
55 : const bpu<Int> & rhs_bpu)
56 : {
57 : assert(lhs_bpu.native_dim() == rhs_bpu.native_dim());
58 :
59 : bpu<Int> prod_bpu = lhs_bpu;
60 : auto rr = bpu_product_inplace(&prod_bpu, rhs_bpu);
61 :
62 : return bpu2_rescale_result<Int>(prod_bpu,
63 : rr.outer_scale_exact_,
64 : rr.outer_scale_sq_);
65 : }
66 :
67 : template <typename Int>
68 : constexpr
69 : scaled_unit<Int>
70 : nu_bpu_product(const natural_unit<Int> & lhs_bpu_array,
71 : const bpu<Int> & rhs_bpu)
72 : {
73 : natural_unit<Int> prod = lhs_bpu_array;
74 : auto rr = nu_product_inplace(&prod, rhs_bpu);
75 :
76 : return scaled_unit<Int>(prod,
77 : rr.outer_scale_exact_,
78 : rr.outer_scale_sq_);
79 : };
80 :
81 : template <typename Int>
82 : constexpr
83 : scaled_unit<Int>
84 3 : nu_product(const natural_unit<Int> & lhs_bpu_array,
85 : const natural_unit<Int> & rhs_bpu_array)
86 : {
87 3 : natural_unit<Int> prod = lhs_bpu_array;
88 :
89 : /* accumulate product of scalefactors spun off by rescaling
90 : * any basis-units in rhs_bpu_array that conflict with the same dimension
91 : * in lh_bpu_array
92 : */
93 3 : auto sfr = (detail::outer_scalefactor_result<Int>
94 3 : (scalefactor_ratio_type(1, 1) /*outer_scale_exact*/,
95 : 1.0 /*outer_scale_sq*/));
96 :
97 6 : for (std::size_t i = 0; i < rhs_bpu_array.n_bpu(); ++i) {
98 3 : auto sfr2 = nu_product_inplace(&prod, rhs_bpu_array[i]);
99 :
100 3 : sfr.outer_scale_exact_ = sfr.outer_scale_exact_ * sfr2.outer_scale_exact_;
101 3 : sfr.outer_scale_sq_ *= sfr2.outer_scale_sq_;
102 : }
103 :
104 : return scaled_unit<Int>(prod,
105 : sfr.outer_scale_exact_,
106 3 : sfr.outer_scale_sq_);
107 : }
108 :
109 : template <typename Int>
110 : constexpr
111 : scaled_unit<Int>
112 19 : nu_ratio(const natural_unit<Int> & nu_lhs,
113 : const natural_unit<Int> & nu_rhs)
114 : {
115 19 : natural_unit<Int> ratio = nu_lhs;
116 :
117 : /* accumulate product of scalefactors spun off by rescaling
118 : * any basis-units in rhs_bpu_array that conflict with the same dimension
119 : * in lh_bpu_array
120 : */
121 19 : auto sfr = (detail::outer_scalefactor_result<Int>
122 19 : (scalefactor_ratio_type(1, 1) /*outer_scale_exact*/,
123 : 1.0 /*outer_scale_sq*/));
124 :
125 38 : for (std::size_t i = 0; i < nu_rhs.n_bpu(); ++i) {
126 19 : auto sfr2 = nu_ratio_inplace(&ratio, nu_rhs[i]);
127 :
128 : /* note: nu_ratio_inplace() reports multiplicative outer scaling factors,
129 : * so multiply is correct here
130 : */
131 19 : sfr.outer_scale_exact_ = sfr.outer_scale_exact_ * sfr2.outer_scale_exact_;
132 19 : sfr.outer_scale_sq_ *= sfr2.outer_scale_sq_;
133 : }
134 :
135 : return scaled_unit<Int>(ratio,
136 : sfr.outer_scale_exact_,
137 19 : sfr.outer_scale_sq_);
138 : }
139 : }
140 :
141 : template <typename Int>
142 : inline constexpr scaled_unit<Int>
143 : operator* (const scaled_unit<Int> & x_unit,
144 : const scaled_unit<Int> & y_unit)
145 : {
146 : auto rr = detail::nu_product(x_unit.natural_unit_,
147 : y_unit.natural_unit_);
148 :
149 : return (scaled_unit<Int>
150 : (rr.natural_unit_,
151 : rr.outer_scale_exact_ * x_unit.outer_scale_exact_ * y_unit.outer_scale_exact_,
152 : rr.outer_scale_sq_ * x_unit.outer_scale_sq_ * y_unit.outer_scale_sq_));
153 : }
154 :
155 : template <typename Int>
156 : inline constexpr scaled_unit<Int>
157 : operator/ (const scaled_unit<Int> & x_unit,
158 : const scaled_unit<Int> & y_unit)
159 : {
160 : auto rr = detail::nu_ratio(x_unit.natural_unit_,
161 : y_unit.natural_unit_);
162 :
163 : return (scaled_unit<Int>
164 : (rr.natural_unit_,
165 : rr.outer_scale_exact_ * x_unit.outer_scale_exact_ * y_unit.outer_scale_exact_,
166 : rr.outer_scale_sq_ * x_unit.outer_scale_sq_ * y_unit.outer_scale_sq_));
167 : }
168 : } /*namespace qty*/
169 : } /*namespace xo*/
170 :
171 : /** end scaled_unit2.hpp **/
|