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