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:
Oliver Schönrock
2020-02-16 02:35:49 +00:00
committed by Mateusz Pusz
parent dfb9042e9d
commit 0566cc631d
4 changed files with 60 additions and 14 deletions

View File

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

View File

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

View File

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

View File

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