1 /////////////////////////////////////////////////////////////////////////////// 2 // Copyright (c) Electronic Arts Inc. All rights reserved. 3 /////////////////////////////////////////////////////////////////////////////// 4 5 6 /////////////////////////////////////////////////////////////////////////////// 7 // Implements the class template eastl::ratio that provides compile-time 8 // rational arithmetic support. Each instantiation of this template exactly 9 // represents any finite rational number as long as its numerator Num and 10 // denominator Denom are representable as compile-time constants of type 11 // intmax_t. In addition, Denom may not be zero and may not be equal to the most 12 // negative value. Both numerator and denominator are automatically reduced to 13 // the lowest terms. 14 /////////////////////////////////////////////////////////////////////////////// 15 16 17 #ifndef EASTL_RATIO_H 18 #define EASTL_RATIO_H 19 20 #if defined(EA_PRAGMA_ONCE_SUPPORTED) 21 #pragma once 22 #endif 23 24 #include <EABase/eabase.h> 25 26 27 ////////////////////////////////////////////////////////////////////////////// 28 // namespace eastl 29 // { 30 // template <intmax_t N, intmax_t D = 1> 31 // class ratio 32 // { 33 // public: 34 // static constexpr intmax_t num; 35 // static constexpr intmax_t den; 36 // typedef ratio<num, den> type; 37 // }; 38 // 39 // // ratio arithmetic 40 // template <class R1, class R2> using ratio_add = ...; 41 // template <class R1, class R2> using ratio_subtract = ...; 42 // template <class R1, class R2> using ratio_multiply = ...; 43 // template <class R1, class R2> using ratio_divide = ...; 44 // 45 // // ratio comparison 46 // template <class R1, class R2> struct ratio_equal; 47 // template <class R1, class R2> struct ratio_not_equal; 48 // template <class R1, class R2> struct ratio_less; 49 // template <class R1, class R2> struct ratio_less_equal; 50 // template <class R1, class R2> struct ratio_greater; 51 // template <class R1, class R2> struct ratio_greater_equal; 52 // 53 // // convenience SI typedefs 54 // typedef ratio<1, 1000000000000000000000000> yocto; // not supported 55 // typedef ratio<1, 1000000000000000000000> zepto; // not supported 56 // typedef ratio<1, 1000000000000000000> atto; 57 // typedef ratio<1, 1000000000000000> femto; 58 // typedef ratio<1, 1000000000000> pico; 59 // typedef ratio<1, 1000000000> nano; 60 // typedef ratio<1, 1000000> micro; 61 // typedef ratio<1, 1000> milli; 62 // typedef ratio<1, 100> centi; 63 // typedef ratio<1, 10> deci; 64 // typedef ratio< 10, 1> deca; 65 // typedef ratio< 100, 1> hecto; 66 // typedef ratio< 1000, 1> kilo; 67 // typedef ratio< 1000000, 1> mega; 68 // typedef ratio< 1000000000, 1> giga; 69 // typedef ratio< 1000000000000, 1> tera; 70 // typedef ratio< 1000000000000000, 1> peta; 71 // typedef ratio< 1000000000000000000, 1> exa; 72 // typedef ratio< 1000000000000000000000, 1> zetta; // not supported 73 // typedef ratio<1000000000000000000000000, 1> yotta; // not supported 74 // } 75 ////////////////////////////////////////////////////////////////////////////// 76 77 78 #include <EASTL/internal/config.h> 79 #include <EASTL/type_traits.h> 80 81 82 namespace eastl 83 { 84 /////////////////////////////////////////////////////////////////////// 85 // compile-time overflow helpers 86 /////////////////////////////////////////////////////////////////////// 87 #define EASTL_RATIO_ABS(x) ((x) < 0 ? -(x) : (x)) 88 89 template <intmax_t X, intmax_t Y> 90 struct AdditionOverFlow 91 { 92 static const bool c1 = (X <= 0 && 0 <= Y) || (Y < 0 && 0 < X); // True if digits do not have the same sign. 93 static const bool c2 = EASTL_RATIO_ABS(Y) <= INTMAX_MAX - EASTL_RATIO_ABS(X); 94 static const bool value = c1 || c2; 95 }; 96 97 template <intmax_t X, intmax_t Y> 98 struct MultiplyOverFlow 99 { 100 static const bool value = (EASTL_RATIO_ABS(X) <= (INTMAX_MAX / EASTL_RATIO_ABS(Y))); 101 }; 102 103 104 /////////////////////////////////////////////////////////////////////// 105 // ratio (C++ Standard: 20.11.3) 106 /////////////////////////////////////////////////////////////////////// 107 template <intmax_t N = 0, intmax_t D = 1> 108 class ratio 109 { 110 public: 111 static EA_CONSTEXPR_OR_CONST intmax_t num = N; 112 static EA_CONSTEXPR_OR_CONST intmax_t den = D; 113 typedef ratio<num, den> type; 114 }; 115 116 namespace Internal 117 { 118 // gcd -- implementation based on euclid's algorithm 119 template <intmax_t X, intmax_t Y> struct gcd { static const intmax_t value = gcd<Y, X % Y>::value; }; 120 template <intmax_t X> struct gcd<X, 0> { static const intmax_t value = X; }; 121 template <> struct gcd<0, 0> { static const intmax_t value = 1; }; 122 123 // lcm 124 template<intmax_t X, intmax_t Y> 125 struct lcm { static const intmax_t value = (X * (Y / gcd<X,Y>::value)); }; 126 127 // ct_add 128 template <intmax_t X, intmax_t Y> 129 struct ct_add 130 { 131 static_assert(AdditionOverFlow<X,Y>::value, "compile-time addition overflow"); 132 static const intmax_t value = X + Y; 133 }; 134 135 // ct_sub 136 template <intmax_t X, intmax_t Y> 137 struct ct_sub 138 { 139 static_assert(AdditionOverFlow<X,-Y>::value, "compile-time addition overflow"); 140 static const intmax_t value = X - Y; 141 }; 142 143 // ct_multi 144 template <intmax_t X, intmax_t Y> 145 struct ct_multi 146 { 147 static_assert(MultiplyOverFlow<X,Y>::value, "compile-time multiply overflow"); 148 static const intmax_t value = X * Y; 149 }; 150 151 // ct_simplify 152 template <class R1> 153 struct ct_simplify 154 { 155 static const intmax_t divisor = Internal::gcd<R1::num, R1::den>::value; 156 static const intmax_t num = R1::num / divisor; 157 static const intmax_t den = R1::den / divisor; 158 159 typedef ratio<num, den> ratio_type; 160 typedef ct_simplify<R1> this_type; 161 }; 162 163 #if EASTL_VARIABLE_TEMPLATES_ENABLED 164 template <intmax_t N1, intmax_t N2> intmax_t ct_add_v = ct_add<N1, N2>::value; 165 template <intmax_t N1, intmax_t N2> intmax_t ct_multi_v = ct_multi<N1, N2>::value; 166 template <class R1, class R2> R2 ct_simplify_t = ct_simplify<R1>::ratio_type; 167 #else 168 template <intmax_t N1, intmax_t N2> struct ct_add_v : public ct_add<N1, N2>::value {}; 169 template <intmax_t N1, intmax_t N2> struct ct_multi_v : public ct_multi<N1, N2>::value {}; 170 template <class R1> struct ct_simplify_t : public ct_simplify<R1>::ratio_type {}; 171 #endif 172 173 /////////////////////////////////////////////////////////////////////// 174 // ratio_add 175 /////////////////////////////////////////////////////////////////////// 176 template <class R1, class R2> 177 struct ratio_add 178 { 179 typedef typename ct_simplify 180 < 181 typename ratio 182 < 183 ct_add 184 < 185 ct_multi<R1::num, R2::den>::value, 186 ct_multi<R2::num, R1::den>::value 187 >::value, 188 ct_multi<R1::den, R2::den>::value 189 >::type 190 >::ratio_type type; 191 }; 192 193 /////////////////////////////////////////////////////////////////////// 194 // ratio_subtract 195 /////////////////////////////////////////////////////////////////////// 196 template <class R1, class R2> 197 struct ratio_subtract 198 { 199 typedef typename ct_simplify 200 < 201 typename ratio 202 < 203 ct_sub 204 < 205 ct_multi<R1::num, R2::den>::value, 206 ct_multi<R2::num, R1::den>::value 207 >::value, 208 ct_multi<R1::den, R2::den>::value 209 >::type 210 >::ratio_type type; 211 }; 212 213 /////////////////////////////////////////////////////////////////////// 214 // ratio_multiply 215 /////////////////////////////////////////////////////////////////////// 216 template <class R1, class R2> 217 struct ratio_multiply 218 { 219 typedef typename ct_simplify 220 < 221 typename ratio 222 < 223 ct_multi<R1::num, R2::num>::value, 224 ct_multi<R1::den, R2::den>::value 225 >::type 226 >::ratio_type type; 227 }; 228 229 /////////////////////////////////////////////////////////////////////// 230 // ratio_divide 231 /////////////////////////////////////////////////////////////////////// 232 template <class R1, class R2> 233 struct ratio_divide 234 { 235 typedef typename ct_simplify 236 < 237 typename ratio 238 < 239 ct_multi<R1::num, R2::den>::value, 240 ct_multi<R1::den, R2::num>::value 241 >::type 242 >::ratio_type type; 243 }; 244 245 /////////////////////////////////////////////////////////////////////// 246 // ratio_equal 247 /////////////////////////////////////////////////////////////////////// 248 template <class R1, class R2> 249 struct ratio_equal 250 { 251 typedef ct_simplify<R1> sr1_t; 252 typedef ct_simplify<R2> sr2_t; 253 254 static const bool value = (sr1_t::num == sr2_t::num) && (sr1_t::den == sr2_t::den); 255 }; 256 257 /////////////////////////////////////////////////////////////////////// 258 // ratio_less 259 /////////////////////////////////////////////////////////////////////// 260 template <class R1, class R2> 261 struct ratio_less 262 { 263 static const bool value = (R1::num * R2::den) < (R2::num * R1::den); 264 }; 265 } // namespace Internal 266 267 268 /////////////////////////////////////////////////////////////////////// 269 // ratio arithmetic (C++ Standard: 20.11.4) 270 /////////////////////////////////////////////////////////////////////// 271 #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) || (defined(_MSC_VER) && (_MSC_VER < 1900)) // prior to VS2015 272 template <class R1, class R2> struct ratio_add : public Internal::ratio_add<R1, R2>::type {}; 273 template <class R1, class R2> struct ratio_subtract : public Internal::ratio_subtract<R1, R2>::type {}; 274 template <class R1, class R2> struct ratio_multiply : public Internal::ratio_multiply<R1, R2>::type {}; 275 template <class R1, class R2> struct ratio_divide : public Internal::ratio_divide<R1, R2>::type {}; 276 #else 277 template <class R1, class R2> using ratio_add = typename Internal::ratio_add<R1, R2>::type; 278 template <class R1, class R2> using ratio_subtract = typename Internal::ratio_subtract<R1, R2>::type; 279 template <class R1, class R2> using ratio_multiply = typename Internal::ratio_multiply<R1, R2>::type; 280 template <class R1, class R2> using ratio_divide = typename Internal::ratio_divide<R1, R2>::type; 281 #endif 282 283 284 /////////////////////////////////////////////////////////////////////// 285 // ratio comparison (C++ Standard: 20.11.5) 286 /////////////////////////////////////////////////////////////////////// 287 template <class R1, class R2> struct ratio_equal : public integral_constant<bool, Internal::ratio_equal<R1, R2>::value> {}; 288 template <class R1, class R2> struct ratio_not_equal : public integral_constant<bool, !ratio_equal<R1, R2>::value> {}; 289 template <class R1, class R2> struct ratio_less : public integral_constant<bool, Internal::ratio_less<R1, R2>::value> {}; 290 template <class R1, class R2> struct ratio_less_equal : public integral_constant<bool, !ratio_less<R2, R1>::value> {}; 291 template <class R1, class R2> struct ratio_greater : public integral_constant<bool, ratio_less<R2, R1>::value> {}; 292 template <class R1, class R2> struct ratio_greater_equal : public integral_constant<bool, !ratio_less<R1, R2>::value> {}; 293 294 295 /////////////////////////////////////////////////////////////////////// 296 // convenience SI typedefs (C++ Standard: 20.11.6) 297 /////////////////////////////////////////////////////////////////////// 298 // typedef ratio<1, 1000000000000000000000000> yocto; // not supported, too big for intmax_t 299 // typedef ratio<1, 1000000000000000000000 > zepto; // not supported, too big for intmax_t 300 typedef ratio<1, 1000000000000000000 > atto; 301 typedef ratio<1, 1000000000000000 > femto; 302 typedef ratio<1, 1000000000000 > pico; 303 typedef ratio<1, 1000000000 > nano; 304 typedef ratio<1, 1000000 > micro; 305 typedef ratio<1, 1000 > milli; 306 typedef ratio<1, 100 > centi; 307 typedef ratio<1, 10 > deci; 308 typedef ratio<10, 1 > deca; 309 typedef ratio<100, 1 > hecto; 310 typedef ratio<1000, 1 > kilo; 311 typedef ratio<1000000, 1 > mega; 312 typedef ratio<1000000000, 1 > giga; 313 typedef ratio<1000000000000, 1 > tera; 314 typedef ratio<1000000000000000, 1 > peta; 315 typedef ratio<1000000000000000000, 1 > exa; 316 // typedef ratio<1000000000000000000000, 1 > zetta; // not supported, too big for intmax_t 317 // typedef ratio<1000000000000000000000000, 1> yotta; // not supported, too big for intmax_t 318 } 319 320 #endif // EASTL_RATIO_H 321