YSTest  PreAlpha_b500_20140530
The YSLib Test Project
 全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义  
rational.hpp
浏览该文件的文档.
1 /*
2  © 2011-2013 FrankHB.
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 "cstdint.hpp"
32 #include "operators.hpp"
33 #include <cmath> // for std::llround;
34 
35 namespace ystdex
36 {
37 
44 template<typename _type, std::uintmax_t _vNum = 1, std::uintmax_t _vDen = 1,
45  bool _bIsFloat = is_floating_point<_type>::value>
47 
48 template<typename _type, std::uintmax_t _vNum, std::uintmax_t _vDen>
49 struct normalized_max<_type, _vNum, _vDen, true>
50 {
51  static yconstexpr _type value = double(_vNum / _vDen);
52 
54  static yconstfn _type
55  get()
56  {
57  return value;
58  }
59 };
60 
61 template<typename _type, std::uintmax_t _vNum, std::uintmax_t _vDen>
62 struct normalized_max<_type, _vNum, _vDen, false>
63 {
64  static yconstexpr _type value = std::numeric_limits<_type>::max();
65 
67  static yconstfn _type
68  get()
69  {
70  return value;
71  }
72 };
74 
75 
82 template<typename _type>
84  : integral_constant<bool, is_floating_point<_type>::value>
85 {};
86 
87 template<>
88 struct is_normalizable<bool> : true_type
89 {};
91 
92 
98 template<typename _type>
100 {
101  using type = typename make_signed_c<typename make_width_int<integer_width<
102  _type>::value << 1>::type, is_signed<_type>::value>::type;
103 };
104 
105 template<>
106 struct fixed_multiplicative<std::int64_t>
107 {
108  using type = std::int64_t;
109 };
110 
111 template<>
112 struct fixed_multiplicative<std::uint64_t>
113 {
114  using type = std::uint64_t;
115 };
116 
117 
136 template<typename _tBase = std::int32_t,
137  size_t _vInt = std::numeric_limits<_tBase>::digits - 6U,
138  size_t _vFrac = std::numeric_limits<_tBase>::digits - _vInt>
139 class fixed_point : public operators<fixed_point<_tBase, _vInt, _vFrac>>
140 {
141  static_assert(is_integral<_tBase>::value, "Non-integral type found.");
142  static_assert(_vInt < size_t(std::numeric_limits<_tBase>::digits),
143  "No sufficient fractional bits found.");
144  static_assert(_vInt + _vFrac == size_t(std::numeric_limits<_tBase>::digits),
145  "Wrong total bits found.");
146 
147  template<typename _OtherBase, size_t _vOtherInt, size_t _vOtherFrac>
148  friend class fixed_point;
149  friend class std::numeric_limits<fixed_point<_tBase, _vInt, _vFrac>>;
150 
151 public:
152  using base_type = _tBase;
153 
155  static yconstexpr size_t int_bit_n = _vInt;
157  static yconstexpr size_t frac_bit_n = _vFrac;
160 
161 private:
163 
164 public:
169  yconstfn
171  {}
172 
174 
175  yconstfn
177  : value(v)
178  {}
179  template<typename _tInt>
180  yconstfn
181  fixed_point(_tInt val, enable_if_t<is_integral<_tInt>::value, _tInt*> = {})
182  ynothrow
183  : value(base_type(val) << frac_bit_n)
184  {}
185  template<typename _tFloat>
186  yconstfn
187  fixed_point(_tFloat val,
188  enable_if_t<is_floating_point<_tFloat>::value, _tFloat*> = {}) ynothrow
189  : value(::llround(base_element() * val))
190  {
191  // TODO: Use std::llround.
192  }
193  template<typename _tFirst, typename _tSecond>
194  yconstfn
195  fixed_point(_tFirst x, _tSecond y, enable_if_t<is_integral<_tFirst>::value
196  && !is_same<_tSecond, raw_tag>::value, _tFirst*> = {})
197  : value((x << frac_bit_n) / y)
198  {}
199  template<typename _tFirst, typename _tSecond>
200  yconstfn
201  fixed_point(_tFirst x, _tSecond y, enable_if_t<is_floating_point<_tFirst>
202  ::value && !is_same<_tSecond, raw_tag>::value, _tFirst*> = {})
203  : fixed_point(x / y)
204  {}
206  yconstfn
207  fixed_point(const fixed_point&) = default;
208  template<size_t _vOtherInt, size_t _vOtherFrac>
209  yconstfn
211  enable_if_t<(_vOtherInt < int_bit_n), base_type*> = {}) ynothrow
212  : value(f.value >> (int_bit_n - _vOtherInt))
213  {}
214  template<size_t _vOtherInt, size_t _vOtherFrac>
215  yconstfn
217  enable_if_t<(int_bit_n < _vOtherInt), base_type*> = {}) ynothrow
218  : value(f.value << (_vOtherInt - int_bit_n))
219  {}
220  template<typename _tOtherBase, size_t _vOtherInt, size_t _vOtherFrac>
221  yconstfn
223  enable_if_t<(frac_bit_n == _vOtherFrac), base_type*> = {}) ynothrow
224  : value(f.value)
225  {}
226  template<typename _tOtherBase, size_t _vOtherInt, size_t _vOtherFrac>
227  yconstfn
229  enable_if_t<(frac_bit_n < _vOtherFrac), base_type*> = {}) ynothrow
230  : value(f.value >> (_vOtherFrac - frac_bit_n))
231  {}
232  template<typename _tOtherBase, size_t _vOtherInt, size_t _vOtherFrac>
233  yconstfn
235  enable_if_t<(_vOtherFrac < frac_bit_n), base_type*> = {}) ynothrow
236  : value(f.value << (frac_bit_n - _vOtherFrac))
237  {}
239 
240  bool
242  {
243  return value < f.value;
244  }
245 
246  bool
248  {
249  return value == f.value;
250  }
251 
252  bool
254  {
255  return value == 0;
256  }
257 
260  {
261  fixed_point result;
262 
263  result.value = -value;
264  return result;
265  }
266 
267  fixed_point&
269  {
270  value += base_element();
271  return *this;
272  }
273 
274  fixed_point&
276  {
277  value -= base_element();
278  return *this;
279  }
280 
281  fixed_point&
283  {
284  value += f.value;
285  return *this;
286  }
287 
288  fixed_point&
290  {
291  value -= f.value;
292  return *this;
293  }
294 
295  fixed_point&
297  {
298  value = mul<frac_bit_n + is_signed<base_type>::value>(value,
299  f.value, integral_constant<bool, is_signed<
301  return *this;
302  }
303 
304  fixed_point&
306  {
308  << frac_bit_n) / f.value;
309  return *this;
310  }
311 
312  fixed_point&
314  {
315  value >>= s;
316  return *this;
317  }
318 
319  fixed_point&
321  {
322  value <<= s;
323  return *this;
324  }
325 
327  template<typename _type,
328  typename = enable_if_t<is_arithmetic<_type>::value, _type>>
329  yconstfn
330  operator _type() const
331  {
332  return this->cast<_type>();
333  }
334 
337  get() const
338  {
339  return value;
340  }
341 
342 private:
344  template<typename _type>
346  cast() const
347  {
348  return value >> frac_bit_n;
349  }
351  template<typename _type>
353  cast() const
354  {
355  return _type(value) / base_element();
356  }
357 
358  template<size_t _vShiftBits>
359  static yconstfn base_type
360  mul(base_type x, base_type y, true_type)
361  {
362  return mul_signed<_vShiftBits>(
363  typename fixed_multiplicative<base_type>::type(x * y));
364  }
365  template<size_t _vShiftBits>
366  static yconstfn base_type
367  mul(base_type x, base_type y, false_type)
368  {
369  // NOTE: Only fit for unsigned type, due to there exists
370  // implementation-defined behavior in conversion and right shifting on
371  // operands of signed types.
372  return (typename fixed_multiplicative<base_type>::type(x) * y)
373  >> _vShiftBits;
374  }
375 
376  template<size_t _vShiftBits>
377  static yconstfn base_type
379  {
380  return tmp < 0 ? -(-tmp >> _vShiftBits) : tmp >> _vShiftBits;
381  }
382 
383 public:
389  static yconstfn base_type
391  {
392  return base_type(1) << frac_bit_n;
393  }
394 
400  static yconstfn fixed_point
402  {
403  return fixed_point(base_element());
404  }
405 
406  friend fixed_point
408  {
409  return x.value < 0 ? -x : x;
410  }
411 
412  friend yconstfn fixed_point
414  {
415  return fixed_point(
416  (x.value + base_element() - 1) & ~(base_element() - 1), raw_tag());
417  }
418 
419  friend yconstfn fixed_point
421  {
422  return fixed_point(x.value & ~(base_element() - 1), raw_tag());
423  }
424 
425  friend yconstfn fixed_point
427  {
428  return fixed_point((x.value + (base_element() >> 1))
429  & ~(base_element() - 1), raw_tag());
430  }
431 };
432 
434 #define YB_FIX_POINT_TMPL_HEAD_2 \
435  template<typename _tBase1, size_t _vInt1, size_t _vFrac1, \
436  typename _tBase2, size_t _vInt2, size_t _vFrac2>
437 #define YB_FIX_POINT_TMPL_OP_2_PARAMS_BODY(_op) \
439  operator _op(const fixed_point<_tBase1, _vInt1, _vFrac1> x, \
440  const fixed_point<_tBase2, _vInt2, _vFrac2>& y) \
441  { \
442  using result_type = common_type_t<fixed_point<_tBase1, _vInt1, \
443  _vFrac1>, fixed_point<_tBase2, _vInt2, _vFrac2>>; \
444  \
445  return result_type(x) _op result_type(y); \
446  }
447 
454 #define YB_FIX_POINT_ARITHMETIC_2(_op) \
456  YB_FIX_POINT_TMPL_HEAD_2 \
457  yconstfn common_type_t<fixed_point<_tBase1, _vInt1, _vFrac1>, \
458  fixed_point<_tBase2, _vInt2, _vFrac2>> \
459  YB_FIX_POINT_TMPL_OP_2_PARAMS_BODY(_op)
460 
465 
466 #undef YB_FIX_POINT_ARITHMETIC_2
467 
468 
475 #define YB_FIX_POINT_RATIONAL_2(_op) \
477  YB_FIX_POINT_TMPL_HEAD_2 \
478  yconstfn bool \
479  YB_FIX_POINT_TMPL_OP_2_PARAMS_BODY(_op)
480 
487 
488 #undef YB_FIX_POINT_RATIONAL_2
489 
490 
491 #undef YB_FIX_POINT_TMPL_HEAD_2
492 #undef YB_FIX_POINT_TMPL_OP_2_PARAMS_BODY
493 
494 
500 template<typename _tBase, size_t _vInt, size_t _vFrac>
501 struct modular_arithmetic<fixed_point<_tBase, _vInt, _vFrac>>
502  : modular_arithmetic<typename fixed_point<_tBase, _vInt, _vFrac>::base_type>
503 {};
504 
505 
510 template<typename _tBase, size_t _vInt, size_t _vFrac>
511 struct is_normalizable<fixed_point<_tBase, _vInt, _vFrac>> : true_type
512 {};
513 
514 } // namespace ystdex;
515 
516 
517 namespace std
518 {
519 
525 template<typename _tBase1, size_t _vInt1, size_t _vFrac1, typename _tBase2,
526  size_t _vInt2, size_t _vFrac2>
527 struct common_type<ystdex::fixed_point<_tBase1, _vInt1, _vFrac1>,
528  ystdex::fixed_point<_tBase2, _vInt2, _vFrac2>>
529 {
530 private:
532 
533  static yconstexpr size_t int_size = _vInt1 < _vInt2 ? _vInt2 : _vInt1;
534 
535 public:
536  using type = ystdex::fixed_point<common_base_type, int_size,
537  std::numeric_limits<common_base_type>::digits - int_size>;
538 };
539 
540 
545 template<typename _tBase, ystdex::size_t _vInt, ystdex::size_t _vFrac>
546 class numeric_limits<ystdex::fixed_point<_tBase, _vInt, _vFrac>>
547 {
548 private:
550  using base_type = typename fp_type::base_type;
551 
552 public:
553  static yconstexpr bool is_specialized = true;
554 
555  static yconstfn fp_type
557  {
558  return fp_type(std::numeric_limits<base_type>::min(),
559  ystdex::raw_tag());
560  }
561 
562  static yconstfn fp_type
564  {
565  return fp_type(std::numeric_limits<base_type>::max(),
566  ystdex::raw_tag());
567  }
568 
569  static yconstfn fp_type
571  {
572  return min();
573  }
574 
575  static yconstexpr int digits = _vInt;
576  static yconstexpr int digits10 = digits * 643L / 2136;
577  static yconstexpr int max_digits10 = 0;
578  static yconstexpr bool is_signed = numeric_limits<base_type>::is_signed;
579  static yconstexpr bool is_integer = {};
580  static yconstexpr bool is_exact = true;
581  static yconstexpr int radix = 2;
582 
583  static yconstfn fp_type
585  {
586  return fp_type(1, typename fp_type::raw_tag());
587  }
588 
589  static yconstfn fp_type
591  {
592  return 0.5;
593  }
594 
595  static yconstexpr int min_exponent = 0;
596  static yconstexpr int min_exponent10 = 0;
597  static yconstexpr int max_exponent = 0;
598  static yconstexpr int max_exponent10 = 0;
599 
600  static yconstexpr bool has_infinity = {};
601  static yconstexpr bool has_quiet_NaN = {};
602  static yconstexpr bool has_signaling_NaN = has_quiet_NaN;
603  static yconstexpr float_denorm_style has_denorm = denorm_absent;
604  static yconstexpr bool has_denorm_loss = {};
605 
606  static yconstfn fp_type
608  {
609  return 0;
610  }
611 
612  static yconstfn fp_type
614  {
615  return 0;
616  }
617 
618  static yconstfn fp_type
620  {
621  return 0;
622  }
623 
624  static yconstfn fp_type
626  {
627  return 0;
628  }
629 
630  static yconstexpr bool is_iec559 = {};
631  static yconstexpr bool is_bounded = true;
632  static yconstexpr bool is_modulo = numeric_limits<base_type>::is_modulo;
633 
634  static yconstexpr bool traps = numeric_limits<base_type>::traps;
635  static yconstexpr bool tinyness_before = {};
636  static yconstexpr float_round_style round_style = round_toward_zero;
637 };
638 
639 } // namespace std;
640 
641 #endif
642 
fixed_point & operator-=(const fixed_point &f)
Definition: rational.hpp:289
取指定整数类型的位宽度。
Definition: cstdint.hpp:43
通用定点数。
Definition: rational.hpp:139
bool operator==(const fixed_point &f) const
Definition: rational.hpp:247
static const size_t frac_bit_n
小数部分二进制位数。
Definition: rational.hpp:157
fixed_point(_tFloat val, enable_if_t< is_floating_point< _tFloat >::value, _tFloat * >={})
Definition: rational.hpp:187
bool return true
Definition: DSMain.cpp:177
fixed_point(const fixed_point< base_type, _vOtherInt, _vOtherFrac > &f, enable_if_t<(_vOtherInt< int_bit_n), base_type * >={})
Definition: rational.hpp:210
fixed_point & operator/=(const fixed_point &f)
Definition: rational.hpp:305
friend fixed_point ceil(fixed_point x)
Definition: rational.hpp:413
static const size_t digit_bit_n
非符号位的二进制位数。
Definition: rational.hpp:159
取按指定宽度的整数类型。
Definition: cstdint.hpp:75
bool operator<(const fixed_point &f) const
Definition: rational.hpp:241
static base_type mul(base_type x, base_type y, false_type)
Definition: rational.hpp:367
fixed_point & operator--()
Definition: rational.hpp:275
fixed_point & operator+=(const fixed_point &f)
Definition: rational.hpp:282
fixed_point()
无参数构造。
Definition: rational.hpp:170
fixed_point & operator++()
Definition: rational.hpp:268
#define YB_FIX_POINT_RATIONAL_2(_op)
不同模板参数的二元关系操作符。
Definition: rational.hpp:476
重载操作符。
fixed_point(_tFirst x, _tSecond y, enable_if_t< is_integral< _tFirst >::value &&!is_same< _tSecond, raw_tag >::value, _tFirst * >={})
Definition: rational.hpp:195
定点数乘除法中间类型。
Definition: rational.hpp:99
fixed_point & operator>>=(size_t s)
Definition: rational.hpp:313
friend fixed_point round(fixed_point x)
Definition: rational.hpp:426
enable_if_t< is_floating_point< _type >::value, _type > cast() const
Definition: rational.hpp:353
fixed_point(const fixed_point< base_type, _vOtherInt, _vOtherFrac > &f, enable_if_t<(int_bit_n< _vOtherInt), base_type * >={})
Definition: rational.hpp:216
#define ynothrow
YSLib 无异常抛出保证:若支持 noexcept 关键字, 指定特定的 noexcept 异常规范。
Definition: ydef.h:514
取指定整数类型和条件表达式对应的有符号或无符号整数类型。
Definition: cstdint.hpp:54
fixed_point(base_type v, raw_tag)
Definition: rational.hpp:176
enable_if_t< is_integral< _type >::value, _type > cast() const
Definition: rational.hpp:346
fixed_point(_tFirst x, _tSecond y, enable_if_t< is_floating_point< _tFirst >::value &&!is_same< _tSecond, raw_tag >::value, _tFirst * >={})
Definition: rational.hpp:201
#define YB_FIX_POINT_ARITHMETIC_2(_op)
不同模板参数的二元算术操作符。
Definition: rational.hpp:455
判断类型是否可满足归一化要求。
Definition: rational.hpp:83
friend fixed_point fabs(fixed_point x)
Definition: rational.hpp:407
#define yconstfn
指定编译时常量函数。
Definition: ydef.h:463
static base_type mul(base_type x, base_type y, true_type)
Definition: rational.hpp:360
_tWidget _fCallable && f
Definition: ywgtevt.h:597
typename make_signed_c< typename make_width_int< integer_width< _type >::value<< 1 >::type, is_signed< _type >::value >::type type
Definition: rational.hpp:102
fixed_point & operator<<=(size_t s)
Definition: rational.hpp:320
friend fixed_point floor(fixed_point x)
Definition: rational.hpp:420
fixed_point(const fixed_point< _tOtherBase, _vOtherInt, _vOtherFrac > &f, enable_if_t<(_vOtherFrac< frac_bit_n), base_type * >={})
Definition: rational.hpp:234
取算术类型的正规化后的最大值。
Definition: rational.hpp:46
#define yconstexpr
指定编译时常量表达式。
Definition: ydef.h:462
fixed_point(const fixed_point< _tOtherBase, _vOtherInt, _vOtherFrac > &f, enable_if_t<(frac_bit_n< _vOtherFrac), base_type * >={})
Definition: rational.hpp:228
空基类模板。
Definition: ydef.h:658
ISO C 标准整数类型操作。
empty_base<> raw_tag
直接构造类型(直接构造重载用)。
Definition: ydef.h:665
fixed_point(const fixed_point< _tOtherBase, _vOtherInt, _vOtherFrac > &f, enable_if_t<(frac_bit_n==_vOtherFrac), base_type * >={})
Definition: rational.hpp:222
fixed_point & operator*=(const fixed_point &f)
Definition: rational.hpp:296
static const size_t int_bit_n
整数部分二进制位数。
Definition: rational.hpp:155
fixed_point(_tInt val, enable_if_t< is_integral< _tInt >::value, _tInt * >={})
Definition: rational.hpp:181
bool operator!() const
Definition: rational.hpp:253
byte v
typename enable_if< _bCond, _type >::type enable_if_t
Definition: type_op.hpp:274
模算术特性:取得不超过模值的最大值。
Definition: cstdint.hpp:146
static base_type mul_signed(typename fixed_multiplicative< base_type >::type tmp)
Definition: rational.hpp:378
static fixed_point identity()
取单位元。
Definition: rational.hpp:401
fixed_point operator-() const
Definition: rational.hpp:259
typename common_type< _types...>::type common_type_t
Definition: type_op.hpp:280
static base_type base_element()
取 base_type 表达的单位元。
Definition: rational.hpp:390