diff --git a/example/custom_systems.cpp b/example/custom_systems.cpp index b2c3419d..9fe72f4e 100644 --- a/example/custom_systems.cpp +++ b/example/custom_systems.cpp @@ -33,7 +33,7 @@ using namespace units; namespace fps { struct foot : named_unit {}; -struct yard : named_scaled_unit(), foot> {}; +struct yard : named_scaled_unit(), foot> {}; struct dim_length : base_dimension<"L", foot> {}; @@ -54,8 +54,8 @@ using length = quantity; namespace fps { -struct foot : named_scaled_unit(), metre> {}; -struct yard : named_scaled_unit(), foot> {}; +struct foot : named_scaled_unit(), metre> {}; +struct yard : named_scaled_unit(), foot> {}; struct dim_length : base_dimension<"L", foot> {}; @@ -94,10 +94,7 @@ void unknown_dimensions() std::cout << si_fps_area << "\n"; } -std::ostream& operator<<(std::ostream& os, const ratio& r) -{ - return os << "ratio{" << r.num << ", " << r.den << ", " << r.exp << "}"; -} +std::ostream& operator<<(std::ostream& os, const ratio& r) { return os << "ratio{" << r.num << ", " << r.den << "}"; } template std::ostream& operator<<(std::ostream& os, const U& u) diff --git a/src/core/include/units/bits/derived_scaled_unit.h b/src/core/include/units/bits/derived_scaled_unit.h index 5a8b4cd7..ecdaf48f 100644 --- a/src/core/include/units/bits/derived_scaled_unit.h +++ b/src/core/include/units/bits/derived_scaled_unit.h @@ -39,8 +39,7 @@ inline constexpr bool compatible_units, Us...> = (UnitOf constexpr Magnitude auto derived_mag(exponent_list) { - return (as_magnitude<1>() * ... * - pow(Us::mag / dimension_unit::mag)); + return (mag<1>() * ... * pow(Us::mag / dimension_unit::mag)); } template diff --git a/src/core/include/units/bits/ratio_maths.h b/src/core/include/units/bits/ratio_maths.h index d9a6494a..a6cbea4c 100644 --- a/src/core/include/units/bits/ratio_maths.h +++ b/src/core/include/units/bits/ratio_maths.h @@ -39,108 +39,20 @@ template return v < 0 ? -v : v; } -// the following functions enable gcd and related computations on ratios -// with exponents. They avoid overflow. Further information here: -// https://github.com/mpusz/units/issues/62#issuecomment-588152833 - -// Computes (a * b) mod m relies on unsigned integer arithmetic, should not -// overflow -[[nodiscard]] constexpr std::uint64_t mulmod(std::uint64_t a, std::uint64_t b, std::uint64_t m) -{ - std::uint64_t res = 0; - - if (b >= m) { - if (m > UINT64_MAX / 2u) { - b -= m; - } else { - b %= m; - } - } - - while (a != 0) { - if (a & 1) { - if (b >= m - res) { - res -= m; - } - res += b; - } - a >>= 1; - - std::uint64_t temp_b = b; - if (b >= m - b) { - temp_b -= m; - } - b += temp_b; - } - - return res; -} - -// Calculates (a ^ e) mod m , should not overflow. -[[nodiscard]] constexpr std::uint64_t modpow(std::uint64_t a, std::uint64_t e, std::uint64_t m) -{ - a %= m; - std::uint64_t result = 1; - - while (e > 0) { - if (e & 1) { - result = mulmod(result, a, m); - } - a = mulmod(a, a, m); - e >>= 1; - } - return result; -} - -// gcd(a * 10 ^ e, b), should not overflow -[[nodiscard]] constexpr std::intmax_t gcdpow(std::intmax_t a, std::intmax_t e, std::intmax_t b) noexcept -{ - assert(a > 0); - assert(e >= 0); - assert(b > 0); - - // gcd(i, j) = gcd(j, i mod j) for j != 0 Euclid; - // - // gcd(a 10^e, b) = gcd(b, a 10^e mod b) - // - // (a 10^e) mod b -> [ (a mod b) (10^e mod b) ] mod b - - return std::gcd( - b, static_cast(mulmod(static_cast(a % b), - modpow(10, static_cast(e), static_cast(b)), - static_cast(b)))); -} - -constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs) -{ - std::intmax_t tmp = lhs; - lhs = rhs; - rhs = tmp; -} - -// Computes the rational gcd of n1/d1 x 10^e1 and n2/d2 x 10^e2 -[[nodiscard]] constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t e1, std::intmax_t n2, - std::intmax_t d2, std::intmax_t e2) noexcept +// Computes the rational gcd of n1/d1 and n2/d2 +[[nodiscard]] constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t n2, std::intmax_t d2) noexcept { // Short cut for equal ratios - if (n1 == n2 && d1 == d2 && e1 == e2) { - return std::array{n1, d1, e1}; + if (n1 == n2 && d1 == d2) { + return std::array{n1, d1}; } - if (e2 > e1) { - detail::cwap(n1, n2); - detail::cwap(d1, d2); - detail::cwap(e1, e2); - } - - std::intmax_t exp = e2; // minimum - // gcd(a/b,c/d) = gcd(a⋅d, c⋅b) / b⋅d assert(std::numeric_limits::max() / n1 > d2); assert(std::numeric_limits::max() / n2 > d1); - std::intmax_t num = detail::gcdpow(n1 * d2, e1 - e2, n2 * d1); + std::intmax_t num = std::gcd(n1 * d2, n2 * d1); assert(std::numeric_limits::max() / d1 > d2); @@ -148,29 +60,19 @@ constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs) std::intmax_t gcd = std::gcd(num, den); - return std::array{num / gcd, den / gcd, exp}; + return std::array{num / gcd, den / gcd}; } -constexpr void normalize(std::intmax_t& num, std::intmax_t& den, std::intmax_t& exp) +constexpr void normalize(std::intmax_t& num, std::intmax_t& den) { if (num == 0) { den = 1; - exp = 0; return; } std::intmax_t gcd = std::gcd(num, den); num = num * (den < 0 ? -1 : 1) / gcd; den = detail::abs(den) / gcd; - - while (num % 10 == 0) { - num /= 10; - ++exp; - } - while (den % 10 == 0) { - den /= 10; - --exp; - } } [[nodiscard]] constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs) diff --git a/src/core/include/units/bits/unit_text.h b/src/core/include/units/bits/unit_text.h index f546a251..db0cf31a 100644 --- a/src/core/include/units/bits/unit_text.h +++ b/src/core/include/units/bits/unit_text.h @@ -37,7 +37,7 @@ constexpr auto magnitude_text() { constexpr auto exp10 = extract_power_of_10(M); - constexpr Magnitude auto base = M / pow(as_magnitude<10>()); + constexpr Magnitude auto base = M / pow(mag<10>()); constexpr Magnitude auto num = numerator(base); constexpr Magnitude auto den = denominator(base); static_assert(base == num / den, "Printing rational powers, or irrational bases, not yet supported"); @@ -72,7 +72,7 @@ constexpr auto magnitude_text() template constexpr auto prefix_or_magnitude_text() { - if constexpr (M == as_magnitude<1>()) { + if constexpr (M == mag<1>()) { // no ratio/prefix return basic_fixed_string(""); } else { diff --git a/src/core/include/units/chrono.h b/src/core/include/units/chrono.h index 91b4ab6b..d7b900a1 100644 --- a/src/core/include/units/chrono.h +++ b/src/core/include/units/chrono.h @@ -34,7 +34,7 @@ namespace units { template struct quantity_like_traits> { private: - static constexpr auto mag = as_magnitude(); + static constexpr auto mag = ::units::mag(); public: using dimension = isq::si::dim_time; using unit = downcast_unit; @@ -48,7 +48,7 @@ struct clock_origin : point_origin {}; template struct quantity_point_like_traits>> { private: - static constexpr auto mag = as_magnitude(); + static constexpr auto mag = ::units::mag(); public: using origin = clock_origin; using unit = downcast_unit; @@ -75,12 +75,7 @@ constexpr std::intmax_t pow_10(std::intmax_t v) template constexpr auto to_std_ratio_impl() { - if constexpr (R.exp == 0) - return std::ratio{}; - else if constexpr (R.exp > 0) - return std::ratio{}; - else - return std::ratio{}; + return std::ratio{}; } } // namespace detail diff --git a/src/core/include/units/generic/dimensionless.h b/src/core/include/units/generic/dimensionless.h index fc7b97e6..576547e6 100644 --- a/src/core/include/units/generic/dimensionless.h +++ b/src/core/include/units/generic/dimensionless.h @@ -31,7 +31,7 @@ namespace units { struct one : derived_unit {}; -struct percent : named_scaled_unit(), one> {}; +struct percent : named_scaled_unit(), one> {}; /** * @brief Dimension one diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index 1257e132..c81fb538 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -189,9 +189,6 @@ constexpr widen_t compute_base_power(BasePower auto bp) if (bp.power.den != 1) { throw std::invalid_argument{"Rational powers not yet supported"}; } - if (bp.power.exp < 0) { - throw std::invalid_argument{"Unsupported exp value"}; - } if (bp.power.num < 0) { if constexpr (std::is_integral_v) { @@ -201,7 +198,7 @@ constexpr widen_t compute_base_power(BasePower auto bp) } } - auto power = numerator(bp.power); + auto power = bp.power.num; return int_power(static_cast>(bp.get_base()), power); } @@ -344,7 +341,7 @@ inline constexpr bool is_base_power_pack_valid = all_base_powers_valid & constexpr bool is_rational(BasePower auto bp) { - return std::is_integral_v && (bp.power.den == 1) && (bp.power.exp >= 0); + return std::is_integral_v && (bp.power.den == 1); } constexpr bool is_integral(BasePower auto bp) { return is_rational(bp) && bp.power.num > 0; } @@ -498,8 +495,8 @@ namespace detail { template constexpr auto integer_part(magnitude) { - constexpr auto power_num = numerator(BP.power); - constexpr auto power_den = denominator(BP.power); + constexpr auto power_num = BP.power.num; + constexpr auto power_den = BP.power.den; if constexpr (std::is_integral_v && (power_num >= power_den)) { constexpr auto largest_integer_power = [=](BasePower auto bp) { @@ -556,7 +553,7 @@ namespace detail { template constexpr auto remove_positive_power(magnitude m) { - if constexpr (numerator(BP.power) < 0) { + if constexpr (BP.power.num < 0) { return m; } else { return magnitude<>{}; @@ -599,7 +596,7 @@ constexpr auto common_magnitude(magnitude, magnitude) } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// `as_magnitude()` implementation. +// `mag()` implementation. // Sometimes we need to give the compiler a "shortcut" when factorizing large numbers (specifically, numbers whose // _first factor_ is very large). If we don't, we can run into limits on the number of constexpr steps or iterations. @@ -650,10 +647,19 @@ inline constexpr auto prime_factorization_v = prime_factorization::value; */ template requires(R.num > 0) -constexpr Magnitude auto as_magnitude() +constexpr Magnitude auto mag() { - return pow(detail::prime_factorization_v<10>) * detail::prime_factorization_v / - detail::prime_factorization_v; + return detail::prime_factorization_v / detail::prime_factorization_v; +} + +/** + * @brief Create a Magnitude which is some rational number raised to a rational power. + */ +template + requires(Base.num > 0) +constexpr Magnitude auto mag_power() +{ + return pow(mag()); } namespace detail { @@ -663,7 +669,7 @@ constexpr ratio get_power(T base, magnitude) return ((BPs.get_base() == base ? BPs.power : ratio{0}) + ... + ratio{0}); } -constexpr std::intmax_t integer_part(ratio r) { return numerator(r) / denominator(r); } +constexpr std::intmax_t integer_part(ratio r) { return r.num / r.den; } constexpr std::intmax_t extract_power_of_10(Magnitude auto m) { diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index 6f9f9d0c..3b45cba2 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -444,7 +444,7 @@ public: }; // CTAD -#if !UNITS_COMP_CLANG || UNITS_COMP_CLANG > 15 +#if !UNITS_COMP_CLANG || UNITS_COMP_CLANG > 16 template explicit(false) quantity(Rep&&)->quantity; #endif diff --git a/src/core/include/units/ratio.h b/src/core/include/units/ratio.h index b57ce06d..d0bd8ec3 100644 --- a/src/core/include/units/ratio.h +++ b/src/core/include/units/ratio.h @@ -43,42 +43,28 @@ constexpr ratio inverse(const ratio& r); /** * @brief Provides compile-time rational arithmetic support. * - * This class is really similar to @c std::ratio but gets an additional `Exp` - * template parameter that defines the exponent of the ratio. Another important - * difference is the fact that the objects of that class are used as class NTTPs - * rather then a type template parameter kind. + * This class is really similar to @c std::ratio. An important difference is the fact that the objects of that class + * are used as class NTTPs rather then a type template parameter kind. */ struct ratio { std::intmax_t num; std::intmax_t den; - std::intmax_t exp; - constexpr explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1, std::intmax_t e = 0) : num(n), den(d), exp(e) + constexpr explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1) : num(n), den(d) { gsl_Expects(den != 0); - detail::normalize(num, den, exp); + detail::normalize(num, den); } [[nodiscard]] friend constexpr bool operator==(const ratio&, const ratio&) = default; [[nodiscard]] friend constexpr auto operator<=>(const ratio& lhs, const ratio& rhs) { return (lhs - rhs).num <=> 0; } - [[nodiscard]] friend constexpr ratio operator-(const ratio& r) { return ratio(-r.num, r.den, r.exp); } + [[nodiscard]] friend constexpr ratio operator-(const ratio& r) { return ratio(-r.num, r.den); } [[nodiscard]] friend constexpr ratio operator+(ratio lhs, ratio rhs) { - // First, get the inputs into a common exponent. - const auto common_exp = std::min(lhs.exp, rhs.exp); - auto commonify = [common_exp](ratio& r) { - while (r.exp > common_exp) { - r.num *= 10; - --r.exp; - } - }; - commonify(lhs); - commonify(rhs); - - return ratio{lhs.num * rhs.den + lhs.den * rhs.num, lhs.den * rhs.den, common_exp}; + return ratio{lhs.num * rhs.den + lhs.den * rhs.num, lhs.den * rhs.den}; } [[nodiscard]] friend constexpr ratio operator-(const ratio& lhs, const ratio& rhs) { return lhs + (-rhs); } @@ -88,96 +74,27 @@ struct ratio { const std::intmax_t gcd1 = std::gcd(lhs.num, rhs.den); const std::intmax_t gcd2 = std::gcd(rhs.num, lhs.den); return ratio(detail::safe_multiply(lhs.num / gcd1, rhs.num / gcd2), - detail::safe_multiply(lhs.den / gcd2, rhs.den / gcd1), lhs.exp + rhs.exp); + detail::safe_multiply(lhs.den / gcd2, rhs.den / gcd1)); } [[nodiscard]] friend constexpr ratio operator/(const ratio& lhs, const ratio& rhs) { return lhs * inverse(rhs); } - - [[nodiscard]] friend constexpr std::intmax_t numerator(const ratio& r) - { - std::intmax_t true_num = r.num; - for (auto i = r.exp; i > 0; --i) { - true_num *= 10; - } - return true_num; - } - - [[nodiscard]] friend constexpr std::intmax_t denominator(const ratio& r) - { - std::intmax_t true_den = r.den; - for (auto i = r.exp; i < 0; ++i) { - true_den *= 10; - } - return true_den; - } }; -[[nodiscard]] constexpr ratio inverse(const ratio& r) { return ratio(r.den, r.num, -r.exp); } +[[nodiscard]] constexpr ratio inverse(const ratio& r) { return ratio(r.den, r.num); } -[[nodiscard]] constexpr bool is_integral(const ratio& r) -{ - if (r.exp < 0) { - return false; - } else { - return detail::gcdpow(r.num, r.exp, r.den) == r.den; - } -} +[[nodiscard]] constexpr bool is_integral(const ratio& r) { return r.num % r.den == 0; } -namespace detail { - -[[nodiscard]] constexpr auto make_exp_align(const ratio& r, std::intmax_t alignment) -{ - gsl_Expects(alignment > 0); - const std::intmax_t rem = r.exp % alignment; - - if (rem == 0) { // already aligned - return std::array{r.num, r.den, r.exp}; - } - - if (r.exp > 0) { // remainder is positive - return std::array{r.num * ipow10(rem), r.den, r.exp - rem}; - } - - // remainder is negative - return std::array{r.num, r.den * ipow10(-rem), r.exp - rem}; -} - -template - requires gt_zero -[[nodiscard]] constexpr ratio root(const ratio& r) -{ - if constexpr (N == 1) { - return r; - } else { - if (r.num == 0) { - return ratio(0); - } - - const auto aligned = make_exp_align(r, N); - return ratio(iroot(aligned[0]), iroot(aligned[1]), aligned[2] / N); - } -} - -} // namespace detail - -template - requires detail::non_zero +template [[nodiscard]] constexpr ratio pow(const ratio& r) { if constexpr (Num == 0) { return ratio(1); - } else if constexpr (Num == Den) { + } else if constexpr (Num == 1) { return r; } else { - // simplify factors first and compute power for positive exponent - constexpr std::intmax_t gcd = std::gcd(Num, Den); - constexpr std::intmax_t num = detail::abs(Num / gcd); - constexpr std::intmax_t den = detail::abs(Den / gcd); + const ratio result = detail::pow_impl(r); - // integer root loses precision so do pow first - const ratio result = detail::root(detail::pow_impl(r)); - - if constexpr (Num * Den < 0) { // account for negative exponent + if constexpr (Num < 0) { // account for negative exponent return inverse(result); } else { return result; @@ -185,15 +102,11 @@ template } } -[[nodiscard]] constexpr ratio sqrt(const ratio& r) { return pow<1, 2>(r); } - -[[nodiscard]] constexpr ratio cbrt(const ratio& r) { return pow<1, 3>(r); } - // common_ratio [[nodiscard]] constexpr ratio common_ratio(const ratio& r1, const ratio& r2) { - const auto res = detail::gcd_frac(r1.num, r1.den, r1.exp, r2.num, r2.den, r2.exp); - return ratio(res[0], res[1], res[2]); + const auto res = detail::gcd_frac(r1.num, r1.den, r2.num, r2.den); + return ratio(res[0], res[1]); } } // namespace units diff --git a/src/core/include/units/unit.h b/src/core/include/units/unit.h index 52b9779c..59e8c327 100644 --- a/src/core/include/units/unit.h +++ b/src/core/include/units/unit.h @@ -80,7 +80,7 @@ struct same_unit_reference : is_same -struct named_unit : downcast_dispatch(), Child>> { +struct named_unit : downcast_dispatch(), Child>> { static constexpr auto symbol = Symbol; }; @@ -126,7 +126,7 @@ struct prefixed_unit : downcast_dispatch -struct derived_unit : downcast_dispatch(), Child>> {}; +struct derived_unit : downcast_dispatch(), Child>> {}; /** * @brief A unit with a deduced ratio and symbol diff --git a/src/systems/isq-iec80000/include/units/isq/iec80000/binary_prefixes.h b/src/systems/isq-iec80000/include/units/isq/iec80000/binary_prefixes.h index 25fdaaa9..a9fe73dd 100644 --- a/src/systems/isq-iec80000/include/units/isq/iec80000/binary_prefixes.h +++ b/src/systems/isq-iec80000/include/units/isq/iec80000/binary_prefixes.h @@ -26,13 +26,13 @@ namespace units::isq::iec80000 { -struct kibi : prefix(as_magnitude<2>())> {}; -struct mebi : prefix(as_magnitude<2>())> {}; -struct gibi : prefix(as_magnitude<2>())> {}; -struct tebi : prefix(as_magnitude<2>())> {}; -struct pebi : prefix(as_magnitude<2>())> {}; -struct exbi : prefix(as_magnitude<2>())> {}; -struct zebi : prefix(as_magnitude<2>())> {}; -struct yobi : prefix(as_magnitude<2>())> {}; +struct kibi : prefix(mag<2>())> {}; +struct mebi : prefix(mag<2>())> {}; +struct gibi : prefix(mag<2>())> {}; +struct tebi : prefix(mag<2>())> {}; +struct pebi : prefix(mag<2>())> {}; +struct exbi : prefix(mag<2>())> {}; +struct zebi : prefix(mag<2>())> {}; +struct yobi : prefix(mag<2>())> {}; } // namespace units::isq::iec80000 diff --git a/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h b/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h index eaf7a7ca..2ca2f0d7 100644 --- a/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h +++ b/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h @@ -53,7 +53,7 @@ struct tebibit : prefixed_unit {}; struct pebibit : prefixed_unit {}; struct exbibit : prefixed_unit {}; -struct byte : named_scaled_unit(), bit> {}; +struct byte : named_scaled_unit(), bit> {}; struct kilobyte : prefixed_unit {}; struct megabyte : prefixed_unit {}; diff --git a/src/systems/si-fps/include/units/isq/si/fps/force.h b/src/systems/si-fps/include/units/isq/si/fps/force.h index a026bd79..f8569719 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/force.h +++ b/src/systems/si-fps/include/units/isq/si/fps/force.h @@ -40,7 +40,7 @@ namespace units::isq::si::fps { struct poundal : named_unit {}; // https://en.wikipedia.org/wiki/Pound_(force) -struct pound_force : named_scaled_unit(), poundal> {}; +struct pound_force : named_scaled_unit(), poundal> {}; struct kilopound_force : prefixed_unit {}; diff --git a/src/systems/si-fps/include/units/isq/si/fps/length.h b/src/systems/si-fps/include/units/isq/si/fps/length.h index 04a9e930..adc29a8d 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/length.h +++ b/src/systems/si-fps/include/units/isq/si/fps/length.h @@ -48,7 +48,7 @@ struct thousandth : alias_unit {}; struct kiloyard : prefixed_unit {}; -struct nautical_mile : named_scaled_unit(), yard> {}; +struct nautical_mile : named_scaled_unit(), yard> {}; struct dim_length : isq::dim_length {}; diff --git a/src/systems/si-fps/include/units/isq/si/fps/mass.h b/src/systems/si-fps/include/units/isq/si/fps/mass.h index 16b23f0a..246aba06 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/mass.h +++ b/src/systems/si-fps/include/units/isq/si/fps/mass.h @@ -35,28 +35,28 @@ namespace units::isq::si::fps { // https://en.wikipedia.org/wiki/Pound_(mass) -struct pound : named_scaled_unit(), si::kilogram> {}; +struct pound : named_scaled_unit(), si::kilogram> {}; struct dim_mass : isq::dim_mass {}; template U, Representation Rep = double> using mass = quantity; -struct grain : named_scaled_unit(), pound> {}; +struct grain : named_scaled_unit(), pound> {}; -struct dram : named_scaled_unit(), pound> {}; +struct dram : named_scaled_unit(), pound> {}; -struct ounce : named_scaled_unit(), pound> {}; +struct ounce : named_scaled_unit(), pound> {}; -struct stone : named_scaled_unit(), pound> {}; +struct stone : named_scaled_unit(), pound> {}; -struct quarter : named_scaled_unit(), pound> {}; +struct quarter : named_scaled_unit(), pound> {}; -struct hundredweight : named_scaled_unit(), pound> {}; +struct hundredweight : named_scaled_unit(), pound> {}; -struct short_ton : named_scaled_unit(), pound> {}; +struct short_ton : named_scaled_unit(), pound> {}; -struct long_ton : named_scaled_unit(), pound> {}; +struct long_ton : named_scaled_unit(), pound> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-fps/include/units/isq/si/fps/power.h b/src/systems/si-fps/include/units/isq/si/fps/power.h index 931c08f4..85930563 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/power.h +++ b/src/systems/si-fps/include/units/isq/si/fps/power.h @@ -42,7 +42,7 @@ struct dim_power : isq::dim_power {}; -struct horse_power : named_scaled_unit(), foot_pound_force_per_second> {}; +struct horse_power : named_scaled_unit(), foot_pound_force_per_second> {}; template U, Representation Rep = double> using power = quantity; diff --git a/src/systems/si-fps/include/units/isq/si/fps/pressure.h b/src/systems/si-fps/include/units/isq/si/fps/pressure.h index 4b036fc1..e155d961 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/pressure.h +++ b/src/systems/si-fps/include/units/isq/si/fps/pressure.h @@ -44,11 +44,10 @@ template U, Representation Rep = double> using pressure = quantity; struct pound_force_per_foot_sq : - named_scaled_unit(), - poundal_per_foot_sq> {}; + named_scaled_unit(), poundal_per_foot_sq> {}; struct pound_force_per_inch_sq : - named_scaled_unit(), pound_force_per_foot_sq> {}; + named_scaled_unit(), pound_force_per_foot_sq> {}; struct kilopound_force_per_inch_sq : prefixed_unit {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/area.h b/src/systems/si-hep/include/units/isq/si/hep/area.h index e08b59eb..65130f8a 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/area.h +++ b/src/systems/si-hep/include/units/isq/si/hep/area.h @@ -37,7 +37,7 @@ namespace units::isq::si::hep { // effective cross-sectional area according to EU council directive 80/181/EEC // https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:01980L0181-20090527#page=10 // https://www.fedlex.admin.ch/eli/cc/1994/3109_3109_3109/de -struct barn : named_scaled_unit(), square_metre> {}; +struct barn : named_scaled_unit(), square_metre> {}; struct yocto_barn : prefixed_unit {}; struct zepto_barn : prefixed_unit {}; struct atto_barn : prefixed_unit {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/mass.h b/src/systems/si-hep/include/units/isq/si/hep/mass.h index e4a895e0..cf97b869 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/mass.h +++ b/src/systems/si-hep/include/units/isq/si/hep/mass.h @@ -44,7 +44,7 @@ namespace units::isq::si::hep { struct eV_per_c2 : named_scaled_unit(), kilogram> {}; + mag() * mag_power<10, -35>(), kilogram> {}; struct feV_per_c2 : prefixed_unit {}; struct peV_per_c2 : prefixed_unit {}; struct neV_per_c2 : prefixed_unit {}; @@ -60,11 +60,14 @@ struct PeV_per_c2 : prefixed_unit {}; struct EeV_per_c2 : prefixed_unit {}; struct YeV_per_c2 : prefixed_unit {}; struct electron_mass : - named_scaled_unit(), kilogram> {}; + named_scaled_unit() * mag_power<10, -31>(), + kilogram> {}; struct proton_mass : - named_scaled_unit(), kilogram> {}; + named_scaled_unit() * mag_power<10, -27>(), + kilogram> {}; struct neutron_mass : - named_scaled_unit(), kilogram> {}; + named_scaled_unit() * mag_power<10, -27>(), + kilogram> {}; struct dim_mass : isq::dim_mass {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/momentum.h b/src/systems/si-hep/include/units/isq/si/hep/momentum.h index c6791501..a03ae821 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/momentum.h +++ b/src/systems/si-hep/include/units/isq/si/hep/momentum.h @@ -41,7 +41,7 @@ namespace units::isq::si::hep { struct kilogram_metre_per_second : derived_unit {}; struct eV_per_c : - named_scaled_unit(), + named_scaled_unit() * mag_power<10, -35>(), kilogram_metre_per_second> {}; struct feV_per_c : prefixed_unit {}; struct peV_per_c : prefixed_unit {}; diff --git a/src/systems/si-iau/include/units/isq/si/iau/length.h b/src/systems/si-iau/include/units/isq/si/iau/length.h index d2e184a1..974dd8fc 100644 --- a/src/systems/si-iau/include/units/isq/si/iau/length.h +++ b/src/systems/si-iau/include/units/isq/si/iau/length.h @@ -36,13 +36,13 @@ namespace units::isq::si::iau { // https://en.wikipedia.org/wiki/Light-year -struct light_year : named_scaled_unit(), si::metre> {}; +struct light_year : named_scaled_unit(), si::metre> {}; // https://en.wikipedia.org/wiki/Parsec -struct parsec : named_scaled_unit(), si::metre> {}; +struct parsec : named_scaled_unit(), si::metre> {}; // https://en.wikipedia.org/wiki/Angstrom -struct angstrom : named_scaled_unit(), si::metre> {}; +struct angstrom : named_scaled_unit(), si::metre> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-imperial/include/units/isq/si/imperial/length.h b/src/systems/si-imperial/include/units/isq/si/imperial/length.h index 5f4be435..f6c278f4 100644 --- a/src/systems/si-imperial/include/units/isq/si/imperial/length.h +++ b/src/systems/si-imperial/include/units/isq/si/imperial/length.h @@ -35,10 +35,10 @@ namespace units::isq::si::imperial { // https://en.wikipedia.org/wiki/Chain_(unit) -struct chain : named_scaled_unit(), si::international::yard> {}; +struct chain : named_scaled_unit(), si::international::yard> {}; // https://en.wikipedia.org/wiki/Rod_(unit) -struct rod : named_scaled_unit(), chain> {}; +struct rod : named_scaled_unit(), chain> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-international/include/units/isq/si/international/length.h b/src/systems/si-international/include/units/isq/si/international/length.h index b61bd2cf..3940cb34 100644 --- a/src/systems/si-international/include/units/isq/si/international/length.h +++ b/src/systems/si-international/include/units/isq/si/international/length.h @@ -37,30 +37,30 @@ namespace units::isq::si::international { // si::international yard // https://en.wikipedia.org/wiki/International_yard_and_pound -struct yard : named_scaled_unit(), si::metre> {}; +struct yard : named_scaled_unit(), si::metre> {}; // si::international foot // https://en.wikipedia.org/wiki/Foot_(unit)#International_foot -struct foot : named_scaled_unit(), yard> {}; +struct foot : named_scaled_unit(), yard> {}; // https://en.wikipedia.org/wiki/Fathom#International_fathom -struct fathom : named_scaled_unit(), yard> {}; +struct fathom : named_scaled_unit(), yard> {}; // si::international inch // https://en.wikipedia.org/wiki/Inch#Equivalences -struct inch : named_scaled_unit(), yard> {}; +struct inch : named_scaled_unit(), yard> {}; // intrnational mile // https://en.wikipedia.org/wiki/Mile#International_mile -struct mile : named_scaled_unit(), si::kilometre> {}; +struct mile : named_scaled_unit(), si::kilometre> {}; // si::international nautical mile // https://en.wikipedia.org/wiki/Nautical_mile -struct nautical_mile : named_scaled_unit(), si::metre> {}; +struct nautical_mile : named_scaled_unit(), si::metre> {}; // thou // https://en.wikipedia.org/wiki/Thousandth_of_an_inch -struct thou : named_scaled_unit(), inch> {}; +struct thou : named_scaled_unit(), inch> {}; // mil - different name for thou // https://en.wikipedia.org/wiki/Thousandth_of_an_inch diff --git a/src/systems/si-typographic/include/units/isq/si/typographic/length.h b/src/systems/si-typographic/include/units/isq/si/typographic/length.h index e69c31c6..e5b409c6 100644 --- a/src/systems/si-typographic/include/units/isq/si/typographic/length.h +++ b/src/systems/si-typographic/include/units/isq/si/typographic/length.h @@ -37,12 +37,13 @@ namespace units::isq::si::typographic { // TODO Conflicts with (https://en.wikipedia.org/wiki/Pica_(typography)), verify correctness of below conversion factors // and provide hyperlinks to definitions -struct pica_comp : - named_scaled_unit(), si::metre> {}; -struct pica_prn : named_scaled_unit(), si::metre> {}; +struct pica_comp : named_scaled_unit() * mag_power<10, -9>(), si::metre> {}; +struct pica_prn : + named_scaled_unit() * mag_power<10, -3>(), si::metre> {}; struct point_comp : - named_scaled_unit(), si::metre> {}; -struct point_prn : named_scaled_unit(), si::metre> {}; + named_scaled_unit() * mag_power<10, -4>(), si::metre> {}; +struct point_prn : + named_scaled_unit() * mag_power<10, -4>(), si::metre> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-uscs/include/units/isq/si/uscs/length.h b/src/systems/si-uscs/include/units/isq/si/uscs/length.h index fe4eb9f1..e2dafbb5 100644 --- a/src/systems/si-uscs/include/units/isq/si/uscs/length.h +++ b/src/systems/si-uscs/include/units/isq/si/uscs/length.h @@ -36,14 +36,14 @@ namespace units::isq::si::uscs { // https://en.wikipedia.org/wiki/Foot_(unit)#US_survey_foot // https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6 -struct foot : named_scaled_unit(), si::metre> {}; +struct foot : named_scaled_unit(), si::metre> {}; // https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6 -struct fathom : named_scaled_unit(), foot> {}; +struct fathom : named_scaled_unit(), foot> {}; // https://en.wikipedia.org/wiki/Mile#U.S._survey_mile // https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6 -struct mile : named_scaled_unit(), foot> {}; +struct mile : named_scaled_unit(), foot> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si/include/units/isq/si/catalytic_activity.h b/src/systems/si/include/units/isq/si/catalytic_activity.h index 07ca426f..926705d6 100644 --- a/src/systems/si/include/units/isq/si/catalytic_activity.h +++ b/src/systems/si/include/units/isq/si/catalytic_activity.h @@ -58,7 +58,7 @@ struct exakatal : prefixed_unit {}; struct zettakatal : prefixed_unit {}; struct yottakatal : prefixed_unit {}; -struct enzyme_unit : named_scaled_unit(), katal> {}; +struct enzyme_unit : named_scaled_unit() * mag_power<10, -6>(), katal> {}; struct dim_catalytic_activity : isq::dim_catalytic_activity {}; diff --git a/src/systems/si/include/units/isq/si/energy.h b/src/systems/si/include/units/isq/si/energy.h index cf0eba26..7511c4d0 100644 --- a/src/systems/si/include/units/isq/si/energy.h +++ b/src/systems/si/include/units/isq/si/energy.h @@ -56,7 +56,7 @@ struct yottajoule : prefixed_unit {}; // N.B. electron charge (and eV) is an exact constant: // https://www.bipm.org/documents/20126/41483022/SI-Brochure-9.pdf#page=147 struct electronvolt : - named_scaled_unit(), joule> {}; + named_scaled_unit() * mag_power<10, -19>(), joule> {}; struct gigaelectronvolt : prefixed_unit {}; struct dim_energy : isq::dim_energy {}; diff --git a/src/systems/si/include/units/isq/si/length.h b/src/systems/si/include/units/isq/si/length.h index aefebdbb..6585ed92 100644 --- a/src/systems/si/include/units/isq/si/length.h +++ b/src/systems/si/include/units/isq/si/length.h @@ -56,7 +56,7 @@ struct exametre : prefixed_unit {}; struct zettametre : prefixed_unit {}; struct yottametre : prefixed_unit {}; -struct astronomical_unit : named_scaled_unit(), metre> {}; +struct astronomical_unit : named_scaled_unit(), metre> {}; struct dim_length : isq::dim_length {}; diff --git a/src/systems/si/include/units/isq/si/luminous_flux.h b/src/systems/si/include/units/isq/si/luminous_flux.h index f2b30290..a1de8d48 100644 --- a/src/systems/si/include/units/isq/si/luminous_flux.h +++ b/src/systems/si/include/units/isq/si/luminous_flux.h @@ -36,7 +36,7 @@ namespace units::isq::si { // TODO Is this correct? Should we account for steradian here? How? -struct lumen : named_scaled_unit(), watt> {}; +struct lumen : named_scaled_unit(), watt> {}; using dim_luminous_flux = dim_power; diff --git a/src/systems/si/include/units/isq/si/magnetic_induction.h b/src/systems/si/include/units/isq/si/magnetic_induction.h index 74bd7ca6..529a7f9a 100644 --- a/src/systems/si/include/units/isq/si/magnetic_induction.h +++ b/src/systems/si/include/units/isq/si/magnetic_induction.h @@ -56,7 +56,7 @@ struct exatesla : prefixed_unit {}; struct zettatesla : prefixed_unit {}; struct yottatesla : prefixed_unit {}; -struct gauss : named_scaled_unit(), tesla> {}; +struct gauss : named_scaled_unit(), tesla> {}; struct dim_magnetic_induction : isq::dim_magnetic_induction {}; diff --git a/src/systems/si/include/units/isq/si/mass.h b/src/systems/si/include/units/isq/si/mass.h index 53a574f4..d57069d8 100644 --- a/src/systems/si/include/units/isq/si/mass.h +++ b/src/systems/si/include/units/isq/si/mass.h @@ -79,7 +79,8 @@ struct zettatonne : prefixed_unit {}; struct yottatonne : prefixed_unit {}; struct dalton : - named_scaled_unit(), kilogram> {}; + named_scaled_unit() * mag_power<10, -27>(), + kilogram> {}; struct dim_mass : isq::dim_mass {}; diff --git a/src/systems/si/include/units/isq/si/prefixes.h b/src/systems/si/include/units/isq/si/prefixes.h index 5ee1ec04..562370b6 100644 --- a/src/systems/si/include/units/isq/si/prefixes.h +++ b/src/systems/si/include/units/isq/si/prefixes.h @@ -27,26 +27,26 @@ namespace units::isq::si { // clang-format off -struct yocto : prefix(as_magnitude<10>())> {}; -struct zepto : prefix(as_magnitude<10>())> {}; -struct atto : prefix(as_magnitude<10>())> {}; -struct femto : prefix(as_magnitude<10>())> {}; -struct pico : prefix(as_magnitude<10>())> {}; -struct nano : prefix(as_magnitude<10>())> {}; -struct micro : prefix(as_magnitude<10>())> {}; -struct milli : prefix(as_magnitude<10>())> {}; -struct centi : prefix(as_magnitude<10>())> {}; -struct deci : prefix(as_magnitude<10>())> {}; -struct deca : prefix(as_magnitude<10>())> {}; -struct hecto : prefix(as_magnitude<10>())> {}; -struct kilo : prefix(as_magnitude<10>())> {}; -struct mega : prefix(as_magnitude<10>())> {}; -struct giga : prefix(as_magnitude<10>())> {}; -struct tera : prefix(as_magnitude<10>())> {}; -struct peta : prefix(as_magnitude<10>())> {}; -struct exa : prefix(as_magnitude<10>())> {}; -struct zetta : prefix(as_magnitude<10>())> {}; -struct yotta : prefix(as_magnitude<10>())> {}; +struct yocto : prefix(mag<10>())> {}; +struct zepto : prefix(mag<10>())> {}; +struct atto : prefix(mag<10>())> {}; +struct femto : prefix(mag<10>())> {}; +struct pico : prefix(mag<10>())> {}; +struct nano : prefix(mag<10>())> {}; +struct micro : prefix(mag<10>())> {}; +struct milli : prefix(mag<10>())> {}; +struct centi : prefix(mag<10>())> {}; +struct deci : prefix(mag<10>())> {}; +struct deca : prefix(mag<10>())> {}; +struct hecto : prefix(mag<10>())> {}; +struct kilo : prefix(mag<10>())> {}; +struct mega : prefix(mag<10>())> {}; +struct giga : prefix(mag<10>())> {}; +struct tera : prefix(mag<10>())> {}; +struct peta : prefix(mag<10>())> {}; +struct exa : prefix(mag<10>())> {}; +struct zetta : prefix(mag<10>())> {}; +struct yotta : prefix(mag<10>())> {}; // clang-format on } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/time.h b/src/systems/si/include/units/isq/si/time.h index 17f47804..f023377a 100644 --- a/src/systems/si/include/units/isq/si/time.h +++ b/src/systems/si/include/units/isq/si/time.h @@ -43,9 +43,9 @@ struct picosecond : prefixed_unit {}; struct nanosecond : prefixed_unit {}; struct microsecond : prefixed_unit {}; struct millisecond : prefixed_unit {}; -struct minute : named_scaled_unit(), second> {}; -struct hour : named_scaled_unit(), minute> {}; -struct day : named_scaled_unit(), hour> {}; +struct minute : named_scaled_unit(), second> {}; +struct hour : named_scaled_unit(), minute> {}; +struct day : named_scaled_unit(), hour> {}; struct dim_time : isq::dim_time {}; diff --git a/test/unit_test/runtime/fmt_test.cpp b/test/unit_test/runtime/fmt_test.cpp index 7cc0f748..bd317b91 100644 --- a/test/unit_test/runtime/fmt_test.cpp +++ b/test/unit_test/runtime/fmt_test.cpp @@ -84,7 +84,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") { SECTION("in terms of base units") { - const length(as_magnitude<10>()), metre>> q(123); + const length(mag<10>()), metre>> q(123); os << q; SECTION("iostream") { CHECK(os.str() == "123 Mm"); } @@ -96,7 +96,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("in terms of derived units") { - const energy(as_magnitude<10>()), joule>> q(60); + const energy(mag<10>()), joule>> q(60); os << q; SECTION("iostream") { CHECK(os.str() == "60 cJ"); } diff --git a/test/unit_test/runtime/fmt_units_test.cpp b/test/unit_test/runtime/fmt_units_test.cpp index 0f611eed..002e58fd 100644 --- a/test/unit_test/runtime/fmt_units_test.cpp +++ b/test/unit_test/runtime/fmt_units_test.cpp @@ -327,7 +327,7 @@ TEST_CASE("std::format on synthesized unit symbols", "[text][fmt]") SECTION("unknown scaled unit with reference different than the dimension's coherent unit") { // TODO(chogg): Reinstate after format/Magnitude redesign. - // constexpr auto mag = units::as_magnitude(); + // constexpr auto mag = units::mag(); // CHECK(STD_FMT::format("{}", mass>(1)) == "1 [2/3 × 10⁻³] kg"); // CHECK(STD_FMT::format("{:%Q %Aq}", mass>(1)) == "1 [2/3 x 10^-3] kg"); } diff --git a/test/unit_test/runtime/magnitude_test.cpp b/test/unit_test/runtime/magnitude_test.cpp index 9fa0aa98..a861b66c 100644 --- a/test/unit_test/runtime/magnitude_test.cpp +++ b/test/unit_test/runtime/magnitude_test.cpp @@ -66,7 +66,7 @@ void check_same_type_and_value(T actual, U expected) template void check_ratio_round_trip_is_identity() { - constexpr Magnitude auto m = as_magnitude(); + constexpr Magnitude auto m = mag(); constexpr ratio round_trip = ratio{ get_value(numerator(m)), get_value(denominator(m)), @@ -125,10 +125,10 @@ TEST_CASE("base_power") SECTION("product with inverse equals identity") { - auto check_product_with_inverse_is_identity = [](auto x) { CHECK(x * pow<-1>(x) == as_magnitude<1>()); }; + auto check_product_with_inverse_is_identity = [](auto x) { CHECK(x * pow<-1>(x) == mag<1>()); }; - check_product_with_inverse_is_identity(as_magnitude<3>()); - check_product_with_inverse_is_identity(as_magnitude()); + check_product_with_inverse_is_identity(mag<3>()); + check_product_with_inverse_is_identity(mag()); check_product_with_inverse_is_identity(pi_to_the()); } @@ -144,28 +144,21 @@ TEST_CASE("make_ratio performs prime factorization correctly") { SECTION("Performs prime factorization when denominator is 1") { - CHECK(as_magnitude<1>() == magnitude<>{}); - CHECK(as_magnitude<2>() == magnitude{}); - CHECK(as_magnitude<3>() == magnitude{}); - CHECK(as_magnitude<4>() == magnitude{}); + CHECK(mag<1>() == magnitude<>{}); + CHECK(mag<2>() == magnitude{}); + CHECK(mag<3>() == magnitude{}); + CHECK(mag<4>() == magnitude{}); - CHECK(as_magnitude<792>() == magnitude{}); + CHECK(mag<792>() == magnitude{}); } - SECTION("Supports fractions") { CHECK(as_magnitude() == magnitude{}); } - - SECTION("Supports nonzero exp") - { - constexpr ratio r{3, 1, 2}; - REQUIRE(r.exp == 2); - CHECK(as_magnitude() == as_magnitude<300>()); - } + SECTION("Supports fractions") { CHECK(mag() == magnitude{}); } SECTION("Can handle prime factor which would be large enough to overflow int") { // This was taken from a case which failed when we used `int` for our base to store prime numbers. // The failure was due to a prime factor which is larger than 2^31. - as_magnitude(); + mag(); } SECTION("Can bypass computing primes by providing known_first_factor") @@ -176,7 +169,7 @@ TEST_CASE("make_ratio performs prime factorization correctly") // In this case, we test that we can represent the largest prime that fits in a signed 64-bit int. The reason this // test can pass is that we have provided the answer, by specializing the `known_first_factor` variable template // above in this file. - as_magnitude<9'223'372'036'854'775'783>(); + mag<9'223'372'036'854'775'783>(); } } @@ -184,7 +177,7 @@ TEST_CASE("magnitude converts to numerical value") { SECTION("Positive integer powers of integer bases give integer values") { - constexpr auto mag_412 = as_magnitude<412>(); + constexpr auto mag_412 = mag<412>(); check_same_type_and_value(get_value(mag_412), 412); check_same_type_and_value(get_value(mag_412), std::size_t{412}); check_same_type_and_value(get_value(mag_412), 412.0f); @@ -193,7 +186,7 @@ TEST_CASE("magnitude converts to numerical value") SECTION("Negative integer powers of integer bases compute correct values") { - constexpr auto mag_0p125 = as_magnitude(); + constexpr auto mag_0p125 = mag(); check_same_type_and_value(get_value(mag_0p125), 0.125f); check_same_type_and_value(get_value(mag_0p125), 0.125); } @@ -226,20 +219,20 @@ TEST_CASE("magnitude converts to numerical value") // Naturally, we cannot actually write a test to verify a compiler error. But any of these can // be uncommented if desired to verify that it breaks the build. - // get_value(as_magnitude<412>()); + // get_value(mag<412>()); // Would work for pow<62>: - // get_value(pow<63>(as_magnitude<2>())); + // get_value(pow<63>(mag<2>())); // Would work for pow<63>: - // get_value(pow<64>(as_magnitude<2>())); + // get_value(pow<64>(mag<2>())); - get_value(pow<308>(as_magnitude<10>())); // Compiles, correctly. - // get_value(pow<309>(as_magnitude<10>())); - // get_value(pow<3099>(as_magnitude<10>())); - // get_value(pow<3099999>(as_magnitude<10>())); + get_value(pow<308>(mag<10>())); // Compiles, correctly. + // get_value(pow<309>(mag<10>())); + // get_value(pow<3099>(mag<10>())); + // get_value(pow<3099999>(mag<10>())); - auto sqrt_2 = pow(as_magnitude<2>()); + auto sqrt_2 = pow(mag<2>()); CHECK(!is_integral(sqrt_2)); // get_value(sqrt_2); } @@ -249,46 +242,40 @@ TEST_CASE("Equality works for magnitudes") { SECTION("Equivalent ratios are equal") { - CHECK(as_magnitude<1>() == as_magnitude<1>()); - CHECK(as_magnitude<3>() == as_magnitude<3>()); - CHECK(as_magnitude() == as_magnitude()); + CHECK(mag<1>() == mag<1>()); + CHECK(mag<3>() == mag<3>()); + CHECK(mag() == mag()); } SECTION("Different ratios are unequal") { - CHECK(as_magnitude<3>() != as_magnitude<5>()); - CHECK(as_magnitude<3>() != as_magnitude()); + CHECK(mag<3>() != mag<5>()); + CHECK(mag<3>() != mag()); } SECTION("Supports constexpr") { - constexpr auto eq = (as_magnitude() == as_magnitude()); + constexpr auto eq = (mag() == mag()); CHECK(!eq); } } TEST_CASE("Multiplication works for magnitudes") { - SECTION("Reciprocals reduce to null magnitude") - { - CHECK(as_magnitude() * as_magnitude() == as_magnitude<1>()); - } + SECTION("Reciprocals reduce to null magnitude") { CHECK(mag() * mag() == mag<1>()); } - SECTION("Products work as expected") - { - CHECK(as_magnitude() * as_magnitude() == as_magnitude()); - } + SECTION("Products work as expected") { CHECK(mag() * mag() == mag()); } SECTION("Products handle pi correctly") { - CHECK(pi_to_the<1>() * as_magnitude() * pi_to_the() == + CHECK(pi_to_the<1>() * mag() * pi_to_the() == magnitude{ratio{1, 2}}>{}); } SECTION("Supports constexpr") { - constexpr auto p = as_magnitude() * as_magnitude(); - CHECK(p == as_magnitude()); + constexpr auto p = mag() * mag(); + CHECK(p == mag()); } } @@ -296,20 +283,20 @@ TEST_CASE("Common Magnitude") { SECTION("Identity for identical magnitudes") { - CHECK(common_magnitude(as_magnitude<1>(), as_magnitude<1>()) == as_magnitude<1>()); - CHECK(common_magnitude(as_magnitude<15>(), as_magnitude<15>()) == as_magnitude<15>()); + CHECK(common_magnitude(mag<1>(), mag<1>()) == mag<1>()); + CHECK(common_magnitude(mag<15>(), mag<15>()) == mag<15>()); CHECK(common_magnitude(pi_to_the(), pi_to_the()) == pi_to_the()); } SECTION("Greatest Common Factor for integers") { - CHECK(common_magnitude(as_magnitude<24>(), as_magnitude<36>()) == as_magnitude<12>()); - CHECK(common_magnitude(as_magnitude<24>(), as_magnitude<37>()) == as_magnitude<1>()); + CHECK(common_magnitude(mag<24>(), mag<36>()) == mag<12>()); + CHECK(common_magnitude(mag<24>(), mag<37>()) == mag<1>()); } SECTION("Handles fractions") { - CHECK(common_magnitude(as_magnitude(), as_magnitude()) == as_magnitude()); + CHECK(common_magnitude(mag(), mag()) == mag()); } } @@ -317,19 +304,16 @@ TEST_CASE("Division works for magnitudes") { SECTION("Dividing anything by itself reduces to null magnitude") { - CHECK(as_magnitude() / as_magnitude() == as_magnitude<1>()); - CHECK(as_magnitude<15>() / as_magnitude<15>() == as_magnitude<1>()); + CHECK(mag() / mag() == mag<1>()); + CHECK(mag<15>() / mag<15>() == mag<1>()); } - SECTION("Quotients work as expected") - { - CHECK(as_magnitude() / as_magnitude() == as_magnitude()); - } + SECTION("Quotients work as expected") { CHECK(mag() / mag() == mag()); } SECTION("Supports constexpr") { - constexpr auto q = as_magnitude() / as_magnitude(); - CHECK(q == as_magnitude()); + constexpr auto q = mag() / mag(); + CHECK(q == mag()); } } @@ -337,17 +321,17 @@ TEST_CASE("Can raise Magnitudes to rational powers") { SECTION("Anything to the 0 is 1") { - CHECK(pow<0>(as_magnitude<1>()) == as_magnitude<1>()); - CHECK(pow<0>(as_magnitude<123>()) == as_magnitude<1>()); - CHECK(pow<0>(as_magnitude()) == as_magnitude<1>()); - CHECK(pow<0>(pi_to_the()) == as_magnitude<1>()); + CHECK(pow<0>(mag<1>()) == mag<1>()); + CHECK(pow<0>(mag<123>()) == mag<1>()); + CHECK(pow<0>(mag()) == mag<1>()); + CHECK(pow<0>(pi_to_the()) == mag<1>()); } SECTION("Anything to the 1 is itself") { - CHECK(pow<1>(as_magnitude<1>()) == as_magnitude<1>()); - CHECK(pow<1>(as_magnitude<123>()) == as_magnitude<123>()); - CHECK(pow<1>(as_magnitude()) == as_magnitude()); + CHECK(pow<1>(mag<1>()) == mag<1>()); + CHECK(pow<1>(mag<123>()) == mag<123>()); + CHECK(pow<1>(mag()) == mag()); CHECK(pow<1>(pi_to_the()) == pi_to_the()); } @@ -366,11 +350,11 @@ TEST_CASE("can distinguish integral, rational, and irrational magnitudes") CHECK(is_rational(m)); }; check_rational_and_integral(magnitude<>{}); - check_rational_and_integral(as_magnitude<1>()); - check_rational_and_integral(as_magnitude<3>()); - check_rational_and_integral(as_magnitude<8>()); - check_rational_and_integral(as_magnitude<412>()); - check_rational_and_integral(as_magnitude()); + check_rational_and_integral(mag<1>()); + check_rational_and_integral(mag<3>()); + check_rational_and_integral(mag<8>()); + check_rational_and_integral(mag<412>()); + check_rational_and_integral(mag()); } SECTION("Fractional magnitudes are rational, but not integral") @@ -379,8 +363,8 @@ TEST_CASE("can distinguish integral, rational, and irrational magnitudes") CHECK(!is_integral(m)); CHECK(is_rational(m)); }; - check_rational_but_not_integral(as_magnitude()); - check_rational_but_not_integral(as_magnitude()); + check_rational_but_not_integral(mag()); + check_rational_but_not_integral(mag()); } } @@ -397,17 +381,17 @@ TEST_CASE("Constructing ratio from rational magnitude") SECTION("Rational magnitude converts to ratio") { - constexpr ratio r = as_ratio(as_magnitude()); + constexpr ratio r = as_ratio(mag()); CHECK(r == ratio{22, 7}); } SECTION("Irrational magnitude does not convert to ratio") { // The following code should not compile. - // as_ratio(pow(as_magnitude<2>())); + // as_ratio(pow(mag<2>())); // The following code should not compile. - // as_ratio(as_magnitude<180>() / pi_to_the<1>()); + // as_ratio(mag<180>() / pi_to_the<1>()); } } @@ -614,26 +598,26 @@ TEST_CASE("extract_power_of_10") { SECTION("Picks out positive powers") { - CHECK(extract_power_of_10(as_magnitude<10>()) == 1); - CHECK(extract_power_of_10(as_magnitude<20>()) == 1); - CHECK(extract_power_of_10(as_magnitude<40>()) == 1); - CHECK(extract_power_of_10(as_magnitude<50>()) == 1); - CHECK(extract_power_of_10(as_magnitude<100>()) == 2); + CHECK(extract_power_of_10(mag<10>()) == 1); + CHECK(extract_power_of_10(mag<20>()) == 1); + CHECK(extract_power_of_10(mag<40>()) == 1); + CHECK(extract_power_of_10(mag<50>()) == 1); + CHECK(extract_power_of_10(mag<100>()) == 2); } SECTION("Picks out negative powers") { - constexpr auto ONE = as_magnitude<1>(); - CHECK(extract_power_of_10(ONE / as_magnitude<10>()) == -1); - CHECK(extract_power_of_10(ONE / as_magnitude<20>()) == -1); - CHECK(extract_power_of_10(ONE / as_magnitude<40>()) == -1); - CHECK(extract_power_of_10(ONE / as_magnitude<50>()) == -1); - CHECK(extract_power_of_10(ONE / as_magnitude<100>()) == -2); + constexpr auto ONE = mag<1>(); + CHECK(extract_power_of_10(ONE / mag<10>()) == -1); + CHECK(extract_power_of_10(ONE / mag<20>()) == -1); + CHECK(extract_power_of_10(ONE / mag<40>()) == -1); + CHECK(extract_power_of_10(ONE / mag<50>()) == -1); + CHECK(extract_power_of_10(ONE / mag<100>()) == -2); } - SECTION("Zero if signs disagree") { CHECK(extract_power_of_10(as_magnitude<2>() / as_magnitude<5>()) == 0); } + SECTION("Zero if signs disagree") { CHECK(extract_power_of_10(mag<2>() / mag<5>()) == 0); } - SECTION("Handles rational powers") { CHECK(extract_power_of_10(sqrt(as_magnitude<1000>())) == 1); } + SECTION("Handles rational powers") { CHECK(extract_power_of_10(sqrt(mag<1000>())) == 1); } } } // namespace diff --git a/test/unit_test/static/quantity_kind_test.cpp b/test/unit_test/static/quantity_kind_test.cpp index c421ec12..1d246f23 100644 --- a/test/unit_test/static/quantity_kind_test.cpp +++ b/test/unit_test/static/quantity_kind_test.cpp @@ -456,9 +456,9 @@ concept invalid_compound_assignments = requires !requires { w *= m; }; requires !requires { w /= m; }; requires !requires { w %= m; }; - requires !requires { w *= quantity_kind, scaled_unit(), one>, int>{1}; }; - requires !requires { w /= quantity_kind, scaled_unit(), one>, int>{1}; }; - requires !requires { w %= quantity_kind, scaled_unit(), one>, int>{1}; }; + requires !requires { w *= quantity_kind, scaled_unit(), one>, int>{1}; }; + requires !requires { w /= quantity_kind, scaled_unit(), one>, int>{1}; }; + requires !requires { w %= quantity_kind, scaled_unit(), one>, int>{1}; }; requires !requires { w %= 1.0; }; requires !requires { w %= quantity(1.0); }; requires !requires { w %= 1.0 * (w / w); }; diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index cf346a27..d631d1a6 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -287,7 +287,7 @@ static_assert(get_length_derived_quantity() == 1_q_m); // CTAD ///////// -#if UNITS_COMP_GCC >= 11 || UNITS_COMP_CLANG > 15 +#if UNITS_COMP_GCC >= 11 || UNITS_COMP_CLANG > 16 static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert( @@ -498,7 +498,7 @@ static_assert(compare> static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1_q_s), - frequency(), hertz>, std::int64_t>>); + frequency(), hertz>, std::int64_t>>); static_assert(is_same_v); static_assert(is_same_v); @@ -529,7 +529,7 @@ static_assert(compare> static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1._q_s), - frequency(), hertz>, long double>>); + frequency(), hertz>, long double>>); static_assert(compare>); static_assert(compare>); static_assert(compare(1)), length>); @@ -551,7 +551,7 @@ static_assert(compare> static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1_q_s), - frequency(), hertz>, long double>>); + frequency(), hertz>, long double>>); // different units static_assert(compare>); @@ -579,25 +579,23 @@ static_assert(is_same_v>); -static_assert( - compare(), metre>, std::int64_t>>); +static_assert(compare(), metre>, std::int64_t>>); static_assert( compare, exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); static_assert(compare>); -static_assert( - compare(), hertz>, std::int64_t>>); +static_assert(compare(), hertz>, std::int64_t>>); static_assert(compare>); -static_assert(compare>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); -static_assert(compare(), one>, std::int64_t>>); +static_assert( + compare>, + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); +static_assert(compare(), one>, std::int64_t>>); static_assert(compare>); static_assert( - compare(), metre_per_second>, std::int64_t>>); + compare(), metre_per_second>, std::int64_t>>); static_assert( compare, exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); static_assert((1_q_m + 1_q_m).number() == 2); static_assert((1_q_m + 1_q_km).number() == 1001); @@ -887,9 +885,8 @@ static_assert(!is_same_v(2_q_dm3)), volume, units::exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); -static_assert( - is_same_v(), metre>, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); +static_assert(is_same_v(), metre>, std::int64_t>>); #else @@ -919,8 +916,7 @@ static_assert(same(quotient_remainder_theorem(3'000 * m, 400), 3'000 * m)); static_assert(comp(quotient_remainder_theorem(3'000 * m, quantity(400)), 3'000 * m)); static_assert(comp(quotient_remainder_theorem(3 * km, quantity(400)), 3 * km)); static_assert(comp(quotient_remainder_theorem(3 * km, quantity(2)), 3 * km)); -static_assert( - comp(quotient_remainder_theorem(3 * km, dimensionless(), one>, int>(400)), - 3 * km)); +static_assert(comp(quotient_remainder_theorem(3 * km, dimensionless(), one>, int>(400)), + 3 * km)); } // namespace diff --git a/test/unit_test/static/ratio_test.cpp b/test/unit_test/static/ratio_test.cpp index ad966950..02828115 100644 --- a/test/unit_test/static/ratio_test.cpp +++ b/test/unit_test/static/ratio_test.cpp @@ -28,11 +28,6 @@ using namespace units; static_assert(ratio(2, 4) == ratio(1, 2)); -// basic exponents tests -static_assert(ratio(2, 40, 1) == ratio(1, 20, 1)); -static_assert(ratio(20, 4, -1) == ratio(10, 2, -1)); -static_assert(ratio(200, 5) == ratio(20'000, 50, -1)); - static_assert(ratio(1) * ratio(3, 8) == ratio(3, 8)); static_assert(ratio(3, 8) * ratio(1) == ratio(3, 8)); static_assert(ratio(4) * ratio(1, 8) == ratio(1, 2)); @@ -45,21 +40,12 @@ static_assert(-ratio(3, 8) == ratio(-3, 8)); // ratio addition static_assert(ratio(1, 2) + ratio(1, 3) == ratio(5, 6)); -static_assert(ratio(1, 3, 2) + ratio(11, 6) == ratio(211, 6)); // 100/3 + 11/6 - -// multiply with exponents -static_assert(ratio(1, 8, 2) * ratio(2, 1, 4) == ratio(1, 4, 6)); -static_assert(ratio(1, 2, -4) * ratio(8, 1, 3) == ratio(4, 1, -1)); static_assert(ratio(4) / ratio(2) == ratio(2)); static_assert(ratio(2) / ratio(8) == ratio(1, 4)); static_assert(ratio(1, 8) / ratio(2) == ratio(1, 16)); static_assert(ratio(6) / ratio(3) == ratio(2)); -// divide with exponents -static_assert(ratio(1, 8, -6) / ratio(2, 1, -8) == ratio(1, 16, 2)); -static_assert(ratio(6, 1, 4) / ratio(3) == ratio(2, 1, 4)); - static_assert(pow<0>(ratio(2)) == ratio(1)); static_assert(pow<1>(ratio(2)) == ratio(2)); static_assert(pow<2>(ratio(2)) == ratio(4)); @@ -69,27 +55,6 @@ static_assert(pow<1>(ratio(1, 2)) == ratio(1, 2)); static_assert(pow<2>(ratio(1, 2)) == ratio(1, 4)); static_assert(pow<3>(ratio(1, 2)) == ratio(1, 8)); -// pow with exponents -static_assert(pow<2>(ratio(1, 2, 3)) == ratio(1, 4, 6)); -static_assert(pow<4, 2>(ratio(1, 2, 3)) == ratio(1, 4, 6)); -static_assert(pow<3>(ratio(1, 2, -6)) == ratio(1, 8, -18)); - -static_assert(sqrt(ratio(9)) == ratio(3)); -static_assert(cbrt(ratio(27)) == ratio(3)); -static_assert(sqrt(ratio(4)) == ratio(2)); -static_assert(cbrt(ratio(8)) == ratio(2)); -static_assert(sqrt(ratio(1)) == ratio(1)); -static_assert(cbrt(ratio(1)) == ratio(1)); -static_assert(sqrt(ratio(0)) == ratio(0)); -static_assert(cbrt(ratio(0)) == ratio(0)); -static_assert(sqrt(ratio(1, 4)) == ratio(1, 2)); -static_assert(cbrt(ratio(1, 8)) == ratio(1, 2)); - -// sqrt with exponents -static_assert(sqrt(ratio(9, 1, 2)) == ratio(3, 1, 1)); -static_assert(cbrt(ratio(27, 1, 3)) == ratio(3, 1, 1)); -static_assert(cbrt(ratio(27, 1, 2)) == ratio(13, 1, 0)); - // common_ratio static_assert(common_ratio(ratio(1), ratio(1000)) == ratio(1)); static_assert(common_ratio(ratio(1000), ratio(1)) == ratio(1)); @@ -98,20 +63,9 @@ static_assert(common_ratio(ratio(1, 1000), ratio(1)) == ratio(1, 1000)); static_assert(common_ratio(ratio(100, 1), ratio(10, 1)) == ratio(10, 1)); static_assert(common_ratio(ratio(100, 1), ratio(1, 10)) == ratio(1, 10)); -// common ratio with exponents -static_assert(common_ratio(ratio(1), ratio(1, 1, 3)) == ratio(1)); -static_assert(common_ratio(ratio(10, 1, -1), ratio(1, 1, -3)) == ratio(1, 1, -3)); - -// numerator and denominator -static_assert(numerator(ratio(3, 4)) == 3); -static_assert(numerator(ratio(3, 7, 2)) == 300); -static_assert(denominator(ratio(3, 4)) == 4); -static_assert(denominator(ratio(3, 7, -2)) == 700); - // comparison static_assert((ratio(3, 4) <=> ratio(6, 8)) == (0 <=> 0)); static_assert((ratio(3, 4) <=> ratio(-3, 4)) == (0 <=> -1)); static_assert((ratio(-3, 4) <=> ratio(3, -4)) == (0 <=> 0)); -static_assert((ratio(1, 1, 1) <=> ratio(10)) == (0 <=> 0)); } // namespace diff --git a/test/unit_test/static/si_test.cpp b/test/unit_test/static/si_test.cpp index 02960463..103e1837 100644 --- a/test/unit_test/static/si_test.cpp +++ b/test/unit_test/static/si_test.cpp @@ -43,7 +43,7 @@ static_assert(1_q_au == 149'597'870'700_q_m); static_assert(1_q_km + 1_q_m == 1001_q_m); static_assert(10_q_km / 5_q_km == 2); static_assert(10_q_km / 5_q_km < 3); -static_assert(100_q_mm / 5_q_cm == dimensionless(), one>>(20)); +static_assert(100_q_mm / 5_q_cm == dimensionless(), one>>(20)); static_assert(100_q_mm / 5_q_cm == dimensionless(2)); static_assert(10_q_km / 2 == 5_q_km); @@ -107,7 +107,7 @@ static_assert(1000 / 1_q_s == 1_q_kHz); static_assert(1 / 1_q_ms == 1_q_kHz); static_assert(3.2_q_GHz == 3'200'000'000_q_Hz); static_assert((10_q_Hz * 1_q_min).number() == 10); -static_assert(10_q_Hz * 1_q_min == dimensionless(), one>>(10)); +static_assert(10_q_Hz * 1_q_min == dimensionless(), one>>(10)); static_assert(10_q_Hz * 1_q_min == dimensionless(600)); static_assert(2 / 1_q_Hz == 2_q_s); diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index 128fac3d..ded5edad 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -36,12 +36,12 @@ using namespace units::isq; struct metre : named_unit {}; struct centimetre : prefixed_unit {}; struct kilometre : prefixed_unit {}; -struct yard : named_scaled_unit(), metre> {}; -struct foot : named_scaled_unit(), yard> {}; +struct yard : named_scaled_unit(), metre> {}; +struct foot : named_scaled_unit(), yard> {}; struct dim_length : base_dimension<"length", metre> {}; struct second : named_unit {}; -struct hour : named_scaled_unit(), second> {}; +struct hour : named_scaled_unit(), second> {}; struct dim_time : base_dimension<"time", second> {}; struct kelvin : named_unit {}; @@ -59,10 +59,10 @@ struct kilometre_per_hour : derived_scaled_unit); static_assert(equivalent); -static_assert(compare(), metre>>, metre>); -static_assert(compare(), metre>>, centimetre>); +static_assert(compare(), metre>>, metre>); +static_assert(compare(), metre>>, centimetre>); static_assert(compare>, yard>); -static_assert(compare(), metre>>, foot>); +static_assert(compare(), metre>>, foot>); static_assert(compare>, kilometre_per_hour>); static_assert(centimetre::symbol == "cm");