Skip to content

Commit

Permalink
✨ add ratio
Browse files Browse the repository at this point in the history
  • Loading branch information
zie87 committed Oct 7, 2023
1 parent 5f9d78a commit 048e21b
Show file tree
Hide file tree
Showing 8 changed files with 694 additions and 0 deletions.
38 changes: 38 additions & 0 deletions include/zll/numeric/ratio.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

#ifndef ZLL_NUMERIC_RATIO_HPP
#define ZLL_NUMERIC_RATIO_HPP

#include "zll/numeric/ratio/ratio_type.hpp"
#include "zll/numeric/ratio/arithmetic.hpp"
#include "zll/numeric/ratio/comparsion.hpp"


namespace zll {

// clang-format off
typedef ratio<1L, 1000000000000000000L> atto;
typedef ratio<1L, 1000000000000000L> femto;
typedef ratio<1L, 1000000000000L> pico;
typedef ratio<1L, 1000000000L> nano;
typedef ratio<1L, 1000000L> micro;
typedef ratio<1L, 1000L> milli;
typedef ratio<1L, 100L> centi;
typedef ratio<1L, 10L> deci;
typedef ratio< 10L, 1L> deca;
typedef ratio< 100L, 1L> hecto;
typedef ratio< 1000L, 1L> kilo;
typedef ratio< 1000000L, 1L> mega;
typedef ratio< 1000000000L, 1L> giga;
typedef ratio< 1000000000000L, 1L> tera;
typedef ratio< 1000000000000000L, 1L> peta;
typedef ratio<1000000000000000000L, 1L> exa;
// clang-format on

} // namespace zll

#endif // ZLL_NUMERIC_RATIO_HPP
105 changes: 105 additions & 0 deletions include/zll/numeric/ratio/arithmetic.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

#ifndef ZLL_NUMERIC_RATIO_ARITHMETIC_HPP
#define ZLL_NUMERIC_RATIO_ARITHMETIC_HPP

#include "zll/numeric/ratio/ratio_type.hpp"
#include "zll/numeric/ratio/helper.hpp"
#include "zll/numeric/ratio/overflow_helper.hpp"

#include "zll/meta/enable_if.hpp"
#include "zll/meta/integral_constant.hpp"

#include "zll/cstdint.hpp"

namespace zll {
namespace detail {
template <typename LHS_T, typename RHS_T>
struct ratio_add_helper {
static const zll::intmax_t gcd = ratio_gcd_helper<LHS_T::den, RHS_T::den>::value;

static const zll::intmax_t num = safe_addition<safe_multiply<LHS_T::num, (RHS_T::den / gcd)>::value,
safe_multiply<RHS_T::num, (LHS_T::den / gcd)>::value>::value;
static const zll::intmax_t den = safe_multiply<LHS_T::den, (RHS_T::den / gcd)>::value;

typedef ratio<num, den> ratio_type;
typedef typename ratio_type::type type;
};

} // namespace detail

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_add {
typedef typename detail::ratio_add_helper<LHS_T, RHS_T>::type type;
};
// clang-format on

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_subtract {
typedef typename detail::ratio_add_helper< LHS_T, ratio<-RHS_T::num, RHS_T::den> >::type type;
};
// clang-format on

namespace detail {

template <typename LHS_T, typename RHS_T>
struct ratio_multiply_helper {
static const zll::intmax_t gcd_x = ratio_gcd_helper<LHS_T::num, RHS_T::den>::value;
static const zll::intmax_t gcd_y = ratio_gcd_helper<RHS_T::num, LHS_T::den>::value;

static const zll::intmax_t num = safe_multiply<LHS_T::num / gcd_x, RHS_T::num / gcd_y>::value;
static const zll::intmax_t den = safe_multiply<LHS_T::den / gcd_y, RHS_T::den / gcd_x>::value;

typedef ratio<num, den> ratio_type;
typedef typename ratio_type::type type;
};

} // namespace detail

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_multiply {
typedef typename detail::ratio_multiply_helper<LHS_T, RHS_T>::type type;
};
// clang-format on
namespace detail {

template <typename LHS_T, typename RHS_T>
struct ratio_divide_helper {
static const zll::intmax_t gcd_num = ratio_gcd_helper<LHS_T::num, RHS_T::num>::value;
static const zll::intmax_t gcd_den = ratio_gcd_helper<RHS_T::den, LHS_T::den>::value;

static const zll::intmax_t num = safe_multiply<LHS_T::num / gcd_num, RHS_T::den / gcd_den>::value;
static const zll::intmax_t den = safe_multiply<RHS_T::num / gcd_num, LHS_T::den / gcd_den>::value;

typedef ratio<num, den> ratio_type;
typedef typename ratio_type::type type;
};

} // namespace detail

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_divide {
typedef typename detail::ratio_divide_helper<LHS_T, RHS_T>::type type;
};
// clang-format on


} // namespace zll

