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>
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>
63 {
64  typedef typename make_signed_c<typename make_fixed_width_int<
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>
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:
131 
132 public:
139  {}
140 
141 private:
142  yconstfn
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
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
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
174  typename std::enable_if<(int_bit_n < _vOtherInt), int>::type = 0)
175  ynothrow
176  : value(f.value << (_vOtherInt - int_bit_n))
177  {}
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  }
198  operator-() const ynothrow
199  {
200  fixed_point result;
201 
202  result.value = -value;
203  return result;
204  }
205 
206  fixed_point&
208  {
209  value += base_element();
210  return *this;
211  }
212 
213  fixed_point&
215  {
216  value -= base_element();
217  return *this;
218  }
219 
222  {
223  value += f.value;
224  return *this;
225  }
226 
227  fixed_point&
229  {
230  value -= f.value;
231  return *this;
232  }
233 
234  fixed_point&
236  {
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&
253  {
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  }
266  fixed_point&
267  operator<<=(size_t s) ynothrow
268  {
269  value <<= s;
270  return *this;
271  }
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
304  {
305  return ystdex::exp2u<base_type, base_type>(frac_bit_n);
306  }
307 
313  static yconstfn fixed_point
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),
337  }
338 
339  friend yconstfn fixed_point
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:
362  typedef typename fp_type::base_type base_type;
364 public:
365  static yconstexpr bool is_specialized = true;
368  min() ynothrow
369  {
370  return fp_type(std::numeric_limits<base_type>::min(),
372  }
373 
374  static yconstfn fp_type
375  max() ynothrow
376  {
377  return fp_type(std::numeric_limits<base_type>::max(),
379  }
380 
382  lowest() ynothrow
383  {
384  return min();
385  }
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  {
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;
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