fixed_point (deprecated)  rev.2
Binary Fixed-Point Arithmetic Library in C++
precise_integer.h
1 
2 // Copyright John McFarlane 2015 - 2017.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file ../LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 #if !defined(SG14_PRECISE_INTEGER_H)
8 #define SG14_PRECISE_INTEGER_H 1
9 
10 #include <sg14/bits/number_base.h>
11 #include <sg14/bits/limits.h>
12 
13 namespace sg14 {
14 
15  struct closest_rounding_tag {
16  template<class To, class From>
17  static constexpr To convert(const From& from)
18  {
19  return static_cast<To>(std::intmax_t(from+((from>=0) ? .5 : -.5)));
20  }
21  };
22 
23  template<class Rep = int, class RoundingTag = closest_rounding_tag>
24  class precise_integer : public _impl::number_base<precise_integer<Rep, RoundingTag>, Rep> {
25  using super = _impl::number_base<precise_integer<Rep, RoundingTag>, Rep>;
26  public:
27  using rounding = RoundingTag;
28 
29  constexpr precise_integer() = default;
30 
31  template<class T, _impl::enable_if_t<std::numeric_limits<T>::is_integer, int> Dummy = 0>
32  constexpr precise_integer(const T& v)
33  : super(static_cast<Rep>(v)) { }
34 
35  template<class T, _impl::enable_if_t<!std::numeric_limits<T>::is_integer, int> Dummy = 0>
36  constexpr precise_integer(const T& v)
37  : super(rounding::template convert<Rep>(v)) { }
38 
39  template<class T>
40  constexpr explicit operator T() const
41  {
42  return static_cast<T>(super::data());
43  }
44  };
45 
47  // numeric type traits
48 
49  template<class Rep, class RoundingTag>
50  struct digits<precise_integer<Rep, RoundingTag>> : digits<Rep> {
51  };
52 
53  template<class Rep, class RoundingTag, _digits_type MinNumBits>
54  struct set_digits<precise_integer<Rep, RoundingTag>, MinNumBits> {
55  using type = precise_integer<set_digits_t<Rep, MinNumBits>, RoundingTag>;
56  };
57 
58  namespace _impl {
59  template<class Rep, class RoundingTag>
60  struct get_rep<precise_integer<Rep, RoundingTag>> {
61  using type = Rep;
62  };
63 
64  template<class OldRep, class RoundingTag, class NewRep>
65  struct set_rep<precise_integer<OldRep, RoundingTag>, NewRep> {
66  using type = precise_integer<NewRep, RoundingTag>;
67  };
68  }
69 
70  template<class Rep, class RoundingTag, class Value>
71  struct from_value<precise_integer<Rep, RoundingTag>, Value> {
72  using type = precise_integer<Value, RoundingTag>;
73  };
74 
75  template<class Rep, class RoundingTag>
76  struct scale<precise_integer<Rep, RoundingTag>>
77  : scale<_impl::number_base<precise_integer<Rep, RoundingTag>, Rep>> {
78  };
79 
80  namespace _precise_integer_impl {
82  // comparison operators
83 
84  template<class T>
85  struct is_precise_integer : std::false_type {
86  };
87 
88  template<class Rep, class RoundingTag>
89  struct is_precise_integer<precise_integer<Rep, RoundingTag>> : std::true_type {
90  };
91  }
92 
94  // binary arithmetic
95 
96  namespace _impl {
97  // for operands with a common tag
98  template<class Operator, class RoundingTag, class LhsRep, class RhsRep, class = enable_if_t<Operator::is_arithmetic>>
99  constexpr auto operate_common_tag(
100  const precise_integer<LhsRep, RoundingTag>& lhs,
101  const precise_integer<RhsRep, RoundingTag>& rhs)
102  -> decltype(from_rep<precise_integer<op_result<Operator, LhsRep, RhsRep>, RoundingTag>>(Operator()(lhs.data(), rhs.data())))
103  {
104  using result_type = precise_integer<op_result<Operator, LhsRep, RhsRep>, RoundingTag>;
105  return from_rep<result_type>(Operator()(lhs.data(), rhs.data()));
106  }
107 
108  // for arithmetic operands with different policies
109  template<class Operator, class RoundingTag, class LhsRep, class RhsRep, enable_if_t<Operator::is_comparison, int> = 0>
110  constexpr auto operate_common_tag(
111  const precise_integer<LhsRep, RoundingTag>& lhs,
112  const precise_integer<RhsRep, RoundingTag>& rhs)
113  -> decltype(Operator()(lhs.data(), rhs.data()))
114  {
115  return Operator()(lhs.data(), rhs.data());
116  }
117 
118  // for arithmetic operands with different policies
119  template<class Operator, class LhsRep, class LhsRoundingTag, class RhsRep, class RhsRoundingTag>
120  constexpr auto operate(
121  const precise_integer<LhsRep, LhsRoundingTag>& lhs,
122  const precise_integer<RhsRep, RhsRoundingTag>& rhs,
123  Operator)
124  -> decltype(operate_common_tag<Operator, common_type_t<LhsRoundingTag, RhsRoundingTag>>(lhs, rhs))
125  {
126  return operate_common_tag<Operator, common_type_t<LhsRoundingTag, RhsRoundingTag>>(lhs, rhs);
127  }
128  }
129 
131  // binary bitwise
132 
133  template<class LhsRep, class LhsRoundingTag, class RhsInteger>
134  constexpr auto operator<<(
135  const precise_integer<LhsRep, LhsRoundingTag>& lhs,
136  const RhsInteger& rhs)
137  -> decltype(from_rep<precise_integer<decltype(_impl::to_rep(lhs) << rhs), LhsRoundingTag>>(_impl::to_rep(lhs) << rhs))
138  {
139  return from_rep<precise_integer<
140  decltype(_impl::to_rep(lhs) << rhs),
141  LhsRoundingTag>>(_impl::to_rep(lhs) << rhs);
142  }
143 }
144 
145 namespace std {
147  // std::numeric_limits specialization for precise_integer
148 
149  template<class Rep, class RoundingTag>
150  struct numeric_limits<sg14::precise_integer<Rep, RoundingTag>>
151  : numeric_limits<sg14::_impl::number_base<sg14::precise_integer<Rep, RoundingTag>, Rep>> {};
152 }
153 
154 #endif
STL namespace.
study group 14 of the C++ working group
Definition: const_integer.h:22