From 0566cc631dad3a9934b897b6f71c03caca12ddf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Sch=C3=B6nrock?= Date: Sun, 16 Feb 2020 02:35:49 +0000 Subject: [PATCH] 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) --- src/include/units/bits/dim_consolidate.h | 6 +-- src/include/units/ratio.h | 48 ++++++++++++++++++++---- test/unit_test/static/math_test.cpp | 1 + test/unit_test/static/ratio_test.cpp | 19 ++++++++-- 4 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/include/units/bits/dim_consolidate.h b/src/include/units/bits/dim_consolidate.h index 7a5e8057..aba1a706 100644 --- a/src/include/units/bits/dim_consolidate.h +++ b/src/include/units/bits/dim_consolidate.h @@ -30,10 +30,10 @@ namespace units::detail { /** * @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 * their exponents. If this accumulation will result with 0, such a dimension is removed from the list. - * + * * @tparam D derived dimension to consolidate */ template @@ -56,7 +56,7 @@ struct dim_consolidate> { template struct dim_consolidate, exp, 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; using r2 = std::ratio; using r = std::ratio_add; diff --git a/src/include/units/ratio.h b/src/include/units/ratio.h index a47020ae..6d2321a4 100644 --- a/src/include/units/ratio.h +++ b/src/include/units/ratio.h @@ -35,13 +35,11 @@ namespace units { namespace detail { template -[[nodiscard]] constexpr T abs(T v) noexcept -{ +[[nodiscard]] constexpr T abs(T v) noexcept { return v < 0 ? -v : v; } -constexpr std::tuple normalize(std::intmax_t num, std::intmax_t den, std::intmax_t exp) -{ +constexpr std::tuple normalize(std::intmax_t num, std::intmax_t den, std::intmax_t exp) { std::intmax_t gcd = std::gcd(num, den); num = num * (den < 0 ? -1 : 1) / gcd; den = detail::abs(den) / gcd; @@ -81,13 +79,47 @@ namespace detail { template inline constexpr bool is_ratio> = true; -} // namespace detail +template +constexpr std::tuple 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 +struct ratio_add_impl { + static constexpr auto detail = ratio_add_detail(); + using type = ratio(detail), std::get<1>(detail), std::get<2>(detail)>; +}; +}// namespace detail // ratio_add -// TODO implement ratio_add -// template -// using ratio_add = detail::ratio_add_impl::type; +template +using ratio_add = detail::ratio_add_impl::type; // ratio_subtract // TODO implement ratio_subtract diff --git a/test/unit_test/static/math_test.cpp b/test/unit_test/static/math_test.cpp index 766ac726..6d9d35ba 100644 --- a/test/unit_test/static/math_test.cpp +++ b/test/unit_test/static/math_test.cpp @@ -39,4 +39,5 @@ namespace { static_assert(std::is_same_v); static_assert(std::is_same_v); + } // namespace diff --git a/test/unit_test/static/ratio_test.cpp b/test/unit_test/static/ratio_test.cpp index 7164a32b..987bd363 100644 --- a/test/unit_test/static/ratio_test.cpp +++ b/test/unit_test/static/ratio_test.cpp @@ -76,9 +76,22 @@ static_assert(std::is_same_v>, ratio<0>>); static_assert(std::is_same_v>, ratio<1, 2>>); - // // sqrt with exponents: TODO not working yet. Also not sure the non exponent version is accurate. - // static_assert(std::is_same_v>, ratio<3, 1, 1>>); - // static_assert(std::is_same_v>, ratio<2>>); + // sqrt with exponents + static_assert(std::is_same_v>, ratio<3, 1, 1>>); + static_assert(std::is_same_v>, ratio<2>>); + + static_assert(std::is_same_v, units::ratio<1, 3, 0>>, units::ratio<5, 6, 0>>); + static_assert(std::is_same_v, units::ratio<1, 3, 1>>, units::ratio<5, 6, 1>>); + static_assert(std::is_same_v, units::ratio<2, 7, 2>>, units::ratio<37, 56, 2>>); + + static_assert(std::is_same_v, units::ratio<2, 7, 1>>, units::ratio<226, 56, 1>>); + static_assert(std::is_same_v, units::ratio<3, 8, 2>>, units::ratio<226, 56, 1>>); + + static_assert(std::is_same_v, units::ratio<2, 7, -1>>, units::ratio<181, 56, -2>>); + static_assert(std::is_same_v, units::ratio<3, 8, -2>>, units::ratio<181, 56, -2>>); + + + // common_ratio // note use of ::type is required because template params are changed while stamping out template