diff --git a/include/xo/unit/Quantity.hpp b/include/xo/unit/Quantity.hpp index c94dbebe..299e0d2d 100644 --- a/include/xo/unit/Quantity.hpp +++ b/include/xo/unit/Quantity.hpp @@ -110,6 +110,31 @@ namespace xo { } } + template + static constexpr + auto subtract(const Quantity & x, const Quantity2 & y) { + using r_repr_type = std::common_type_t; + using r_int_type = std::common_type_t; + + /* conversion to get y in same units as x: multiply by y/x */ + auto rr = detail::nu_ratio(y.unit(), x.unit()); + + if (rr.natural_unit_.is_dimensionless()) { + r_repr_type r_scale = (static_cast(x.scale()) + - (::sqrt(rr.outer_scale_sq_) + * rr.outer_scale_exact_.template to() + * static_cast(y.scale()))); + + return Quantity(r_scale, x.unit_.template to_repr()); + } else { + /* units don't match! */ + return Quantity(std::numeric_limits::quiet_NaN(), + x.unit_.template to_repr()); + } + } + private: /** @brief quantity represents this multiple of a unit amount **/ Repr scale_ = Repr{}; @@ -167,6 +192,16 @@ namespace xo { return Quantity::add(x, y); } + /** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr) + **/ + template + requires quantity2_concept && quantity2_concept + constexpr auto + operator- (const Quantity & x, const Quantity2 & y) + { + return Quantity::subtract(x, y); + } + namespace unit { constexpr auto nanogram = natural_unit_qty(nu2::nanogram); } diff --git a/utest/unit.test.cpp b/utest/unit.test.cpp index 80be39db..09ddcea1 100644 --- a/utest/unit.test.cpp +++ b/utest/unit.test.cpp @@ -1158,6 +1158,45 @@ namespace xo { //REQUIRE(ng2.scale() == 1); } /*TEST_CASE(Quantity6)*/ + + TEST_CASE("Quantity7", "[Quantity]") { + constexpr bool c_debug_flag = true; + + // can get bits from /dev/random by uncommenting the 2nd line below + //uint64_t seed = xxx; + //rng::Seed seed; + + //auto rng = xo::rng::xoshiro256ss(seed); + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.Quantity7")); + //log && log("(A)", xtag("foo", foo)); + + /* not constexpr until c++26 */ + Quantity ng = unit_qty(su2::nanogram); + Quantity ug = unit_qty(su2::microgram); + + { + auto sum1 = ng - ug; + log && log(xtag("ng-ug", sum1)); + + /* units will be nanograms, since that's on lhs */ + REQUIRE(sum1.unit().n_bpu() == 1); + REQUIRE(sum1.unit()[0].scalefactor() == scalefactor_ratio_type(1, 1000000000)); + REQUIRE(sum1.scale() == -999.0); + } + + { + auto sum2 = ug - ng; + log && log(xtag("ug-ng", sum2)); + + /* units will be micrograms, since that's on rhs */ + REQUIRE(sum2.unit().n_bpu() == 1); + REQUIRE(sum2.unit()[0].scalefactor() == scalefactor_ratio_type(1, 1000000)); + REQUIRE(sum2.scale() == 0.999); + } + + //REQUIRE(ng2.scale() == 1); + } /*TEST_CASE(Quantity7)*/ } /*namespace ut*/ } /*namespace xo*/