mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-31 19:04:27 +02:00
Merge pull request #368 from chiphogg/chiphogg/print-mag
Migrate remaining ratio template parameters to Magnitude
This commit is contained in:
@@ -40,11 +40,11 @@ namespace units {
|
||||
// Prefix
|
||||
namespace detail {
|
||||
|
||||
template<ratio R>
|
||||
template<Magnitude auto M>
|
||||
struct prefix_base;
|
||||
|
||||
template<ratio R>
|
||||
void to_prefix_base(const volatile prefix_base<R>*);
|
||||
template<Magnitude auto M>
|
||||
void to_prefix_base(const volatile prefix_base<M>*);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
@@ -32,24 +32,35 @@ namespace units::detail {
|
||||
|
||||
inline constexpr basic_symbol_text base_multiplier("\u00D7 10", "x 10");
|
||||
|
||||
template<ratio R>
|
||||
constexpr auto ratio_text()
|
||||
template<Magnitude auto M>
|
||||
constexpr auto magnitude_text()
|
||||
{
|
||||
if constexpr (R.num == 1 && R.den == 1 && R.exp != 0) {
|
||||
return base_multiplier + superscript<R.exp>();
|
||||
} else if constexpr (R.num != 1 || R.den != 1 || R.exp != 0) {
|
||||
auto txt = basic_fixed_string("[") + regular<R.num>();
|
||||
if constexpr (R.den == 1) {
|
||||
if constexpr (R.exp == 0) {
|
||||
constexpr auto exp10 = extract_power_of_10(M);
|
||||
|
||||
constexpr Magnitude auto base = M / pow<exp10>(as_magnitude<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");
|
||||
|
||||
constexpr auto num_value = get_value<std::intmax_t>(num);
|
||||
constexpr auto den_value = get_value<std::intmax_t>(den);
|
||||
|
||||
|
||||
if constexpr (num_value == 1 && den_value == 1 && exp10 != 0) {
|
||||
return base_multiplier + superscript<exp10>();
|
||||
} else if constexpr (num_value != 1 || den_value != 1 || exp10 != 0) {
|
||||
auto txt = basic_fixed_string("[") + regular<num_value>();
|
||||
if constexpr (den_value == 1) {
|
||||
if constexpr (exp10 == 0) {
|
||||
return txt + basic_fixed_string("]");
|
||||
} else {
|
||||
return txt + " " + base_multiplier + superscript<R.exp>() + basic_fixed_string("]");
|
||||
return txt + " " + base_multiplier + superscript<exp10>() + basic_fixed_string("]");
|
||||
}
|
||||
} else {
|
||||
if constexpr (R.exp == 0) {
|
||||
return txt + basic_fixed_string("/") + regular<R.den>() + basic_fixed_string("]");
|
||||
if constexpr (exp10 == 0) {
|
||||
return txt + basic_fixed_string("/") + regular<den_value>() + basic_fixed_string("]");
|
||||
} else {
|
||||
return txt + basic_fixed_string("/") + regular<R.den>() + " " + base_multiplier + superscript<R.exp>() +
|
||||
return txt + basic_fixed_string("/") + regular<den_value>() + " " + base_multiplier + superscript<exp10>() +
|
||||
basic_fixed_string("]");
|
||||
}
|
||||
}
|
||||
@@ -58,22 +69,22 @@ constexpr auto ratio_text()
|
||||
}
|
||||
}
|
||||
|
||||
template<Unit U, ratio R, std::size_t SymbolLen>
|
||||
constexpr auto prefix_or_ratio_text()
|
||||
template<Unit U, Magnitude auto M, std::size_t SymbolLen>
|
||||
constexpr auto prefix_or_magnitude_text()
|
||||
{
|
||||
if constexpr (R.num == 1 && R.den == 1 && R.exp == 0) {
|
||||
if constexpr (M == as_magnitude<1>()) {
|
||||
// no ratio/prefix
|
||||
return basic_fixed_string("");
|
||||
} else {
|
||||
// try to form a prefix
|
||||
using prefix = downcast<detail::prefix_base<R>>;
|
||||
using prefix = downcast<detail::prefix_base<M>>;
|
||||
|
||||
if constexpr (can_be_prefixed<U> && !is_same_v<prefix, prefix_base<R>>) {
|
||||
if constexpr (can_be_prefixed<U> && !is_same_v<prefix, prefix_base<M>>) {
|
||||
// print as a prefixed unit
|
||||
return prefix::symbol;
|
||||
} else {
|
||||
// print as a ratio of the coherent unit
|
||||
constexpr auto txt = ratio_text<R>();
|
||||
constexpr auto txt = magnitude_text<M>();
|
||||
if constexpr (SymbolLen > 0 && txt.standard().size() > 0)
|
||||
return txt + basic_fixed_string(" ");
|
||||
else
|
||||
@@ -147,7 +158,7 @@ constexpr auto unit_text()
|
||||
}();
|
||||
|
||||
constexpr auto prefix_txt =
|
||||
prefix_or_ratio_text<U, as_ratio(U::mag / coherent_unit::mag), symbol_text.standard().size()>();
|
||||
prefix_or_magnitude_text<U, U::mag / coherent_unit::mag, symbol_text.standard().size()>();
|
||||
return prefix_txt + symbol_text;
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -34,9 +34,9 @@ namespace units {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<ratio R>
|
||||
struct prefix_base : downcast_base<prefix_base<R>> {
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = as_magnitude<R>();
|
||||
template<Magnitude auto M>
|
||||
struct prefix_base : downcast_base<prefix_base<M>> {
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@@ -54,8 +54,8 @@ struct prefix_base : downcast_base<prefix_base<R>> {
|
||||
* @tparam Symbol a text representation of the prefix
|
||||
* @tparam R factor to be used to scale a unit
|
||||
*/
|
||||
template<typename Child, basic_symbol_text Symbol, ratio R>
|
||||
struct prefix : downcast_dispatch<Child, detail::prefix_base<R>, downcast_mode::on> {
|
||||
template<typename Child, basic_symbol_text Symbol, Magnitude auto M>
|
||||
struct prefix : downcast_dispatch<Child, detail::prefix_base<M>, downcast_mode::on> {
|
||||
static constexpr auto symbol = Symbol;
|
||||
};
|
||||
|
||||
|
@@ -26,11 +26,13 @@
|
||||
|
||||
namespace units::isq::iec80000 {
|
||||
|
||||
struct kibi : prefix<kibi, "Ki", ratio(1'024)> {};
|
||||
struct mebi : prefix<mebi, "Mi", ratio(1'048'576)> {};
|
||||
struct gibi : prefix<gibi, "Gi", ratio(1'073'741'824)> {};
|
||||
struct tebi : prefix<tebi, "Ti", ratio(1'099'511'627'776)> {};
|
||||
struct pebi : prefix<pebi, "Pi", ratio(1'125'899'906'842'624)> {};
|
||||
struct exbi : prefix<exbi, "Ei", ratio(1'152'921'504'606'846'976)> {};
|
||||
struct kibi : prefix<kibi, "Ki", pow<10>(as_magnitude<2>())> {};
|
||||
struct mebi : prefix<mebi, "Mi", pow<20>(as_magnitude<2>())> {};
|
||||
struct gibi : prefix<gibi, "Gi", pow<30>(as_magnitude<2>())> {};
|
||||
struct tebi : prefix<tebi, "Ti", pow<40>(as_magnitude<2>())> {};
|
||||
struct pebi : prefix<pebi, "Pi", pow<50>(as_magnitude<2>())> {};
|
||||
struct exbi : prefix<exbi, "Ei", pow<60>(as_magnitude<2>())> {};
|
||||
struct zebi : prefix<zebi, "Zi", pow<70>(as_magnitude<2>())> {};
|
||||
struct yobi : prefix<yobi, "Yi", pow<80>(as_magnitude<2>())> {};
|
||||
|
||||
} // namespace units::isq::iec80000
|
||||
|
@@ -27,26 +27,26 @@
|
||||
namespace units::isq::si {
|
||||
|
||||
// clang-format off
|
||||
struct yocto : prefix<yocto, "y", ratio(1, 1, -24)> {};
|
||||
struct zepto : prefix<zepto, "z", ratio(1, 1, -21)> {};
|
||||
struct atto : prefix<atto, "a", ratio(1, 1, -18)> {};
|
||||
struct femto : prefix<femto, "f", ratio(1, 1, -15)> {};
|
||||
struct pico : prefix<pico, "p", ratio(1, 1, -12)> {};
|
||||
struct nano : prefix<nano, "n", ratio(1, 1, -9)> {};
|
||||
struct micro : prefix<micro, basic_symbol_text{"\u00b5", "u"}, ratio(1, 1, -6)> {};
|
||||
struct milli : prefix<milli, "m", ratio(1, 1, -3)> {};
|
||||
struct centi : prefix<centi, "c", ratio(1, 1, -2)> {};
|
||||
struct deci : prefix<deci, "d", ratio(1, 1, -1)> {};
|
||||
struct deca : prefix<deca, "da", ratio(1, 1, 1)> {};
|
||||
struct hecto : prefix<hecto, "h", ratio(1, 1, 2)> {};
|
||||
struct kilo : prefix<kilo, "k", ratio(1, 1, 3)> {};
|
||||
struct mega : prefix<mega, "M", ratio(1, 1, 6)> {};
|
||||
struct giga : prefix<giga, "G", ratio(1, 1, 9)> {};
|
||||
struct tera : prefix<tera, "T", ratio(1, 1, 12)> {};
|
||||
struct peta : prefix<peta, "P", ratio(1, 1, 15)> {};
|
||||
struct exa : prefix<exa, "E", ratio(1, 1, 18)> {};
|
||||
struct zetta : prefix<zetta, "Z", ratio(1, 1, 21)> {};
|
||||
struct yotta : prefix<yotta, "Y", ratio(1, 1, 24)> {};
|
||||
struct yocto : prefix<yocto, "y", pow<-24>(as_magnitude<10>())> {};
|
||||
struct zepto : prefix<zepto, "z", pow<-21>(as_magnitude<10>())> {};
|
||||
struct atto : prefix<atto, "a", pow<-18>(as_magnitude<10>())> {};
|
||||
struct femto : prefix<femto, "f", pow<-15>(as_magnitude<10>())> {};
|
||||
struct pico : prefix<pico, "p", pow<-12>(as_magnitude<10>())> {};
|
||||
struct nano : prefix<nano, "n", pow<-9>(as_magnitude<10>())> {};
|
||||
struct micro : prefix<micro, basic_symbol_text{"\u00b5", "u"}, pow<-6>(as_magnitude<10>())> {};
|
||||
struct milli : prefix<milli, "m", pow<-3>(as_magnitude<10>())> {};
|
||||
struct centi : prefix<centi, "c", pow<-2>(as_magnitude<10>())> {};
|
||||
struct deci : prefix<deci, "d", pow<-1>(as_magnitude<10>())> {};
|
||||
struct deca : prefix<deca, "da", pow<1>(as_magnitude<10>())> {};
|
||||
struct hecto : prefix<hecto, "h", pow<2>(as_magnitude<10>())> {};
|
||||
struct kilo : prefix<kilo, "k", pow<3>(as_magnitude<10>())> {};
|
||||
struct mega : prefix<mega, "M", pow<6>(as_magnitude<10>())> {};
|
||||
struct giga : prefix<giga, "G", pow<9>(as_magnitude<10>())> {};
|
||||
struct tera : prefix<tera, "T", pow<12>(as_magnitude<10>())> {};
|
||||
struct peta : prefix<peta, "P", pow<15>(as_magnitude<10>())> {};
|
||||
struct exa : prefix<exa, "E", pow<18>(as_magnitude<10>())> {};
|
||||
struct zetta : prefix<zetta, "Z", pow<21>(as_magnitude<10>())> {};
|
||||
struct yotta : prefix<yotta, "Y", pow<24>(as_magnitude<10>())> {};
|
||||
// clang-format on
|
||||
|
||||
} // namespace units::isq::si
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user