#endif // ZLL_NUMERIC_RATIO_ARITHMETIC_HPP
94 changes: 94 additions & 0 deletions include/zll/numeric/ratio/comparsion.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

#ifndef ZLl_NUMERIC_RATIO_COMPARSION_HPP
#define ZLl_NUMERIC_RATIO_COMPARSION_HPP

#include "zll/numeric/ratio/ratio_type.hpp"
#include "zll/numeric/ratio/helper.hpp"
#include "zll/numeric/ratio/overflow_helper.hpp"

#include "zll/meta/enable_if.hpp"
#include "zll/meta/integral_constant.hpp"

namespace zll {

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_equal : meta::bool_constant<((LHS_T::num == RHS_T::num) && (LHS_T::den == RHS_T::den))> {};
// clang-format on

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_not_equal : meta::bool_constant< !(ratio_equal<LHS_T,RHS_T>::value) > {};
// clang-format on

namespace detail {
// clang-format off
template <typename LHS_T, typename RHS_T>
struct ratio_less_helper_impl {
static const zll::intmax_t lhs = detail::safe_multiply<LHS_T::num, RHS_T::den>::value;
static const zll::intmax_t rhs = detail::safe_multiply<RHS_T::num, LHS_T::den>::value;
static const bool value = lhs < rhs;
};
// clang-format on

// clang-format off
template <typename LHS_T, typename RHS_T,
zll::intmax_t LHS_SIGN_V = ratio_sign_helper<LHS_T::num>::value,
zll::intmax_t RHS_SIGN_V = ratio_sign_helper<RHS_T::num>::value>
struct ratio_less_helper : meta::bool_constant<(LHS_SIGN_V < RHS_SIGN_V)> {};
// clang-format on

// clang-format off
template <typename LHS_T, typename RHS_T>
struct ratio_less_helper<LHS_T, RHS_T, 1, 1>
: meta::bool_constant<ratio_less_helper_impl<LHS_T, RHS_T>::value> {};
// clang-format on

// clang-format off
template <typename LHS_T, typename RHS_T>
struct ratio_less_helper<LHS_T, RHS_T, -1, -1>
: meta::bool_constant<ratio_less_helper_impl< ratio<-LHS_T::num, LHS_T::den>,
ratio<-RHS_T::num, RHS_T::den> >::value> {};
// clang-format on
} // namespace detail

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_less : detail::ratio_less_helper<LHS_T, RHS_T> {};
// clang-format on

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_greater : detail::ratio_less_helper<RHS_T, LHS_T> {};
// clang-format on

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_less_equal : meta::bool_constant<!(ratio_greater<LHS_T, RHS_T>::value)> {};
// clang-format on

// clang-format off
template <typename LHS_T, typename RHS_T,
typename meta::enable_if<is_ratio<LHS_T>::value, bool>::type = true,
typename meta::enable_if<is_ratio<RHS_T>::value, bool>::type = true>
struct ratio_greater_equal : meta::bool_constant<!(ratio_less<LHS_T, RHS_T>::value)> {};
// clang-format on

} // namespace zll

#endif // ZLl_NUMERIC_RATIO_COMPARSION_HPP
49 changes: 49 additions & 0 deletions include/zll/numeric/ratio/helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

#ifndef ZLL_NUMERIC_RATIO_HELPER_HPP
#define ZLL_NUMERIC_RATIO_HELPER_HPP

#include "zll/meta/integral_constant.hpp"

#include "zll/cstdint.hpp"

