mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 18:37:15 +02:00
feat: power<Num, Den>()
support added for dimensions and units
This commit is contained in:
@ -112,13 +112,17 @@ inline constexpr bool is_specialization_of_power<power<F, Ints...>> = true;
|
||||
template<typename T, ratio R>
|
||||
consteval auto power_or_T_impl()
|
||||
{
|
||||
if constexpr (R.den == 1) {
|
||||
if constexpr (R.num == 1)
|
||||
return T{};
|
||||
else
|
||||
return power<T, R.num>{};
|
||||
if constexpr (is_specialization_of_power<T>) {
|
||||
return power_or_T_impl<typename T::factor, T::exponent * R>();
|
||||
} else {
|
||||
return power<T, R.num, R.den>{};
|
||||
if constexpr (R.den == 1) {
|
||||
if constexpr (R.num == 1)
|
||||
return T{};
|
||||
else
|
||||
return power<T, R.num>{};
|
||||
} else {
|
||||
return power<T, R.num, R.den>{};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -437,6 +441,32 @@ template<template<typename...> typename To, typename OneType, typename T>
|
||||
return To<OneType, per<T>>{};
|
||||
}
|
||||
|
||||
|
||||
template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To, typename OneType,
|
||||
template<typename, typename> typename Pred, typename... Nums, typename... Dens>
|
||||
requires detail::non_zero<Den>
|
||||
[[nodiscard]] consteval auto expr_pow_impl(type_list<Nums...>, type_list<Dens...>)
|
||||
{
|
||||
return detail::get_optimized_expression<type_list<power_or_T<Nums, ratio{Num, Den}>...>,
|
||||
type_list<power_or_T<Dens, ratio{Num, Den}>...>, OneType, Pred, To>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the value of an expression raised to the `Num/Den` power
|
||||
*
|
||||
* @tparam Num Exponent numerator
|
||||
* @tparam Den Exponent denominator
|
||||
* @tparam T Expression being the base of the operation
|
||||
*/
|
||||
template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To, typename OneType,
|
||||
template<typename, typename> typename Pred, typename T>
|
||||
requires detail::non_zero<Den>
|
||||
[[nodiscard]] consteval auto expr_pow(T)
|
||||
{
|
||||
return expr_pow_impl<Num, Den, To, OneType, Pred>(typename T::_num_{}, typename T::_den_{});
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace units
|
||||
|
@ -285,6 +285,28 @@ template<Dimension D1, Dimension D2>
|
||||
return std::derived_from<D1, D2> || std::derived_from<D2, D1>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the value of a dimension raised to the `Num/Den` power
|
||||
*
|
||||
* @tparam Num Exponent numerator
|
||||
* @tparam Den Exponent denominator
|
||||
* @param d Dimension being the base of the operation
|
||||
*
|
||||
* @return Dimension The result of computation
|
||||
*/
|
||||
template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
|
||||
requires detail::non_zero<Den>
|
||||
[[nodiscard]] consteval Dimension auto pow(D d)
|
||||
{
|
||||
if constexpr (BaseDimension<D>) {
|
||||
if constexpr (Den == 1)
|
||||
return derived_dimension<power<D, Num>>{};
|
||||
else
|
||||
return derived_dimension<power<D, Num, Den>>{};
|
||||
} else
|
||||
return detail::expr_pow<Num, Den, derived_dimension, struct one_dim, detail::type_list_of_base_dimension_less>(d);
|
||||
}
|
||||
|
||||
// TODO consider adding the support for text output of the dimensional equation
|
||||
|
||||
} // namespace units
|
||||
|
@ -471,6 +471,33 @@ template<Unit Lhs, Unit Rhs>
|
||||
return is_same_v<decltype(canonical_lhs.reference_unit), decltype(canonical_rhs.reference_unit)>;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the value of a unit raised to the `Num/Den` power
|
||||
*
|
||||
* @tparam Num Exponent numerator
|
||||
* @tparam Den Exponent denominator
|
||||
* @param u Unit being the base of the operation
|
||||
*
|
||||
* @return Unit The result of computation
|
||||
*/
|
||||
template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
|
||||
requires detail::non_zero<Den>
|
||||
[[nodiscard]] consteval Unit auto pow(U u)
|
||||
{
|
||||
if constexpr (requires { U::symbol; }) {
|
||||
if constexpr (Den == 1)
|
||||
return derived_unit<power<U, Num>>{};
|
||||
else
|
||||
return derived_unit<power<U, Num, Den>>{};
|
||||
} else if constexpr (detail::is_specialization_of_scaled_unit<U>) {
|
||||
return scaled_unit<pow<ratio{Num, Den}>(U::mag), std::remove_const_t<decltype(pow<Num, Den>(U::reference_unit))>>{};
|
||||
} else {
|
||||
return detail::expr_pow<Num, Den, derived_unit, struct one, detail::type_list_of_unit_less>(u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Helper variable templates to create common powers
|
||||
template<Unit auto U>
|
||||
inline constexpr decltype(U * U) square;
|
||||
|
@ -207,4 +207,19 @@ static_assert(!convertible(length_dim, time_dim));
|
||||
static_assert(acceleration_dim != speed_dim);
|
||||
static_assert(!convertible(acceleration_dim, speed_dim));
|
||||
|
||||
// power
|
||||
static_assert(is_of_type<pow<2>(length_dim), derived_dimension<power<length_dim_, 2>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length_dim), derived_dimension<power<length_dim_, 1, 2>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length_dim* length_dim), length_dim_>);
|
||||
static_assert(is_of_type<pow<1, 3>(length_dim* length_dim* length_dim), length_dim_>);
|
||||
static_assert(is_of_type<pow<1, 3>(length_dim* length_dim), derived_dimension<power<length_dim_, 2, 3>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length_dim / time_dim),
|
||||
derived_dimension<power<length_dim_, 1, 2>, per<power<time_dim_, 1, 2>>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length_dim / (time_dim * time_dim)),
|
||||
derived_dimension<power<length_dim_, 1, 2>, per<time_dim_>>>);
|
||||
|
||||
static_assert(is_same_v<decltype(pow<2>(length_dim)), decltype(length_dim * length_dim)>);
|
||||
static_assert(
|
||||
is_same_v<decltype(pow<2>(length_dim / time_dim)), decltype(length_dim * length_dim / time_dim / time_dim)>);
|
||||
|
||||
} // namespace
|
||||
|
@ -357,6 +357,30 @@ static_assert(joule == newton * metre);
|
||||
static_assert(watt == joule / second);
|
||||
static_assert(watt == kilogram * square<metre> / cubic<second>);
|
||||
|
||||
// power
|
||||
static_assert(is_same_v<decltype(pow<2>(metre)), decltype(metre * metre)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(kilometre)), decltype(kilometre * kilometre)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(si::kilo<metre>)), decltype(si::kilo<metre> * si::kilo<metre>)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(hour)), decltype(hour * hour)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(mag<3600> * second)), decltype((mag<3600> * second) * (mag<3600> * second))>);
|
||||
static_assert(is_same_v<decltype(pow<2>(metre / second)), decltype(metre * metre / second / second)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(kilometre / hour)), decltype(kilometre * kilometre / hour / hour)>);
|
||||
|
||||
static_assert(is_of_type<pow<2>(metre), derived_unit<power<metre_, 2>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(metre), derived_unit<power<metre_, 1, 2>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(metre* metre), metre_>);
|
||||
static_assert(is_of_type<pow<1, 3>(metre* metre* metre), metre_>);
|
||||
static_assert(is_of_type<pow<1, 3>(metre* metre), derived_unit<power<metre_, 2, 3>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(metre / second), derived_unit<power<metre_, 1, 2>, per<power<second_, 1, 2>>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(metre / (second * second)), derived_unit<power<metre_, 1, 2>, per<second_>>>);
|
||||
static_assert(is_of_type<kilometre * kilometre, derived_unit<power<kilometre_, 2>>>);
|
||||
|
||||
static_assert(is_of_type<pow<2>(kilometre), derived_unit<power<kilometre_, 2>>>);
|
||||
static_assert(is_of_type<pow<2>(si::kilo<metre>), derived_unit<power<si::kilo_<metre>, 2>>>);
|
||||
static_assert(is_of_type<pow<2>(hour), derived_unit<power<hour_, 2>>>);
|
||||
static_assert(
|
||||
is_of_type<pow<2>(mag<3600>* second), scaled_unit<mag<3600> * mag<3600>, derived_unit<power<second_, 2>>>>);
|
||||
|
||||
// common_type
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(gram), decltype(gram)>, gram_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(kilogram), decltype(kilogram)>, kilogram_>);
|
||||
|
Reference in New Issue
Block a user