diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index ddf18cce..1257e132 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -656,4 +656,26 @@ constexpr Magnitude auto as_magnitude() detail::prime_factorization_v; } +namespace detail { +template +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 extract_power_of_10(Magnitude auto m) +{ + const auto power_of_2 = get_power(2, m); + const auto power_of_5 = get_power(5, m); + + if ((power_of_2 * power_of_5).num <= 0) { + return 0; + } + + return integer_part((detail::abs(power_of_2) < detail::abs(power_of_5)) ? power_of_2 : power_of_5); +} +} // namespace detail + } // namespace units diff --git a/test/unit_test/runtime/magnitude_test.cpp b/test/unit_test/runtime/magnitude_test.cpp index 0715df8f..9fa0aa98 100644 --- a/test/unit_test/runtime/magnitude_test.cpp +++ b/test/unit_test/runtime/magnitude_test.cpp @@ -610,4 +610,30 @@ TEST_CASE("strictly_increasing") } } +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); + } + + 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); + } + + SECTION("Zero if signs disagree") { CHECK(extract_power_of_10(as_magnitude<2>() / as_magnitude<5>()) == 0); } + + SECTION("Handles rational powers") { CHECK(extract_power_of_10(sqrt(as_magnitude<1000>())) == 1); } +} + } // namespace