/////////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Implements the class template eastl::ratio that provides compile-time // rational arithmetic support. Each instantiation of this template exactly // represents any finite rational number as long as its numerator Num and // denominator Denom are representable as compile-time constants of type // intmax_t. In addition, Denom may not be zero and may not be equal to the most // negative value. Both numerator and denominator are automatically reduced to // the lowest terms. /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_RATIO_H #define EASTL_RATIO_H #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif #include ////////////////////////////////////////////////////////////////////////////// // namespace eastl // { // template // class ratio // { // public: // static constexpr intmax_t num; // static constexpr intmax_t den; // typedef ratio type; // }; // // // ratio arithmetic // template using ratio_add = ...; // template using ratio_subtract = ...; // template using ratio_multiply = ...; // template using ratio_divide = ...; // // // ratio comparison // template struct ratio_equal; // template struct ratio_not_equal; // template struct ratio_less; // template struct ratio_less_equal; // template struct ratio_greater; // template struct ratio_greater_equal; // // // convenience SI typedefs // typedef ratio<1, 1000000000000000000000000> yocto; // not supported // typedef ratio<1, 1000000000000000000000> zepto; // not supported // typedef ratio<1, 1000000000000000000> atto; // typedef ratio<1, 1000000000000000> femto; // typedef ratio<1, 1000000000000> pico; // typedef ratio<1, 1000000000> nano; // typedef ratio<1, 1000000> micro; // typedef ratio<1, 1000> milli; // typedef ratio<1, 100> centi; // typedef ratio<1, 10> deci; // typedef ratio< 10, 1> deca; // typedef ratio< 100, 1> hecto; // typedef ratio< 1000, 1> kilo; // typedef ratio< 1000000, 1> mega; // typedef ratio< 1000000000, 1> giga; // typedef ratio< 1000000000000, 1> tera; // typedef ratio< 1000000000000000, 1> peta; // typedef ratio< 1000000000000000000, 1> exa; // typedef ratio< 1000000000000000000000, 1> zetta; // not supported // typedef ratio<1000000000000000000000000, 1> yotta; // not supported // } ////////////////////////////////////////////////////////////////////////////// #include #include namespace eastl { /////////////////////////////////////////////////////////////////////// // compile-time overflow helpers /////////////////////////////////////////////////////////////////////// #define EASTL_RATIO_ABS(x) ((x) < 0 ? -(x) : (x)) template struct AdditionOverFlow { static const bool c1 = (X <= 0 && 0 <= Y) || (Y < 0 && 0 < X); // True if digits do not have the same sign. static const bool c2 = EASTL_RATIO_ABS(Y) <= INTMAX_MAX - EASTL_RATIO_ABS(X); static const bool value = c1 || c2; }; template struct MultiplyOverFlow { static const bool value = (EASTL_RATIO_ABS(X) <= (INTMAX_MAX / EASTL_RATIO_ABS(Y))); }; /////////////////////////////////////////////////////////////////////// // ratio (C++ Standard: 20.11.3) /////////////////////////////////////////////////////////////////////// template class ratio { public: static EA_CONSTEXPR_OR_CONST intmax_t num = N; static EA_CONSTEXPR_OR_CONST intmax_t den = D; typedef ratio type; }; namespace Internal { // gcd -- implementation based on euclid's algorithm template struct gcd { static const intmax_t value = gcd::value; }; template struct gcd { static const intmax_t value = X; }; template <> struct gcd<0, 0> { static const intmax_t value = 1; }; // lcm template struct lcm { static const intmax_t value = (X * (Y / gcd::value)); }; // ct_add template struct ct_add { static_assert(AdditionOverFlow::value, "compile-time addition overflow"); static const intmax_t value = X + Y; }; // ct_sub template struct ct_sub { static_assert(AdditionOverFlow::value, "compile-time addition overflow"); static const intmax_t value = X - Y; }; // ct_multi template struct ct_multi { static_assert(MultiplyOverFlow::value, "compile-time multiply overflow"); static const intmax_t value = X * Y; }; // ct_simplify template struct ct_simplify { static const intmax_t divisor = Internal::gcd::value; static const intmax_t num = R1::num / divisor; static const intmax_t den = R1::den / divisor; typedef ratio ratio_type; typedef ct_simplify this_type; }; #if EASTL_VARIABLE_TEMPLATES_ENABLED template intmax_t ct_add_v = ct_add::value; template intmax_t ct_multi_v = ct_multi::value; template R2 ct_simplify_t = ct_simplify::ratio_type; #else template struct ct_add_v : public ct_add::value {}; template struct ct_multi_v : public ct_multi::value {}; template struct ct_simplify_t : public ct_simplify::ratio_type {}; #endif /////////////////////////////////////////////////////////////////////// // ratio_add /////////////////////////////////////////////////////////////////////// template struct ratio_add { typedef typename ct_simplify < typename ratio < ct_add < ct_multi::value, ct_multi::value >::value, ct_multi::value >::type >::ratio_type type; }; /////////////////////////////////////////////////////////////////////// // ratio_subtract /////////////////////////////////////////////////////////////////////// template struct ratio_subtract { typedef typename ct_simplify < typename ratio < ct_sub < ct_multi::value, ct_multi::value >::value, ct_multi::value >::type >::ratio_type type; }; /////////////////////////////////////////////////////////////////////// // ratio_multiply /////////////////////////////////////////////////////////////////////// template struct ratio_multiply { typedef typename ct_simplify < typename ratio < ct_multi::value, ct_multi::value >::type >::ratio_type type; }; /////////////////////////////////////////////////////////////////////// // ratio_divide /////////////////////////////////////////////////////////////////////// template struct ratio_divide { typedef typename ct_simplify < typename ratio < ct_multi::value, ct_multi::value >::type >::ratio_type type; }; /////////////////////////////////////////////////////////////////////// // ratio_equal /////////////////////////////////////////////////////////////////////// template struct ratio_equal { typedef ct_simplify sr1_t; typedef ct_simplify sr2_t; static const bool value = (sr1_t::num == sr2_t::num) && (sr1_t::den == sr2_t::den); }; /////////////////////////////////////////////////////////////////////// // ratio_less /////////////////////////////////////////////////////////////////////// template struct ratio_less { static const bool value = (R1::num * R2::den) < (R2::num * R1::den); }; } // namespace Internal /////////////////////////////////////////////////////////////////////// // ratio arithmetic (C++ Standard: 20.11.4) /////////////////////////////////////////////////////////////////////// #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) || (defined(_MSC_VER) && (_MSC_VER < 1900)) // prior to VS2015 template struct ratio_add : public Internal::ratio_add::type {}; template struct ratio_subtract : public Internal::ratio_subtract::type {}; template struct ratio_multiply : public Internal::ratio_multiply::type {}; template struct ratio_divide : public Internal::ratio_divide::type {}; #else template using ratio_add = typename Internal::ratio_add::type; template using ratio_subtract = typename Internal::ratio_subtract::type; template using ratio_multiply = typename Internal::ratio_multiply::type; template using ratio_divide = typename Internal::ratio_divide::type; #endif /////////////////////////////////////////////////////////////////////// // ratio comparison (C++ Standard: 20.11.5) /////////////////////////////////////////////////////////////////////// template struct ratio_equal : public integral_constant::value> {}; template struct ratio_not_equal : public integral_constant::value> {}; template struct ratio_less : public integral_constant::value> {}; template struct ratio_less_equal : public integral_constant::value> {}; template struct ratio_greater : public integral_constant::value> {}; template struct ratio_greater_equal : public integral_constant::value> {}; /////////////////////////////////////////////////////////////////////// // convenience SI typedefs (C++ Standard: 20.11.6) /////////////////////////////////////////////////////////////////////// // typedef ratio<1, 1000000000000000000000000> yocto; // not supported, too big for intmax_t // typedef ratio<1, 1000000000000000000000 > zepto; // not supported, too big for intmax_t typedef ratio<1, 1000000000000000000 > atto; typedef ratio<1, 1000000000000000 > femto; typedef ratio<1, 1000000000000 > pico; typedef ratio<1, 1000000000 > nano; typedef ratio<1, 1000000 > micro; typedef ratio<1, 1000 > milli; typedef ratio<1, 100 > centi; typedef ratio<1, 10 > deci; typedef ratio<10, 1 > deca; typedef ratio<100, 1 > hecto; typedef ratio<1000, 1 > kilo; typedef ratio<1000000, 1 > mega; typedef ratio<1000000000, 1 > giga; typedef ratio<1000000000000, 1 > tera; typedef ratio<1000000000000000, 1 > peta; typedef ratio<1000000000000000000, 1 > exa; // typedef ratio<1000000000000000000000, 1 > zetta; // not supported, too big for intmax_t // typedef ratio<1000000000000000000000000, 1> yotta; // not supported, too big for intmax_t } #endif // EASTL_RATIO_H