diff --git a/include/xo/unit/basis_unit2.hpp b/include/xo/unit/basis_unit2.hpp index 37724236..ae6d35d5 100644 --- a/include/xo/unit/basis_unit2.hpp +++ b/include/xo/unit/basis_unit2.hpp @@ -13,6 +13,158 @@ namespace xo { using scalefactor_ratio_type = xo::ratio::ratio; + namespace abbrev { + // ----- units for dim::mass ----- + + static + constexpr basis_unit2_abbrev_type + mass_unit2_abbrev(const scalefactor_ratio_type & scalefactor) + { + if (scalefactor.num() == 1) { + switch (scalefactor.den()) { + case 1: + return basis_unit2_abbrev_type::from_chars("g"); + case 1000: + return basis_unit2_abbrev_type::from_chars("mg"); + case 1000000: + return basis_unit2_abbrev_type::from_chars("ug"); + case 1000000000: + return basis_unit2_abbrev_type::from_chars("ng"); + } + } + + if (scalefactor.den() == 1) { + switch (scalefactor.num()) { + case 1000: + return basis_unit2_abbrev_type::from_chars("kg"); + case 1000000: + return basis_unit2_abbrev_type::from_chars("t"); + case 1000000000: + return basis_unit2_abbrev_type::from_chars("kt"); + } + } + + /* e.g. unit of '1000 grams' will have abbrev '1000g' in absence + * of a specialization for scaled_native_unit_abbrev + */ + return (basis_unit2_abbrev_type::from_flatstring + (flatstring_concat + (scalefactor.to_str(), + native_unit2_v[static_cast(dim::mass)].abbrev_str()))); + } + + // ----- units for dim::distance ----- + + static + constexpr basis_unit2_abbrev_type + distance_unit2_abbrev(const scalefactor_ratio_type & scalefactor) + { + if (scalefactor.num() == 1) { + switch (scalefactor.den()) { + case 1: + return basis_unit2_abbrev_type::from_chars("m"); + case 1000: + return basis_unit2_abbrev_type::from_chars("mm"); + case 1000000: + return basis_unit2_abbrev_type::from_chars("um"); + case 1000000000: + return basis_unit2_abbrev_type::from_chars("nm"); + } + } + + if (scalefactor.den() == 1) { + switch (scalefactor.num()) { + case 1000: + return basis_unit2_abbrev_type::from_chars("km"); + case 1000000: + return basis_unit2_abbrev_type::from_chars("Mm"); + case 1000000000: + return basis_unit2_abbrev_type::from_chars("Gm"); + } + } + + /* e.g. unit of '1000 grams' will have abbrev '1000g' in absence + * of a specialization for scaled_native_unit_abbrev + */ + return (basis_unit2_abbrev_type::from_flatstring + (flatstring_concat + (scalefactor.to_str(), + native_unit2_v[static_cast(dim::mass)].abbrev_str()))); + } + + // ----- units for dim::time ----- + + static + constexpr basis_unit2_abbrev_type + time_unit2_abbrev(const scalefactor_ratio_type & scalefactor) + { + if (scalefactor.num() == 1) { + switch (scalefactor.den()) { + case 1: + return basis_unit2_abbrev_type::from_chars("s"); + case 1000: + return basis_unit2_abbrev_type::from_chars("ms"); + case 1000000: + return basis_unit2_abbrev_type::from_chars("us"); + case 1000000000: + return basis_unit2_abbrev_type::from_chars("ns"); + } + } + + if (scalefactor.den() == 1) { + switch (scalefactor.num()) { + case 60: + return basis_unit2_abbrev_type::from_chars("min"); + case 3600: + return basis_unit2_abbrev_type::from_chars("hr"); + case 24*3600: + return basis_unit2_abbrev_type::from_chars("dy"); + case 7*24*3600: + return basis_unit2_abbrev_type::from_chars("wk"); + case 30*24*3600: + return basis_unit2_abbrev_type::from_chars("mo"); + case 250*24*3600: + return basis_unit2_abbrev_type::from_chars("yr250"); + case 360*24*3600: + return basis_unit2_abbrev_type::from_chars("yr360"); + case 365*24*3600: + return basis_unit2_abbrev_type::from_chars("yr365"); + } + } + + /* e.g. unit of '1000 grams' will have abbrev '1000g' in absence + * of a specialization for scaled_native_unit_abbrev + */ + return (basis_unit2_abbrev_type::from_flatstring + (flatstring_concat + (scalefactor.to_str(), + native_unit2_v[static_cast(dim::mass)].abbrev_str()))); + } + + static + constexpr basis_unit2_abbrev_type + basis_unit2_abbrev(dim native_dim, + const scalefactor_ratio_type & scalefactor) + { + switch(native_dim) { + case dim::mass: + return mass_unit2_abbrev(scalefactor); + case dim::distance: + return distance_unit2_abbrev(scalefactor); + case dim::time: + return time_unit2_abbrev(scalefactor); + } + + /* e.g. unit of '1000 grams' will have abbrev '1000g' in absence + * of a specialization for scaled_native_unit_abbrev + */ + return (basis_unit2_abbrev_type::from_flatstring + (flatstring_concat + (scalefactor.to_str(), + native_unit2_v[static_cast(native_dim)].abbrev_str()))); + } + }; /*abbrev*/ + /** @class basis_unit2 * @brief A dimensionless multiple of a single natively-specified basis dimension * @@ -20,6 +172,7 @@ namespace xo { **/ struct basis_unit2 { public: + constexpr basis_unit2() = default; constexpr basis_unit2(dim native_dim, const scalefactor_ratio_type & scalefactor) : native_dim_{native_dim}, scalefactor_{scalefactor} @@ -28,12 +181,27 @@ namespace xo { constexpr dim native_dim() const { return native_dim_; } constexpr const scalefactor_ratio_type & scalefactor() const { return scalefactor_; } + constexpr basis_unit2_abbrev_type abbrev() const { + return abbrev::basis_unit2_abbrev(native_dim_, + scalefactor_); + } + + constexpr basis_unit2 & operator=(const basis_unit2 & x) = default; + /** @brief identifies a native unit, e.g. time (in seconds) **/ - const dim native_dim_; + dim native_dim_ = dim::invalid; /** @brief this unit defined as multiple scalefactor times native unit **/ - const scalefactor_ratio_type scalefactor_; + scalefactor_ratio_type scalefactor_; }; + namespace bu2 { + constexpr basis_unit2 nanogram = basis_unit2(dim::mass, scalefactor_ratio_type(1, 1000000000)); + constexpr basis_unit2 microgram = basis_unit2(dim::mass, scalefactor_ratio_type(1, 1000000)); + constexpr basis_unit2 milligram = basis_unit2(dim::mass, scalefactor_ratio_type(1, 1000)); + constexpr basis_unit2 gram = basis_unit2(dim::mass, scalefactor_ratio_type(1, 1)); + constexpr basis_unit2 kilogram = basis_unit2(dim::mass, scalefactor_ratio_type(1000, 1)); + } + namespace units { /** for runtime work, would like to be able to promptly find special abbreviation * keyed by (native_dim, scalefactor). @@ -92,10 +260,8 @@ namespace xo { // xo::ratio::ratio(InnerScaleNum, InnerScaleDen)); }; - // ----- units for dim::mass ----- - template <> - struct scaled_native_unit2_abbrev { + struct scaled_native_unit2_abbrev { static constexpr const basis_unit2_abbrev_type value = basis_unit2_abbrev_type::from_chars("ng"); }; @@ -199,145 +365,6 @@ namespace xo { constexpr auto scaled_native_unit2_abbrev_v = scaled_native_unit2_abbrev::value; } - /** @class basis_unit2_store - * @brief Store known basis units for runtime - **/ - template - struct basis_unit2_store { - basis_unit2_store() : bu_abbrev_vv_(static_cast(dim::n_dim)) { - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - this->bu_establish_abbrev_for(); - - this->bu_establish_abbrev_for(); - - this->bu_establish_abbrev_for(); - } - - /* e.g. - * [(1/1000000000, "nm"), (1/1000000, "um"), (1/1000, "mm"), (1/1, "m"), (1000/1, "km")] - */ - using native_scale_v = std::vector>; - - /** @brief get basis-unit abbreviation at runtime **/ - basis_unit2_abbrev_type bu_abbrev(dim basis_dim, - const scalefactor_ratio_type & scalefactor) const { - const auto & bu_abbrev_v = bu_abbrev_vv_[static_cast(basis_dim)]; - - std::size_t i_abbrev = bu_abbrev_lub_ix(basis_dim, scalefactor, bu_abbrev_v); - - if ((i_abbrev < bu_abbrev_v.size()) - && (bu_abbrev_v[i_abbrev].first == scalefactor)) - { - return bu_abbrev_v[i_abbrev].second; - } else { - return units::bu_fallback_abbrev(basis_dim, scalefactor); - } - } - - template - void bu_establish_abbrev_for() { - this->bu_establish_abbrev(basis_unit2(BasisDim, - scalefactor_ratio_type(InnerScaleNum, InnerScaleDen)), - units::scaled_native_unit2_abbrev_v); - } - - /** @brief establish abbreviation @p abbrev for basis unit @p bu - **/ - void bu_establish_abbrev(const basis_unit2 & bu, - const basis_unit2_abbrev_type & abbrev) { - - auto & bu_abbrev_v = bu_abbrev_vv_[static_cast(bu.native_dim())]; - - std::int32_t i_abbrev = 0; - - if (!bu_abbrev_v.empty()) { - i_abbrev = bu_abbrev_lub_ix(bu.native_dim(), - bu.scalefactor(), - bu_abbrev_v); - } - - auto entry = std::make_pair(bu.scalefactor(), abbrev); - - if ((i_abbrev < bu_abbrev_v.size()) - && (bu_abbrev_v[i_abbrev].first == bu.scalefactor())) - { - bu_abbrev_v[i_abbrev] = entry; - } else { - bu_abbrev_v.insert(bu_abbrev_v.begin() + i_abbrev, entry); - } - } - - private: - /** @brief get least-upper-bound index position in bu_abbrev_v[] - * - * return value in [0, n] where n = bu_abbrev_v.size() - **/ - static std::size_t bu_abbrev_lub_ix(dim basis_dim, - const scalefactor_ratio_type & scalefactor, - const native_scale_v & bu_abbrev_v) - { - std::size_t n = bu_abbrev_v.size(); - - if (n == 0) - return 0; - - std::size_t lo = 0; - std::size_t hi = n-1; - - if (scalefactor <= bu_abbrev_v[lo].first) - return 0; - - auto cmp = (scalefactor <=> bu_abbrev_v[hi].first); - - if (cmp > 0) - return n; - - if (cmp == 0) - return hi; - - while (hi-lo > 1) { - /* inv: - * bu_abbrev_v[lo].first < scalefactor <= bu_abbrev_v[hi].first - */ - - std::size_t mid = lo + (hi - lo)/2; - - if (scalefactor > bu_abbrev_v[mid].first) - lo = mid; - else - hi = mid; - } - - return hi; - } - - private: - /* bu_abbrev_v[dim] holds known units for native unit dim */ - std::vector bu_abbrev_vv_; - }; - } /*namespace unit*/ } /*namespace xo*/ diff --git a/include/xo/unit/dim_util.hpp b/include/xo/unit/dim_util.hpp index 18086f34..7d369bc2 100644 --- a/include/xo/unit/dim_util.hpp +++ b/include/xo/unit/dim_util.hpp @@ -31,6 +31,20 @@ namespace xo { n_dim }; + inline const char * + dim2str(dim x) + { + switch(x) { + case dim::mass: return "mass"; + case dim::distance: return "distance"; + case dim::time: return "time"; + case dim::currency: return "currency"; + case dim::price: return "price"; + default: break; + } + return "?dim"; + } + static constexpr std::size_t n_dim = static_cast(dim::n_dim); enum class native_unit_id { diff --git a/include/xo/unit/native_bpu2.hpp b/include/xo/unit/native_bpu2.hpp index 2db88bdf..62786d44 100644 --- a/include/xo/unit/native_bpu2.hpp +++ b/include/xo/unit/native_bpu2.hpp @@ -5,7 +5,9 @@ #pragma once +#include "xo/indentlog/print/tag.hpp" #include "basis_unit2.hpp" +#include "dim_iostream.hpp" namespace xo { namespace unit { @@ -13,6 +15,41 @@ namespace xo { using power_ratio_type = xo::ratio::ratio; + namespace abbrev { + using power_abbrev_type = flatstring<16>; + + constexpr power_abbrev_type + flatstring_from_exponent(std::int64_t num, + std::int64_t den) + { + if (den == 1) { + if (num == 1) { + return power_abbrev_type::from_chars(""); + } else { + return (power_abbrev_type::from_flatstring + (flatstring_concat(flatstring("^"), + power_abbrev_type::from_int(num)))); + } + } else { + return (power_abbrev_type::from_flatstring + (flatstring_concat(flatstring("^"), + xo::ratio::make_ratio(num, den) + .to_str()))); + } + } + + static constexpr bpu2_abbrev_type + bpu2_abbrev(dim native_dim, + const scalefactor_ratio_type & scalefactor, + const power_ratio_type & power) + { + return (bpu2_abbrev_type::from_flatstring + (flatstring_concat + (basis_unit2_abbrev(native_dim, scalefactor), + flatstring_from_exponent(power.num(), power.den())))); + } + } + /** @class native_bpu2 * * @brief represent product of a compile-time scale-factor with a rational power of a native unit @@ -23,19 +60,58 @@ namespace xo { template struct bpu2 : basis_unit2 { public: - constexpr bpu2(power_ratio_type power, - dim native_dim, - scalefactor_ratio_type scalefactor) + using ratio_int_type = Int; + + public: + constexpr bpu2() = default; + constexpr bpu2(const basis_unit2 & bu, + const power_ratio_type & power) + : basis_unit2{bu}, + power_{power} + {} + constexpr bpu2(dim native_dim, + const scalefactor_ratio_type & scalefactor, + const power_ratio_type & power) : basis_unit2(native_dim, scalefactor), power_{power} {} + static constexpr bpu2 unit_power(const basis_unit2 & bu) { + return bpu2(bu, power_ratio_type(1,1)); + } + constexpr const power_ratio_type & power() const { return power_; } + /** @brief abbreviation for this dimension + * + * @code + * bpu2(dim::time, + * scalefactor_ratio_type(60,1), + * power_ratio_type(-2,1)).abbrev() => "min^-2" + * @endcode + **/ + constexpr bpu2_abbrev_type abbrev() const + { + return abbrev::bpu2_abbrev(native_dim_, + scalefactor_, + power_); + } + + /* for bpu x, x.reciprocal() represents dimension of 1/x */ + constexpr bpu2 reciprocal() const { + return bpu2(native_dim(), scalefactor(), power_.negate()); + } + /** @brief this unit represents native dimension taken to this power **/ power_ratio_type power_; }; + template + constexpr auto make_unit_power(const basis_unit2 & bu) { + return bpu2::unit_power(bu); + } + +#ifdef NOT_USING template < dim BasisDim, std::int64_t InnerScaleNum, std::int64_t InnerScaleDen, @@ -44,20 +120,12 @@ namespace xo { constexpr bpu2_abbrev_type bpu2_assemble_abbrev_helper() { - return flatstring_concat - (units::scaled_native_unit2_abbrev_v, - flatstring_from_exponent()); - }; - - template < typename BPU > - constexpr auto bpu2_assemble_abbrev(const BPU & bpu) { - // bpu.power(), bpu.native_dim(), bpu.scalefactor() - - return bpu2_assemble_abbrev_helper< - bpu.native_dim(), - bpu.scalefactor().num(), bpu.scalefactor().den(), - bpu.power().num(), bpu.power().den()>; + return (bpu2_abbrev_type::from_flatstring + (flatstring_concat + (units::scaled_native_unit2_abbrev_v, + flatstring_from_exponent()))); }; +#endif } /*namespace unit*/ } /*namespace xo*/ diff --git a/utest/unit.test.cpp b/utest/unit.test.cpp index 2ce3f0e8..9e911699 100644 --- a/utest/unit.test.cpp +++ b/utest/unit.test.cpp @@ -1,14 +1,21 @@ /* @file dimension.test.cpp */ #include "xo/unit/unit.hpp" +#include "xo/unit/Quantity2_iostream.hpp" +#include "xo/unit/Quantity2.hpp" +#include "xo/unit/scaled_unit_iostream.hpp" +#include "xo/unit/natural_unit.hpp" +#include "xo/unit/natural_unit_iostream.hpp" +#include "xo/unit/bpu_store.hpp" +#include "xo/unit/native_bpu2.hpp" +#include "xo/unit/native_bpu2_iostream.hpp" #include "xo/unit/basis_unit2.hpp" #include "xo/unit/dim_util2.hpp" #include "xo/reflect/Reflect.hpp" -#include "xo/cxxutil/demangle.hpp" +//#include "xo/cxxutil/demangle.hpp" #include "xo/indentlog/scope.hpp" #include "xo/indentlog/print/tag.hpp" #include -#include namespace xo { namespace ut { @@ -16,6 +23,9 @@ namespace xo { using xo::reflect::Reflect; + namespace su2 = xo::unit::su2; + + using xo::unit::Quantity2; using xo::unit::dim; using xo::unit::basis_unit2_abbrev_type; using xo::unit::native_unit2; @@ -23,7 +33,20 @@ namespace xo { using xo::unit::scalefactor_ratio_type; using xo::unit::units::scaled_native_unit2_abbrev; using xo::unit::units::scaled_native_unit2_abbrev_v; + using xo::unit::basis_unit2; + using xo::unit::abbrev::basis_unit2_abbrev;; + using xo::unit::bpu2_abbrev_type; + using xo::unit::abbrev::bpu2_abbrev; using xo::unit::basis_unit2_store; + using xo::unit::power_ratio_type; + using xo::unit::abbrev::flatstring_from_exponent; + using xo::unit::bpu2; + using xo::unit::detail::bpu2_rescale; + using xo::unit::detail::bpu2_product; + using xo::unit::natural_unit; + using xo::unit::bpu_array_maker; + using xo::unit::detail::nu_product; + using xo::unit::unit_qty; using xo::unit::native_unit_abbrev_v; using xo::unit::units::scaled_native_unit_abbrev_v; @@ -84,6 +107,76 @@ namespace xo { static_assert(native_unit2_v[static_cast(dim::currency)].native_dim() == dim::currency); static_assert(native_unit2_v[static_cast(dim::price)].native_dim() == dim::price); + log && log(xtag("mass*10^3", basis_unit2_abbrev(dim::mass, scalefactor_ratio_type(1000, 1)))); + + static_assert(basis_unit2_abbrev(dim::mass, scalefactor_ratio_type(1000, 1)) + == basis_unit2_abbrev_type::from_chars("kg")); + + log && log("---------------------"); + + static_assert(basis_unit2(dim::mass, scalefactor_ratio_type(1, 1000000000)).abbrev() + == basis_unit2_abbrev_type::from_chars("ng")); + static_assert(basis_unit2(dim::mass, scalefactor_ratio_type(1, 1000000)).abbrev() + == basis_unit2_abbrev_type::from_chars("ug")); + static_assert(basis_unit2(dim::mass, scalefactor_ratio_type(1, 1000)).abbrev() + == basis_unit2_abbrev_type::from_chars("mg")); + static_assert(basis_unit2(dim::mass, scalefactor_ratio_type(1, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("g")); + static_assert(basis_unit2(dim::mass, scalefactor_ratio_type(1000, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("kg")); + static_assert(basis_unit2(dim::mass, scalefactor_ratio_type(1000000, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("t")); + static_assert(basis_unit2(dim::mass, scalefactor_ratio_type(1000000000, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("kt")); + + log && log(xtag("distance", basis_unit2_abbrev(dim::distance, scalefactor_ratio_type(1, 1)))); + + static_assert(basis_unit2(dim::distance, scalefactor_ratio_type(1, 1000000000)).abbrev() + == basis_unit2_abbrev_type::from_chars("nm")); + static_assert(basis_unit2(dim::distance, scalefactor_ratio_type(1, 1000000)).abbrev() + == basis_unit2_abbrev_type::from_chars("um")); + static_assert(basis_unit2(dim::distance, scalefactor_ratio_type(1, 1000)).abbrev() + == basis_unit2_abbrev_type::from_chars("mm")); + static_assert(basis_unit2(dim::distance, scalefactor_ratio_type(1, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("m")); + static_assert(basis_unit2(dim::distance, scalefactor_ratio_type(1000, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("km")); + static_assert(basis_unit2(dim::distance, scalefactor_ratio_type(1000000, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("Mm")); + static_assert(basis_unit2(dim::distance, scalefactor_ratio_type(1000000000, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("Gm")); + + log && log(xtag("time", basis_unit2_abbrev(dim::time, scalefactor_ratio_type(1, 1)))); + + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(1, 1000000000)).abbrev() + == basis_unit2_abbrev_type::from_chars("ns")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(1, 1000000)).abbrev() + == basis_unit2_abbrev_type::from_chars("us")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(1, 1000000)).abbrev() + == basis_unit2_abbrev_type::from_chars("us")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(1, 1000)).abbrev() + == basis_unit2_abbrev_type::from_chars("ms")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(1, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("s")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(60, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("min")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(3600, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("hr")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(24*3600, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("dy")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(7*24*3600, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("wk")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(30*24*3600, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("mo")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(250*24*3600, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("yr250")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(360*24*3600, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("yr360")); + static_assert(basis_unit2(dim::time, scalefactor_ratio_type(365*24*3600, 1)).abbrev() + == basis_unit2_abbrev_type::from_chars("yr365")); + + log && log("---------------------"); + log && log(xtag("mass*10^-9", scaled_native_unit2_abbrev_v)); log && log(xtag("mass*10^-6", scaled_native_unit2_abbrev_v)); log && log(xtag("mass*10^-3", scaled_native_unit2_abbrev_v)); @@ -122,7 +215,7 @@ namespace xo { } /*TEST_CASE(basis_unit2)*/ TEST_CASE("basis_unit2_store", "[basis_unit2_store]") { - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; // can get bits from /dev/random by uncommenting the 2nd line below //uint64_t seed = xxx; @@ -160,45 +253,112 @@ namespace xo { log && log(xtag("time*360*24*3600", bu_store.bu_abbrev(dim::time, scalefactor_ratio_type(360*24*3600, 1)))); log && log(xtag("time*365*24*3600", bu_store.bu_abbrev(dim::time, scalefactor_ratio_type(365*24*3600, 1)))); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::mass, scalefactor_ratio_type( 1, 1000000000)).c_str(), "ng") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::mass, scalefactor_ratio_type( 1, 1000000)).c_str(), "ug") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::mass, scalefactor_ratio_type( 1, 1000)).c_str(), "mg") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::mass, scalefactor_ratio_type( 1, 1)).c_str(), "g") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::mass, scalefactor_ratio_type( 1000, 1)).c_str(), "kg") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::mass, scalefactor_ratio_type( 1000000, 1)).c_str(), "t") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::mass, scalefactor_ratio_type( 1000000000, 1)).c_str(), "kt") == 0); -#ifdef NOT_USING - log && log(xtag("mass*10^-9", scaled_native_unit2_abbrev_v)); - log && log(xtag("mass*10^-6", scaled_native_unit2_abbrev_v)); - log && log(xtag("mass*10^-3", scaled_native_unit2_abbrev_v)); - log && log(xtag("mass", scaled_native_unit2_abbrev_v)); - log && log(xtag("mass*10^3", scaled_native_unit2_abbrev_v)); - log && log(xtag("mass*10^6", scaled_native_unit2_abbrev_v)); - log && log(xtag("mass*10^9", scaled_native_unit2_abbrev_v)); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::distance, scalefactor_ratio_type( 1, 1000000000)).c_str(), "nm") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::distance, scalefactor_ratio_type( 1, 1000000)).c_str(), "um") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::distance, scalefactor_ratio_type( 1, 1000)).c_str(), "mm") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::distance, scalefactor_ratio_type( 1, 1)).c_str(), "m") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::distance, scalefactor_ratio_type( 1000, 1)).c_str(), "km") == 0); - log && log(xtag("distance*10^-9", scaled_native_unit2_abbrev_v)); - log && log(xtag("distance*10^-6", scaled_native_unit2_abbrev_v)); - log && log(xtag("distance*10^-3", scaled_native_unit2_abbrev_v)); - log && log(xtag("distance", scaled_native_unit2_abbrev_v)); - log && log(xtag("distance*10^3", scaled_native_unit2_abbrev_v)); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type( 1, 1000000000)).c_str(), "ns") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type( 1, 1000000)).c_str(), "us") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type( 1, 1000)).c_str(), "ms") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type( 1, 1)).c_str(), "s") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type( 60, 1)).c_str(), "min") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type( 3600, 1)).c_str(), "hr") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type( 24*3600, 1)).c_str(), "dy") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type(250*24*3600, 1)).c_str(), "yr250") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type(360*24*3600, 1)).c_str(), "yr360") == 0); + REQUIRE(::strcmp(bu_store.bu_abbrev(dim::time, scalefactor_ratio_type(365*24*3600, 1)).c_str(), "yr365") == 0); - log && log(xtag("time*10^-9", scaled_native_unit2_abbrev_v)); - log && log(xtag("time*10^-6", scaled_native_unit2_abbrev_v)); - log && log(xtag("time*10^-3", scaled_native_unit2_abbrev_v)); - log && log(xtag("time", scaled_native_unit2_abbrev_v)); - log && log(xtag("time*60", scaled_native_unit2_abbrev_v)); - log && log(xtag("time*3600", scaled_native_unit2_abbrev_v)); - log && log(xtag("time*24*3600", scaled_native_unit2_abbrev_v)); - log && log(xtag("time*250*24*3600", scaled_native_unit2_abbrev_v)); - log && log(xtag("time*360*24*3600", scaled_native_unit2_abbrev_v)); - log && log(xtag("time*365*24*3600", scaled_native_unit2_abbrev_v)); - - log && log(xtag("currency", scaled_native_unit2_abbrev_v)); - - log && log(xtag("price", scaled_native_unit2_abbrev_v)); - - REQUIRE(xo::unit::units::scaled_native_unit2_abbrev::value == xo::flatstring("g")); - - /* proof that scaled_native_unit2_abbrev::value is constexpr */ - static_assert(scaled_native_unit2_abbrev_v - == basis_unit2_abbrev_type::from_flatstring(xo::flatstring("g"))); -#endif } /*TEST_CASE(basis_unit2_store)*/ + TEST_CASE("flatstring_from_exponent", "[flatstring_from_exponent]") { + constexpr bool c_debug_flag = false; + + // 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.flatstring_from_exponent")); + //log && log("(A)", xtag("foo", foo)); + + log && log(xtag("^-3", flatstring_from_exponent(-3,1))); + log && log(xtag("^-2", flatstring_from_exponent(-2,1))); + log && log(xtag("^-1", flatstring_from_exponent(-1,1))); + log && log(xtag("^-1/2", flatstring_from_exponent(-1,2))); + log && log(xtag("^0", flatstring_from_exponent(0,1))); + log && log(xtag("^1/2", flatstring_from_exponent(1,2))); + log && log(xtag("^1", flatstring_from_exponent(1,1))); + log && log(xtag("^2", flatstring_from_exponent(2,1))); + log && log(xtag("^3", flatstring_from_exponent(3,1))); + + static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(-3,1)) + == flatstring<5>::from_flatstring(flatstring("^-3"))); + static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(-2,1)) + == flatstring<5>::from_flatstring(flatstring("^-2"))); + static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(-1,1)) + == flatstring<5>::from_flatstring(flatstring("^-1"))); + static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(-1,2)) + == flatstring<5>::from_flatstring(flatstring("^(-1/2)"))); + static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(1,2)) + == flatstring<5>::from_flatstring(flatstring("^(1/2)"))); + static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(1,1)) + == flatstring<5>::from_flatstring(flatstring(""))); + static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(2,1)) + == flatstring<5>::from_flatstring(flatstring("^2"))); + static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(3,1)) + == flatstring<5>::from_flatstring(flatstring("^3"))); + } /*TEST_CASE(flatstring_from_exponent)*/ + + TEST_CASE("bpu2_abbrev", "[bpu2_abbrev]") { + 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.bpu2_assemble_abbrev")); + //log && log("(A)", xtag("foo", foo)); + + log && log(xtag("1/(kg*kg)", bpu2_abbrev(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(-2, 1)))); + log && log(xtag("1/kg", bpu2_abbrev(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(-1, 1)))); + log && log(xtag("kg", bpu2_abbrev(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1)))); + log && log(xtag("kg*kg", bpu2_abbrev(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(2, 1)))); + + static_assert(bpu2(dim::mass, scalefactor_ratio_type(1, 1), power_ratio_type(1, 1)).abbrev() + == bpu2_abbrev_type::from_chars("g")); + static_assert(bpu2(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1)).abbrev() + == bpu2_abbrev_type::from_chars("kg")); + static_assert(bpu2(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(-1, 1)).abbrev() + == bpu2_abbrev_type::from_chars("kg^-1")); + static_assert(bpu2(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(-2, 1)).abbrev() + == bpu2_abbrev_type::from_chars("kg^-2")); + + static_assert(bpu2(dim::time, scalefactor_ratio_type(60, 1), power_ratio_type(-2, 1)).abbrev() + == bpu2_abbrev_type::from_chars("min^-2")); + static_assert(bpu2(dim::time, scalefactor_ratio_type(3600, 1), power_ratio_type(-1, 1)).abbrev() + == bpu2_abbrev_type::from_chars("hr^-1")); + static_assert(bpu2(dim::time, scalefactor_ratio_type(24*3600, 1), power_ratio_type(-1, 1)).abbrev() + == bpu2_abbrev_type::from_chars("dy^-1")); + static_assert(bpu2(dim::time, scalefactor_ratio_type(360*24*3600, 1), power_ratio_type(-1, 1)).abbrev() + == bpu2_abbrev_type::from_chars("yr360^-1")); + static_assert(bpu2(dim::time, scalefactor_ratio_type(360*24*3600, 1), power_ratio_type(-1, 2)).abbrev() + == bpu2_abbrev_type::from_chars("yr360^(-1/2)")); + } /*TEST_CASE(bpu2_abbrev)*/ + + TEST_CASE("native_unit_abbrev", "[native_dim_abbrev]") { constexpr bool c_debug_flag = true; @@ -318,9 +478,534 @@ namespace xo { } /*TEST_CASE(native_dim_abbrev)*/ - TEST_CASE("dimension", "[dimension]") { + TEST_CASE("bpu_rescale", "[bpu_rescale]") { 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.bpu_rescale")); + //log && log("(A)", xtag("foo", foo)); + + /* keep spelled-out test. Will generalize to fractional powers when c++26 available */ + { + constexpr auto p = power_ratio_type(1, 1); + + constexpr auto orig_bpu = bpu2(dim::mass, + scalefactor_ratio_type(1000, 1), + power_ratio_type(1, 1)); + static_assert(orig_bpu.native_dim() == dim::mass); + + constexpr auto new_scalefactor = scalefactor_ratio_type(1000000, 1); + + constexpr auto mult = orig_bpu.scalefactor() / new_scalefactor; + static_assert(mult.num() == 1); + static_assert(mult.den() == 1000); + + constexpr auto p_floor = orig_bpu.power().floor(); + static_assert(p_floor == 1); + + constexpr auto p_frac = orig_bpu.power().frac().template to(); + static_assert(p_frac == 0.0); + + constexpr auto outer_sf_exact = mult.power(p_floor); + static_assert(outer_sf_exact.num() == 1); + static_assert(outer_sf_exact.den() == 1000); + + constexpr auto mult_inexact = mult.template to(); + static_assert(mult_inexact == 0.001); + + constexpr auto rr = bpu2_rescale(orig_bpu, scalefactor_ratio_type(1000000, 1)); + + static_assert(rr.bpu_rescaled_.power() == power_ratio_type(1,1)); + static_assert(rr.outer_scale_exact_ == outer_sf_exact); + static_assert(rr.outer_scale_sq_ == 1.0); + } + + /* keep spelled-out test. Will generalize to other fractional powers when c++26 available */ + { + constexpr auto p = power_ratio_type(-1, 2); + + constexpr auto orig_bpu = bpu2(dim::time, + scalefactor_ratio_type(360*24*3600, 1), + power_ratio_type(-1, 2)); + static_assert(orig_bpu.native_dim() == dim::time); + + constexpr auto new_scalefactor = scalefactor_ratio_type(30*24*3600, 1); + + constexpr auto mult = orig_bpu.scalefactor() / new_scalefactor; + log && log(xtag("mult", mult)); + static_assert(mult.num() == 12); + static_assert(mult.den() == 1); + + constexpr auto p_floor = orig_bpu.power().floor(); + static_assert(p_floor == 0); + + constexpr auto p_frac = orig_bpu.power().frac().template to(); + static_assert(p_frac == -0.5); + + constexpr auto outer_sf_exact = mult.power(p_floor); + static_assert(outer_sf_exact.num() == 1); + static_assert(outer_sf_exact.den() == 1); + + constexpr auto mult_inexact = mult.template to(); + static_assert(mult_inexact == 12.0); + + constexpr auto rr = bpu2_rescale(orig_bpu, scalefactor_ratio_type(30*24*3600, 1)); + + log && log(xtag("rr.outer_scale_exact", rr.outer_scale_exact_), + xtag("rr.outer_scale_sq", rr.outer_scale_sq_)); + + static_assert(rr.bpu_rescaled_.power() == power_ratio_type(-1,2)); + static_assert(rr.outer_scale_exact_ == outer_sf_exact); + static_assert(rr.outer_scale_sq_ == 12.0); + } + + /* keep spelled-out test. Will generalize to other fractional powers when c++26 available */ + { + constexpr auto p = power_ratio_type(-3, 2); + + constexpr auto orig_bpu = bpu2(dim::time, + scalefactor_ratio_type(360*24*3600, 1), + power_ratio_type(-3, 2)); + static_assert(orig_bpu.native_dim() == dim::time); + + constexpr auto new_scalefactor = scalefactor_ratio_type(30*24*3600, 1); + + constexpr auto mult = orig_bpu.scalefactor() / new_scalefactor; + log && log(xtag("mult", mult)); + static_assert(mult.num() == 12); + static_assert(mult.den() == 1); + + constexpr auto p_floor = orig_bpu.power().floor(); + static_assert(p_floor == -1); + + constexpr auto p_frac = orig_bpu.power().frac().template to(); + static_assert(p_frac == -0.5); + + constexpr auto outer_sf_exact = mult.power(p_floor); + static_assert(outer_sf_exact.num() == 1); + static_assert(outer_sf_exact.den() == 12); + + constexpr auto mult_inexact = mult.template to(); + static_assert(mult_inexact == 12.0); + + constexpr auto rr = bpu2_rescale(orig_bpu, scalefactor_ratio_type(30*24*3600, 1)); + + log && log(xtag("rr.outer_scale_exact", rr.outer_scale_exact_), + xtag("rr.outer_scale_sq", rr.outer_scale_sq_)); + + static_assert(rr.bpu_rescaled_.power() == power_ratio_type(-3,2)); + static_assert(rr.outer_scale_exact_ == outer_sf_exact); + static_assert(rr.outer_scale_sq_ == 12.0); + } + } /*TEST_CASE(bpu_rescale)*/ + + TEST_CASE("bpu_product", "[bpu_product]") { + 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.bpu_product")); + //log && log("(A)", xtag("foo", foo)); + + { + constexpr auto bpu_x = bpu2(dim::time, + scalefactor_ratio_type(360*24*3600, 1), + power_ratio_type(-3,2)); + static_assert(bpu_x.native_dim() == dim::time); + + constexpr auto bpu_y = bpu2(dim::time, + scalefactor_ratio_type(360*24*3600, 1), + power_ratio_type(1,2)); + static_assert(bpu_y.native_dim() == dim::time); + + constexpr auto bpu_prod = bpu2_product(bpu_x, bpu_y); + + log && log(xtag("bpu_prod.bpu_rescaled", bpu_prod.bpu_rescaled_)); + log && log(xtag("bpu_prod.outer_scale_exact", bpu_prod.outer_scale_exact_)); + log && log(xtag("bpu_prod.outer_scale_sq", bpu_prod.outer_scale_sq_)); + + static_assert(bpu_prod.bpu_rescaled_.native_dim() == dim::time); + static_assert(bpu_prod.bpu_rescaled_.scalefactor() == scalefactor_ratio_type(360*24*3600, 1)); + static_assert(bpu_prod.bpu_rescaled_.power() == power_ratio_type(-1, 1)); + static_assert(bpu_prod.outer_scale_exact_ == scalefactor_ratio_type(1,1)); + static_assert(bpu_prod.outer_scale_sq_ == 1.0); + } + } /*TEST_CASE(bpu_product)*/ + + TEST_CASE("bpu_product2", "[bpu_product]") { + 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.bpu_product2")); + //log && log("(A)", xtag("foo", foo)); + + { + constexpr auto bpu_x = bpu2(dim::time, + scalefactor_ratio_type(360*24*3600, 1), + power_ratio_type(-3,2)); + static_assert(bpu_x.native_dim() == dim::time); + + constexpr auto bpu_y = bpu2(dim::time, + scalefactor_ratio_type(30*24*3600, 1), + power_ratio_type(1,2)); + static_assert(bpu_y.native_dim() == dim::time); + + constexpr auto bpu_prod = bpu2_product(bpu_x, bpu_y); + + log && log(xtag("bpu_prod.bpu_rescaled", bpu_prod.bpu_rescaled_)); + log && log(xtag("bpu_prod.outer_scale_exact", bpu_prod.outer_scale_exact_)); + log && log(xtag("bpu_prod.outer_scale_sq", bpu_prod.outer_scale_sq_)); + + static_assert(bpu_prod.bpu_rescaled_.native_dim() == dim::time); + static_assert(bpu_prod.bpu_rescaled_.scalefactor() == scalefactor_ratio_type(360*24*3600, 1)); + static_assert(bpu_prod.bpu_rescaled_.power() == power_ratio_type(-1, 1)); + static_assert(bpu_prod.outer_scale_exact_ == scalefactor_ratio_type(1,1)); + static_assert(bpu_prod.outer_scale_sq_ == 1.0/12.0); + } + } /*TEST_CASE(bpu_product2)*/ + + TEST_CASE("bpu_array", "[bpu_array]") { + constexpr bool c_debug_flag = false; + + // 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.bpu_array")); + //log && log("(A)", xtag("foo", foo)); + + { + constexpr natural_unit v; + + static_assert(v.n_bpu() == 0); + } + + { + constexpr natural_unit v + = (bpu_array_maker::make_bpu_array + (bpu2(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1)))); + + static_assert(v.n_bpu() == 1); + } + + { + constexpr natural_unit v + = (bpu_array_maker::make_bpu_array + (bpu2(dim::distance, scalefactor_ratio_type(1, 1000), power_ratio_type(2, 1)), + bpu2(dim::mass, scalefactor_ratio_type(1, 1000), power_ratio_type(-1, 1)))); + + static_assert(v.n_bpu() == 2); + } + } /*TEST_CASE(bpu_array)*/ + + TEST_CASE("bpu_array_product0", "[bpu_array_product]") { + 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.bpu_array_product0")); + //log && log("(A)", xtag("foo", foo)); + + { + constexpr natural_unit v + = (bpu_array_maker::make_bpu_array + (bpu2(dim::distance, scalefactor_ratio_type(1, 1000), power_ratio_type(2, 1)), + bpu2(dim::mass, scalefactor_ratio_type(1, 1000), power_ratio_type(-1, 1)))); + + static_assert(v.n_bpu() == 2); + + constexpr bpu2 bpu(dim::time, + scalefactor_ratio_type(250*24*3600, 1), + power_ratio_type(-1, 2)); + + static_assert(bpu.power() == power_ratio_type(-1, 2)); + + constexpr auto prod_rr = nu_product(v, bpu); + + log && log(xtag("prod_rr.bpu_array", prod_rr.natural_unit_)); + log && log(xtag("prod_rr.outer_scale_exact", prod_rr.outer_scale_exact_)); + log && log(xtag("prod_rr.outer_scale_sq", prod_rr.outer_scale_sq_)); + + static_assert(prod_rr.natural_unit_.n_bpu() == 3); + static_assert(prod_rr.natural_unit_[0].native_dim() == dim::distance); + static_assert(prod_rr.natural_unit_[0].scalefactor() == scalefactor_ratio_type(1, 1000)); + static_assert(prod_rr.natural_unit_[0].power() == power_ratio_type(2, 1)); + static_assert(prod_rr.natural_unit_[1].native_dim() == dim::mass); + static_assert(prod_rr.natural_unit_[1].scalefactor() == scalefactor_ratio_type(1, 1000)); + static_assert(prod_rr.natural_unit_[1].power() == power_ratio_type(-1, 1)); + static_assert(prod_rr.natural_unit_[2].native_dim() == dim::time); + static_assert(prod_rr.natural_unit_[2].scalefactor() == scalefactor_ratio_type(250*24*3600, 1)); + static_assert(prod_rr.natural_unit_[2].power() == power_ratio_type(-1, 2)); + static_assert(prod_rr.outer_scale_exact_ == scalefactor_ratio_type(1, 1)); + static_assert(prod_rr.outer_scale_sq_ == 1.0); + } + } /*TEST_CASE(bpu_array_product0)*/ + + TEST_CASE("bpu_array_product1", "[bpu_array_product]") { + 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.bpu_array_product1")); + //log && log("(A)", xtag("foo", foo)); + + { + constexpr natural_unit v + = (bpu_array_maker::make_bpu_array + (bpu2(dim::distance, scalefactor_ratio_type(1, 1000), power_ratio_type(2, 1)), + bpu2(dim::time, scalefactor_ratio_type(30*24*3600, 1), power_ratio_type(-1, 2)))); + + static_assert(v.n_bpu() == 2); + + constexpr bpu2 bpu(dim::time, + scalefactor_ratio_type(360*24*3600, 1), + power_ratio_type(-1, 2)); + + static_assert(bpu.power() == power_ratio_type(-1, 2)); + + constexpr auto prod_rr = nu_product(v, bpu); + + log && log(xtag("prod_rr.bpu_array", prod_rr.natural_unit_)); + log && log(xtag("prod_rr.outer_scale_exact", prod_rr.outer_scale_exact_)); + log && log(xtag("prod_rr.outer_scale_sq", prod_rr.outer_scale_sq_)); + + static_assert(prod_rr.natural_unit_.n_bpu() == 2); + static_assert(prod_rr.natural_unit_[0].native_dim() == dim::distance); + static_assert(prod_rr.natural_unit_[0].scalefactor() == scalefactor_ratio_type(1, 1000)); + static_assert(prod_rr.natural_unit_[0].power() == power_ratio_type(2, 1)); + static_assert(prod_rr.natural_unit_[1].native_dim() == dim::time); + static_assert(prod_rr.natural_unit_[1].scalefactor() == scalefactor_ratio_type(30*24*3600, 1)); + static_assert(prod_rr.natural_unit_[1].power() == power_ratio_type(-1, 1)); + static_assert(prod_rr.outer_scale_exact_ == scalefactor_ratio_type(1, 1)); + static_assert(prod_rr.outer_scale_sq_ == 12.0); + } + } /*TEST_CASE(bpu_array_product1)*/ + + TEST_CASE("bpu_array_product2", "[bpu_array_product]") { + 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.bpu_array_product2")); + //log && log("(A)", xtag("foo", foo)); + + { + constexpr natural_unit v + = (bpu_array_maker::make_bpu_array + (bpu2(dim::distance, scalefactor_ratio_type(1, 1000), power_ratio_type(2, 1)), + bpu2(dim::mass, scalefactor_ratio_type(1, 1000), power_ratio_type(-1, 1)))); + + static_assert(v.n_bpu() == 2); + + constexpr bpu2 bpu(dim::distance, + scalefactor_ratio_type(1, 1000), + power_ratio_type(-1, 1)); + + static_assert(bpu.power() == power_ratio_type(-1, 1)); + + constexpr auto prod_rr = nu_product(v, bpu); + + log && log(xtag("prod_rr.bpu_array", prod_rr.natural_unit_)); + log && log(xtag("prod_rr.outer_scale_exact", prod_rr.outer_scale_exact_)); + log && log(xtag("prod_rr.outer_scale_sq", prod_rr.outer_scale_sq_)); + + static_assert(prod_rr.natural_unit_.n_bpu() == 2); + static_assert(prod_rr.natural_unit_[0].native_dim() == dim::distance); + static_assert(prod_rr.natural_unit_[0].scalefactor() == scalefactor_ratio_type(1, 1000)); + static_assert(prod_rr.natural_unit_[0].power() == power_ratio_type(1, 1)); + static_assert(prod_rr.natural_unit_[1].native_dim() == dim::mass); + static_assert(prod_rr.natural_unit_[1].scalefactor() == scalefactor_ratio_type(1, 1000)); + static_assert(prod_rr.natural_unit_[1].power() == power_ratio_type(-1, 1)); + static_assert(prod_rr.outer_scale_exact_ == scalefactor_ratio_type(1, 1)); + static_assert(prod_rr.outer_scale_sq_ == 1.0); + } + } /*TEST_CASE(bpu_array_product2)*/ + + TEST_CASE("bpu_array_product3", "[bpu_array_product]") { + 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.bpu_array_product3")); + //log && log("(A)", xtag("foo", foo)); + + { + constexpr natural_unit v + = (bpu_array_maker::make_bpu_array + (bpu2(dim::distance, scalefactor_ratio_type(1, 1000), power_ratio_type(2, 1)), + bpu2(dim::mass, scalefactor_ratio_type(1, 1000), power_ratio_type(-1, 1)))); + + static_assert(v.n_bpu() == 2); + + constexpr natural_unit w + = (bpu_array_maker::make_bpu_array + (bpu2(dim::time, scalefactor_ratio_type(30*24*3600, 1), power_ratio_type(-1, 2)))); + + static_assert(w.n_bpu() == 1); + + constexpr auto prod_rr = nu_product(v, w); + + log && log(xtag("prod_rr.bpu_array", prod_rr.natural_unit_)); + log && log(xtag("prod_rr.outer_scale_exact", prod_rr.outer_scale_exact_)); + log && log(xtag("prod_rr.outer_scale_sq", prod_rr.outer_scale_sq_)); + + static_assert(prod_rr.natural_unit_.n_bpu() == 3); + static_assert(prod_rr.natural_unit_[0].native_dim() == dim::distance); + static_assert(prod_rr.natural_unit_[0].scalefactor() == scalefactor_ratio_type(1, 1000)); + static_assert(prod_rr.natural_unit_[0].power() == power_ratio_type(2, 1)); + static_assert(prod_rr.natural_unit_[1].native_dim() == dim::mass); + static_assert(prod_rr.natural_unit_[1].scalefactor() == scalefactor_ratio_type(1, 1000)); + static_assert(prod_rr.natural_unit_[1].power() == power_ratio_type(-1, 1)); + static_assert(prod_rr.natural_unit_[2].native_dim() == dim::time); + static_assert(prod_rr.natural_unit_[2].scalefactor() == scalefactor_ratio_type(30*24*3600, 1)); + static_assert(prod_rr.natural_unit_[2].power() == power_ratio_type(-1, 2)); + static_assert(prod_rr.outer_scale_exact_ == scalefactor_ratio_type(1, 1)); + static_assert(prod_rr.outer_scale_sq_ == 1.0); + } + } /*TEST_CASE(bpu_array_product3)*/ + + TEST_CASE("scaled_unit0", "[scaled_unit0]") { + 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.scaled_unit0")); + //log && log("(A)", xtag("foo", foo)); + + constexpr auto ng = su2::nanogram; + constexpr auto ng2 = ng * ng; + + log && log(xtag("ng", ng)); + log && log(xtag("ng*ng", ng2)); + //log && log(xtag("ng/ng", + + static_assert(ng.natural_unit_.n_bpu() == 1); + static_assert(ng2.natural_unit_.n_bpu() == 1); + } /*TEST_CASE(scaled_unit0)*/ + + TEST_CASE("Quantity", "[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.Quantity")); + //log && log("(A)", xtag("foo", foo)); + + /* not constexpr until c++26 */ + auto ng = unit_qty(su2::nanogram); + + log && log(xtag("ng", ng)); + + REQUIRE(ng.scale() == 1); + } /*TEST_CASE(Quantity)*/ + + TEST_CASE("Quantity2", "[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.Quantity2")); + //log && log("(A)", xtag("foo", foo)); + + /* not constexpr until c++26 */ + Quantity2 ng = unit_qty(su2::nanogram); + auto ng2 = ng * ng; + + log && log(xtag("ng*ng", ng2)); + + REQUIRE(ng2.scale() == 1); + } /*TEST_CASE(Quantity2)*/ + + TEST_CASE("Quantity3", "[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.Quantity3")); + //log && log("(A)", xtag("foo", foo)); + + /* not constexpr until c++26 */ + Quantity2 ng = unit_qty(su2::nanogram); + Quantity2 ug = unit_qty(su2::microgram); + + { + auto prod1 = ng * ug; + log && log(xtag("ng*ug", prod1)); + + /* units will be nanograms, since that's on lhs */ + REQUIRE(prod1.unit().n_bpu() == 1); + REQUIRE(prod1.unit()[0].native_dim() == dim::mass); + REQUIRE(prod1.unit()[0].scalefactor() == scalefactor_ratio_type(1, 1000000000)); + REQUIRE(prod1.unit()[0].power() == power_ratio_type(2, 1)); + REQUIRE(prod1.scale() == 1000); + } + + { + auto prod2 = ug * ng; + log && log(xtag("ug*ng", prod2)); + + REQUIRE(prod2.unit().n_bpu() == 1); + REQUIRE(prod2.unit()[0].native_dim() == dim::mass); + REQUIRE(prod2.unit()[0].native_dim() == dim::mass); + REQUIRE(prod2.unit()[0].scalefactor() == scalefactor_ratio_type(1, 1000000)); + REQUIRE(prod2.unit()[0].power() == power_ratio_type(2, 1)); + REQUIRE(prod2.scale() == 0.001); + } + + //REQUIRE(ng2.scale() == 1); + } /*TEST_CASE(Quantity3)*/ + + TEST_CASE("dimension", "[dimension]") { + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.dimension")); //log && log("(A)", xtag("foo", foo)); @@ -399,7 +1084,7 @@ namespace xo { } TEST_CASE("dimension2", "[dimension2]") { - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; // can get bits from /dev/random by uncommenting the 2nd line below //uint64_t seed = xxx; @@ -424,7 +1109,7 @@ namespace xo { } /*TEST_CASE(dimension2)*/ TEST_CASE("dimension3", "[dimension3]") { - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; // can get bits from /dev/random by uncommenting the 2nd line below //uint64_t seed = xxx;