AMInteger  201909
String localization library
AMInteger.h
Go to the documentation of this file.
1 
7 #ifndef AMCORE_AMINTEGER_H
8 #define AMCORE_AMINTEGER_H
9 
10 #include <type_traits>
11 #include <limits>
12 
18 namespace AMCore {
19 
32  template<typename TIntType>
33  TIntType AMIntegerHi(TIntType x)
34  {
35  return (x >> (sizeof(TIntType) * 4));
36  }
37 
43  template<typename TIntType>
44  TIntType AMIntegerLo(TIntType x)
45  {
46  TIntType res = ((1ULL << sizeof(TIntType) * 4) - 1) & x;
47  return res;
48  }
49 
58  template<typename TIntType>
59  bool AMIntegerMultiply(TIntType a, TIntType b, TIntType& result) {
60 
61  static_assert(std::is_integral<TIntType>::value, "Integral required.");
62 
63  if constexpr (sizeof(long long) >= sizeof(TIntType) * 2) {
64  if constexpr (std::is_signed<TIntType>::value) {
65  long long tresult = (long long) a * (long long) b;
66  long long cresult = tresult >> (sizeof(TIntType) * 8);
67  bool rsign = tresult & (1ULL << (sizeof(TIntType) * 8 -1));
68  if (cresult == 0 || cresult == -1) {
69  if ((a >= 0 && b >= 0 && !rsign)
70  || (a <= 0 && b <= 0 && !rsign)
71  || (a < 0 && b > 0 && rsign)
72  || (a > 0 && b < 0 && rsign)) {
73  result = (TIntType) tresult;
74  return true;
75  }
76  }
77  if ((a < 0 && b < 0) || (a > 0 && b > 0)) {
78  result = std::numeric_limits<TIntType>::max();
79  } else {
80  result = std::numeric_limits<TIntType>::min();
81  }
82  return false;
83  } else {
84  unsigned long long tresult = (unsigned long long) a * (unsigned long long) b;
85  unsigned long long cresult = tresult >> (sizeof(TIntType) * (sizeof(unsigned long long) == sizeof(TIntType) ? 0 : 8));
86  if (cresult == 0) {
87  result = (TIntType)tresult;
88  return true;
89  }
90  result = std::numeric_limits<TIntType>::max();
91  return false;
92  }
93  } else {
94  typedef std::conditional_t<std::is_signed<TIntType>::value, TIntType, typename std::make_unsigned<TIntType>::type> TUIntType;
95  const TUIntType mask = (1ULL << sizeof(TIntType) * 4) - 1;
96 
97  TUIntType s0, s11, s12, s21, s22, s3;
98  TUIntType loa = AMIntegerLo((TUIntType)a), lob = AMIntegerLo((TUIntType)b), hia = AMIntegerHi((TUIntType)a), hib = AMIntegerHi((TUIntType)b);
99 
100  TUIntType x1 = loa * lob;
101  s0 = AMIntegerLo(x1);
102 
103  TUIntType x2 = hia * lob + AMIntegerHi(x1);
104  s11 = AMIntegerLo(x2);
105  s21 = AMIntegerHi(x2);
106 
107  TUIntType x3 = s11 + loa * hib;
108  s12 = AMIntegerLo(x3);
109 
110  TUIntType x4 = s21 + hia * hib + AMIntegerHi(x3);;
111  s22 = AMIntegerLo(x4);
112  s3 = AMIntegerHi(x4);
113 
114  if constexpr (std::is_signed<TIntType>::value) {
115  if (((s22 & mask) != 0 || (s3 & mask) != 0)
116  && ((s22 & mask) != (((TUIntType) - 1) & mask) || (s3 & mask) != (((TUIntType) - 1) & mask))) {
117  if (s3 >= 0) {
118  result = std::numeric_limits<TIntType>::max();
119  } else {
120  result = std::numeric_limits<TIntType>::min();
121  }
122  return false;
123  }
124  TIntType tresult = s12 << (sizeof(TIntType) * 4) | s0;
125  if ((a >= 0 && b >= 0 && tresult >= 0)
126  || (a <= 0 && b <= 0 && tresult >= 0)
127  || (a < 0 && b > 0 && tresult < 0)
128  || (a > 0 && b < 0 && tresult < 0)) {
129  result = tresult;
130  return true;
131  }
132  if (s3 >= 0) {
133  result = std::numeric_limits<TIntType>::max();
134  } else {
135  result = std::numeric_limits<TIntType>::min();
136  }
137  return false;
138  } else {
139  if (s22 > 0 || s3 > 0) {
140  result = std::numeric_limits<TIntType>::max();
141  return false;
142  }
143  result = s12 << (sizeof(TIntType) * 4) | s0;
144  return true;
145  }
146  }
147  }
148 
157  template<typename TIntType>
158  bool AMIntegerAdd(TIntType a, TIntType b, TIntType& result) {
159 
160  static_assert(std::is_integral<TIntType>::value, "Integral required.");
161 
162  if constexpr ((sizeof(long long) >= sizeof(TIntType) * 2) || std::is_signed<TIntType>::value) {
163  if constexpr (std::is_signed<TIntType>::value) {
164  TIntType tresult = a + b;
165  if (a > 0 && b > 0 && tresult < 0) {
166  result = std::numeric_limits<TIntType>::max();
167  return false;
168  } else if (a < 0 && b < 0 && tresult > 0) {
169  result = std::numeric_limits<TIntType>::min();
170  return false;
171  } else {
172  result = tresult;
173  return true;
174  }
175  } else {
176  unsigned long long tresult = (unsigned long long) a + (unsigned long long) b;
177  long long cresult = tresult & (-1LL ^ ((1ULL << sizeof(TIntType)*8) - 1));
178  if (cresult > 0) {
179  result = std::numeric_limits<TIntType>::max();
180  return false;
181  }
182  result = (TIntType)tresult;
183  return true;
184  }
185  } else {
186  typedef std::conditional_t<std::is_signed<TIntType>::value, TIntType, typename std::make_unsigned<TIntType>::type> TUIntType;
187 
188  TUIntType s0, s1, s2;
189  TUIntType loa = AMIntegerLo((TUIntType)a), lob = AMIntegerLo((TUIntType)b), hia = AMIntegerHi((TUIntType)a), hib = AMIntegerHi((TUIntType)b);
190 
191  TUIntType x1 = loa + lob;
192  s0 = AMIntegerLo(x1);
193 
194  TUIntType x2 = hia + hib + AMIntegerHi(x1);
195  s1 = AMIntegerLo(x2);
196  s2 = AMIntegerHi(x2);
197 
198  if (s2 > 0) {
199  result = std::numeric_limits<TIntType>::max();
200  return false;
201  }
202  result = s1 << (sizeof(TIntType) * 4) | s0;
203  return true;
204  }
205  }
206 
207  template<typename TIntType>
208  bool AMIntegerPow(TIntType x, unsigned int p, TIntType& result)
209  {
210  if (p == 0) return 1;
211  if (p == 1) return x;
212 
213  TIntType tmp;
214  if (!AMIntegerPow(x, p/2, tmp)) {
215  return false;
216  }
217  if (AMIntegerHi(tmp)) {
218  return false;
219  }
220  if (p%2 == 0) {
221  result = tmp * tmp;
222  }
223  else {
224  TIntType tres;
225  if (!AMIntegerMultiply(x, tmp * tmp, tres)) {
226  return false;
227  }
228  result = tres;
229  }
230  return true;
231  }
232 
233  template<typename TIntType>
234  TIntType AMIntegerPowRaw(TIntType x, unsigned int p)
235  {
236  if (p == 0) return 1;
237  if (p == 1) return x;
238 
239  int tmp = AMIntegerPowRaw(x, p/2);
240  if (p%2 == 0) {
241  return tmp * tmp;
242  }
243  else return x * tmp * tmp;
244  }
245 }
246 
249 #endif //AMCORE_AMINTEGER_H
AMCore::AMIntegerMultiply
bool AMIntegerMultiply(TIntType a, TIntType b, TIntType &result)
Safe multiply with overflow detection.
Definition: AMInteger.h:59
AMCore::AMIntegerAdd
bool AMIntegerAdd(TIntType a, TIntType b, TIntType &result)
Safe addition with overflow detection.
Definition: AMInteger.h:158
AMCore::AMIntegerHi
TIntType AMIntegerHi(TIntType x)
Safe integer operations with overflow detection.
Definition: AMInteger.h:33
AMCore::AMIntegerLo
TIntType AMIntegerLo(TIntType x)
Low bits (a half) of argument.
Definition: AMInteger.h:44