YSTest: rational.hpp 源文件

YSTest PreAlpha_b400_20130424 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

全部 类 命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义 组 页
rational.hpp
浏览该文件的文档.
1 ﻿/*
2 Copyright by FrankHB 2011 - 2013.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #ifndef YB_INC_ystdex_rational_hpp_
29 #define YB_INC_ystdex_rational_hpp_ 1
30
31 #include "type_op.hpp"
32 #include "operators.hpp"
33 #include <cmath> // for std::llround;
34 #include <limits>
35
36 namespace ystdex
37 {
38
46 template<typename _tDst, typename _tSrc>
47 yconstfn YB_STATELESS _tDst
48 exp2u(_tSrc n) ynothrow
49 {
50 static_assert(is_unsigned<_tSrc>::value, "Non-integer type found.");
51
52 return _tSrc(1) << n;
53 }
54
55
61 template<typename _type>
62 struct fixed_multiplicative
63 {
64 typedef typename make_signed_c<typename make_fixed_width_int<
65 integer_width<_type>::value << 1>::type,
66 std::is_signed<_type>::value>::type type;
67 };
68
69 template<>
70 struct fixed_multiplicative<std::int64_t>
71 {
72 typedef std::int64_t type;
73 };
74
75 template<>
76 struct fixed_multiplicative<std::uint64_t>
77 {
78 typedef std::uint64_t type;
79 };
80
81
98 template<typename _tBase = std::int32_t,
99 size_t _vInt = std::numeric_limits<_tBase>::digits - 6U,
100 size_t _vFrac = std::numeric_limits<_tBase>::digits - _vInt>
101 class fixed_point : operators::ordered_field_operators<
102 fixed_point<_tBase, _vInt, _vFrac>, operators::unit_steppable<
103 fixed_point<_tBase, _vInt, _vFrac>, operators::shiftable<fixed_point<
104 _tBase, _vInt, _vFrac>, size_t>>>
105 {
106 static_assert(std::is_integral<_tBase>::value, "Non-integral type found.");
107 static_assert(_vInt < size_t(std::numeric_limits<_tBase>::digits),
108 "No sufficient fractional bits found.");
109 static_assert(_vInt + _vFrac == size_t(std::numeric_limits<_tBase>::digits),
110 "Wrong total bits found.");
111
112 template<typename _OtherBase, size_t _vOtherInt, size_t _vOtherFrac>
113 friend class fixed_point;
114 friend class std::numeric_limits<fixed_point<_tBase, _vInt, _vFrac>>;
115
116 public:
117 typedef _tBase base_type;
118
120 static yconstexpr size_t int_bit_n = _vInt;
122 static yconstexpr size_t frac_bit_n = _vFrac;
124 static yconstexpr size_t digit_bit_n = int_bit_n + frac_bit_n;
125
126 private:
128 typedef empty_base<fixed_point> internal_construct_tag;
129
130 base_type value;
131
132 public:
137 yconstfn
138 fixed_point() ynothrow
139 {}
140
141 private:
142 yconstfn
143 fixed_point(base_type v, internal_construct_tag) ynothrow
144 : value(v)
145 {}
146
147 public:
148 template<typename _tInt>
149 yconstfn
150 fixed_point(_tInt val, typename std::enable_if<
151 std::is_integral<_tInt>::value, int>::type = 0) ynothrow
152 : value(base_type(val) << frac_bit_n)
153 {}
154 template<typename _tFloat>
155 yconstfn
156 fixed_point(_tFloat val, typename std::enable_if<std::is_floating_point<
157 _tFloat>::value, int>::type = 0) ynothrow
158 : value(::llround(base_element() * val))
159 {
160 // TODO: Use std::llround.
161 }
162 yconstfn
163 fixed_point(const fixed_point&) = default;
164 template<size_t _vOtherInt, size_t _vOtherFrac>
165 yconstfn
166 fixed_point(const fixed_point<base_type, _vOtherInt, _vOtherFrac>& f,
167 typename std::enable_if<(_vOtherInt < int_bit_n), int>::type = 0)
168 ynothrow
169 : value(f.value >> (int_bit_n - _vOtherInt))
170 {}
171 template<size_t _vOtherInt, size_t _vOtherFrac>
172 yconstfn
173 fixed_point(const fixed_point<base_type, _vOtherInt, _vOtherFrac>& f,
174 typename std::enable_if<(int_bit_n < _vOtherInt), int>::type = 0)
175 ynothrow
176 : value(f.value << (_vOtherInt - int_bit_n))
177 {}
178
179 bool
180 operator<(const fixed_point& f) const ynothrow
181 {
182 return value < f.value;
183 }
184
185 bool
186 operator==(const fixed_point& f) const ynothrow
187 {
188 return value == f.value;
189 }
190
191 bool
192 operator!() const ynothrow
193 {
194 return value == 0;
195 }
196
197 fixed_point
198 operator-() const ynothrow
199 {
200 fixed_point result;
201
202 result.value = -value;
203 return result;
204 }
205
206 fixed_point&
207 operator++() ynothrow
208 {
209 value += base_element();
210 return *this;
211 }
212
213 fixed_point&
214 operator--() ynothrow
215 {
216 value -= base_element();
217 return *this;
218 }
219
220 fixed_point&
221 operator+=(const fixed_point& f) ynothrow
222 {
223 value += f.value;
224 return *this;
225 }
226
227 fixed_point&
228 operator-=(const fixed_point& f) ynothrow
229 {
230 value -= f.value;
231 return *this;
232 }
233
234 fixed_point&
235 operator*=(const fixed_point& f) ynothrow
236 {
237 typename fixed_multiplicative<base_type>::type
238 tmp(value * f.value);
239 yconstexpr size_t shift_bit_n(frac_bit_n
240 + std::is_signed<base_type>::value);
241
242 value = tmp < 0 ? -(-tmp >> shift_bit_n) : tmp >> shift_bit_n;
243 // NOTE: Code below is only fit for unsigned type, due to there exists
244 // implementation-defined in conversion and right shifting on
245 // operands of signed types.
246 // value = (typename fixed_multiplicative<base_type>::type(value)
247 // * f.value) >> shift_bit_n;
248 return *this;
249 }
250
251 fixed_point&
252 operator/=(const fixed_point& f) ynothrow
253 {
254 value = (typename fixed_multiplicative<base_type>::type(value)
255 << frac_bit_n) / f.value;
256 return *this;
257 }
258
259 fixed_point&
260 operator>>=(size_t s) ynothrow
261 {
262 value >>= s;
263 return *this;
264 }
265
266 fixed_point&
267 operator<<=(size_t s) ynothrow
268 {
269 value <<= s;
270 return *this;
271 }
272
273 template<typename _type>
274 inline
275 operator _type() const
276 {
277 return this->cast<_type>();
278 }
279
280 private:
281 template<typename _type>
282 inline typename std::enable_if<std::is_integral<_type>::value,
283 _type>::type
284 cast() const
285 {
286 return value >> frac_bit_n;
287 }
288 template<typename _type>
289 typename std::enable_if<std::is_floating_point<_type>::value,
290 _type>::type
291 cast() const
292 {
293 return _type(value) / base_element();
294 }
295
296 public:
302 static yconstfn base_type
303 base_element() ynothrow
304 {
305 return ystdex::exp2u<base_type, base_type>(frac_bit_n);
306 }
307
313 static yconstfn fixed_point
314 identity() ynothrow
315 {
316 return fixed_point(base_element());
317 }
318
319 friend fixed_point
320 fabs(fixed_point x)
321 {
322 return x.value < 0 ? -x : x;
323 }
324
325 friend yconstfn fixed_point
326 ceil(fixed_point x)
327 {
328 return fixed_point((x.value + base_element() - 1)
329 & ~(base_element() - 1), internal_construct_tag());
330 }
331
332 friend yconstfn fixed_point
333 floor(fixed_point x)
334 {
335 return fixed_point(x.value & ~(base_element() - 1),
336 internal_construct_tag());
337 }
338
339 friend yconstfn fixed_point
340 round(fixed_point x)
341 {
342 return fixed_point((x.value + (base_element() >> 1))
343 & ~(base_element() - 1), internal_construct_tag());
344 }
345 };
346
347 } // namespace ystdex;
348
349
350 namespace std
351 {
352
357 template<typename _tBase, ystdex::size_t _vInt, ystdex::size_t _vFrac>
358 class numeric_limits<ystdex::fixed_point<_tBase, _vInt, _vFrac>>
359 {
360 private:
361 typedef ystdex::fixed_point<_tBase, _vInt, _vFrac> fp_type;
362 typedef typename fp_type::base_type base_type;
363
364 public:
365 static yconstexpr bool is_specialized = true;
366
367 static yconstfn fp_type
368 min() ynothrow
369 {
370 return fp_type(std::numeric_limits<base_type>::min(),
371 fp_type::internal_construct_tag());
372 }
373
374 static yconstfn fp_type
375 max() ynothrow
376 {
377 return fp_type(std::numeric_limits<base_type>::max(),
378 fp_type::internal_construct_tag());
379 }
380
381 static yconstfn fp_type
382 lowest() ynothrow
383 {
384 return min();
385 }
386
387 static yconstexpr int digits = _vInt;
388 static yconstexpr int digits10 = digits * 643L / 2136;
389 static yconstexpr int max_digits10 = 0;
390 static yconstexpr bool is_signed = numeric_limits<base_type>::is_signed;
391 static yconstexpr bool is_integer = false;
392 static yconstexpr bool is_exact = true;
393 static yconstexpr int radix = 2;
394
395 static yconstfn fp_type
396 epsilon() ynothrow
397 {
398 return fp_type(1, fp_type::internal_construct_tag());
399 }
400
401 static yconstfn fp_type
402 round_error() ynothrow
403 {
404 return 0.5;
405 }
406
407 static yconstexpr int min_exponent = 0;
408 static yconstexpr int min_exponent10 = 0;
409 static yconstexpr int max_exponent = 0;
410 static yconstexpr int max_exponent10 = 0;
411
412 static yconstexpr bool has_infinity = false;
413 static yconstexpr bool has_quiet_NaN = false;
414 static yconstexpr bool has_signaling_NaN = has_quiet_NaN;
415 static yconstexpr float_denorm_style has_denorm = denorm_absent;
416 static yconstexpr bool has_denorm_loss = false;
417
418 static yconstfn fp_type
419 infinity() ynothrow
420 {
421 return 0;
422 }
423
424 static yconstfn fp_type
425 quiet_NaN() ynothrow
426 {
427 return 0;
428 }
429
430 static yconstfn fp_type
431 signaling_NaN() ynothrow
432 {
433 return 0;
434 }
435
436 static yconstfn fp_type
437 denorm_min() ynothrow
438 {
439 return 0;
440 }
441
442 static yconstexpr bool is_iec559 = false;
443 static yconstexpr bool is_bounded = true;
444 static yconstexpr bool is_modulo = numeric_limits<base_type>::is_modulo;
445
446 static yconstexpr bool traps = numeric_limits<base_type>::traps;
447 static yconstexpr bool tinyness_before = false;
448 static yconstexpr float_round_style round_style = round_toward_zero;
449 };
450
451 } // namespace std;
452
453 #endif
454