-
Notifications
You must be signed in to change notification settings - Fork 7
/
ratio.h
320 lines (282 loc) · 12.2 KB
/
ratio.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
///////////////////////////////////////////////////////////////////////////////
// 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(EASTL_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include <eastl/EABase/eabase.h>
//////////////////////////////////////////////////////////////////////////////
// namespace eastl
// {
// template <intmax_t N, intmax_t D = 1>
// class ratio
// {
// public:
// static constexpr intmax_t num;
// static constexpr intmax_t den;
// typedef ratio<num, den> type;
// };
//
// // ratio arithmetic
// template <class R1, class R2> using ratio_add = ...;
// template <class R1, class R2> using ratio_subtract = ...;
// template <class R1, class R2> using ratio_multiply = ...;
// template <class R1, class R2> using ratio_divide = ...;
//
// // ratio comparison
// template <class R1, class R2> struct ratio_equal;
// template <class R1, class R2> struct ratio_not_equal;
// template <class R1, class R2> struct ratio_less;
// template <class R1, class R2> struct ratio_less_equal;
// template <class R1, class R2> struct ratio_greater;
// template <class R1, class R2> 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 <eastl/internal/config.h>
#include <eastl/type_traits.h>
namespace eastl
{
///////////////////////////////////////////////////////////////////////
// compile-time overflow helpers
///////////////////////////////////////////////////////////////////////
#define EASTL_RATIO_ABS(x) ((x) < 0 ? -(x) : (x))
template <intmax_t X, intmax_t Y>
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 <intmax_t X, intmax_t Y>
struct MultiplyOverFlow
{
static const bool value = (EASTL_RATIO_ABS(X) <= (INTMAX_MAX / EASTL_RATIO_ABS(Y)));
};
///////////////////////////////////////////////////////////////////////
// ratio (C++ Standard: 20.11.3)
///////////////////////////////////////////////////////////////////////
template <intmax_t N = 0, intmax_t D = 1>
class ratio
{
public:
static EA_CONSTEXPR_OR_CONST intmax_t num = N;
static EA_CONSTEXPR_OR_CONST intmax_t den = D;
typedef ratio<num, den> type;
};
namespace Internal
{
// gcd -- implementation based on euclid's algorithm
template <intmax_t X, intmax_t Y> struct gcd { static const intmax_t value = gcd<Y, X % Y>::value; };
template <intmax_t X> struct gcd<X, 0> { static const intmax_t value = X; };
template <> struct gcd<0, 0> { static const intmax_t value = 1; };
// lcm
template<intmax_t X, intmax_t Y>
struct lcm { static const intmax_t value = (X * (Y / gcd<X,Y>::value)); };
// ct_add
template <intmax_t X, intmax_t Y>
struct ct_add
{
static_assert(AdditionOverFlow<X,Y>::value, "compile-time addition overflow");
static const intmax_t value = X + Y;
};
// ct_sub
template <intmax_t X, intmax_t Y>
struct ct_sub
{
static_assert(AdditionOverFlow<X,-Y>::value, "compile-time addition overflow");
static const intmax_t value = X - Y;
};
// ct_multi
template <intmax_t X, intmax_t Y>
struct ct_multi
{
static_assert(MultiplyOverFlow<X,Y>::value, "compile-time multiply overflow");
static const intmax_t value = X * Y;
};
// ct_simplify
template <class R1>
struct ct_simplify
{
static const intmax_t divisor = Internal::gcd<R1::num, R1::den>::value;
static const intmax_t num = R1::num / divisor;
static const intmax_t den = R1::den / divisor;
typedef ratio<num, den> ratio_type;
typedef ct_simplify<R1> this_type;
};
#if EASTL_VARIABLE_TEMPLATES_ENABLED
template <intmax_t N1, intmax_t N2> intmax_t ct_add_v = ct_add<N1, N2>::value;
template <intmax_t N1, intmax_t N2> intmax_t ct_multi_v = ct_multi<N1, N2>::value;
template <class R1, class R2> R2 ct_simplify_t = ct_simplify<R1>::ratio_type;
#else
template <intmax_t N1, intmax_t N2> struct ct_add_v : public ct_add<N1, N2>::value {};
template <intmax_t N1, intmax_t N2> struct ct_multi_v : public ct_multi<N1, N2>::value {};
template <class R1> struct ct_simplify_t : public ct_simplify<R1>::ratio_type {};
#endif
///////////////////////////////////////////////////////////////////////
// ratio_add
///////////////////////////////////////////////////////////////////////
template <class R1, class R2>
struct ratio_add
{
typedef typename ct_simplify
<
typename ratio
<
ct_add
<
ct_multi<R1::num, R2::den>::value,
ct_multi<R2::num, R1::den>::value
>::value,
ct_multi<R1::den, R2::den>::value
>::type
>::ratio_type type;
};
///////////////////////////////////////////////////////////////////////
// ratio_subtract
///////////////////////////////////////////////////////////////////////
template <class R1, class R2>
struct ratio_subtract
{
typedef typename ct_simplify
<
typename ratio
<
ct_sub
<
ct_multi<R1::num, R2::den>::value,
ct_multi<R2::num, R1::den>::value
>::value,
ct_multi<R1::den, R2::den>::value
>::type
>::ratio_type type;
};
///////////////////////////////////////////////////////////////////////
// ratio_multiply
///////////////////////////////////////////////////////////////////////
template <class R1, class R2>
struct ratio_multiply
{
typedef typename ct_simplify
<
typename ratio
<
ct_multi<R1::num, R2::num>::value,
ct_multi<R1::den, R2::den>::value
>::type
>::ratio_type type;
};
///////////////////////////////////////////////////////////////////////
// ratio_divide
///////////////////////////////////////////////////////////////////////
template <class R1, class R2>
struct ratio_divide
{
typedef typename ct_simplify
<
typename ratio
<
ct_multi<R1::num, R2::den>::value,
ct_multi<R1::den, R2::num>::value
>::type
>::ratio_type type;
};
///////////////////////////////////////////////////////////////////////
// ratio_equal
///////////////////////////////////////////////////////////////////////
template <class R1, class R2>
struct ratio_equal
{
typedef ct_simplify<R1> sr1_t;
typedef ct_simplify<R2> sr2_t;
static const bool value = (sr1_t::num == sr2_t::num) && (sr1_t::den == sr2_t::den);
};
///////////////////////////////////////////////////////////////////////
// ratio_less
///////////////////////////////////////////////////////////////////////
template <class R1, class R2>
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 <class R1, class R2> struct ratio_add : public Internal::ratio_add<R1, R2>::type {};
template <class R1, class R2> struct ratio_subtract : public Internal::ratio_subtract<R1, R2>::type {};
template <class R1, class R2> struct ratio_multiply : public Internal::ratio_multiply<R1, R2>::type {};
template <class R1, class R2> struct ratio_divide : public Internal::ratio_divide<R1, R2>::type {};
#else
template <class R1, class R2> using ratio_add = typename Internal::ratio_add<R1, R2>::type;
template <class R1, class R2> using ratio_subtract = typename Internal::ratio_subtract<R1, R2>::type;
template <class R1, class R2> using ratio_multiply = typename Internal::ratio_multiply<R1, R2>::type;
template <class R1, class R2> using ratio_divide = typename Internal::ratio_divide<R1, R2>::type;
#endif
///////////////////////////////////////////////////////////////////////
// ratio comparison (C++ Standard: 20.11.5)
///////////////////////////////////////////////////////////////////////
template <class R1, class R2> struct ratio_equal : public integral_constant<bool, Internal::ratio_equal<R1, R2>::value> {};
template <class R1, class R2> struct ratio_not_equal : public integral_constant<bool, !ratio_equal<R1, R2>::value> {};
template <class R1, class R2> struct ratio_less : public integral_constant<bool, Internal::ratio_less<R1, R2>::value> {};
template <class R1, class R2> struct ratio_less_equal : public integral_constant<bool, !ratio_less<R2, R1>::value> {};
template <class R1, class R2> struct ratio_greater : public integral_constant<bool, ratio_less<R2, R1>::value> {};
template <class R1, class R2> struct ratio_greater_equal : public integral_constant<bool, !ratio_less<R1, R2>::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