namespace zll {
namespace detail {

template <zll::intmax_t LHS_V, zll::intmax_t RHS_V>
struct ratio_gcd_helper_impl {
static const zll::intmax_t value = ratio_gcd_helper_impl<RHS_V, LHS_V % RHS_V>::value;
};

template <zll::intmax_t V>
struct ratio_gcd_helper_impl<V, 0> {
static const zll::intmax_t value = V;
};

template <>
struct ratio_gcd_helper_impl<0, 0> {
static const zll::intmax_t value = 1;
};

template <zll::intmax_t V>
struct ratio_sign_helper_impl {
static const zll::intmax_t value = (V == 0) ? 0 : ((V < 0) ? -1 : 1);
};

template <zll::intmax_t LHS_V, zll::intmax_t RHS_V>
struct ratio_gcd_helper : meta::integral_constant<zll::intmax_t, ratio_gcd_helper_impl<LHS_V, RHS_V>::value> {};

template <zll::intmax_t V>
struct ratio_abs_helper : meta::integral_constant<zll::intmax_t, ((V < 0) ? -V : V)> {};

template <zll::intmax_t V>
struct ratio_sign_helper : meta::integral_constant<zll::intmax_t, ratio_sign_helper_impl<V>::value> {};

} // namespace detail
} // namespace zll

#endif // ZLL_NUMERIC_RATIO_HELPER_HPP
76 changes: 76 additions & 0 deletions include/zll/numeric/ratio/overflow_helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

#ifndef ZLL_NUMER_RATIO_OVERFLOWHELPER_HPP
#define ZLL_NUMER_RATIO_OVERFLOWHELPER_HPP

#include "zll/debug/static_assert.hpp"
#include "zll/meta/integral_constant.hpp"
#include "zll/numeric/ratio/helper.hpp"

#include "zll/cstdint.hpp"

namespace zll {
namespace detail {

template <zll::intmax_t LHS_V, zll::intmax_t RHS_V>
struct safe_multiply_helper {
static const zll::intmax_t lhs_abs = ratio_abs_helper<LHS_V>::value;
static const zll::intmax_t rhs_abs = ratio_abs_helper<RHS_V>::value;

static const bool value = lhs_abs <= (INTMAX_MAX / rhs_abs);
};

template <zll::intmax_t V>
struct safe_multiply_helper<V, 0> {
static const bool value = true;
};

// clang-format off
template <zll::intmax_t LHS_V, zll::intmax_t RHS_V,
bool NO_OVERFLOW_V = safe_multiply_helper<LHS_V, RHS_V>::value>
struct safe_multiply : meta::integral_constant<zll::intmax_t, (LHS_V * RHS_V)> {};
// clang-format on

template <zll::intmax_t LHS_V, zll::intmax_t RHS_V>
struct safe_multiply<LHS_V, RHS_V, false> {
static const bool no_overflow = safe_multiply_helper<LHS_V, RHS_V>::value;
ZLL_STATIC_ASSERT(no_overflow);
};

// clang-format off
template <zll::intmax_t LHS_V, zll::intmax_t RHS_V,
zll::intmax_t LHS_SIGN_V = ratio_sign_helper<LHS_V>::value,
zll::intmax_t RHS_SIGN_V = ratio_sign_helper<RHS_V>::value>
struct safe_addition_helper {
static const bool value = true;
};
// clang-format on

template <zll::intmax_t LHS_V, zll::intmax_t RHS_V, zll::intmax_t SIGN_V>
struct safe_addition_helper<LHS_V, RHS_V, SIGN_V, SIGN_V> {
static const zll::intmax_t lhs_abs = ratio_abs_helper<LHS_V>::value;
static const zll::intmax_t rhs_abs = ratio_abs_helper<RHS_V>::value;

static const bool value = lhs_abs <= (INTMAX_MAX - rhs_abs);
};

// clang-format off
template <zll::intmax_t LHS_V, zll::intmax_t RHS_V,
bool NO_OVERFLOW_V = safe_addition_helper<LHS_V, RHS_V>::value>
struct safe_addition : meta::integral_constant<zll::intmax_t, (LHS_V + RHS_V)> {};
// clang-format on

template <zll::intmax_t LHS_V, zll::intmax_t RHS_V>
struct safe_addition<LHS_V, RHS_V, false> {
static const bool no_overflow = safe_addition_helper<LHS_V, RHS_V>::value;
ZLL_STATIC_ASSERT(no_overflow);
};

} // namespace detail
} // namespace zll

#endif // ZLL_NUMER_RATIO_OVERFLOWHELPER_HPP
Loading

0 comments on commit 048e21b

Please sign in to comment.