Mantid
Loading...
Searching...
No Matches
WideIntImpl.h
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#pragma once
8
9#include "WideInt.h"
10
11#include <algorithm>
12#include <array>
13#include <cstring>
14#include <iterator>
15#include <numeric>
16
18namespace std {
19#define CT(x) \
20 std::common_type_t<std::decay_t<decltype(rhs)>, std::decay_t<decltype(lhs)>> { x }
21
22// numeric limits
23template <size_t Bits, typename Signed> class numeric_limits<wide_integer<Bits, Signed>> {
24public:
25 static constexpr bool is_specialized = true;
26 static constexpr bool is_signed = is_same<Signed, signed>::value;
27 static constexpr bool is_integer = true;
28 static constexpr bool is_exact = true;
29 static constexpr bool has_infinity = false;
30 static constexpr bool has_quiet_NaN = false;
31 static constexpr bool has_signaling_NaN = true;
32 static constexpr std::float_denorm_style has_denorm = std::denorm_absent;
33 static constexpr bool has_denorm_loss = false;
34 static constexpr std::float_round_style round_style = std::round_toward_zero;
35 static constexpr bool is_iec559 = false;
36 static constexpr bool is_bounded = true;
37 static constexpr bool is_modulo = true;
38 static constexpr int digits = Bits - (is_same<Signed, signed>::value ? 1 : 0);
39 static constexpr int digits10 = static_cast<int>(digits * 0.30103) /*std::log10(2)*/;
40 static constexpr int max_digits10 = 0;
41 static constexpr int radix = 2;
42 static constexpr int min_exponent = 0;
43 static constexpr int min_exponent10 = 0;
44 static constexpr int max_exponent = 0;
45 static constexpr int max_exponent10 = 0;
46 static constexpr bool traps = true;
47 static constexpr bool tinyness_before = false;
48
49 static constexpr wide_integer<Bits, Signed> min() noexcept {
50 if (is_same<Signed, signed>::value) {
51 wide_integer<Bits, signed> res{};
52 res.m_arr[0] = std::numeric_limits<typename wide_integer<Bits, Signed>::signed_base_type>::min();
53 return res;
54 } else {
55 return 0;
56 }
57 }
58
59 static constexpr wide_integer<Bits, Signed> lowest() noexcept { return min(); }
60
61 static constexpr wide_integer<Bits, Signed> max() noexcept {
62 wide_integer<Bits, Signed> res{};
63 res.m_arr[0] = is_same<Signed, signed>::value
64 ? std::numeric_limits<typename wide_integer<Bits, Signed>::signed_base_type>::max()
65 : std::numeric_limits<typename wide_integer<Bits, Signed>::base_type>::max();
66 for (int i = 1; i < wide_integer<Bits, Signed>::_impl::arr_size; ++i) {
67 res.m_arr[i] = std::numeric_limits<typename wide_integer<Bits, Signed>::base_type>::max();
68 }
69 return res;
70 }
71
72 static constexpr wide_integer<Bits, Signed> epsilon() noexcept { return 0; }
73
74 static constexpr wide_integer<Bits, Signed> round_error() noexcept { return 0; }
75
76 static constexpr wide_integer<Bits, Signed> infinity() noexcept { return 0; }
77
78 static constexpr wide_integer<Bits, Signed> quiet_NaN() noexcept { return 0; }
79
80 static constexpr wide_integer<Bits, Signed> signaling_NaN() noexcept { return 0; }
81
82 static constexpr wide_integer<Bits, Signed> denorm_min() noexcept { return 0; }
83};
84
85namespace detail {
86template <class T> constexpr bool valid_specialized_numeric_limits(std::false_type /*is_array*/) {
87 return std::numeric_limits<T>::is_specialized;
88}
89template <class T> constexpr bool valid_specialized_numeric_limits(std::true_type /*is_array*/) { return false; }
90} // namespace detail
91
92template <typename T> static constexpr bool ArithmeticConcept() noexcept {
93 return std::detail::valid_specialized_numeric_limits<T>(std::is_array<T>());
94}
95
96namespace detail {
97template <class T> constexpr bool valid_specialized_numeric_limits_and_integral(std::false_type /*is_array*/) {
98 return std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_integer;
99}
100template <class T> constexpr bool valid_specialized_numeric_limits_and_integral(std::true_type /*is_array*/) {
101 return false;
102}
103} // namespace detail
104
105template <typename T> static constexpr bool IntegralConcept() noexcept {
106 return std::detail::valid_specialized_numeric_limits_and_integral<T>(std::is_array<T>());
107}
108
109// type traits
110template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
111struct common_type<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>> {
112 using type = std::conditional_t < Bits == Bits2,
113 wide_integer<Bits,
114 std::conditional_t<(std::is_same<Signed, Signed2>::value && std::is_same<Signed2, signed>::value),
115 signed, unsigned>>,
116 std::conditional_t<Bits2<Bits, wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>>;
117};
118
119template <size_t Bits, typename Signed, typename Arithmetic>
120struct common_type<wide_integer<Bits, Signed>, Arithmetic> {
121 static_assert(ArithmeticConcept<Arithmetic>(), "");
122
123 using type = std::conditional_t<
124 std::is_floating_point<Arithmetic>::value, Arithmetic,
125 std::conditional_t<sizeof(Arithmetic) < Bits * sizeof(long), wide_integer<Bits, Signed>,
126 std::conditional_t<Bits * sizeof(long) < sizeof(Arithmetic), Arithmetic,
127 std::conditional_t<Bits * sizeof(long) == sizeof(Arithmetic) &&
128 (is_same<Signed, signed>::value ||
129 std::is_signed<Arithmetic>::value),
130 Arithmetic, wide_integer<Bits, Signed>>>>>;
131};
132
133template <typename Arithmetic, size_t Bits, typename Signed>
134struct common_type<Arithmetic, wide_integer<Bits, Signed>> : std::common_type<wide_integer<Bits, Signed>, Arithmetic> {
135};
136
137template <size_t Bits, typename Signed> struct wide_integer<Bits, Signed>::_impl {
138 static_assert(Bits % CHAR_BIT == 0, "=)");
139
140 // utils
141 static const int base_bits = sizeof(base_type) * CHAR_BIT;
142 static const int arr_size = Bits / base_bits;
143
144 template <size_t B> constexpr static bool is_negative(const wide_integer<B, signed> &n) noexcept {
145 return static_cast<signed_base_type>(n.m_arr[0]) < 0;
146 }
147
148 template <size_t B, class T> constexpr static bool is_negative(const wide_integer<B, T> &) noexcept { return false; }
149
150 template <size_t B, class S> constexpr static wide_integer<B, S> make_positive(const wide_integer<B, S> &n) noexcept {
151 return is_negative(n) ? operator_unary_minus(n) : n;
152 }
153
154 template <typename T, class = typename std::enable_if<std::is_signed<T>::value, T>::type>
155 constexpr static int64_t to_Integral(T f) noexcept {
156 return static_cast<int64_t>(f);
157 }
158 template <typename T, class = typename std::enable_if<!std::is_signed<T>::value, T>::type>
159 constexpr static uint64_t to_Integral(T f) noexcept {
160 return static_cast<uint64_t>(f);
161 }
162
163 template <typename Integral>
164 constexpr static void wide_integer_from_bultin(wide_integer<Bits, Signed> &self, Integral rhs) noexcept {
165 auto r = _impl::to_Integral(rhs);
166
167 int r_idx = 0;
168
169 for (; static_cast<size_t>(r_idx) < sizeof(Integral) / sizeof(base_type) && r_idx < arr_size; ++r_idx) {
170 base_type &curr = self.m_arr[arr_size - 1 - r_idx];
171 base_type curr_rhs =
172 static_cast<base_type>(r >> (r_idx * CHAR_BIT * sizeof(base_type))) & std::numeric_limits<base_type>::max();
173 curr = curr_rhs;
174 }
175
176 for (; r_idx < arr_size; ++r_idx) {
177 base_type &curr = self.m_arr[arr_size - 1 - r_idx];
178 curr = r < 0 ? std::numeric_limits<base_type>::max() : 0;
179 }
180 }
181
182 constexpr static void wide_integer_from_bultin(wide_integer<Bits, Signed> &self, double rhs) noexcept {
183 if ((rhs > 0 && rhs < std::numeric_limits<uint64_t>::max()) ||
184 (rhs < 0 && rhs > std::numeric_limits<int64_t>::min())) {
185 self = to_Integral(rhs);
186 return;
187 }
188
189 long double r = rhs;
190 if (r < 0) {
191 r = -r;
192 }
193
194 size_t count = static_cast<size_t>(r / std::numeric_limits<uint64_t>::max());
195 self = count;
196 self *= std::numeric_limits<uint64_t>::max();
197 long double to_diff = count;
198 to_diff *= std::numeric_limits<uint64_t>::max();
199
200 self += to_Integral(r - to_diff);
201
202 if (rhs < 0) {
203 self = -self;
204 }
205 }
206
207 template <size_t Bits2, typename Signed2>
208 constexpr static void wide_integer_from_wide_integer(wide_integer<Bits, Signed> &self,
209 const wide_integer<Bits2, Signed2> &rhs) noexcept {
210 // int Bits_to_copy = std::min(arr_size, rhs.arr_size);
211 auto rhs_arr_size = wide_integer<Bits2, Signed2>::_impl::arr_size;
212 int base_elems_to_copy = _impl::arr_size < rhs_arr_size ? _impl::arr_size : rhs_arr_size;
213 for (int i = 0; i < base_elems_to_copy; ++i) {
214 self.m_arr[_impl::arr_size - 1 - i] = rhs.m_arr[rhs_arr_size - 1 - i];
215 }
216 for (int i = 0; i < arr_size - base_elems_to_copy; ++i) {
217 self.m_arr[i] = is_negative(rhs) ? std::numeric_limits<base_type>::max() : 0;
218 }
219 }
220
221 template <typename T>
222 using __keep_size = typename std::enable_if<sizeof(T) * CHAR_BIT <= Bits, wide_integer<Bits, Signed>>::type;
223 template <size_t Bits2, typename Signed2>
224 using __need_increase_size = typename std::enable_if < Bits<Bits2, wide_integer<Bits2, Signed>>::type;
225
226 template <typename T2, typename = std::enable_if<std::is_integral<T2>::value && std::is_unsigned<T2>::value>>
227 constexpr static wide_integer<Bits, unsigned> shift_left(const wide_integer<Bits, unsigned> &rhs, T2 n) {
228 if (static_cast<size_t>(n) >= base_bits * arr_size)
229 return 0;
230 if (n <= 0)
231 return rhs;
232
233 wide_integer<Bits, Signed> lhs = rhs;
234 int cur_shift = n % base_bits;
235 if (cur_shift) {
236 lhs.m_arr[0] = static_cast<base_type>(lhs.m_arr[0] << cur_shift);
237 for (int i = 1; i < arr_size; ++i) {
238 lhs.m_arr[i - 1] = static_cast<base_type>(lhs.m_arr[i - 1] | (lhs.m_arr[i] >> (base_bits - cur_shift)));
239 lhs.m_arr[i] = static_cast<base_type>(lhs.m_arr[i] << cur_shift);
240 }
241 n -= cur_shift;
242 }
243 if (n) {
244 decltype(arr_size - n / base_bits) i = 0;
245 for (; i < arr_size - n / base_bits; ++i) {
246 lhs.m_arr[i] = lhs.m_arr[i + n / base_bits];
247 }
248 for (; i < arr_size; ++i) {
249 lhs.m_arr[i] = 0;
250 }
251 }
252 return lhs;
253 }
254
255 template <typename T2, typename = std::enable_if<std::is_integral<T2>::value && std::is_unsigned<T2>::value>>
256 constexpr static wide_integer<Bits, signed> shift_left(const wide_integer<Bits, signed> &rhs, T2 n) {
257 // static_assert(is_negative(rhs), "shift left for negative lhsbers is
258 // underfined!");
259 if (is_negative(rhs)) {
260 throw std::runtime_error("shift left for negative lhsbers is underfined!");
261 }
262 return wide_integer<Bits, signed>(shift_left(wide_integer<Bits, unsigned>(rhs), n));
263 }
264
265 template <typename T2, typename = std::enable_if<std::is_integral<T2>::value && std::is_unsigned<T2>::value>>
266 constexpr static wide_integer<Bits, unsigned> shift_right(const wide_integer<Bits, unsigned> &rhs, T2 n) noexcept {
267 if (static_cast<size_t>(n) >= base_bits * arr_size)
268 return 0;
269 if (n <= 0)
270 return rhs;
271
272 wide_integer<Bits, Signed> lhs = rhs;
273 int cur_shift = n % base_bits;
274 if (cur_shift) {
275 lhs.m_arr[arr_size - 1] = static_cast<base_type>(lhs.m_arr[arr_size - 1] >> cur_shift);
276 for (int i = arr_size - 2; i >= 0; --i) {
277 lhs.m_arr[i + 1] |= static_cast<base_type>(lhs.m_arr[i + 1] | (lhs.m_arr[i] << (base_bits - cur_shift)));
278 lhs.m_arr[i] = static_cast<base_type>(lhs.m_arr[i] >> cur_shift);
279 }
280 n -= cur_shift;
281 }
282 if (n) {
283 decltype(n / base_bits) i = arr_size - 1;
284 for (; i >= n / base_bits; --i) {
285 lhs.m_arr[i] = lhs.m_arr[i - n / base_bits];
286 }
287 for (; i >= 0; --i) {
288 lhs.m_arr[i] = 0;
289 }
290 }
291 return lhs;
292 }
293
294 template <typename T2, typename = std::enable_if<std::is_integral<T2>::value && std::is_unsigned<T2>::value>>
295 constexpr static wide_integer<Bits, signed> shift_right(const wide_integer<Bits, signed> &rhs, T2 n) noexcept {
296 if (static_cast<size_t>(n) >= base_bits * arr_size)
297 return 0;
298 if (n <= 0)
299 return rhs;
300
301 bool is_neg = is_negative(rhs);
302 if (!is_neg) {
303 return shift_right(wide_integer<Bits, unsigned>(rhs), n);
304 }
305
306 wide_integer<Bits, Signed> lhs = rhs;
307 int cur_shift = n % base_bits;
308 if (cur_shift) {
309 lhs = shift_right(wide_integer<Bits, unsigned>(lhs), cur_shift);
310 lhs.m_arr[0] |= std::numeric_limits<base_type>::max() << (base_bits - cur_shift);
311 n -= cur_shift;
312 }
313 if (n) {
314 decltype(n / base_bits) i = arr_size - 1;
315 for (; i >= n / base_bits; --i) {
316 lhs.m_arr[i] = lhs.m_arr[i - n / base_bits];
317 }
318 for (; i >= 0; --i) {
319 lhs.m_arr[i] = std::numeric_limits<base_type>::max();
320 }
321 }
322 return lhs;
323 }
324
325 template <typename T, typename std::enable_if_t<std::is_signed<T>::value, void *> = nullptr>
326 constexpr static wide_integer<Bits, Signed> operator_plus_T(const wide_integer<Bits, Signed> &lhs,
327 T rhs) noexcept(is_same<Signed, unsigned>::value) {
328 if (rhs < 0) {
329 return _operator_minus_T(lhs, -rhs);
330 } else {
331 return _operator_plus_T(lhs, rhs);
332 }
333 }
334
335 template <typename T, typename std::enable_if_t<!std::is_signed<T>::value, void *> = nullptr>
336 constexpr static wide_integer<Bits, Signed> operator_plus_T(const wide_integer<Bits, Signed> &lhs,
337 T rhs) noexcept(is_same<Signed, unsigned>::value) {
338 return _operator_plus_T(lhs, rhs);
339 }
340
341private:
342 template <typename T>
343 constexpr static wide_integer<Bits, Signed> _operator_minus_T(const wide_integer<Bits, Signed> &lhs,
344 T rhs) noexcept(is_same<Signed, unsigned>::value) {
345 wide_integer<Bits, Signed> res = lhs;
346
347 bool is_underflow = false;
348 int r_idx = 0;
349 for (; static_cast<size_t>(r_idx) < sizeof(T) && r_idx < arr_size; ++r_idx) {
350 base_type &res_i = res.m_arr[arr_size - 1 - r_idx];
351 base_type curr_rhs = static_cast<base_type>(rhs >> (r_idx * CHAR_BIT)) & std::numeric_limits<base_type>::max();
352
353 if (is_underflow) {
354 --res_i;
355 is_underflow = res_i == std::numeric_limits<base_type>::max();
356 }
357
358 if (res_i < curr_rhs) {
359 is_underflow = true;
360 }
361 res_i = static_cast<base_type>(res_i - curr_rhs);
362 }
363
364 if (is_underflow && r_idx < arr_size) {
365 --res.m_arr[arr_size - 1 - r_idx];
366 for (int i = arr_size - 1 - r_idx - 1; i >= 0; --i) {
367 if (res.m_arr[i + 1] == std::numeric_limits<base_type>::max()) {
368 --res.m_arr[i];
369 } else {
370 break;
371 }
372 }
373 }
374
375 return res;
376 }
377
378 template <typename T>
379 constexpr static wide_integer<Bits, Signed> _operator_plus_T(const wide_integer<Bits, Signed> &lhs,
380 T rhs) noexcept(is_same<Signed, unsigned>::value) {
381 wide_integer<Bits, Signed> res = lhs;
382
383 bool is_overflow = false;
384 int r_idx = 0;
385 for (; static_cast<size_t>(r_idx) < sizeof(T) && r_idx < arr_size; ++r_idx) {
386 base_type &res_i = res.m_arr[arr_size - 1 - r_idx];
387 base_type curr_rhs = static_cast<base_type>((rhs >> (r_idx * CHAR_BIT))) & std::numeric_limits<base_type>::max();
388
389 if (is_overflow) {
390 ++res_i;
391 is_overflow = res_i == 0;
392 }
393
394 res_i = static_cast<base_type>(res_i + curr_rhs);
395 if (res_i < curr_rhs) {
396 is_overflow = true;
397 }
398 }
399
400 if (is_overflow && r_idx < arr_size) {
401 ++res.m_arr[arr_size - 1 - r_idx];
402 for (int i = arr_size - 1 - r_idx - 1; i >= 0; --i) {
403 if (res.m_arr[i + 1] == 0) {
404 ++res.m_arr[i];
405 } else {
406 break;
407 }
408 }
409 }
410
411 return res;
412 }
413
414public:
415 constexpr static wide_integer<Bits, Signed> operator_unary_tilda(const wide_integer<Bits, Signed> &lhs) noexcept {
416 wide_integer<Bits, Signed> res{};
417 for (int i = 0; i < arr_size; ++i) {
418 res.m_arr[i] = static_cast<base_type>(lhs.m_arr[i]);
419 }
420 return res;
421 }
422
423 constexpr static wide_integer<Bits, Signed>
424 operator_unary_minus(const wide_integer<Bits, Signed> &lhs) noexcept(is_same<Signed, unsigned>::value) {
425 return operator_plus_T(operator_unary_tilda(lhs), 1);
426 }
427
428 template <typename T, class = __keep_size<T>>
429 constexpr static wide_integer<Bits, Signed> operator_plus(const wide_integer<Bits, Signed> &lhs,
430 const T &rhs) noexcept(is_same<Signed, unsigned>::value) {
431 wide_integer<Bits, Signed> t = rhs;
432 if (is_negative(t)) {
433 return _operator_minus_wide_integer(lhs, operator_unary_minus(t));
434 } else {
435 return _operator_plus_wide_integer(lhs, t);
436 }
437 }
438
439 // clang-format off
440 // The __need_increase_size variants are currently disabled due to a suspected bug in the MSVC
441 // compiler producing warnings such as:
442 // warning C4717: 'operator_amp<128, ?? :: ?? >': recursive on all control paths, function will cause runtime stack overflow
443 // `class = __need_increase_size<Bits2, Signed2>>` should fail substitution when Bits2 == Bits - the arguments have the same width, but it doesn't.
444 // Mantid only uses a single type of wide integer so these functions are not currently required.
445 // clang-format on
446
447 // template <size_t Bits2, typename Signed2,
448 // class = __need_increase_size<Bits2, Signed2>>
449 // constexpr static typename std::enable_if<Bits2==Bits,wide_integer<Bits2,
450 // Signed>>::type operator_plus(const wide_integer<Bits, Signed> &lhs, const
451 // wide_integer<Bits2, Signed2> &rhs) noexcept(is_same<Signed,
452 // unsigned>::value) {
453 // return std::common_type_t<wide_integer<Bits, Signed>,
454 // wide_integer<Bits2, Signed2>>::_impl::
455 // operator_plus(wide_integer<Bits2, Signed>(lhs), rhs);
456 // }
457
458 template <typename T, class = __keep_size<T>>
459 constexpr static wide_integer<Bits, Signed> operator_minus(const wide_integer<Bits, Signed> &lhs,
460 const T &rhs) noexcept(is_same<Signed, unsigned>::value) {
461 wide_integer<Bits, Signed> t = rhs;
462 if (is_negative(t)) {
463 return _operator_plus_wide_integer(lhs, operator_unary_minus(t));
464 } else {
465 return _operator_minus_wide_integer(lhs, t);
466 }
467 }
468
469 // template <size_t Bits2, typename Signed2,
470 // class = __need_increase_size<Bits2, Signed2>>
471 // constexpr static typename std::enable_if<Bits2==Bits,wide_integer<Bits2,
472 // Signed>>::type operator_minus(const wide_integer<Bits, Signed> &lhs, const
473 // wide_integer<Bits2, Signed2> &rhs) noexcept(is_same<Signed,
474 // unsigned>::value) {
475 // return std::common_type_t<wide_integer<Bits, Signed>,
476 // wide_integer<Bits2, Signed2>>::_impl::
477 // operator_minus(wide_integer<Bits2, Signed>(lhs), rhs);
478 // }
479
480private:
481 constexpr static wide_integer<Bits, Signed>
482 _operator_minus_wide_integer(const wide_integer<Bits, Signed> &lhs,
483 const wide_integer<Bits, Signed> &rhs) noexcept(is_same<Signed, unsigned>::value) {
484 wide_integer<Bits, Signed> res = lhs;
485
486 bool is_underflow = false;
487 for (int idx = arr_size - 1; idx >= 0; --idx) {
488 base_type &res_i = res.m_arr[idx];
489 const base_type rhs_i = rhs.m_arr[idx];
490
491 if (is_underflow) {
492 --res_i;
493 is_underflow = res_i == std::numeric_limits<base_type>::max();
494 }
495
496 if (res_i < rhs_i) {
497 is_underflow = true;
498 }
499 res_i = static_cast<base_type>(res_i - rhs_i);
500 }
501
502 return res;
503 }
504
505 constexpr static wide_integer<Bits, Signed>
506 _operator_plus_wide_integer(const wide_integer<Bits, Signed> &lhs,
507 const wide_integer<Bits, Signed> &rhs) noexcept(is_same<Signed, unsigned>::value) {
508 wide_integer<Bits, Signed> res = lhs;
509
510 bool is_overflow = false;
511 for (int idx = arr_size - 1; idx >= 0; --idx) {
512 base_type &res_i = res.m_arr[idx];
513 const base_type rhs_i = rhs.m_arr[idx];
514
515 if (is_overflow) {
516 ++res_i;
517 is_overflow = res_i == 0;
518 }
519
520 res_i = static_cast<base_type>(res_i + rhs_i);
521 if (res_i < rhs_i) {
522 is_overflow = true;
523 }
524 }
525
526 return res;
527 }
528
529public:
530 template <typename T, class = __keep_size<T>>
531 constexpr static wide_integer<Bits, Signed> operator_star(const wide_integer<Bits, Signed> &lhs, const T &rhs) {
532 const wide_integer<Bits, unsigned> a = make_positive(lhs);
533 wide_integer<Bits, unsigned> t = make_positive(wide_integer<Bits, Signed>(rhs));
534
535 wide_integer<Bits, Signed> res = 0;
536
537 for (size_t i = 0; i < arr_size * base_bits; ++i) {
538 if (t.m_arr[arr_size - 1] & 1) {
539 res = operator_plus(res, shift_left(a, i));
540 }
541
542 t = shift_right(t, 1);
543 }
544
545 if (is_same<Signed, signed>::value && is_negative(wide_integer<Bits, Signed>(rhs)) != is_negative(lhs)) {
546 res = operator_unary_minus(res);
547 }
548
549 return res;
550 }
551
552 // template <size_t Bits2, typename Signed2,
553 // class = __need_increase_size<Bits2, Signed2>>
554 // constexpr static typename std::enable_if<Bits == Bits2, wide_integer<Bits2,
555 // Signed2>>::type operator_star(const wide_integer<Bits, Signed> &lhs, const
556 // wide_integer<Bits2, Signed2> &rhs) {
557 // return std::common_type_t<wide_integer<Bits, Signed>,
558 // wide_integer<Bits2, Signed2>>::_impl::
559 // operator_star(wide_integer<Bits2, Signed2>(lhs), rhs);
560 // }
561
562 template <typename T, class = __keep_size<T>>
563 constexpr static bool operator_more(const wide_integer<Bits, Signed> &lhs, const T &rhs) noexcept {
564 // static_assert(Signed == std::is_signed<T>::value,
565 // "warning: operator_more: comparison of integers of
566 // different signs");
567
568 wide_integer<Bits, Signed> t = rhs;
569
570 if (std::numeric_limits<T>::is_signed && (is_negative(lhs) != is_negative(t))) {
571 return is_negative(t);
572 }
573
574 for (int i = 0; i < arr_size; ++i) {
575 if (lhs.m_arr[i] != t.m_arr[i]) {
576 return lhs.m_arr[i] > t.m_arr[i];
577 }
578 }
579
580 return false;
581 }
582
583 // template <size_t Bits2, class = __need_increase_size<Bits2, Signed>>
584 // constexpr static bool
585 // operator_more(const wide_integer<Bits, Signed> &lhs,
586 // const wide_integer<Bits2, Signed> &rhs) noexcept {
587 // return std::common_type_t<wide_integer<Bits, Signed>,
588 // wide_integer<Bits2, Signed>>::_impl::
589 // operator_more(wide_integer<Bits2, Signed>(lhs), rhs);
590 // }
591
592 template <typename T, class = __keep_size<T>>
593 constexpr static bool operator_less(const wide_integer<Bits, Signed> &lhs, const T &rhs) noexcept {
594 // static_assert(Signed == std::is_signed<T>::value,
595 // "warning: operator_less: comparison of integers of
596 // different signs");
597
598 wide_integer<Bits, Signed> t = rhs;
599
600 if (std::numeric_limits<T>::is_signed && (is_negative(lhs) != is_negative(t))) {
601 return is_negative(lhs);
602 }
603
604 for (int i = 0; i < arr_size; ++i) {
605 if (lhs.m_arr[i] != t.m_arr[i]) {
606 return lhs.m_arr[i] < t.m_arr[i];
607 }
608 }
609
610 return false;
611 }
612
613 // template <size_t Bits2, class = __need_increase_size<Bits2, Signed>>
614 // constexpr static bool
615 // operator_less(const wide_integer<Bits, Signed> &lhs,
616 // const wide_integer<Bits2, Signed> &rhs) noexcept {
617 // return std::common_type_t<wide_integer<Bits, Signed>,
618 // wide_integer<Bits2, Signed>>::_impl::
619 // operator_less(wide_integer<Bits2, Signed>(lhs), rhs);
620 // }
621
622 template <typename T, class = __keep_size<T>>
623 constexpr static bool operator_eq(const wide_integer<Bits, Signed> &lhs, const T &rhs) noexcept {
624 wide_integer<Bits, Signed> t = rhs;
625
626 for (int i = 0; i < arr_size; ++i) {
627 if (lhs.m_arr[i] != t.m_arr[i]) {
628 return false;
629 }
630 }
631
632 return true;
633 }
634
635 // template <size_t Bits2, class = __need_increase_size<Bits2, Signed>>
636 // constexpr static bool
637 // operator_eq(const wide_integer<Bits, Signed> &lhs,
638 // const wide_integer<Bits2, Signed> &rhs) noexcept {
639 // return std::common_type_t<wide_integer<Bits, Signed>,
640 // wide_integer<Bits2, Signed>>::_impl::
641 // operator_eq(wide_integer<Bits2, Signed>(lhs), rhs);
642 // }
643
644 template <typename T, class = __keep_size<T>>
645 constexpr static wide_integer<Bits, Signed> operator_pipe(const wide_integer<Bits, Signed> &lhs,
646 const T &rhs) noexcept {
647 wide_integer<Bits, Signed> t = rhs;
648 wide_integer<Bits, Signed> res = lhs;
649
650 for (int i = 0; i < arr_size; ++i) {
651 res.m_arr[i] |= t.m_arr[i];
652 }
653
654 return res;
655 }
656
657 // template <size_t Bits2, class = __need_increase_size<Bits2, Signed>>
658 // constexpr static typename std::enable_if<Bits == Bits2, wide_integer<Bits2,
659 // Signed>>::type operator_pipe(const wide_integer<Bits, Signed> &lhs, const
660 // wide_integer<Bits2, Signed> &rhs) noexcept {
661 // static_assert(!std::is_same_v<wide_integer<Bits, Signed>,
662 // std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2,
663 // Signed>>>); return std::common_type_t<wide_integer<Bits, Signed>,
664 // wide_integer<Bits2, Signed>>::_impl::
665 // operator_pipe(wide_integer<Bits2, Signed>(lhs), rhs);
666 // }
667
668 template <typename T, class = __keep_size<T>>
669 constexpr static wide_integer<Bits, Signed> operator_amp(const wide_integer<Bits, Signed> &lhs,
670 const T &rhs) noexcept {
671 wide_integer<Bits, Signed> t = rhs;
672 wide_integer<Bits, Signed> res = lhs;
673
674 for (int i = 0; i < arr_size; ++i) {
675 res.m_arr[i] &= t.m_arr[i];
676 }
677
678 return res;
679 }
680
681 // template <size_t Bits2, class = __need_increase_size<Bits2, Signed>>
682 // constexpr static typename std::enable_if<Bits == Bits2, wide_integer<Bits2,
683 // Signed>>::type operator_amp(const wide_integer<Bits, Signed> &lhs, const
684 // wide_integer<Bits2, Signed> &rhs) noexcept {
685 // return std::common_type_t<wide_integer<Bits, Signed>,
686 // wide_integer<Bits2, Signed>>::_impl::
687 // operator_amp(wide_integer<Bits2, Signed>(lhs), rhs);
688 // }
689
690private:
691 template <typename T>
692 constexpr static void divide(const T &lhserator, const T &denominator, T &quotient, T &remainder) {
693 bool is_zero =
694 std::all_of(std::cbegin(denominator.m_arr), std::cend(denominator.m_arr), [](const auto &c) { return c == 0; });
695
696 if (is_zero) {
697 throw std::domain_error("divide by zero");
698 }
699
700 T n = lhserator;
701 T d = denominator;
702 T x = 1;
703 T answer = 0;
704
705 while (!operator_more(d, n) && operator_eq(operator_amp(shift_right(d, base_bits * arr_size - 1), 1), 0)) {
706 x = shift_left(x, 1);
707 d = shift_left(d, 1);
708 }
709
710 while (!operator_eq(x, 0)) {
711 if (!operator_more(d, n)) {
712 n = operator_minus(n, d);
713 answer = operator_pipe(answer, x);
714 }
715
716 x = shift_right(x, 1);
717 d = shift_right(d, 1);
718 }
719
720 quotient = answer;
721 remainder = n;
722 }
723
724public:
725 template <typename T, class = __keep_size<T>>
726 constexpr static wide_integer<Bits, Signed> operator_slash(const wide_integer<Bits, Signed> &lhs, const T &rhs) {
727 wide_integer<Bits, Signed> o = rhs;
728 wide_integer<Bits, Signed> quotient{}, remainder{};
729 divide(make_positive(lhs), make_positive(o), quotient, remainder);
730
731 if (is_same<Signed, signed>::value && is_negative(o) != is_negative(lhs)) {
732 quotient = operator_unary_minus(quotient);
733 }
734
735 return quotient;
736 }
737
738 // template <size_t Bits2, typename Signed2,
739 // class = __need_increase_size<Bits2, Signed2>>
740 // constexpr static wide_integer<Bits2, Signed2>
741 // operator_slash(const wide_integer<Bits, Signed> &lhs,
742 // const wide_integer<Bits2, Signed2> &rhs) {
743 // return std::common_type_t<wide_integer<Bits, Signed>,
744 // wide_integer<Bits2, Signed>>::
745 // operator_slash(wide_integer<Bits2, Signed2>(lhs), rhs);
746 // }
747
748 template <typename T, class = __keep_size<T>>
749 constexpr static wide_integer<Bits, Signed> operator_percent(const wide_integer<Bits, Signed> &lhs, const T &rhs) {
750 wide_integer<Bits, Signed> o = rhs;
751 wide_integer<Bits, Signed> quotient{}, remainder{};
752 divide(make_positive(lhs), make_positive(o), quotient, remainder);
753 if (is_same<Signed, signed>::value && is_negative(lhs)) {
754 remainder = operator_unary_minus(remainder);
755 }
756 return remainder;
757 }
758
759 // template <size_t Bits2, typename Signed2,
760 // class = __need_increase_size<Bits2, Signed2>>
761 // constexpr static wide_integer<Bits2, Signed2>
762 // operator_percent(const wide_integer<Bits, Signed> &lhs,
763 // const wide_integer<Bits2, Signed2> &rhs) {
764 // return std::common_type_t<wide_integer<Bits, Signed>,
765 // wide_integer<Bits2, Signed>>::
766 // operator_percent(wide_integer<Bits2, Signed2>(lhs), rhs);
767 // }
768
769 // ^
770 template <typename T, class = __keep_size<T>>
771 constexpr static wide_integer<Bits, Signed> operator_circumflex(const wide_integer<Bits, Signed> &lhs,
772 const T &rhs) noexcept {
773 wide_integer<Bits, Signed> t(rhs);
774 wide_integer<Bits, Signed> res = lhs;
775
776 for (int i = 0; i < arr_size; ++i) {
777 res.m_arr[i] ^= t.m_arr[i];
778 }
779
780 return res;
781 }
782
783 // template <size_t Bits2, typename Signed2,
784 // class = __need_increase_size<Bits2, Signed2>>
785 // constexpr static wide_integer<Bits2, Signed2>
786 // operator_circumflex(const wide_integer<Bits, Signed> &lhs,
787 // const wide_integer<Bits2, Signed2> &rhs) noexcept {
788 // return wide_integer<Bits2, Signed2>::operator_circumflex(
789 // wide_integer<Bits2, Signed2>(lhs), rhs);
790 // }
791
792 constexpr static wide_integer<Bits, Signed> from_str(const char *c) {
793 wide_integer<Bits, Signed> res = 0;
794
795 bool is_neg = is_same<Signed, signed>::value && *c == '-';
796 if (is_neg) {
797 ++c;
798 }
799
800 if (*c == '0' && (*(c + 1) == 'x' || *(c + 1) == 'X')) { // hex
801 ++c;
802 ++c;
803 while (*c) {
804 if (*c >= '0' && *c <= '9') {
805 res = operator_star(res, 16U);
806 res = operator_plus_T(res, *c - '0');
807 ++c;
808 } else if (*c >= 'a' && *c <= 'f') {
809 res = operator_star(res, 16U);
810 res = operator_plus_T(res, *c - 'a' + 10U);
811 ++c;
812 } else if (*c >= 'A' && *c <= 'F') { // tolower must be used, but it is not constexpr
813 res = operator_star(res, 16U);
814 res = operator_plus_T(res, *c - 'A' + 10U);
815 ++c;
816 } else {
817 throw std::runtime_error("invalid char from");
818 }
819 }
820 } else { // dec
821 while (*c) {
822 if (*c < '0' || *c > '9') {
823 throw std::runtime_error("invalid char from");
824 }
825 res = operator_star(res, 10U);
826 res = operator_plus_T(res, *c - '0');
827 ++c;
828 }
829 }
830
831 if (is_neg) {
832 res = operator_unary_minus(res);
833 }
834
835 return res;
836 }
837
838 constexpr static wide_integer<Bits, Signed> from_str(const wchar_t *c) {
839 wide_integer<Bits, Signed> res = 0;
840
841 bool is_neg = is_same<Signed, signed>::value && *c == L'-';
842 if (is_neg) {
843 ++c;
844 }
845
846 if (*c == L'0' && (*(c + 1) == L'x' || *(c + 1) == L'X')) { // hex
847 ++c;
848 ++c;
849 while (*c) {
850 if (*c >= L'0' && *c <= L'9') {
851 res = operator_star(res, 16U);
852 res = operator_plus_T(res, *c - L'0');
853 ++c;
854 } else if (*c >= L'a' && *c <= L'f') {
855 res = operator_star(res, 16U);
856 res = operator_plus_T(res, *c - L'a' + 10U);
857 ++c;
858 } else if (*c >= L'A' && *c <= L'F') { // tolower must be used, but it is not constexpr
859 res = operator_star(res, 16U);
860 res = operator_plus_T(res, *c - L'A' + 10U);
861 ++c;
862 } else {
863 throw std::runtime_error("invalid char from");
864 }
865 }
866 } else { // dec
867 while (*c) {
868 if (*c < L'0' || *c > L'9') {
869 throw std::runtime_error("invalid char from");
870 }
871 res = operator_star(res, 10U);
872 res = operator_plus_T(res, *c - L'0');
873 ++c;
874 }
875 }
876
877 if (is_neg) {
878 res = operator_unary_minus(res);
879 }
880
881 return res;
882 }
883};
884
885// Members
886
887template <size_t Bits, typename Signed>
888template <typename T>
889constexpr wide_integer<Bits, Signed>::wide_integer(T rhs) noexcept : m_arr{} {
890 _impl::wide_integer_from_bultin(*this, rhs);
891}
892
893template <size_t Bits, typename Signed>
894template <size_t Bits2, typename Signed2>
895constexpr wide_integer<Bits, Signed>::wide_integer(const wide_integer<Bits2, Signed2> &rhs) noexcept : m_arr{} {
896 _impl::wide_integer_from_wide_integer(*this, rhs);
897}
898
899template <size_t Bits, typename Signed>
900template <size_t Bits2, typename Signed2>
901constexpr wide_integer<Bits, Signed> &
902wide_integer<Bits, Signed>::operator=(const wide_integer<Bits2, Signed2> &rhs) noexcept {
903 _impl::wide_integer_from_wide_integer(*this, rhs);
904 return *this;
905}
906
907template <size_t Bits, typename Signed>
908template <typename T>
909constexpr wide_integer<Bits, Signed> &wide_integer<Bits, Signed>::operator=(T rhs) noexcept {
910 _impl::wide_integer_from_bultin(*this, rhs);
911 return *this;
912}
913
914template <size_t Bits, typename Signed>
915template <typename T>
916constexpr wide_integer<Bits, Signed> &wide_integer<Bits, Signed>::operator*=(const T &rhs) {
917 *this = *this * rhs;
918 return *this;
919}
920
921template <size_t Bits, typename Signed>
922template <typename T>
923constexpr wide_integer<Bits, Signed> &wide_integer<Bits, Signed>::operator/=(const T &rhs) {
924 *this = *this / rhs;
925 return *this;
926}
927
928template <size_t Bits, typename Signed>
929template <typename T>
930constexpr wide_integer<Bits, Signed> &
931wide_integer<Bits, Signed>::operator+=(const T &rhs) noexcept(is_same<Signed, unsigned>::value) {
932 *this = *this + rhs;
933 return *this;
934}
935
936template <size_t Bits, typename Signed>
937template <typename T>
938constexpr wide_integer<Bits, Signed> &
939wide_integer<Bits, Signed>::operator-=(const T &rhs) noexcept(is_same<Signed, unsigned>::value) {
940 *this = *this - rhs;
941 return *this;
942}
943
944template <size_t Bits, typename Signed>
945template <typename T>
946constexpr wide_integer<Bits, Signed> &wide_integer<Bits, Signed>::operator%=(const T &rhs) {
947 *this = *this % rhs;
948 return *this;
949}
950
951template <size_t Bits, typename Signed>
952template <typename T>
953constexpr wide_integer<Bits, Signed> &wide_integer<Bits, Signed>::operator&=(const T &rhs) noexcept {
954 *this = *this & rhs;
955 return *this;
956}
957
958template <size_t Bits, typename Signed>
959template <typename T>
960constexpr wide_integer<Bits, Signed> &wide_integer<Bits, Signed>::operator|=(const T &rhs) noexcept {
961 *this = *this | rhs;
962 return *this;
963}
964
965template <size_t Bits, typename Signed>
966template <typename T>
967constexpr wide_integer<Bits, Signed> &wide_integer<Bits, Signed>::operator^=(const T &rhs) noexcept {
968 *this = *this ^ rhs;
969 return *this;
970}
971
972template <size_t Bits, typename Signed>
973template <typename T2, typename>
974constexpr wide_integer<Bits, Signed> &wide_integer<Bits, Signed>::operator<<=(T2 n) noexcept {
975 *this = _impl::shift_left(*this, n);
976 return *this;
977}
978
979template <size_t Bits, typename Signed>
980template <typename T2, typename>
981constexpr wide_integer<Bits, Signed> &wide_integer<Bits, Signed>::operator>>=(T2 n) noexcept {
982 *this = _impl::shift_right(*this, n);
983 return *this;
984}
985
986template <size_t Bits, typename Signed>
987constexpr wide_integer<Bits, Signed> &
988wide_integer<Bits, Signed>::operator++() noexcept(is_same<Signed, unsigned>::value) {
989 *this = _impl::operator_plus(*this, 1);
990 return *this;
991}
992
993template <size_t Bits, typename Signed>
994constexpr wide_integer<Bits, Signed>
995wide_integer<Bits, Signed>::operator++(int) noexcept(is_same<Signed, unsigned>::value) {
996 auto tmp = *this;
997 *this = _impl::operator_plus(*this, 1);
998 return tmp;
999}
1000
1001template <size_t Bits, typename Signed>
1002constexpr wide_integer<Bits, Signed> &
1003wide_integer<Bits, Signed>::operator--() noexcept(is_same<Signed, unsigned>::value) {
1004 *this = _impl::operator_minus(*this, 1);
1005 return *this;
1006}
1007
1008template <size_t Bits, typename Signed>
1009constexpr wide_integer<Bits, Signed>
1010wide_integer<Bits, Signed>::operator--(int) noexcept(is_same<Signed, unsigned>::value) {
1011 auto tmp = *this;
1012 *this = _impl::operator_minus(*this, 1);
1013 return tmp;
1014}
1015
1016template <size_t Bits, typename Signed> constexpr wide_integer<Bits, Signed>::operator bool() const noexcept {
1017 return !_impl::operator_eq(*this, 0);
1018}
1019
1020template <size_t Bits, typename Signed>
1021template <class T, class>
1022constexpr wide_integer<Bits, Signed>::operator T() const noexcept {
1023 static_assert(std::numeric_limits<T>::is_integer, "");
1024 T res = 0;
1025 for (size_t r_idx = 0; r_idx < _impl::arr_size && r_idx < sizeof(T) / sizeof(base_type); ++r_idx) {
1026 res |= (T(m_arr[_impl::arr_size - 1 - r_idx]) << (_impl::base_bits * r_idx * sizeof(base_type)));
1027 }
1028 return res;
1029}
1030
1031template <size_t Bits, typename Signed> constexpr wide_integer<Bits, Signed>::operator long double() const noexcept {
1032 if (_impl::operator_eq(*this, 0)) {
1033 return 0;
1034 }
1035
1036 wide_integer<Bits, Signed> tmp = *this;
1037 if (_impl::is_negative(*this)) {
1038 tmp = -tmp;
1039 }
1040
1041 long double res = 0;
1042 for (size_t idx = 0; idx < _impl::arr_size; ++idx) {
1043 long double t = res;
1044 res *= std::numeric_limits<base_type>::max();
1045 res += t;
1046 res += tmp.m_arr[idx];
1047 }
1048
1049 if (_impl::is_negative(*this)) {
1050 res = -res;
1051 }
1052
1053 return res;
1054}
1055
1056template <size_t Bits, typename Signed> constexpr wide_integer<Bits, Signed>::operator double() const noexcept {
1057 return static_cast<long double>(*this);
1058}
1059
1060template <size_t Bits, typename Signed> constexpr wide_integer<Bits, Signed>::operator float() const noexcept {
1061 return static_cast<long double>(*this);
1062}
1063
1064// Unary operators
1065template <size_t Bits, typename Signed>
1066constexpr wide_integer<Bits, Signed> operator~(const wide_integer<Bits, Signed> &lhs) noexcept {
1067 return wide_integer<Bits, Signed>::_impl::operator_unary_tilda(lhs);
1068}
1069
1070template <size_t Bits, typename Signed>
1071constexpr wide_integer<Bits, Signed>
1072operator-(const wide_integer<Bits, Signed> &lhs) noexcept(is_same<Signed, unsigned>::value) {
1073 return wide_integer<Bits, Signed>::_impl::operator_unary_minus(lhs);
1074}
1075
1076template <size_t Bits, typename Signed>
1077constexpr wide_integer<Bits, Signed>
1078operator+(const wide_integer<Bits, Signed> &lhs) noexcept(is_same<Signed, unsigned>::value) {
1079 return lhs;
1080}
1081
1082// Binary operators
1083template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1084std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>> constexpr
1085operator*(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1086 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_star(lhs, rhs);
1087}
1088
1089template <typename Arithmetic, typename Arithmetic2, class>
1090std::common_type_t<Arithmetic, Arithmetic2> constexpr operator*(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1091 return CT(lhs) * CT(rhs);
1092}
1093
1094template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1095std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>> constexpr
1096operator/(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1097 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_slash(lhs, rhs);
1098}
1099template <typename Arithmetic, typename Arithmetic2, class>
1100std::common_type_t<Arithmetic, Arithmetic2> constexpr operator/(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1101 return CT(lhs) / CT(rhs);
1102}
1103
1104template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1105std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>> constexpr
1106operator+(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1107 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_plus(lhs, rhs);
1108}
1109template <typename Arithmetic, typename Arithmetic2, class>
1110std::common_type_t<Arithmetic, Arithmetic2> constexpr operator+(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1111 return CT(lhs) + CT(rhs);
1112}
1113
1114template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1115std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>> constexpr
1116operator-(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1117 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_minus(lhs, rhs);
1118}
1119template <typename Arithmetic, typename Arithmetic2, class>
1120std::common_type_t<Arithmetic, Arithmetic2> constexpr operator-(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1121 return CT(lhs) - CT(rhs);
1122}
1123
1124template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1125std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>> constexpr
1126operator%(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1127 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_percent(lhs,
1128 rhs);
1129}
1130template <typename Integral, typename Integral2, class>
1131std::common_type_t<Integral, Integral2> constexpr operator%(const Integral &lhs, const Integral2 &rhs) {
1132 return CT(lhs) % CT(rhs);
1133}
1134
1135template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1136std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>> constexpr
1137operator&(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1138 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_amp(lhs, rhs);
1139}
1140template <typename Integral, typename Integral2, class>
1141std::common_type_t<Integral, Integral2> constexpr operator&(const Integral &lhs, const Integral2 &rhs) {
1142 return CT(lhs) & CT(rhs);
1143}
1144
1145template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1146std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>> constexpr
1147operator|(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1148 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_pipe(lhs, rhs);
1149}
1150template <typename Integral, typename Integral2, class>
1151std::common_type_t<Integral, Integral2> constexpr operator|(const Integral &lhs, const Integral2 &rhs) {
1152 return CT(lhs) | CT(rhs);
1153}
1154
1155template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1156std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>> constexpr
1157operator^(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1158 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_circumflex(lhs,
1159 rhs);
1160}
1161template <typename Integral, typename Integral2, class>
1162std::common_type_t<Integral, Integral2> constexpr operator^(const Integral &lhs, const Integral2 &rhs) {
1163 return CT(lhs) ^ CT(rhs);
1164}
1165
1166template <size_t Bits, typename Signed>
1167constexpr wide_integer<Bits, Signed> operator<<(const wide_integer<Bits, Signed> &lhs, int n) noexcept {
1168 return wide_integer<Bits, Signed>::_impl::shift_left(lhs, n);
1169}
1170template <size_t Bits, typename Signed>
1171constexpr wide_integer<Bits, Signed> operator>>(const wide_integer<Bits, Signed> &lhs, int n) noexcept {
1172 return wide_integer<Bits, Signed>::_impl::shift_right(lhs, n);
1173}
1174
1175template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1176constexpr bool operator<(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1177 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_less(lhs, rhs);
1178}
1179template <typename Arithmetic, typename Arithmetic2, class>
1180constexpr bool operator<(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1181 return CT(lhs) < CT(rhs);
1182}
1183
1184template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1185constexpr bool operator>(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1186 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_more(lhs, rhs);
1187}
1188template <typename Arithmetic, typename Arithmetic2, class>
1189constexpr bool operator>(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1190 return CT(lhs) > CT(rhs);
1191}
1192
1193template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1194constexpr bool operator<=(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1195 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_less(lhs, rhs) ||
1196 std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_eq(lhs, rhs);
1197}
1198template <typename Arithmetic, typename Arithmetic2, class>
1199constexpr bool operator<=(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1200 return CT(lhs) <= CT(rhs);
1201}
1202
1203template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1204constexpr bool operator>=(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1205 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_more(lhs, rhs) ||
1206 std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_eq(lhs, rhs);
1207}
1208template <typename Arithmetic, typename Arithmetic2, class>
1209constexpr bool operator>=(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1210 return CT(lhs) >= CT(rhs);
1211}
1212
1213template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1214constexpr bool operator==(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1215 return std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_eq(lhs, rhs);
1216}
1217template <typename Arithmetic, typename Arithmetic2, class>
1218constexpr bool operator==(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1219 return CT(lhs) == CT(rhs);
1220}
1221
1222template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
1223constexpr bool operator!=(const wide_integer<Bits, Signed> &lhs, const wide_integer<Bits2, Signed2> &rhs) {
1224 return !std::common_type_t<wide_integer<Bits, Signed>, wide_integer<Bits2, Signed2>>::_impl::operator_eq(lhs, rhs);
1225}
1226template <typename Arithmetic, typename Arithmetic2, class>
1227constexpr bool operator!=(const Arithmetic &lhs, const Arithmetic2 &rhs) {
1228 return CT(lhs) != CT(rhs);
1229}
1230
1231template <size_t Bits, typename Signed> std::string to_string(const wide_integer<Bits, Signed> &n) {
1232 std::string res;
1233 if (wide_integer<Bits, Signed>::_impl::operator_eq(n, 0U)) {
1234 return "0";
1235 }
1236
1237 wide_integer<Bits, unsigned> t;
1238 bool is_neg = wide_integer<Bits, Signed>::_impl::is_negative(n);
1239 if (is_neg) {
1240 t = wide_integer<Bits, Signed>::_impl::operator_unary_minus(n);
1241 } else {
1242 t = n;
1243 }
1244
1245 while (!wide_integer<Bits, unsigned>::_impl::operator_eq(t, 0U)) {
1246 res.insert(res.begin(), '0' + char(wide_integer<Bits, unsigned>::_impl::operator_percent(t, 10U)));
1247 t = wide_integer<Bits, unsigned>::_impl::operator_slash(t, 10U);
1248 }
1249
1250 if (is_neg) {
1251 res.insert(res.begin(), '-');
1252 }
1253
1254 return res;
1255}
1256
1257template <size_t Bits, typename Signed> std::wstring to_wstring(const wide_integer<Bits, Signed> &n) {
1258 std::wstring res;
1259 if (wide_integer<Bits, Signed>::_impl::operator_eq(n, 0U)) {
1260 return L"0";
1261 }
1262
1263 wide_integer<Bits, unsigned> t;
1264 bool is_neg = wide_integer<Bits, Signed>::_impl::is_negative(n);
1265 if (is_neg) {
1266 t = wide_integer<Bits, Signed>::_impl::operator_unary_minus(n);
1267 } else {
1268 t = n;
1269 }
1270
1271 while (!wide_integer<Bits, unsigned>::_impl::operator_eq(t, 0U)) {
1272 res.insert(res.begin(), '0' + wchar_t(wide_integer<Bits, unsigned>::_impl::operator_percent(t, 10U)));
1273 t = wide_integer<Bits, unsigned>::_impl::operator_slash(t, 10U);
1274 }
1275
1276 if (is_neg) {
1277 res.insert(res.begin(), '-');
1278 }
1279
1280 return res;
1281}
1282
1283template <size_t Bits, typename Signed>
1284std::ostream &operator<<(std::ostream &out, const wide_integer<Bits, Signed> &n) {
1285 out << to_string(n);
1286 return out;
1287}
1288
1289template <size_t Bits, typename Signed>
1290std::wostream &operator<<(std::wostream &out, const wide_integer<Bits, Signed> &n) {
1291 out << to_wstring(n);
1292 return out;
1293}
1294
1295template <size_t Bits, typename Signed> std::istream &operator>>(std::istream &in, wide_integer<Bits, Signed> &n) {
1296 std::string s;
1297 in >> s;
1298 n = wide_integer<Bits, Signed>::_impl::from_str(s.c_str());
1299 return in;
1300}
1301
1302template <size_t Bits, typename Signed> std::wistream &operator>>(std::wistream &in, wide_integer<Bits, Signed> &n) {
1303 std::wstring s;
1304 in >> s;
1305 n = wide_integer<Bits, Signed>::_impl::from_str(s.c_str());
1306 return in;
1307}
1308
1309template <size_t Bits, typename Signed>
1310to_chars_result to_chars(char *first, char *last, const wide_integer<Bits, Signed> &value, int base) {
1311 if (base < 2 || base > 36) {
1312 return {last, std::make_error_code(std::errc::invalid_argument)};
1313 }
1314 if (first >= last) {
1315 return {last, std::make_error_code(std::errc::invalid_argument)};
1316 }
1317
1318 if (value == 0) {
1319 *first = '0';
1320 *(++first) = '\0';
1321 return {++first, {}};
1322 }
1323
1324 wide_integer<Bits, Signed> v = value;
1325 if (v < 0) {
1326 v = -v;
1327 *(first++) = '-';
1328 }
1329
1330 char *cur = last;
1331
1332 while (v != 0 && --cur >= first) {
1333 static const char ALPHA[] = "0123456789abcdefghijklmnopqrstuvwxyz";
1334 *cur = ALPHA[v % base];
1335 v /= base;
1336 }
1337
1338 if (v && cur + 1 == first) {
1339 return {nullptr, std::make_error_code(std::errc::value_too_large)};
1340 }
1341
1342 while (cur < last) {
1343 *(first++) = *(cur++);
1344 }
1345 if (first < last) {
1346 *first = '\0';
1347 }
1348
1349 return {first, {}};
1350}
1351
1352std::array<char, 256> inline genReverseAlpha() noexcept {
1353 static const char ALPHA[] = "0123456789abcdefghijklmnopqrstuvwxyz";
1354 std::array<char, 256> res;
1355 res.fill(-1);
1356 for (size_t i = 0; i < sizeof(ALPHA); ++i) {
1357 res[ALPHA[i]] = static_cast<char>(i);
1358 }
1359 return res;
1360}
1361
1362template <size_t Bits, typename Signed>
1363from_chars_result from_chars(const char *first, const char *last, wide_integer<Bits, Signed> &value, int base) {
1364 if (base < 2 || base > 36) {
1365 return {first, std::make_error_code(std::errc::invalid_argument)};
1366 }
1367 if (first >= last) {
1368 return {first, std::make_error_code(std::errc::invalid_argument)};
1369 }
1370
1371 bool is_negative = *first == '-';
1372 if (is_negative) {
1373 if (!is_same<Signed, signed>::value) {
1374 return {first, std::make_error_code(std::errc::result_out_of_range)};
1375 }
1376 if (++first >= last) {
1377 return {first, std::make_error_code(std::errc::invalid_argument)};
1378 }
1379 }
1380
1381 wide_integer<Bits, Signed> v = 0;
1382 const char *cur = first;
1383
1384 do {
1385 static const std::array<char, 256> ALPHA = genReverseAlpha();
1386 char cv = ALPHA[*cur];
1387 if (cv >= base || cv == -1) {
1388 if (cur == first) {
1389 return {cur, std::make_error_code(std::errc::result_out_of_range)};
1390 } else {
1391 value = v;
1392 return {cur, {}};
1393 }
1394 }
1395
1396 v *= base;
1397 v += cv;
1398 } while (++cur < last);
1399
1400 value = is_negative ? -v : v;
1401 return {cur, {}};
1402}
1403
1404constexpr int128_t operator"" _cppi128(const char *n) { return int128_t::_impl::from_str(n); }
1405constexpr int256_t operator"" _cppi256(const char *n) { return int256_t::_impl::from_str(n); }
1406constexpr int512_t operator"" _cppi512(const char *n) { return int512_t::_impl::from_str(n); }
1407constexpr uint128_t operator"" _cppui128(const char *n) { return uint128_t::_impl::from_str(n); }
1408constexpr uint256_t operator"" _cppui256(const char *n) { return uint256_t::_impl::from_str(n); }
1409constexpr uint512_t operator"" _cppui512(const char *n) { return uint512_t::_impl::from_str(n); }
1410
1411template <size_t Bits, typename Signed> struct hash<wide_integer<Bits, Signed>> {
1412 std::size_t operator()(const wide_integer<Bits, Signed> &lhs) const {
1413 size_t res = std::accumulate(std::cbegin(lhs.m_arr), std::cend(lhs.m_arr), 0);
1414 return hash<size_t>()(res);
1415 }
1416};
1417
1418#undef CT
1419} // namespace std
gsl_vector * tmp
const std::vector< double > & rhs
double value
The value of the point.
Definition: FitMW.cpp:51
int count
counter
Definition: Matrix.cpp:37
constexpr wide_integer< Bits, Signed > & operator>>=(T2 n) noexcept
constexpr wide_integer< Bits, Signed > & operator<<=(T2 n) noexcept
constexpr wide_integer< Bits, Signed > & operator++() noexcept(is_same< Signed, unsigned >::value)
constexpr wide_integer< Bits, Signed > & operator&=(const Integral &rhs) noexcept
int32_t signed_base_type
Definition: WideInt.h:73
constexpr wide_integer< Bits, Signed > & operator*=(const Arithmetic &rhs)
uint32_t base_type
Definition: WideInt.h:72
constexpr wide_integer< Bits, Signed > & operator|=(const Integral &rhs) noexcept
constexpr wide_integer< Bits, Signed > & operator--() noexcept(is_same< Signed, unsigned >::value)
friend class wide_integer
Definition: WideInt.h:133
constexpr wide_integer< Bits, Signed > & operator=(const wide_integer< Bits2, Signed2 > &rhs) noexcept
constexpr wide_integer< Bits, Signed > & operator+=(const Arithmetic &rhs) noexcept(is_same< Signed, unsigned >::value)
constexpr wide_integer< Bits, Signed > & operator-=(const Arithmetic &rhs) noexcept(is_same< Signed, unsigned >::value)
constexpr wide_integer< Bits, Signed > & operator%=(const Integral &rhs)
constexpr wide_integer< Bits, Signed > & operator^=(const Integral &rhs) noexcept
constexpr wide_integer< Bits, Signed > & operator/=(const Arithmetic &rhs)
STL namespace.
constexpr wide_integer< Bits, Signed > operator-(const wide_integer< Bits, Signed > &lhs) noexcept(is_same< Signed, unsigned >::value)
static constexpr bool ArithmeticConcept() noexcept
constexpr bool operator==(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
static constexpr bool IntegralConcept() noexcept
std::common_type_t< wide_integer< Bits, Signed >, wide_integer< Bits2, Signed2 > > constexpr operator|(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
from_chars_result from_chars(const char *first, const char *last, wide_integer< Bits, Signed > &value, int base=10)
std::wstring to_wstring(const wide_integer< Bits, Signed > &n)
constexpr bool operator>=(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
std::common_type_t< wide_integer< Bits, Signed >, wide_integer< Bits2, Signed2 > > constexpr operator%(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
constexpr bool operator!=(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
std::common_type_t< wide_integer< Bits, Signed >, wide_integer< Bits2, Signed2 > > constexpr operator*(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
constexpr wide_integer< Bits, Signed > operator+(const wide_integer< Bits, Signed > &lhs) noexcept(is_same< Signed, unsigned >::value)
to_chars_result to_chars(char *first, char *last, const wide_integer< Bits, Signed > &value, int base=10)
constexpr bool operator<=(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
constexpr bool operator>(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
constexpr wide_integer< Bits, Signed > operator~(const wide_integer< Bits, Signed > &lhs) noexcept
std::string to_string(const wide_integer< Bits, Signed > &n)
constexpr bool operator<(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
std::common_type_t< wide_integer< Bits, Signed >, wide_integer< Bits2, Signed2 > > constexpr operator/(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
constexpr wide_integer< Bits, Signed > operator>>(const wide_integer< Bits, Signed > &lhs, T2 n) noexcept
std::common_type_t< wide_integer< Bits, Signed >, wide_integer< Bits2, Signed2 > > constexpr operator&(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)
constexpr wide_integer< Bits, Signed > operator<<(const wide_integer< Bits, Signed > &lhs, T2 n) noexcept
std::common_type_t< wide_integer< Bits, Signed >, wide_integer< Bits2, Signed2 > > constexpr operator^(const wide_integer< Bits, Signed > &lhs, const wide_integer< Bits2, Signed2 > &rhs)