Add extract_power_of_10(Magnitude) utility

This will help with pretty-printing magnitudes by extracting a
reasonable power of 10.
This commit is contained in:
Chip Hogg
2022-07-07 16:10:34 +00:00
parent 3710b249f3
commit 407a13c48f
2 changed files with 48 additions and 0 deletions

View File

@@ -656,4 +656,26 @@ constexpr Magnitude auto as_magnitude()
detail::prime_factorization_v<R.den>;
}
namespace detail {
template<typename T, BasePower auto... BPs>
constexpr ratio get_power(T base, magnitude<BPs...>)
{
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

View File

@@ -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