forked from mpusz/mp-units
implementing units::ratio_add and tests
not yet used in src/include/units/bits/dim_consolidate.h because it breaks and cascades (due to new exponent we think)
This commit is contained in:
committed by
Mateusz Pusz
parent
dfb9042e9d
commit
0566cc631d
@@ -30,10 +30,10 @@ namespace units::detail {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Consolidates contiguous ranges of exponents of the same dimension
|
* @brief Consolidates contiguous ranges of exponents of the same dimension
|
||||||
*
|
*
|
||||||
* If there is more than one exponent with the same dimension they are aggregated into one exponent by adding
|
* If there is more than one exponent with the same dimension they are aggregated into one exponent by adding
|
||||||
* their exponents. If this accumulation will result with 0, such a dimension is removed from the list.
|
* their exponents. If this accumulation will result with 0, such a dimension is removed from the list.
|
||||||
*
|
*
|
||||||
* @tparam D derived dimension to consolidate
|
* @tparam D derived dimension to consolidate
|
||||||
*/
|
*/
|
||||||
template<typename ExpList>
|
template<typename ExpList>
|
||||||
@@ -56,7 +56,7 @@ struct dim_consolidate<exp_list<E1, ERest...>> {
|
|||||||
|
|
||||||
template<BaseDimension Dim, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, typename... ERest>
|
template<BaseDimension Dim, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, typename... ERest>
|
||||||
struct dim_consolidate<exp_list<exp<Dim, Num1, Den1>, exp<Dim, Num2, Den2>, ERest...>> {
|
struct dim_consolidate<exp_list<exp<Dim, Num1, Den1>, exp<Dim, Num2, Den2>, ERest...>> {
|
||||||
// TODO: provide custom implementation for ratio_add
|
// TODO: we have ration_add now, but dim_consolidate etc, now need to cope with our new ratio
|
||||||
using r1 = std::ratio<Num1, Den1>;
|
using r1 = std::ratio<Num1, Den1>;
|
||||||
using r2 = std::ratio<Num2, Den2>;
|
using r2 = std::ratio<Num2, Den2>;
|
||||||
using r = std::ratio_add<r1, r2>;
|
using r = std::ratio_add<r1, r2>;
|
||||||
|
@@ -35,13 +35,11 @@ namespace units {
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] constexpr T abs(T v) noexcept
|
[[nodiscard]] constexpr T abs(T v) noexcept {
|
||||||
{
|
|
||||||
return v < 0 ? -v : v;
|
return v < 0 ? -v : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::tuple<std::intmax_t, std::intmax_t, std::intmax_t> normalize(std::intmax_t num, std::intmax_t den, std::intmax_t exp)
|
constexpr std::tuple<std::intmax_t, std::intmax_t, std::intmax_t> normalize(std::intmax_t num, std::intmax_t den, std::intmax_t exp) {
|
||||||
{
|
|
||||||
std::intmax_t gcd = std::gcd(num, den);
|
std::intmax_t gcd = std::gcd(num, den);
|
||||||
num = num * (den < 0 ? -1 : 1) / gcd;
|
num = num * (den < 0 ? -1 : 1) / gcd;
|
||||||
den = detail::abs(den) / gcd;
|
den = detail::abs(den) / gcd;
|
||||||
@@ -81,13 +79,47 @@ namespace detail {
|
|||||||
template<intmax_t Num, intmax_t Den, intmax_t Exp>
|
template<intmax_t Num, intmax_t Den, intmax_t Exp>
|
||||||
inline constexpr bool is_ratio<ratio<Num, Den, Exp>> = true;
|
inline constexpr bool is_ratio<ratio<Num, Den, Exp>> = true;
|
||||||
|
|
||||||
} // namespace detail
|
template<Ratio R1, Ratio R2>
|
||||||
|
constexpr std::tuple<std::intmax_t, std::intmax_t, std::intmax_t> ratio_add_detail() {
|
||||||
|
std::intmax_t num1 = R1::num;
|
||||||
|
std::intmax_t num2 = R2::num;
|
||||||
|
|
||||||
|
// align exponents
|
||||||
|
std::intmax_t new_exp = R1::exp;
|
||||||
|
if constexpr (R1::exp > R2::exp) {
|
||||||
|
new_exp = R1::exp;
|
||||||
|
while (new_exp > R2::exp) {
|
||||||
|
num1 *= 10;
|
||||||
|
--new_exp;
|
||||||
|
}
|
||||||
|
} else if constexpr (R1::exp < R2::exp) {
|
||||||
|
new_exp = R2::exp;
|
||||||
|
while (R1::exp < new_exp) {
|
||||||
|
num2 *= 10;
|
||||||
|
--new_exp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// common denominator
|
||||||
|
std::intmax_t lcm_den = std::lcm(R1::den, R2::den);
|
||||||
|
num1 = num1 * (lcm_den / R1::den);
|
||||||
|
num2 = num2 * (lcm_den / R2::den);
|
||||||
|
|
||||||
|
return std::make_tuple(num1 + num2, lcm_den, new_exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<Ratio R1, Ratio R2>
|
||||||
|
struct ratio_add_impl {
|
||||||
|
static constexpr auto detail = ratio_add_detail<R1, R2>();
|
||||||
|
using type = ratio<std::get<0>(detail), std::get<1>(detail), std::get<2>(detail)>;
|
||||||
|
};
|
||||||
|
}// namespace detail
|
||||||
|
|
||||||
|
|
||||||
// ratio_add
|
// ratio_add
|
||||||
// TODO implement ratio_add
|
template<Ratio R1, Ratio R2>
|
||||||
// template<Ratio R1, Ratio R2>
|
using ratio_add = detail::ratio_add_impl<R1, R2>::type;
|
||||||
// using ratio_add = detail::ratio_add_impl<R1, R2>::type;
|
|
||||||
|
|
||||||
// ratio_subtract
|
// ratio_subtract
|
||||||
// TODO implement ratio_subtract
|
// TODO implement ratio_subtract
|
||||||
|
@@ -39,4 +39,5 @@ namespace {
|
|||||||
static_assert(std::is_same_v<decltype(sqrt(4km2)), decltype(2km)>);
|
static_assert(std::is_same_v<decltype(sqrt(4km2)), decltype(2km)>);
|
||||||
static_assert(std::is_same_v<decltype(sqrt(4ft2)), decltype(2ft)>);
|
static_assert(std::is_same_v<decltype(sqrt(4ft2)), decltype(2ft)>);
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@@ -76,9 +76,22 @@
|
|||||||
static_assert(std::is_same_v<ratio_sqrt<ratio<0>>, ratio<0>>);
|
static_assert(std::is_same_v<ratio_sqrt<ratio<0>>, ratio<0>>);
|
||||||
static_assert(std::is_same_v<ratio_sqrt<ratio<1, 4>>, ratio<1, 2>>);
|
static_assert(std::is_same_v<ratio_sqrt<ratio<1, 4>>, ratio<1, 2>>);
|
||||||
|
|
||||||
// // sqrt with exponents: TODO not working yet. Also not sure the non exponent version is accurate.
|
// sqrt with exponents
|
||||||
// static_assert(std::is_same_v<ratio_sqrt<ratio<9, 1, 2>>, ratio<3, 1, 1>>);
|
static_assert(std::is_same_v<ratio_sqrt<ratio<9, 1, 2>>, ratio<3, 1, 1>>);
|
||||||
// static_assert(std::is_same_v<ratio_sqrt<ratio<4>>, ratio<2>>);
|
static_assert(std::is_same_v<ratio_sqrt<ratio<4>>, ratio<2>>);
|
||||||
|
|
||||||
|
static_assert(std::is_same_v<units::ratio_add<units::ratio<1, 2, 0>, units::ratio<1, 3, 0>>, units::ratio<5, 6, 0>>);
|
||||||
|
static_assert(std::is_same_v<units::ratio_add<units::ratio<1, 2, 1>, units::ratio<1, 3, 1>>, units::ratio<5, 6, 1>>);
|
||||||
|
static_assert(std::is_same_v<units::ratio_add<units::ratio<3, 8, 2>, units::ratio<2, 7, 2>>, units::ratio<37, 56, 2>>);
|
||||||
|
|
||||||
|
static_assert(std::is_same_v<units::ratio_add<units::ratio<3, 8, 2>, units::ratio<2, 7, 1>>, units::ratio<226, 56, 1>>);
|
||||||
|
static_assert(std::is_same_v<units::ratio_add<units::ratio<2, 7, 1>, units::ratio<3, 8, 2>>, units::ratio<226, 56, 1>>);
|
||||||
|
|
||||||
|
static_assert(std::is_same_v<units::ratio_add<units::ratio<3, 8, -2>, units::ratio<2, 7, -1>>, units::ratio<181, 56, -2>>);
|
||||||
|
static_assert(std::is_same_v<units::ratio_add<units::ratio<2, 7, -1>, units::ratio<3, 8, -2>>, units::ratio<181, 56, -2>>);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// common_ratio
|
// common_ratio
|
||||||
// note use of ::type is required because template params are changed while stamping out template
|
// note use of ::type is required because template params are changed while stamping out template
|
||||||
|
Reference in New Issue
Block a user