libTriton version 1.0 build 1590
Loading...
Searching...
No Matches
uintwide_t.h
1
2// Copyright Christopher Kormanyos 1999 - 2022. //
3// Distributed under the Boost Software License, //
4// Version 1.0. (See accompanying file LICENSE_1_0.txt //
5// or copy at http://www.boost.org/LICENSE_1_0.txt) //
7
8#ifndef UINTWIDE_T_2018_10_02_H // NOLINT(llvm-header-guard)
9#define UINTWIDE_T_2018_10_02_H
10
11#include <algorithm>
12#include <array>
13#if defined(__GNUC__) || defined(__clang__)
14#if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64)
15#include <cinttypes>
16#endif
17#endif
18#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
19#include <cmath>
20#endif
21#include <cstddef>
22#include <cstdint>
23#include <cstdlib>
24#include <cstring>
25#include <initializer_list>
26#if !defined(WIDE_INTEGER_DISABLE_IOSTREAM)
27#include <iomanip>
28#include <istream>
29#endif
30#include <iterator>
31#include <limits>
32#if !defined(WIDE_INTEGER_DISABLE_IMPLEMENT_UTIL_DYNAMIC_ARRAY)
33#include <memory>
34#endif
35#if !defined(WIDE_INTEGER_DISABLE_IOSTREAM)
36#include <ostream>
37#include <sstream>
38#endif
39#include <type_traits>
40
41#if (defined(__clang__) && (__clang_major__ <= 9))
42#define WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE struct // NOLINT(cppcoreguidelines-macro-usage)
43#else
44#define WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE class // NOLINT(cppcoreguidelines-macro-usage)
45#endif
46
47#if defined(_MSC_VER)
48#if (_MSC_VER >= 1900) && defined(_HAS_CXX20) && (_HAS_CXX20 != 0)
49#define WIDE_INTEGER_CONSTEXPR constexpr // NOLINT(cppcoreguidelines-macro-usage)
50#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 1 // NOLINT(cppcoreguidelines-macro-usage)
51#define WIDE_INTEGER_NODISCARD [[nodiscard]] // NOLINT(cppcoreguidelines-macro-usage)
52#else
53#define WIDE_INTEGER_CONSTEXPR
54#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 0 // NOLINT(cppcoreguidelines-macro-usage)
55#define WIDE_INTEGER_NODISCARD
56#endif
57#else
58#if (defined(__cplusplus) && (__cplusplus >= 201402L))
59#if defined(__AVR__) && (!defined(__GNUC__) || (defined(__GNUC__) && (__GNUC__ > 6)))
60#define WIDE_INTEGER_CONSTEXPR constexpr // NOLINT(cppcoreguidelines-macro-usage)
61#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 1 // NOLINT(cppcoreguidelines-macro-usage)
62#define WIDE_INTEGER_NODISCARD [[nodiscard]] // NOLINT(cppcoreguidelines-macro-usage)
63#elif (defined(__cpp_lib_constexpr_algorithms) && (__cpp_lib_constexpr_algorithms>=201806))
64#if defined(__clang__)
65#if (__clang_major__ > 9)
66#define WIDE_INTEGER_CONSTEXPR constexpr // NOLINT(cppcoreguidelines-macro-usage)
67#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 1 // NOLINT(cppcoreguidelines-macro-usage)
68#define WIDE_INTEGER_NODISCARD [[nodiscard]] // NOLINT(cppcoreguidelines-macro-usage)
69#else
70#define WIDE_INTEGER_CONSTEXPR
71#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 0 // NOLINT(cppcoreguidelines-macro-usage)
72#define WIDE_INTEGER_NODISCARD
73#endif
74#else
75#define WIDE_INTEGER_CONSTEXPR constexpr // NOLINT(cppcoreguidelines-macro-usage)
76#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 1 // NOLINT(cppcoreguidelines-macro-usage)
77#define WIDE_INTEGER_NODISCARD [[nodiscard]] // NOLINT(cppcoreguidelines-macro-usage)
78#endif
79#elif (defined(__clang__) && (__clang_major__ >= 10)) && (defined(__cplusplus) && (__cplusplus > 201703L))
80#if defined(__x86_64__)
81#define WIDE_INTEGER_CONSTEXPR constexpr // NOLINT(cppcoreguidelines-macro-usage)
82#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 1 // NOLINT(cppcoreguidelines-macro-usage)
83#define WIDE_INTEGER_NODISCARD [[nodiscard]] // NOLINT(cppcoreguidelines-macro-usage)
84#else
85#define WIDE_INTEGER_CONSTEXPR
86#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 0 // NOLINT(cppcoreguidelines-macro-usage)
87#define WIDE_INTEGER_NODISCARD
88#endif
89#else
90#define WIDE_INTEGER_CONSTEXPR
91#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 0 // NOLINT(cppcoreguidelines-macro-usage)
92#define WIDE_INTEGER_NODISCARD
93#endif
94#else
95#define WIDE_INTEGER_CONSTEXPR
96#define WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST 0 // NOLINT(cppcoreguidelines-macro-usage)
97#define WIDE_INTEGER_NODISCARD
98#endif
99#endif
100
101#if defined(WIDE_INTEGER_NAMESPACE_BEGIN) || defined(WIDE_INTEGER_NAMESPACE_END)
102#error internal pre-processor macro already defined
103#endif
104
105#if defined(WIDE_INTEGER_NAMESPACE)
106#define WIDE_INTEGER_NAMESPACE_BEGIN namespace WIDE_INTEGER_NAMESPACE { // NOLINT(cppcoreguidelines-macro-usage)
107#define WIDE_INTEGER_NAMESPACE_END } // namespace WIDE_INTEGER_NAMESPACE // NOLINT(cppcoreguidelines-macro-usage)
108#else
109#define WIDE_INTEGER_NAMESPACE_BEGIN
110#define WIDE_INTEGER_NAMESPACE_END
111#endif
112
113#if !defined(WIDE_INTEGER_DISABLE_IMPLEMENT_UTIL_DYNAMIC_ARRAY)
114
115WIDE_INTEGER_NAMESPACE_BEGIN
116
117namespace util {
118
119 template<typename ValueType,
120 typename AllocatorType = std::allocator<ValueType>,
121 typename SizeType = std::size_t,
122 typename DiffType = std::ptrdiff_t>
123 class dynamic_array;
124
125 template<typename ValueType,
126 typename AllocatorType,
127 typename SizeType,
128 typename DiffType>
130 {
131 public:
132 // Type definitions.
133 using allocator_type = typename std::allocator_traits<AllocatorType>::template rebind_alloc<ValueType>;
134 using value_type = typename allocator_type::value_type;
135 using reference = value_type &;
136 using const_reference = const value_type &;
137 using iterator = value_type *;
138 using const_iterator = const value_type*;
139 using pointer = value_type *;
140 using const_pointer = const value_type*;
141 using size_type = SizeType;
142 using difference_type = DiffType;
143 using reverse_iterator = std::reverse_iterator<iterator>;
144 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
145
146 // Constructors.
147 constexpr dynamic_array() : elem_count(0U),
148 elems(nullptr) { }
149
150 explicit WIDE_INTEGER_CONSTEXPR dynamic_array(size_type count,
151 const_reference v = value_type(),
152 const allocator_type& a = allocator_type())
153 : elem_count(count),
154 elems(nullptr)
155 {
156 allocator_type my_a(a);
157
158 if (elem_count > 0U)
159 {
160 elems = std::allocator_traits<allocator_type>::allocate(my_a, elem_count);
161 }
162
163 iterator it = begin();
164
165 while (it != end())
166 {
167 std::allocator_traits<allocator_type>::construct(my_a, it, v);
168
169 ++it;
170 }
171 }
172
173 WIDE_INTEGER_CONSTEXPR dynamic_array(const dynamic_array& other)
174 : elem_count(other.size()),
175 elems(nullptr)
176 {
177 allocator_type my_a;
178
179 if (elem_count > 0U)
180 {
181 elems = std::allocator_traits<allocator_type>::allocate(my_a, elem_count);
182 }
183
184 std::copy(other.elems, other.elems + elem_count, elems);
185 }
186
187 template<typename input_iterator>
188 WIDE_INTEGER_CONSTEXPR dynamic_array(input_iterator first,
189 input_iterator last,
190 const allocator_type& a = allocator_type())
191 : elem_count(static_cast<size_type>(std::distance(first, last))),
192 elems(nullptr)
193 {
194 allocator_type my_a(a);
195
196 if (elem_count > 0U)
197 {
198 elems = std::allocator_traits<allocator_type>::allocate(my_a, elem_count);
199 }
200
201 std::copy(first, last, elems);
202 }
203
204 WIDE_INTEGER_CONSTEXPR dynamic_array(std::initializer_list<value_type> lst,
205 const allocator_type& a = allocator_type())
206 : elem_count(lst.size()),
207 elems(nullptr)
208 {
209 allocator_type my_a(a);
210
211 if (elem_count > 0U)
212 {
213 elems = std::allocator_traits<allocator_type>::allocate(my_a, elem_count);
214 }
215
216 std::copy(lst.begin(), lst.end(), elems);
217 }
218
219 // Move constructor.
220 WIDE_INTEGER_CONSTEXPR dynamic_array(dynamic_array&& other) noexcept : elem_count(other.elem_count),
221 elems(other.elems)
222 {
223 other.elem_count = 0U;
224 other.elems = nullptr;
225 }
226
227 // Destructor.
228 WIDE_INTEGER_CONSTEXPR virtual ~dynamic_array()
229 {
230 pointer p = elems; // NOLINT(altera-id-dependent-backward-branch)
231
232 using local_allocator_traits_type = std::allocator_traits<allocator_type>;
233
234 allocator_type my_a;
235
236 while (p != elems + elem_count) // NOLINT(altera-id-dependent-backward-branch)
237 {
238 local_allocator_traits_type::destroy(my_a, p);
239
240 ++p;
241 }
242
243 // Destroy the elements and deallocate the range.
244 local_allocator_traits_type::deallocate(my_a, elems, elem_count);
245 }
246
247 // Assignment operator.
248 WIDE_INTEGER_CONSTEXPR auto operator=(const dynamic_array& other) -> dynamic_array &
249 {
250 if (this != &other)
251 {
252 std::copy(other.elems,
253 other.elems + (std::min)(elem_count, other.elem_count),
254 elems);
255 }
256
257 return *this;
258 }
259
260 // Move assignment operator.
261 WIDE_INTEGER_CONSTEXPR auto operator=(dynamic_array&& other) noexcept -> dynamic_array &
262 {
263 // Destroy the elements and deallocate the range.
264 pointer p = elems; // NOLINT(altera-id-dependent-backward-branch)
265
266 using local_allocator_traits_type = std::allocator_traits<allocator_type>;
267
268 allocator_type my_a;
269
270 while (p != elems + elem_count) // NOLINT(altera-id-dependent-backward-branch)
271 {
272 local_allocator_traits_type::destroy(my_a, p);
273
274 ++p;
275 }
276
277 local_allocator_traits_type::deallocate(my_a, elems, elem_count);
278
279 elem_count = other.elem_count;
280 elems = other.elems;
281
282 other.elem_count = 0U;
283 other.elems = nullptr;
284
285 return *this;
286 }
287
288 // Iterator members:
289 WIDE_INTEGER_CONSTEXPR auto begin() -> iterator { return elems; }
290 WIDE_INTEGER_CONSTEXPR auto end() -> iterator { return elems + elem_count; }
291 WIDE_INTEGER_CONSTEXPR auto begin() const -> const_iterator { return elems; }
292 WIDE_INTEGER_CONSTEXPR auto end() const -> const_iterator { return elems + elem_count; }
293 WIDE_INTEGER_CONSTEXPR auto cbegin() const -> const_iterator { return elems; }
294 WIDE_INTEGER_CONSTEXPR auto cend() const -> const_iterator { return elems + elem_count; }
295 WIDE_INTEGER_CONSTEXPR auto rbegin() -> reverse_iterator { return reverse_iterator(elems + elem_count); }
296 WIDE_INTEGER_CONSTEXPR auto rend() -> reverse_iterator { return reverse_iterator(elems); }
297 WIDE_INTEGER_CONSTEXPR auto rbegin() const -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); }
298 WIDE_INTEGER_CONSTEXPR auto rend() const -> const_reverse_iterator { return const_reverse_iterator(elems); }
299 WIDE_INTEGER_CONSTEXPR auto crbegin() const -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); }
300 WIDE_INTEGER_CONSTEXPR auto crend() const -> const_reverse_iterator { return const_reverse_iterator(elems); }
301
302 // Raw pointer access.
303 WIDE_INTEGER_CONSTEXPR auto data() -> pointer { return elems; }
304 WIDE_INTEGER_CONSTEXPR auto data() const -> const_pointer { return elems; }
305
306 // Size and capacity.
307 constexpr auto size() const -> size_type { return elem_count; }
308 constexpr auto max_size() const -> size_type { return elem_count; }
309 constexpr auto empty() const -> bool { return (elem_count == 0U); }
310
311 // Element access members.
312 WIDE_INTEGER_CONSTEXPR auto operator[](const size_type i) -> reference { return elems[i]; }
313 WIDE_INTEGER_CONSTEXPR auto operator[](const size_type i) const -> const_reference { return elems[i]; }
314
315 WIDE_INTEGER_CONSTEXPR auto front() -> reference { return elems[0U]; }
316 WIDE_INTEGER_CONSTEXPR auto front() const -> const_reference { return elems[0U]; }
317
318 WIDE_INTEGER_CONSTEXPR auto back() -> reference { return ((elem_count > static_cast<size_type>(0U)) ? elems[elem_count - 1U] : elems[0U]); }
319 WIDE_INTEGER_CONSTEXPR auto back() const -> const_reference { return ((elem_count > static_cast<size_type>(0U)) ? elems[elem_count - 1U] : elems[0U]); }
320
321 WIDE_INTEGER_CONSTEXPR auto at(const size_type i) -> reference { return ((i < elem_count) ? elems[i] : elems[0U]); }
322 WIDE_INTEGER_CONSTEXPR auto at(const size_type i) const -> const_reference { return ((i < elem_count) ? elems[i] : elems[0U]); }
323
324 // Element manipulation members.
325 WIDE_INTEGER_CONSTEXPR void fill(const value_type& v)
326 {
327 std::fill_n(begin(), elem_count, v);
328 }
329
330 WIDE_INTEGER_CONSTEXPR void swap(dynamic_array& other)
331 {
332 if (this != &other)
333 {
334 pointer tmp_elems = elems;
335
336 elems = other.elems;
337 other.elems = tmp_elems;
338
339 std::swap(elem_count, other.elem_count);
340 }
341 }
342
343 WIDE_INTEGER_CONSTEXPR void swap(dynamic_array&& other)
344 {
345 pointer tmp_elems = elems;
346
347 elems = other.elems;
348 other.elems = tmp_elems;
349
350 std::swap(elem_count, other.elem_count);
351 }
352
353 private:
354 mutable size_type elem_count; // NOLINT(readability-identifier-naming)
355 pointer elems; // NOLINT(readability-identifier-naming,altera-id-dependent-backward-branch)
356 };
357
358 template<typename ValueType, typename AllocatorType>
359 WIDE_INTEGER_CONSTEXPR auto operator==(const dynamic_array<ValueType, AllocatorType>& lhs,
361 {
362 bool left_and_right_are_equal = false;
363
364 const bool sizes_are_equal = (lhs.size() == rhs.size());
365
366 if (sizes_are_equal)
367 {
368 using size_type = typename dynamic_array<ValueType, AllocatorType>::size_type;
369
370 const bool size_of_left_is_zero = (lhs.size() == static_cast<size_type>(0U));
371
372 left_and_right_are_equal =
373 (size_of_left_is_zero || std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()));
374 }
375 else
376 {
377 ;
378 }
379
380 return left_and_right_are_equal;
381 }
382
383 template<typename ValueType, typename AllocatorType>
384 WIDE_INTEGER_CONSTEXPR auto operator<(const dynamic_array<ValueType, AllocatorType>& lhs,
385 const dynamic_array<ValueType, AllocatorType>& rhs) -> bool
386 {
387 using size_type = typename dynamic_array<ValueType, AllocatorType>::size_type;
388
389 const bool size_of_left_is_zero = (lhs.size() == static_cast<size_type>(0U));
390
391 bool b_result{ };
392
393 if (size_of_left_is_zero)
394 {
395 const bool size_of_right_is_zero = (rhs.size() == static_cast<size_type>(0U));
396
397 b_result = (!size_of_right_is_zero);
398 }
399 else
400 {
401 if (size_of_left_is_zero)
402 {
403 const bool size_of_right_is_zero = (rhs.size() == static_cast<size_type>(0U));
404
405 b_result = (!size_of_right_is_zero);
406 }
407 else
408 {
409 const size_type count = (std::min)(lhs.size(), rhs.size());
410
411 b_result = std::lexicographical_compare(lhs.cbegin(),
412 lhs.cbegin() + count,
413 rhs.cbegin(),
414 rhs.cbegin() + count);
415 }
416 }
417
418 return b_result;
419 }
420
421 template<typename ValueType, typename AllocatorType>
422 WIDE_INTEGER_CONSTEXPR auto operator!=(const dynamic_array<ValueType, AllocatorType>& lhs,
423 const dynamic_array<ValueType, AllocatorType>& rhs) -> bool
424 {
425 return (!(lhs == rhs));
426 }
427
428 template<typename ValueType, typename AllocatorType>
429 WIDE_INTEGER_CONSTEXPR auto operator>(const dynamic_array<ValueType, AllocatorType>& lhs,
430 const dynamic_array<ValueType, AllocatorType>& rhs) -> bool
431 {
432 return (rhs < lhs);
433 }
434
435 template<typename ValueType, typename AllocatorType>
436 WIDE_INTEGER_CONSTEXPR auto operator>=(const dynamic_array<ValueType, AllocatorType>& lhs,
437 const dynamic_array<ValueType, AllocatorType>& rhs) -> bool
438 {
439 return (!(lhs < rhs));
440 }
441
442 template<typename ValueType, typename AllocatorType>
443 WIDE_INTEGER_CONSTEXPR auto operator<=(const dynamic_array<ValueType, AllocatorType>& lhs,
444 const dynamic_array<ValueType, AllocatorType>& rhs) -> bool
445 {
446 return (!(rhs < lhs));
447 }
448
449 template<typename ValueType, typename AllocatorType>
450 WIDE_INTEGER_CONSTEXPR void swap(dynamic_array<ValueType, AllocatorType>& x,
451 dynamic_array<ValueType, AllocatorType>& y)
452 {
453 x.swap(y);
454 }
455
456} // namespace util
457
458WIDE_INTEGER_NAMESPACE_END
459
460WIDE_INTEGER_NAMESPACE_BEGIN
461
462#if(__cplusplus >= 201703L)
463namespace math::wide_integer::detail {
464#else
465namespace math {
466 namespace wide_integer {
467 namespace detail { // NOLINT(modernize-concat-nested-namespaces)
468#endif
469
471
472#if(__cplusplus >= 201703L)
473 } // namespace math::wide_integer::detail
474#else
475 } // namespace detail
476} // namespace wide_integer
477} // namespace math
478#endif
479
480WIDE_INTEGER_NAMESPACE_END
481
482#else
483
484#include <util/utility/util_dynamic_array.h>
485
486WIDE_INTEGER_NAMESPACE_BEGIN
487
488#if(__cplusplus >= 201703L)
489namespace math::wide_integer::detail {
490#else
491namespace math {
492 namespace wide_integer {
493 namespace detail { // NOLINT(modernize-concat-nested-namespaces)
494#endif
495
497
498#if(__cplusplus >= 201703L)
499 } // namespace math::wide_integer::detail
500#else
501 } // namespace detail
502} // namespace wide_integer
503} // namespace math
504#endif
505
506WIDE_INTEGER_NAMESPACE_END
507
508#endif
509
510WIDE_INTEGER_NAMESPACE_BEGIN
511
512#if(__cplusplus >= 201703L)
513namespace math::wide_integer {
514#else
515namespace math {
516 namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces)
517#endif
518
519 namespace detail {
520
521 using size_t = std::uint32_t;
522 using ptrdiff_t = std::int32_t;
523
524 static_assert(((std::numeric_limits<size_t>::digits >= std::numeric_limits<std::uint16_t>::digits)
525 && (std::numeric_limits<ptrdiff_t>::digits + 1 >= std::numeric_limits<std::uint16_t>::digits)),
526 "Error: size type and pointer difference type must be at least 16 bits in width (or wider)");
527
528 template<const size_t Width2> struct verify_power_of_two // NOLINT(altera-struct-pack-align)
529 {
530 // TBD: Which powers should be checked if size_t is not 32 bits?
531 static constexpr bool conditional_value =
532 (Width2 == static_cast<size_t>(1ULL << 0U)) || (Width2 == static_cast<size_t>(1ULL << 1U)) || (Width2 == static_cast<size_t>(1ULL << 2U)) || (Width2 == static_cast<size_t>(1ULL << 3U))
533 || (Width2 == static_cast<size_t>(1ULL << 4U)) || (Width2 == static_cast<size_t>(1ULL << 5U)) || (Width2 == static_cast<size_t>(1ULL << 6U)) || (Width2 == static_cast<size_t>(1ULL << 7U))
534 || (Width2 == static_cast<size_t>(1ULL << 8U)) || (Width2 == static_cast<size_t>(1ULL << 9U)) || (Width2 == static_cast<size_t>(1ULL << 10U)) || (Width2 == static_cast<size_t>(1ULL << 11U))
535 || (Width2 == static_cast<size_t>(1ULL << 12U)) || (Width2 == static_cast<size_t>(1ULL << 13U)) || (Width2 == static_cast<size_t>(1ULL << 14U)) || (Width2 == static_cast<size_t>(1ULL << 15U))
536 || (Width2 == static_cast<size_t>(1ULL << 16U)) || (Width2 == static_cast<size_t>(1ULL << 17U)) || (Width2 == static_cast<size_t>(1ULL << 18U)) || (Width2 == static_cast<size_t>(1ULL << 19U))
537 || (Width2 == static_cast<size_t>(1ULL << 20U)) || (Width2 == static_cast<size_t>(1ULL << 21U)) || (Width2 == static_cast<size_t>(1ULL << 22U)) || (Width2 == static_cast<size_t>(1ULL << 23U))
538 || (Width2 == static_cast<size_t>(1ULL << 24U)) || (Width2 == static_cast<size_t>(1ULL << 25U)) || (Width2 == static_cast<size_t>(1ULL << 26U)) || (Width2 == static_cast<size_t>(1ULL << 27U))
539 || (Width2 == static_cast<size_t>(1ULL << 28U)) || (Width2 == static_cast<size_t>(1ULL << 29U)) || (Width2 == static_cast<size_t>(1ULL << 30U)) || (Width2 == static_cast<size_t>(1ULL << 31U))
540 ;
541 };
542
543 template<const size_t BitCount,
544 typename EnableType = void>
545 struct uint_type_helper
546 {
547#if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64)
548 static_assert((((BitCount >= 8U) && (BitCount <= 128U)) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
549 && (verify_power_of_two<BitCount>::conditional_value)),
550 "Error: uint_type_helper is not intended to be used for this BitCount");
551#else
552 static_assert((((BitCount >= 8U) && (BitCount <= 64U)) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
553 && (verify_power_of_two<BitCount>::conditional_value)),
554 "Error: uint_type_helper is not intended to be used for this BitCount");
555#endif
556
557 using exact_unsigned_type = std::uintmax_t;
558 };
559
560 template<const size_t BitCount> struct uint_type_helper<BitCount, typename std::enable_if< (BitCount <= 8U)>::type> { using exact_unsigned_type = std::uint8_t; using fast_unsigned_type = std::uint_fast8_t; using fast_signed_type = std::int_fast8_t; }; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
561 template<const size_t BitCount> struct uint_type_helper<BitCount, typename std::enable_if<(BitCount >= 9U) && (BitCount <= 16U)>::type> { using exact_unsigned_type = std::uint16_t; using fast_unsigned_type = std::uint_fast16_t; using fast_signed_type = std::int_fast16_t; }; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
562 template<const size_t BitCount> struct uint_type_helper<BitCount, typename std::enable_if<(BitCount >= 17U) && (BitCount <= 32U)>::type> { using exact_unsigned_type = std::uint32_t; using fast_unsigned_type = std::uint_fast32_t; using fast_signed_type = std::int_fast32_t; }; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
563 template<const size_t BitCount> struct uint_type_helper<BitCount, typename std::enable_if<(BitCount >= 33U) && (BitCount <= 64U)>::type> { using exact_unsigned_type = std::uint64_t; using fast_unsigned_type = std::uint_fast64_t; using fast_signed_type = std::int_fast64_t; }; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
564#if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64)
565 template<const size_t BitCount> struct uint_type_helper<BitCount, typename std::enable_if<(BitCount >= 65U) && (BitCount <= 128U)>::type> { using exact_unsigned_type = unsigned __int128; using fast_unsigned_type = unsigned __int128; using fast_signed_type = signed __int128; }; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
566#endif
567
568 using unsigned_fast_type = typename uint_type_helper<static_cast<size_t>(std::numeric_limits<size_t >::digits + 0)>::fast_unsigned_type;
569 using signed_fast_type = typename uint_type_helper<static_cast<size_t>(std::numeric_limits<ptrdiff_t>::digits + 1)>::fast_signed_type;
570
571#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
572 namespace my_own {
573
574 template<typename FloatingPointType> WIDE_INTEGER_CONSTEXPR auto frexp(FloatingPointType x, int* expptr) -> typename std::enable_if<((std::is_floating_point<FloatingPointType>::value) && (std::numeric_limits<FloatingPointType>::is_iec559)), FloatingPointType>::type;
575 template<typename FloatingPointType> WIDE_INTEGER_CONSTEXPR auto frexp(FloatingPointType x, int* expptr) -> typename std::enable_if<((std::is_floating_point<FloatingPointType>::value) && (!std::numeric_limits<FloatingPointType>::is_iec559)), FloatingPointType>::type;
576 template<typename FloatingPointType> WIDE_INTEGER_CONSTEXPR auto isfinite(FloatingPointType x) -> typename std::enable_if<((std::is_floating_point<FloatingPointType>::value) && (std::numeric_limits<FloatingPointType>::is_iec559)), bool>::type;
577 template<typename FloatingPointType> WIDE_INTEGER_CONSTEXPR auto isfinite(FloatingPointType x) -> typename std::enable_if<((std::is_floating_point<FloatingPointType>::value) && (!std::numeric_limits<FloatingPointType>::is_iec559)), bool>::type;
578
579 } // namespace my_own
580#endif
581
582 } // namespace detail
583
584 using detail::size_t;
585 using detail::ptrdiff_t;
586 using detail::unsigned_fast_type;
587 using detail::signed_fast_type;
588
589 // Forward declaration of the uintwide_t template class.
590 template<const size_t Width2,
591 typename LimbType = std::uint32_t,
592 typename AllocatorType = void,
593 const bool IsSigned = false>
594 class uintwide_t;
595
596 // Forward declarations of non-member binary add, sub, mul, div, mod of (uintwide_t op uintwide_t).
597 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
598 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator-(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
599 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator*(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
600 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
601 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator%(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
602
603 // Forward declarations of non-member binary logic operations of (uintwide_t op uintwide_t).
604 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator| (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
605 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator^ (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
606 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator& (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
607
608 // Forward declarations of non-member binary add, sub, mul, div, mod of (uintwide_t op IntegralType).
609 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
610 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator-(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
611 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator*(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
612 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
613
614 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned>
615 constexpr auto operator%(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<((std::is_integral<IntegralType>::value)
616 && (!std::is_unsigned<IntegralType>::value)),
617 uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
618
619 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned>
620 WIDE_INTEGER_CONSTEXPR auto operator%(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<((std::is_integral <IntegralType>::value)
621 && (std::is_unsigned <IntegralType>::value)
622 && (std::numeric_limits<IntegralType>::digits <= std::numeric_limits<LimbType>::digits)),
623 typename uintwide_t<Width2, LimbType, AllocatorType, IsSigned>::limb_type>::type;
624
625 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned>
626 constexpr auto operator%(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<((std::is_integral <IntegralType>::value)
627 && (std::is_unsigned <IntegralType>::value)
628 && (std::numeric_limits<IntegralType>::digits > std::numeric_limits<LimbType>::digits)),
629 uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
630
631 // Forward declarations of non-member binary add, sub, mul, div, mod of (IntegralType op uintwide_t).
632 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
633 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator-(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
634 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator*(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
635 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
636 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator%(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
637
638#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
639 // Forward declarations of non-member binary add, sub, mul, div, mod of (uintwide_t op FloatingPointType).
640 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
641 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator-(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
642 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator*(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
643 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
644 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator%(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
645
646 // Forward declarations of non-member binary add, sub, mul, div, mod of (FloatingPointType op uintwide_t).
647 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
648 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator-(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
649 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator*(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
650 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
651 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator%(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
652#endif
653
654 // Forward declarations of non-member binary logic operations of (uintwide_t op IntegralType).
655 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator|(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
656 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator^(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
657 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator&(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
658
659 // Forward declarations of non-member binary binary logic operations of (IntegralType op uintwide_t).
660 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator|(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
661 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator^(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
662 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator&(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type;
663
664 // Forward declarations of non-member shift functions of (uintwide_t shift IntegralType).
665 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<<(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType n) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type; // NOLINT(readability-avoid-const-params-in-decls)
666 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>>(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType n) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type; // NOLINT(readability-avoid-const-params-in-decls)
667
668 // Forward declarations of non-member comparison functions of (uintwide_t cmp uintwide_t).
669 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool;
670 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool;
671 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool;
672 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool;
673 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool;
674 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool;
675
676 // Forward declarations of non-member comparison functions of (uintwide_t cmp IntegralType).
677 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
678 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
679 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
680 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
681 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
682 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
683
684 // Forward declarations of non-member comparison functions of (IntegralType cmp uintwide_t).
685 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
686 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
687 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
688 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
689 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
690 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type;
691
692#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
693 // Non-member comparison functions of (uintwide_t cmp FloatingPointType).
694 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
695 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
696 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
697 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
698 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
699 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
700
701 // Non-member comparison functions of (FloatingPointType cmp uintwide_t).
702 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
703 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
704 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
705 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
706 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
707 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type;
708#endif
709
710#if !defined(WIDE_INTEGER_DISABLE_IOSTREAM)
711
712 // Forward declarations of I/O streaming functions.
713 template<typename char_type,
714 typename traits_type,
715 const size_t Width2,
716 typename LimbType,
717 typename AllocatorType,
718 const bool IsSigned>
719 auto operator<<(std::basic_ostream<char_type, traits_type>& out,
720 const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x)->std::basic_ostream<char_type, traits_type> &;
721
722 template<typename char_type,
723 typename traits_type,
724 const size_t Width2,
725 typename LimbType,
726 typename AllocatorType,
727 const bool IsSigned>
728 auto operator>>(std::basic_istream<char_type, traits_type>& in,
729 uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x)->std::basic_istream<char_type, traits_type> &;
730
731#endif
732
733 // Forward declarations of various number-theoretical tools.
734 template<const size_t Width2,
735 typename LimbType,
736 typename AllocatorType,
737 const bool IsSigned>
738 WIDE_INTEGER_CONSTEXPR void swap(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x,
739 uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& y);
740
741 template<const size_t Width2,
742 typename LimbType,
743 typename AllocatorType,
744 const bool IsSigned>
745 WIDE_INTEGER_CONSTEXPR auto lsb(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x)->unsigned_fast_type;
746
747 template<const size_t Width2,
748 typename LimbType,
749 typename AllocatorType,
750 const bool IsSigned>
751 WIDE_INTEGER_CONSTEXPR auto msb(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x)->unsigned_fast_type;
752
753 template<const size_t Width2,
754 typename LimbType,
755 typename AllocatorType,
756 const bool IsSigned>
757 constexpr auto abs(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
758
759 template<const size_t Width2,
760 typename LimbType,
761 typename AllocatorType,
762 const bool IsSigned>
763 WIDE_INTEGER_CONSTEXPR auto sqrt(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& m)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
764
765 template<const size_t Width2,
766 typename LimbType,
767 typename AllocatorType,
768 const bool IsSigned>
769 WIDE_INTEGER_CONSTEXPR auto cbrt(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& m)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
770
771 template<const size_t Width2,
772 typename LimbType,
773 typename AllocatorType,
774 const bool IsSigned>
775 WIDE_INTEGER_CONSTEXPR auto rootk(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& m, const std::uint_fast8_t k)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>; // NOLINT(readability-avoid-const-params-in-decls)
776
777 template<typename OtherUnsignedIntegralTypeP,
778 const size_t Width2,
779 typename LimbType,
780 typename AllocatorType,
781 const bool IsSigned>
782 WIDE_INTEGER_CONSTEXPR auto pow(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& b, const OtherUnsignedIntegralTypeP& p)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
783
784 template<typename OtherUnsignedIntegralTypeP,
785 typename OtherUnsignedIntegralTypeM,
786 const size_t Width2,
787 typename LimbType,
788 typename AllocatorType,
789 const bool IsSigned>
790 WIDE_INTEGER_CONSTEXPR auto powm(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& b,
791 const OtherUnsignedIntegralTypeP& p,
792 const OtherUnsignedIntegralTypeM& m)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
793
794 template<const size_t Width2,
795 typename LimbType,
796 typename AllocatorType,
797 const bool IsSigned>
798 WIDE_INTEGER_CONSTEXPR auto gcd(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& a,
799 const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& b)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
800
801 template<typename UnsignedShortType>
802 WIDE_INTEGER_CONSTEXPR auto gcd(const UnsignedShortType& u, const UnsignedShortType& v) -> typename std::enable_if<((std::is_integral<UnsignedShortType>::value)
803 && (std::is_unsigned<UnsignedShortType>::value)), UnsignedShortType>::type;
804
805 template<const size_t Width2,
806 typename LimbType,
807 typename AllocatorType,
808 const bool IsSigned>
809 WIDE_INTEGER_CONSTEXPR auto lcm(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& a,
810 const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& b)->uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
811
812 template<typename UnsignedShortType>
813 WIDE_INTEGER_CONSTEXPR auto lcm(const UnsignedShortType& a, const UnsignedShortType& b) -> typename std::enable_if<((std::is_integral<UnsignedShortType>::value)
814 && (std::is_unsigned<UnsignedShortType>::value)), UnsignedShortType>::type;
815
816 template<const size_t Width2,
817 typename LimbType = std::uint32_t,
818 typename AllocatorType = void,
819 const bool IsSigned = false>
820 class default_random_engine;
821
822 template<const size_t Width2,
823 typename LimbType = std::uint32_t,
824 typename AllocatorType = void,
825 const bool IsSigned = false>
826 class uniform_int_distribution;
827
828 template<const size_t Width2,
829 typename LimbType,
830 typename AllocatorType,
831 const bool IsSigned>
832 constexpr auto operator==(const uniform_int_distribution<Width2, LimbType, AllocatorType, IsSigned>& lhs,
833 const uniform_int_distribution<Width2, LimbType, AllocatorType, IsSigned>& rhs) -> bool;
834
835 template<const size_t Width2,
836 typename LimbType,
837 typename AllocatorType,
838 const bool IsSigned>
839 constexpr auto operator!=(const uniform_int_distribution<Width2, LimbType, AllocatorType, IsSigned>& lhs,
840 const uniform_int_distribution<Width2, LimbType, AllocatorType, IsSigned>& rhs) -> bool;
841
842 template<typename DistributionType,
843 typename GeneratorType,
844 const size_t Width2,
845 typename LimbType,
846 typename AllocatorType,
847 const bool IsSigned>
848 auto miller_rabin(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& n,
849 const unsigned_fast_type number_of_trials, // NOLINT(readability-avoid-const-params-in-decls)
850 DistributionType& distribution,
851 GeneratorType& generator) -> bool;
852
853#if(__cplusplus >= 201703L)
854 } // namespace math::wide_integer
855#else
856} // namespace wide_integer
857} // namespace math
858#endif
859
860WIDE_INTEGER_NAMESPACE_END
861
862namespace std
863{
864 // Forward declaration of specialization of std::numeric_limits<uintwide_t>.
865#if defined(WIDE_INTEGER_NAMESPACE)
866 template<const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t Width2,
867 typename LimbType,
868 typename AllocatorType,
869 const bool IsSigned>
870 WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits<WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>;
871#else
872 template<const ::math::wide_integer::size_t Width2,
873 typename LimbType,
874 typename AllocatorType,
875 const bool IsSigned>
876 WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits<::math::wide_integer::uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>;
877#endif
878} // namespace std
879
880WIDE_INTEGER_NAMESPACE_BEGIN
881
882#if(__cplusplus >= 201703L)
883namespace math::wide_integer::detail {
884#else
885namespace math {
886 namespace wide_integer {
887 namespace detail { // NOLINT(modernize-concat-nested-namespaces)
888#endif
889
890 template<typename MyType,
891 const size_t MySize,
892 typename MyAlloc>
893 class fixed_dynamic_array final : public detail::dynamic_array<MyType, MyAlloc, size_t, ptrdiff_t>
894 {
895 private:
897
898 public:
899 static constexpr auto static_size() -> typename base_class_type::size_type { return MySize; }
900
901 explicit WIDE_INTEGER_CONSTEXPR fixed_dynamic_array(const typename base_class_type::size_type s = MySize,
902 const typename base_class_type::value_type& v = typename base_class_type::value_type(),
903 const typename base_class_type::allocator_type& a = typename base_class_type::allocator_type())
904 : base_class_type(MySize, typename base_class_type::value_type(), a)
905 {
906 std::fill(base_class_type::begin(),
907 base_class_type::begin() + (std::min)(MySize, static_cast<typename base_class_type::size_type>(s)),
908 v);
909 }
910
911 constexpr fixed_dynamic_array(const fixed_dynamic_array& other_array)
912 : base_class_type(static_cast<const base_class_type&>(other_array)) { }
913
914 WIDE_INTEGER_CONSTEXPR fixed_dynamic_array(std::initializer_list<typename base_class_type::value_type> lst)
915 : base_class_type(MySize)
916 {
917 std::copy(lst.begin(),
918 lst.begin() + (std::min)(static_cast<typename base_class_type::size_type>(lst.size()), MySize),
919 base_class_type::begin());
920 }
921
922 constexpr fixed_dynamic_array(fixed_dynamic_array&& other_array) noexcept
923 : base_class_type(static_cast<base_class_type&&>(other_array)) { }
924
925 WIDE_INTEGER_CONSTEXPR auto operator=(const fixed_dynamic_array& other_array) -> fixed_dynamic_array & // NOLINT(cert-oop54-cpp)
926 {
927 base_class_type::operator=(static_cast<const base_class_type&>(other_array));
928
929 return *this;
930 }
931
932 WIDE_INTEGER_CONSTEXPR auto operator=(fixed_dynamic_array&& other_array) noexcept -> fixed_dynamic_array &
933 {
934 base_class_type::operator=(static_cast<base_class_type&&>(other_array));
935
936 return *this;
937 }
938
939 WIDE_INTEGER_CONSTEXPR ~fixed_dynamic_array() override = default;
940 };
941
942 template<typename MyType,
943 const size_t MySize>
944 class fixed_static_array final : public std::array<MyType, static_cast<std::size_t>(MySize)>
945 {
946 private:
947 using base_class_type = std::array<MyType, static_cast<std::size_t>(MySize)>;
948
949 public:
950 using size_type = size_t;
951 using value_type = typename base_class_type::value_type;
952
953 static constexpr auto static_size() -> size_type { return MySize; }
954
955 constexpr fixed_static_array() = default;
956
957 explicit WIDE_INTEGER_CONSTEXPR fixed_static_array(const size_type s,
958 const value_type& v = value_type())
959 {
960 if (s < static_size())
961 {
962 std::fill(base_class_type::begin(), base_class_type::begin() + s, v);
963 std::fill(base_class_type::begin() + s, base_class_type::end(), value_type());
964 }
965 else
966 {
967 base_class_type::fill(v);
968 }
969 }
970
971 WIDE_INTEGER_CONSTEXPR fixed_static_array(const fixed_static_array&) = default;
972 WIDE_INTEGER_CONSTEXPR fixed_static_array(fixed_static_array&&) noexcept = default;
973
974 WIDE_INTEGER_CONSTEXPR fixed_static_array(std::initializer_list<typename base_class_type::value_type> lst)
975 {
976 const auto size_to_copy =
977 (std::min)(static_cast<size_type>(lst.size()),
978 static_cast<size_type>(MySize));
979
980 if (size_to_copy < static_cast<size_type>(base_class_type::size()))
981 {
982 std::copy(lst.begin(),
983 lst.begin() + size_to_copy,
984 base_class_type::begin());
985
986 std::fill(base_class_type::begin() + size_to_copy,
987 base_class_type::end(),
988 static_cast<typename base_class_type::value_type>(0U));
989 }
990 else
991 {
992 std::copy(lst.begin(),
993 lst.begin() + size_to_copy,
994 base_class_type::begin());
995 }
996 }
997
998 WIDE_INTEGER_CONSTEXPR ~fixed_static_array() = default;
999
1000 WIDE_INTEGER_CONSTEXPR auto operator=(const fixed_static_array& other_array)->fixed_static_array & = default;
1001 WIDE_INTEGER_CONSTEXPR auto operator=(fixed_static_array&& other_array) noexcept->fixed_static_array & = default;
1002
1003 WIDE_INTEGER_CONSTEXPR auto operator[](const size_type i) -> typename base_class_type::reference { return base_class_type::operator[](static_cast<typename base_class_type::size_type>(i)); }
1004 WIDE_INTEGER_CONSTEXPR auto operator[](const size_type i) const -> typename base_class_type::const_reference { return base_class_type::operator[](static_cast<typename base_class_type::size_type>(i)); }
1005 };
1006
1007 template<const size_t Width2> struct verify_power_of_two_times_granularity_one_sixty_fourth // NOLINT(altera-struct-pack-align)
1008 {
1009 // List of numbers used to identify the form 2^n times 1...63.
1010 static constexpr bool conditional_value =
1011 (verify_power_of_two<static_cast<size_t>(Width2 / 1U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 3U)>::conditional_value
1012 || verify_power_of_two<static_cast<size_t>(Width2 / 5U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 7U)>::conditional_value
1013 || verify_power_of_two<static_cast<size_t>(Width2 / 9U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 11U)>::conditional_value
1014 || verify_power_of_two<static_cast<size_t>(Width2 / 13U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 15U)>::conditional_value
1015 || verify_power_of_two<static_cast<size_t>(Width2 / 17U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 19U)>::conditional_value
1016 || verify_power_of_two<static_cast<size_t>(Width2 / 21U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 23U)>::conditional_value
1017 || verify_power_of_two<static_cast<size_t>(Width2 / 25U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 27U)>::conditional_value
1018 || verify_power_of_two<static_cast<size_t>(Width2 / 29U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 31U)>::conditional_value
1019 || verify_power_of_two<static_cast<size_t>(Width2 / 33U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 35U)>::conditional_value
1020 || verify_power_of_two<static_cast<size_t>(Width2 / 37U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 39U)>::conditional_value
1021 || verify_power_of_two<static_cast<size_t>(Width2 / 41U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 43U)>::conditional_value
1022 || verify_power_of_two<static_cast<size_t>(Width2 / 45U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 47U)>::conditional_value
1023 || verify_power_of_two<static_cast<size_t>(Width2 / 49U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 51U)>::conditional_value
1024 || verify_power_of_two<static_cast<size_t>(Width2 / 53U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 55U)>::conditional_value
1025 || verify_power_of_two<static_cast<size_t>(Width2 / 57U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 59U)>::conditional_value
1026 || verify_power_of_two<static_cast<size_t>(Width2 / 61U)>::conditional_value || verify_power_of_two<static_cast<size_t>(Width2 / 63U)>::conditional_value);
1027 };
1028
1029 template<typename UnsignedIntegralType>
1030 inline WIDE_INTEGER_CONSTEXPR auto lsb_helper(const UnsignedIntegralType& u)->unsigned_fast_type;
1031
1032 template<typename UnsignedIntegralType>
1033 inline WIDE_INTEGER_CONSTEXPR auto msb_helper(const UnsignedIntegralType& u)->unsigned_fast_type;
1034
1035 template<>
1036 inline WIDE_INTEGER_CONSTEXPR auto msb_helper<std::uint32_t>(const std::uint32_t& u)->unsigned_fast_type;
1037
1038 template<>
1039 inline WIDE_INTEGER_CONSTEXPR auto msb_helper<std::uint16_t>(const std::uint16_t& u)->unsigned_fast_type;
1040
1041 template<>
1042 inline WIDE_INTEGER_CONSTEXPR auto msb_helper<std::uint8_t>(const std::uint8_t& u)->unsigned_fast_type;
1043
1044 // Use a local implementation of string copy.
1045 inline WIDE_INTEGER_CONSTEXPR auto strcpy_unsafe(char* dst, const char* src) -> char*
1046 {
1047 while ((*dst++ = *src++) != static_cast<char>('\0')) { ; } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1048
1049 return dst;
1050 }
1051
1052 // Use a local implementation of string length.
1053 inline WIDE_INTEGER_CONSTEXPR auto strlen_unsafe(const char* p_str) -> unsigned_fast_type
1054 {
1055 const char* p_str_copy{};
1056
1057 for (p_str_copy = p_str; (*p_str_copy != static_cast<char>('\0')); ++p_str_copy) { ; } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,altera-id-dependent-backward-branch)
1058
1059 return static_cast<unsigned_fast_type>(p_str_copy - p_str);
1060 }
1061
1062 template<typename UnsignedShortType,
1063 typename UnsignedLargeType = typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<UnsignedShortType>::digits * 2)>::exact_unsigned_type>
1064 constexpr auto make_lo(const UnsignedLargeType & u) -> UnsignedShortType
1065 {
1066 // From an unsigned integral input parameter of type UnsignedLargeType,
1067 // extract the low part of it. The type of the extracted
1068 // low part is UnsignedShortType, which has half the width of UnsignedLargeType.
1069
1070 using local_ushort_type = UnsignedShortType;
1071 using local_ularge_type = UnsignedLargeType;
1072
1073 // Compile-time checks.
1074#if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64)
1075 static_assert(((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type)),
1076 "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType");
1077#else
1078 static_assert(((std::numeric_limits<local_ushort_type>::is_integer)
1079 && (std::numeric_limits<local_ularge_type>::is_integer)
1080 && (!std::numeric_limits<local_ushort_type>::is_signed)
1081 && (!std::numeric_limits<local_ularge_type>::is_signed)
1082 && ((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type))),
1083 "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType");
1084#endif
1085
1086 return static_cast<local_ushort_type>(u);
1087 }
1088
1089 template<typename UnsignedShortType,
1090 typename UnsignedLargeType = typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<UnsignedShortType>::digits * 2)>::exact_unsigned_type>
1091 constexpr auto make_hi(const UnsignedLargeType & u) -> UnsignedShortType
1092 {
1093 // From an unsigned integral input parameter of type UnsignedLargeType,
1094 // extract the high part of it. The type of the extracted
1095 // high part is UnsignedShortType, which has half the width of UnsignedLargeType.
1096
1097 using local_ushort_type = UnsignedShortType;
1098 using local_ularge_type = UnsignedLargeType;
1099
1100 // Compile-time checks.
1101#if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64)
1102 static_assert(((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type)),
1103 "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType");
1104#else
1105 static_assert(((std::numeric_limits<local_ushort_type>::is_integer)
1106 && (std::numeric_limits<local_ularge_type>::is_integer)
1107 && (!std::numeric_limits<local_ushort_type>::is_signed)
1108 && (!std::numeric_limits<local_ularge_type>::is_signed)
1109 && ((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type))),
1110 "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType");
1111#endif
1112
1113 return static_cast<local_ushort_type>(u >> static_cast<local_ushort_type>(std::numeric_limits<local_ushort_type>::digits));
1114 }
1115
1116 template<typename UnsignedShortType,
1117 typename UnsignedLargeType = typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<UnsignedShortType>::digits * 2)>::exact_unsigned_type>
1118 constexpr auto make_large(const UnsignedShortType & lo, const UnsignedShortType & hi) -> UnsignedLargeType
1119 {
1120 // Create a composite unsigned integral value having type UnsignedLargeType.
1121 // Two constituents are used having type UnsignedShortType, whereby the
1122 // width of UnsignedShortType is half the width of UnsignedLargeType.
1123
1124 using local_ushort_type = UnsignedShortType;
1125 using local_ularge_type = UnsignedLargeType;
1126
1127 // Compile-time checks.
1128#if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64)
1129 static_assert(((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type)),
1130 "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType");
1131#else
1132 static_assert(((std::numeric_limits<local_ushort_type>::is_integer)
1133 && (std::numeric_limits<local_ularge_type>::is_integer)
1134 && (!std::numeric_limits<local_ushort_type>::is_signed)
1135 && (!std::numeric_limits<local_ularge_type>::is_signed)
1136 && ((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type))),
1137 "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType");
1138#endif
1139
1140 return static_cast<local_ularge_type>(static_cast<local_ularge_type>(static_cast<local_ularge_type>(hi) << static_cast<unsigned>(std::numeric_limits<UnsignedShortType>::digits)) | lo);
1141 }
1142
1143 template<typename UnsignedIntegralType>
1144 constexpr auto negate(UnsignedIntegralType u) -> typename std::enable_if< (std::is_integral<UnsignedIntegralType>::value)
1145 && (std::is_unsigned<UnsignedIntegralType>::value), UnsignedIntegralType>::type
1146 {
1147 return static_cast<UnsignedIntegralType>((static_cast<UnsignedIntegralType>(~u)) + 1U);
1148 }
1149
1150 template<typename SignedIntegralType>
1151 constexpr auto negate(SignedIntegralType n) -> typename std::enable_if< (std::is_integral<SignedIntegralType>::value)
1152 && (std::is_signed <SignedIntegralType>::value), SignedIntegralType>::type
1153 {
1154 using local_unsigned_type =
1155 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<SignedIntegralType>::digits + 1)>::exact_unsigned_type;
1156
1157 return static_cast<SignedIntegralType>(negate(static_cast<local_unsigned_type>(n)));
1158 }
1159
1160#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
1161 template<typename FloatingPointType>
1163 {
1164 public:
1165 // Emphasize: This template class can be used with native floating-point
1166 // types like float, double and long double. Note: For long double,
1167 // you need to verify that the mantissa fits in unsigned long long.
1168 explicit WIDE_INTEGER_CONSTEXPR native_float_parts(const FloatingPointType f)
1169 : my_mantissa_part(0ULL),
1170 my_exponent_part(0)
1171 {
1172 using native_float_type = FloatingPointType;
1173
1174 static_assert(std::numeric_limits<native_float_type>::digits <= std::numeric_limits<unsigned long long>::digits, // NOLINT(google-runtime-int)
1175 "Error: The width of the mantissa does not fit in unsigned long long");
1176
1177 const native_float_type ff = ((f < static_cast<native_float_type>(0)) ? -f : f);
1178
1179 if (ff < (std::numeric_limits<native_float_type>::min)())
1180 {
1181 return;
1182 }
1183
1184 using my_own::frexp;
1185
1186 // Get the fraction and base-2 exponent.
1187 auto man = static_cast<native_float_type>(frexp(f, &my_exponent_part));
1188
1189 unsigned n2 = 0U;
1190
1191 for (auto i = static_cast<std::uint_fast16_t>(0U); i < static_cast<std::uint_fast16_t>(std::numeric_limits<native_float_type>::digits); ++i)
1192 {
1193 // Extract the mantissa of the floating-point type in base-2
1194 // (one bit at a time) and store it in an unsigned long long.
1195 man *= 2;
1196
1197 n2 = static_cast<unsigned>(man);
1198 man -= static_cast<native_float_type>(n2);
1199
1200 if (n2 != static_cast<unsigned>(0U))
1201 {
1202 my_mantissa_part |= 1U;
1203 }
1204
1205 if (i < static_cast<unsigned>(std::numeric_limits<native_float_type>::digits - 1))
1206 {
1207 my_mantissa_part <<= 1U;
1208 }
1209 }
1210
1211 // Ensure that the value is normalized and adjust the exponent.
1212 my_mantissa_part |= static_cast<unsigned long long>(1ULL << static_cast<unsigned>(std::numeric_limits<native_float_type>::digits - 1)); // NOLINT(google-runtime-int)
1213 my_exponent_part -= 1;
1214 }
1215
1216 constexpr native_float_parts(const native_float_parts& other) : my_mantissa_part(other.my_mantissa_part),
1217 my_exponent_part(other.my_exponent_part) { }
1218
1219 constexpr native_float_parts(native_float_parts&& other) noexcept : my_mantissa_part(other.my_mantissa_part),
1220 my_exponent_part(other.my_exponent_part) { }
1221
1222 WIDE_INTEGER_CONSTEXPR ~native_float_parts() = default;
1223
1224 WIDE_INTEGER_CONSTEXPR auto operator=(const native_float_parts& other) noexcept -> native_float_parts &
1225 {
1226 if (this != &other)
1227 {
1228 my_mantissa_part = other.my_mantissa_part;
1229 my_exponent_part = other.my_exponent_part;
1230 }
1231
1232 return *this;
1233 }
1234
1235 WIDE_INTEGER_CONSTEXPR auto operator=(native_float_parts&& other) noexcept -> native_float_parts &
1236 {
1237 my_mantissa_part = other.my_mantissa_part;
1238 my_exponent_part = other.my_exponent_part;
1239
1240 return *this;
1241 }
1242
1243 WIDE_INTEGER_NODISCARD WIDE_INTEGER_CONSTEXPR auto get_mantissa() const -> unsigned long long { return my_mantissa_part; } // NOLINT(google-runtime-int)
1244 WIDE_INTEGER_NODISCARD WIDE_INTEGER_CONSTEXPR auto get_exponent() const -> int { return my_exponent_part; }
1245
1246 WIDE_INTEGER_CONSTEXPR native_float_parts() = delete;
1247
1248 private:
1249 unsigned long long my_mantissa_part; // NOLINT(readability-identifier-naming,google-runtime-int)
1250 int my_exponent_part; // NOLINT(readability-identifier-naming)
1251 };
1252#endif
1253
1254#if(__cplusplus >= 201703L)
1255 } // namespace math::wide_integer::detail
1256#else
1257 } // namespace detail
1258} // namespace wide_integer
1259} // namespace math
1260#endif
1261
1262#if(__cplusplus >= 201703L)
1263namespace math::wide_integer {
1264#else
1265namespace math {
1266 namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces)
1267#endif
1268
1269 template<const size_t Width2,
1270 typename LimbType,
1271 typename AllocatorType,
1272 const bool IsSigned>
1273 class uintwide_t
1274 {
1275 public:
1276 template<const size_t OtherWidth2,
1277 typename OtherLimbType,
1278 typename OtherAllocatorType,
1279 const bool OtherIsSigned>
1280 friend class uintwide_t;
1281
1282 // Class-local type definitions.
1283 using limb_type = LimbType;
1284
1285 using double_limb_type =
1286 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<limb_type>::digits * 2)>::exact_unsigned_type;
1287
1288 // Legacy ularge and ushort types. These are no longer used
1289 // in the class, but provided for legacy compatibility.
1290 using ushort_type = limb_type;
1291 using ularge_type = double_limb_type;
1292
1293 // More compile-time checks.
1294#if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64)
1295 static_assert(((sizeof(limb_type) * 2U) == sizeof(double_limb_type)),
1296 "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType");
1297#else
1298 static_assert(((std::numeric_limits<limb_type>::is_integer)
1299 && (std::numeric_limits<double_limb_type>::is_integer)
1300 && (!std::numeric_limits<limb_type>::is_signed)
1301 && (!std::numeric_limits<double_limb_type>::is_signed)
1302 && ((sizeof(limb_type) * 2U) == sizeof(double_limb_type))),
1303 "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType");
1304#endif
1305
1306 // Helper constants for the digit characteristics.
1307 static constexpr size_t my_width2 = Width2;
1308
1309 // The number of limbs.
1310 static constexpr size_t number_of_limbs =
1311 static_cast<size_t>(my_width2 / static_cast<size_t>(std::numeric_limits<limb_type>::digits));
1312
1313 static constexpr size_t number_of_limbs_karatsuba_threshold = static_cast<size_t>(128U + 1U);
1314
1315 // Verify that the Width2 template parameter (mirrored with my_width2):
1316 // * Is equal to 2^n times 1...63.
1317 // * And that there are at least 16, 24 or 32 binary digits, or more.
1318 // * And that the number of binary digits is an exact multiple of the number of limbs.
1319 static_assert((detail::verify_power_of_two_times_granularity_one_sixty_fourth<my_width2>::conditional_value)
1320 && (my_width2 >= 16U) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
1321 && (my_width2 == (number_of_limbs * static_cast<size_t>(std::numeric_limits<limb_type>::digits))),
1322 "Error: Width2 must be 2^n times 1...63 (with n >= 3), while being 16, 24, 32 or larger, and exactly divisible by limb count");
1323
1324 // The type of the internal data representation.
1325 using representation_type =
1326 typename std::conditional
1327 <std::is_same<AllocatorType, void>::value,
1328 detail::fixed_static_array <limb_type,
1329 number_of_limbs>,
1330 detail::fixed_dynamic_array<limb_type,
1331 number_of_limbs,
1332 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
1333 std::allocator<void>,
1334 AllocatorType>::type>::template rebind_alloc<limb_type>>
1335 >::type;
1336
1337 // The iterator types of the internal data representation.
1338 using iterator = typename representation_type::iterator;
1339 using const_iterator = typename representation_type::const_iterator;
1340 using reverse_iterator = typename representation_type::reverse_iterator;
1341 using const_reverse_iterator = typename representation_type::const_reverse_iterator;
1342
1343 // Define a class-local type that has double the width of *this.
1344 using double_width_type = uintwide_t<static_cast<size_t>(Width2 * 2U), limb_type, AllocatorType, IsSigned>;
1345
1346 // Default constructor.
1347 constexpr uintwide_t() = default;
1348
1349 // Constructors from built-in unsigned integral types that
1350 // are less wide than limb_type or exactly as wide as limb_type.
1351 template<typename UnsignedIntegralType>
1352 constexpr uintwide_t(const UnsignedIntegralType v, // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
1353 typename std::enable_if<((std::is_integral <UnsignedIntegralType>::value)
1354 && (std::is_unsigned <UnsignedIntegralType>::value)
1355 && (std::numeric_limits<UnsignedIntegralType>::digits <= std::numeric_limits<limb_type>::digits))>::type* = nullptr) // NOLINT(hicpp-named-parameter,readability-named-parameter)
1356 : values(1U, v) { }
1357
1358 // Constructors from built-in unsigned integral types that
1359 // are wider than limb_type, and do not have exactly the
1360 // same width as limb_type.
1361 template<typename UnsignedIntegralType>
1362 WIDE_INTEGER_CONSTEXPR uintwide_t(const UnsignedIntegralType v, // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
1363 typename std::enable_if<((std::is_integral <UnsignedIntegralType>::value)
1364 && (std::is_unsigned <UnsignedIntegralType>::value)
1365 && (std::numeric_limits<UnsignedIntegralType>::digits > std::numeric_limits<limb_type>::digits))>::type* p_nullparam = nullptr)
1366 {
1367 static_cast<void>(p_nullparam == nullptr);
1368
1369 auto right_shift_amount_v = static_cast<unsigned_fast_type>(0U);
1370 auto index_u = static_cast<std::uint_fast8_t> (0U);
1371
1372 for (; ((index_u < values.size()) // NOLINT(altera-id-dependent-backward-branch)
1373 && (right_shift_amount_v < static_cast<unsigned_fast_type>(std::numeric_limits<UnsignedIntegralType>::digits)));
1374 ++index_u)
1375 {
1376 *(values.begin() + static_cast<size_t>(index_u)) = static_cast<limb_type>(v >> static_cast<unsigned>(right_shift_amount_v));
1377
1378 right_shift_amount_v += static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits);
1379 }
1380
1381 std::fill(values.begin() + index_u, values.end(), static_cast<limb_type>(0U));
1382 }
1383
1384 // Constructors from built-in signed integral types.
1385 template<typename SignedIntegralType>
1386 WIDE_INTEGER_CONSTEXPR uintwide_t(const SignedIntegralType v, // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
1387 typename std::enable_if<((std::is_integral<SignedIntegralType>::value)
1388 && (std::is_signed <SignedIntegralType>::value))>::type* p_nullparam = nullptr)
1389 {
1390 static_cast<void>(p_nullparam == nullptr);
1391
1392 using local_signed_integral_type = SignedIntegralType;
1393 using local_unsigned_integral_type =
1394 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_signed_integral_type>::digits + 1)>::exact_unsigned_type;
1395
1396 const bool v_is_neg = (v < static_cast<local_signed_integral_type>(0));
1397
1398 const local_unsigned_integral_type u =
1399 ((!v_is_neg) ? static_cast<local_unsigned_integral_type>(v)
1400 : static_cast<local_unsigned_integral_type>(detail::negate(v)));
1401
1402 operator=(uintwide_t(u));
1403
1404 if (v_is_neg) { negate(); }
1405 }
1406
1407#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
1408 template<typename FloatingPointType,
1409 typename std::enable_if<(std::is_floating_point<FloatingPointType>::value)>::type const* = nullptr>
1410 WIDE_INTEGER_CONSTEXPR uintwide_t(const FloatingPointType f) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
1411 {
1412 using local_builtin_float_type = FloatingPointType;
1413
1414 using detail::my_own::isfinite;
1415
1416 if (!isfinite(f))
1417 {
1418 operator=(0U);
1419 }
1420 else
1421 {
1422 const bool f_is_neg = (f < static_cast<local_builtin_float_type>(0.0F));
1423
1424 const local_builtin_float_type a = ((!f_is_neg) ? f : -f);
1425
1426 const bool a_is_zero = (a < static_cast<local_builtin_float_type>(1.0F));
1427
1428 if (!a_is_zero)
1429 {
1430 const detail::native_float_parts<local_builtin_float_type> ld_parts(a);
1431
1432 // Create a decwide_t from the fractional part of the
1433 // mantissa expressed as an unsigned long long.
1434 *this = uintwide_t(ld_parts.get_mantissa());
1435
1436 // Scale the unsigned long long representation to the fractional
1437 // part of the long double and multiply with the base-2 exponent.
1438 const int p2 = ld_parts.get_exponent() - (std::numeric_limits<FloatingPointType>::digits - 1);
1439
1440 if (p2 < 0) { *this >>= static_cast<unsigned>(-p2); }
1441 else if (p2 == 0) { ; }
1442 else { *this <<= static_cast<unsigned>(p2); }
1443
1444 if (f_is_neg)
1445 {
1446 negate();
1447 }
1448 }
1449 else
1450 {
1451 operator=(0U);
1452 }
1453 }
1454 }
1455#endif
1456
1457 // Copy constructor.
1458#if !defined(WIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS)
1459 constexpr uintwide_t(const uintwide_t& other) = default;
1460#else
1461 constexpr uintwide_t(const uintwide_t& other) : values(other.values) { }
1462#endif
1463
1464 // Copy-like constructor from the other signed-ness type.
1465 template<const bool OtherIsSigned,
1466 typename std::enable_if<(OtherIsSigned != IsSigned)>::type const* = nullptr>
1467 constexpr uintwide_t(const uintwide_t<Width2, LimbType, AllocatorType, OtherIsSigned> & other) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
1468 : values(other.values) { }
1469
1470 // Copy-like constructor from the another type having width that is wider
1471 // (but has the same limb type) and possibly a different signed-ness.
1472 template<const size_t OtherWidth2,
1473 const bool OtherIsSigned,
1474 typename std::enable_if<(Width2 < OtherWidth2)>::type const* = nullptr>
1475 explicit WIDE_INTEGER_CONSTEXPR uintwide_t(const uintwide_t<OtherWidth2, LimbType, AllocatorType, OtherIsSigned> & v)
1476 {
1477 using other_wide_integer_type = uintwide_t<OtherWidth2, LimbType, AllocatorType, OtherIsSigned>;
1478
1479 const bool v_is_neg = (other_wide_integer_type::is_neg(v));
1480
1481 constexpr auto sz = static_cast<size_t>(number_of_limbs);
1482
1483 if (!v_is_neg)
1484 {
1485 std::copy(v.crepresentation().cbegin(),
1486 v.crepresentation().cbegin() + sz,
1487 values.begin());
1488 }
1489 else
1490 {
1491 const other_wide_integer_type uv(-v);
1492
1493 std::copy(uv.crepresentation().cbegin(),
1494 uv.crepresentation().cbegin() + sz,
1495 values.begin());
1496
1497 negate();
1498 }
1499 }
1500
1501 // Copy-like constructor from the another type having width that is less wide
1502 // (but has the same limb type) and possibly a different signed-ness.
1503 template<const size_t OtherWidth2,
1504 const bool OtherIsSigned,
1505 typename std::enable_if<(Width2 > OtherWidth2)>::type const* = nullptr>
1506 explicit WIDE_INTEGER_CONSTEXPR uintwide_t(const uintwide_t<OtherWidth2, LimbType, AllocatorType, OtherIsSigned> & v)
1507 {
1508 using other_wide_integer_type = uintwide_t<OtherWidth2, LimbType, AllocatorType, OtherIsSigned>;
1509
1510 const bool v_is_neg = (other_wide_integer_type::is_neg(v));
1511
1512 constexpr auto sz = static_cast<size_t>(other_wide_integer_type::number_of_limbs);
1513
1514 if (!v_is_neg)
1515 {
1516 std::copy(v.crepresentation().cbegin(),
1517 v.crepresentation().cbegin() + sz,
1518 values.begin());
1519
1520 std::fill(values.begin() + sz, values.end(), static_cast<limb_type>(0U));
1521 }
1522 else
1523 {
1524 const other_wide_integer_type uv(-v);
1525
1526 std::copy(uv.crepresentation().cbegin(),
1527 uv.crepresentation().cbegin() + sz,
1528 values.begin());
1529
1530 std::fill(values.begin() + sz, values.end(), static_cast<limb_type>(0U));
1531
1532 negate();
1533 }
1534 }
1535
1536 // Constructor from a constant character string.
1537 WIDE_INTEGER_CONSTEXPR uintwide_t(const char* str_input) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
1538 {
1539 if (!rd_string(str_input))
1540 {
1541 std::fill(values.begin(), values.end(), (std::numeric_limits<limb_type>::max)());
1542 }
1543 }
1544
1545 // Move constructor.
1546 constexpr uintwide_t(uintwide_t&& other) noexcept = default;
1547
1548 // Move-like constructor from the other signed-ness type.
1549 // This constructor is non-explicit because it is a trivial conversion.
1550 template<const bool OtherIsSigned,
1551 typename std::enable_if<(IsSigned != OtherIsSigned)>::type const* = nullptr>
1552 constexpr uintwide_t(uintwide_t<Width2, LimbType, AllocatorType, OtherIsSigned> && other) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
1553 : values(static_cast<representation_type&&>(other.values)) { }
1554
1555 // Default destructor.
1556 WIDE_INTEGER_CONSTEXPR ~uintwide_t() = default;
1557
1558 // Assignment operator.
1559 WIDE_INTEGER_CONSTEXPR auto operator=(const uintwide_t& other)->uintwide_t & = default;
1560
1561 // Assignment operator from the other signed-ness type.
1562 template<const bool OtherIsSigned,
1563 typename std::enable_if<(OtherIsSigned != IsSigned)>::type const* = nullptr>
1564 WIDE_INTEGER_CONSTEXPR auto operator=(const uintwide_t<Width2, LimbType, AllocatorType, OtherIsSigned> & other) -> uintwide_t &
1565 {
1566 values = other.values;
1567
1568 return *this;
1569 }
1570
1571 // Trivial move assignment operator.
1572 WIDE_INTEGER_CONSTEXPR auto operator=(uintwide_t&& other) noexcept->uintwide_t & = default;
1573
1574 // Trivial move assignment operator from the other signed-ness type.
1575 template<const bool OtherIsSigned,
1576 typename std::enable_if<(IsSigned != OtherIsSigned)>::type const* = nullptr>
1577 WIDE_INTEGER_CONSTEXPR auto operator=(uintwide_t<Width2, LimbType, AllocatorType, OtherIsSigned> && other) -> uintwide_t &
1578 {
1579 values = static_cast<representation_type&&>(other.values);
1580
1581 return *this;
1582 }
1583
1584#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
1585 explicit constexpr operator long double() const { return extract_builtin_floating_point_type<long double>(); }
1586 explicit constexpr operator double() const { return extract_builtin_floating_point_type<double>(); }
1587 explicit constexpr operator float() const { return extract_builtin_floating_point_type<float>(); }
1588#endif
1589
1590 template<typename IntegralType,
1591 typename = typename std::enable_if<std::is_integral<IntegralType>::value>::type>
1592 explicit constexpr operator IntegralType() const
1593 {
1594 using local_integral_type = IntegralType;
1595
1596 return ((!is_neg(*this))
1597 ? extract_builtin_integral_type<local_integral_type>()
1598 : detail::negate((-*this).template extract_builtin_integral_type<local_integral_type>()));
1599 }
1600
1601 // Cast operator to built-in Boolean type.
1602 explicit constexpr operator bool() const { return (!is_zero()); }
1603
1604 // Cast operator that casts to a uintwide_t having a different width
1605 // (but having the same limb type) and possibly a different signed-ness.
1606 template<const size_t OtherWidth2,
1607 const bool OtherIsSigned,
1608 typename = typename std::enable_if<(Width2 != OtherWidth2), uintwide_t<OtherWidth2, LimbType, AllocatorType, OtherIsSigned>>::type>
1609 WIDE_INTEGER_CONSTEXPR operator uintwide_t<OtherWidth2, LimbType, AllocatorType, OtherIsSigned>() const // NOLINT(hicpp-explicit-conversions,google-explicit-constructor)
1610 {
1611 const bool this_is_neg = (is_neg(*this));
1612
1613 using other_wide_integer_type = uintwide_t<OtherWidth2, LimbType, AllocatorType, OtherIsSigned>;
1614
1615 constexpr auto sz =
1616 static_cast<size_t>
1617 (
1618 (Width2 < OtherWidth2) ? static_cast<size_t>(number_of_limbs)
1619 : static_cast<size_t>(other_wide_integer_type::number_of_limbs)
1620 );
1621
1622 other_wide_integer_type other;
1623
1624 if (!this_is_neg)
1625 {
1626 std::copy(crepresentation().cbegin(),
1627 crepresentation().cbegin() + sz,
1628 other.values.begin());
1629
1630 if (Width2 < OtherWidth2)
1631 {
1632 std::fill(other.values.begin() + sz, other.values.end(), static_cast<limb_type>(0U));
1633 }
1634 }
1635 else
1636 {
1637 other_wide_integer_type uv(*this);
1638
1639 uv.negate();
1640
1641 std::copy(uv.crepresentation().cbegin(),
1642 uv.crepresentation().cbegin() + sz,
1643 other.values.begin());
1644
1645 if (Width2 < OtherWidth2)
1646 {
1647 std::fill(other.values.begin() + sz, other.values.end(), static_cast<limb_type>(0U));
1648 }
1649
1650 other.negate();
1651 }
1652
1653 return other;
1654 }
1655
1656 // Cast operator that casts to a uintwide_t having a type with the same width
1657 // (and having the same limb type) but definitely having a different signed-ness.
1658 template<const bool OtherIsSigned,
1659 typename = typename std::enable_if<(OtherIsSigned != IsSigned), uintwide_t<Width2, LimbType, AllocatorType, OtherIsSigned>>::type>
1660 WIDE_INTEGER_CONSTEXPR operator uintwide_t<Width2, LimbType, AllocatorType, OtherIsSigned>() const // NOLINT(hicpp-explicit-conversions,google-explicit-constructor)
1661 {
1662 using other_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, OtherIsSigned>;
1663
1664 other_wide_integer_type other;
1665
1666 std::copy(crepresentation().cbegin(),
1667 crepresentation().cend(),
1668 other.representation().begin());
1669
1670 return other;
1671 }
1672
1673 // Provide a user interface to the internal data representation.
1674 WIDE_INTEGER_CONSTEXPR auto representation() -> representation_type & { return values; }
1675 WIDE_INTEGER_NODISCARD WIDE_INTEGER_CONSTEXPR auto representation() const -> const representation_type & { return values; }
1676 WIDE_INTEGER_NODISCARD WIDE_INTEGER_CONSTEXPR auto crepresentation() const -> const representation_type & { return values; }
1677
1678 // Unary operators: not, plus and minus.
1679 WIDE_INTEGER_CONSTEXPR auto operator+() const -> const uintwide_t & { return *this; }
1680 WIDE_INTEGER_CONSTEXPR auto operator-() const -> uintwide_t { uintwide_t tmp(*this); tmp.negate(); return tmp; }
1681
1682 WIDE_INTEGER_CONSTEXPR auto operator+=(const uintwide_t& other) -> uintwide_t &
1683 {
1684 if (this == &other)
1685 {
1686 const uintwide_t self(other);
1687
1688 // Unary addition function.
1689 const limb_type carry = eval_add_n(values.data(),
1690 values.data(),
1691 self.values.data(),
1692 static_cast<unsigned_fast_type>(number_of_limbs),
1693 static_cast<limb_type>(0U));
1694
1695 static_cast<void>(carry);
1696 }
1697 else
1698 {
1699 // Unary addition function.
1700 const limb_type carry = eval_add_n(values.data(),
1701 values.data(),
1702 other.values.data(),
1703 static_cast<unsigned_fast_type>(number_of_limbs),
1704 static_cast<limb_type>(0U));
1705
1706 static_cast<void>(carry);
1707 }
1708
1709 return *this;
1710 }
1711
1712 WIDE_INTEGER_CONSTEXPR auto operator-=(const uintwide_t& other) -> uintwide_t &
1713 {
1714 if (this == &other)
1715 {
1716 values.fill(0U);
1717 }
1718 else
1719 {
1720 // Unary subtraction function.
1721 const limb_type has_borrow = eval_subtract_n(values.data(),
1722 values.data(),
1723 other.values.data(),
1724 number_of_limbs,
1725 false);
1726
1727 static_cast<void>(has_borrow);
1728 }
1729
1730 return *this;
1731 }
1732
1733 WIDE_INTEGER_CONSTEXPR auto operator*=(const uintwide_t& other) -> uintwide_t &
1734 {
1735 if (this == &other)
1736 {
1737 const uintwide_t other_as_self_copy(other); // NOLINT(performance-unnecessary-copy-initialization)
1738
1739 eval_mul_unary(*this, other_as_self_copy);
1740 }
1741 else
1742 {
1743 eval_mul_unary(*this, other);
1744 }
1745
1746 return *this;
1747 }
1748
1749 WIDE_INTEGER_CONSTEXPR auto mul_by_limb(const limb_type v) -> uintwide_t &
1750 {
1751 if (v == static_cast<limb_type>(0U))
1752 {
1753 values.fill(0U);
1754 }
1755 else if (v > static_cast<limb_type>(1U))
1756 {
1757 static_cast<void>(eval_multiply_1d(values.data(),
1758 values.data(),
1759 v,
1760 number_of_limbs));
1761 }
1762
1763 return *this;
1764 }
1765
1766 WIDE_INTEGER_CONSTEXPR auto operator/=(const uintwide_t& other) -> uintwide_t &
1767 {
1768 if (this == &other)
1769 {
1770 values.front() = 1U;
1771
1772 std::fill(values.begin() + 1U, values.end(), static_cast<limb_type>(0U));
1773 }
1774 else if (other.is_zero())
1775 {
1776 *this = limits_helper_max(IsSigned);
1777 }
1778 else
1779 {
1780 // Unary division function.
1781
1782 const bool numererator_was_neg = is_neg(*this);
1783 const bool denominator_was_neg = is_neg(other);
1784
1785 if (numererator_was_neg || denominator_was_neg)
1786 {
1787 using local_unsigned_wide_type = uintwide_t<Width2, limb_type, AllocatorType, false>;
1788
1789 local_unsigned_wide_type a(*this);
1790 local_unsigned_wide_type b(other);
1791
1792 if (numererator_was_neg) { a.negate(); }
1793 if (denominator_was_neg) { b.negate(); }
1794
1795 a.eval_divide_knuth(b, nullptr);
1796
1797 if (numererator_was_neg != denominator_was_neg) { a.negate(); }
1798
1799 values = a.values;
1800 }
1801 else
1802 {
1803 eval_divide_knuth(other, nullptr);
1804 }
1805 }
1806
1807 return *this;
1808 }
1809
1810 WIDE_INTEGER_CONSTEXPR auto operator%=(const uintwide_t& other) -> uintwide_t &
1811 {
1812 if (this == &other)
1813 {
1814 std::fill(values.begin(), values.end(), static_cast<limb_type>(0U));
1815 }
1816 else
1817 {
1818 // Unary modulus function.
1819 const bool numererator_was_neg = is_neg(*this);
1820 const bool denominator_was_neg = is_neg(other);
1821
1822 if (numererator_was_neg || denominator_was_neg)
1823 {
1824 using local_unsigned_wide_type = uintwide_t<Width2, limb_type, AllocatorType, false>;
1825
1826 local_unsigned_wide_type a(*this);
1827 local_unsigned_wide_type b(other);
1828
1829 if (numererator_was_neg) { a.negate(); }
1830 if (denominator_was_neg) { b.negate(); }
1831
1832 local_unsigned_wide_type remainder;
1833
1834 a.eval_divide_knuth(b, &remainder);
1835
1836 // The sign of the remainder follows the sign of the denominator.
1837 if (numererator_was_neg) { remainder.negate(); }
1838
1839 values = remainder.values;
1840 }
1841 else
1842 {
1843 uintwide_t remainder;
1844
1845 eval_divide_knuth(other, &remainder);
1846
1847 values = remainder.values;
1848 }
1849 }
1850
1851 return *this;
1852 }
1853
1854 // Operators pre-increment and pre-decrement.
1855 WIDE_INTEGER_CONSTEXPR auto operator++() -> uintwide_t & { preincrement(); return *this; }
1856 WIDE_INTEGER_CONSTEXPR auto operator--() -> uintwide_t & { predecrement(); return *this; }
1857
1858 // Operators post-increment and post-decrement.
1859 WIDE_INTEGER_CONSTEXPR auto operator++(int) -> uintwide_t { const uintwide_t w(*this); preincrement(); return w; }
1860 WIDE_INTEGER_CONSTEXPR auto operator--(int) -> uintwide_t { const uintwide_t w(*this); predecrement(); return w; }
1861
1862 WIDE_INTEGER_CONSTEXPR auto operator~() -> uintwide_t &
1863 {
1864 // Perform bitwise NOT.
1865 bitwise_not();
1866
1867 return *this;
1868 }
1869
1870 WIDE_INTEGER_CONSTEXPR auto operator|=(const uintwide_t& other) -> uintwide_t &
1871 {
1872 if (this != &other)
1873 {
1874 // Perform bitwise OR.
1875 for (auto i = static_cast<unsigned_fast_type>(0U); i < number_of_limbs; ++i)
1876 {
1877 *(values.begin() + static_cast<size_t>(i)) = static_cast<limb_type>(*(values.cbegin() + static_cast<size_t>(i)) | *(other.values.cbegin() + static_cast<size_t>(i)));
1878 }
1879 }
1880
1881 return *this;
1882 }
1883
1884 WIDE_INTEGER_CONSTEXPR auto operator^=(const uintwide_t& other) -> uintwide_t &
1885 {
1886 if (this == &other)
1887 {
1888 values.fill(0U);
1889 }
1890 else
1891 {
1892 // Perform bitwise XOR.
1893 for (auto i = static_cast<unsigned_fast_type>(0U); i < number_of_limbs; ++i)
1894 {
1895 *(values.begin() + static_cast<size_t>(i)) = static_cast<limb_type>(*(values.cbegin() + static_cast<size_t>(i)) ^ *(other.values.cbegin() + static_cast<size_t>(i)));
1896 }
1897 }
1898
1899 return *this;
1900 }
1901
1902 WIDE_INTEGER_CONSTEXPR auto operator&=(const uintwide_t& other) -> uintwide_t &
1903 {
1904 if (this != &other)
1905 {
1906 // Perform bitwise AND.
1907 for (auto i = static_cast<unsigned_fast_type>(0U); i < number_of_limbs; ++i)
1908 {
1909 *(values.begin() + static_cast<size_t>(i)) = static_cast<limb_type>(*(values.cbegin() + static_cast<size_t>(i)) & *(other.values.cbegin() + static_cast<size_t>(i)));
1910 }
1911 }
1912
1913 return *this;
1914 }
1915
1916 template<typename SignedIntegralType>
1917 WIDE_INTEGER_CONSTEXPR auto operator<<=(const SignedIntegralType n) -> typename std::enable_if<((std::is_integral<SignedIntegralType>::value)
1918 && (std::is_signed <SignedIntegralType>::value)), uintwide_t>::type &
1919 {
1920 // Implement left-shift operator for signed integral argument.
1921 if (n < 0)
1922 {
1923 using local_unsigned_type =
1924 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<SignedIntegralType>::digits + 1)>::exact_unsigned_type;
1925
1926 operator>>=(static_cast<local_unsigned_type>(detail::negate(n)));
1927 }
1928 else if (n == 0)
1929 {
1930 ;
1931 }
1932 else if (static_cast<unsigned_fast_type>(n) >= my_width2)
1933 {
1934 std::fill(values.begin(), values.end(), static_cast<limb_type>(0U));
1935 }
1936 else
1937 {
1938 const auto offset = static_cast<unsigned_fast_type>(static_cast<unsigned_fast_type>(n) / static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits));
1939 const auto left_shift_amount = static_cast<std::uint_fast16_t>(static_cast<unsigned_fast_type>(n) % static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits));
1940
1941 shl(offset, left_shift_amount);
1942 }
1943
1944 return *this;
1945 }
1946
1947 template<typename UnsignedIntegralType>
1948 WIDE_INTEGER_CONSTEXPR auto operator<<=(const UnsignedIntegralType n) -> typename std::enable_if<((std::is_integral<UnsignedIntegralType>::value)
1949 && (!std::is_signed <UnsignedIntegralType>::value)), uintwide_t>::type &
1950 {
1951 // Implement left-shift operator for unsigned integral argument.
1952 if (n == 0)
1953 {
1954 ;
1955 }
1956 else if (static_cast<unsigned_fast_type>(n) >= my_width2)
1957 {
1958 std::fill(values.begin(), values.end(), static_cast<limb_type>(0U));
1959 }
1960 else
1961 {
1962 const auto offset = static_cast<unsigned_fast_type>(static_cast<unsigned_fast_type>(n) / static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits));
1963 const auto left_shift_amount = static_cast<std::uint_fast16_t>(static_cast<unsigned_fast_type>(n) % static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits));
1964
1965 shl(offset, left_shift_amount);
1966 }
1967
1968 return *this;
1969 }
1970
1971 template<typename SignedIntegralType>
1972 WIDE_INTEGER_CONSTEXPR auto operator>>=(const SignedIntegralType n) -> typename std::enable_if<((std::is_integral<SignedIntegralType>::value)
1973 && (std::is_signed <SignedIntegralType>::value)), uintwide_t>::type &
1974 {
1975 // Implement right-shift operator for signed integral argument.
1976 if (n < 0)
1977 {
1978 using local_unsigned_type =
1979 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<SignedIntegralType>::digits + 1)>::exact_unsigned_type;
1980
1981 operator<<=(static_cast<local_unsigned_type>(detail::negate(n)));
1982 }
1983 else if (n == 0)
1984 {
1985 ;
1986 }
1987 else if (static_cast<unsigned_fast_type>(n) >= my_width2)
1988 {
1989 // Fill with either 0's or 1's. Note also the implementation-defined
1990 // behavior of excessive right-shift of negative value.
1991 if (!is_neg(*this))
1992 {
1993 std::fill(values.begin(), values.end(), static_cast<limb_type>(0U));
1994 }
1995 else
1996 {
1997 std::fill(values.begin(), values.end(), (std::numeric_limits<limb_type>::max)());
1998 }
1999 }
2000 else
2001 {
2002 const auto offset = static_cast<unsigned_fast_type>(static_cast<unsigned_fast_type>(n) / static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits));
2003 const auto right_shift_amount = static_cast<std::uint_fast16_t>(static_cast<unsigned_fast_type>(n) % static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits));
2004
2005 shr(offset, right_shift_amount);
2006 }
2007
2008 return *this;
2009 }
2010
2011 template<typename UnsignedIntegralType>
2012 WIDE_INTEGER_CONSTEXPR auto operator>>=(const UnsignedIntegralType n) -> typename std::enable_if<((std::is_integral<UnsignedIntegralType>::value)
2013 && (!std::is_signed <UnsignedIntegralType>::value)), uintwide_t>::type &
2014 {
2015 // Implement right-shift operator for unsigned integral argument.
2016 if (n == 0)
2017 {
2018 ;
2019 }
2020 else if (static_cast<unsigned_fast_type>(n) >= my_width2)
2021 {
2022 std::fill(values.begin(), values.end(), static_cast<limb_type>(0U));
2023 }
2024 else
2025 {
2026 const auto offset = static_cast<unsigned_fast_type>(static_cast<unsigned_fast_type>(n) / static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits));
2027 const auto right_shift_amount = static_cast<std::uint_fast16_t>(static_cast<unsigned_fast_type>(n) % static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits));
2028
2029 shr(offset, right_shift_amount);
2030 }
2031
2032 return *this;
2033 }
2034
2035 // Implement comparison operators.
2036 constexpr auto operator==(const uintwide_t& other) const -> bool { return (compare(other) == static_cast<std::int_fast8_t>(0)); }
2037 constexpr auto operator< (const uintwide_t& other) const -> bool { return (compare(other) == static_cast<std::int_fast8_t>(-1)); }
2038 constexpr auto operator> (const uintwide_t& other) const -> bool { return (compare(other) == static_cast<std::int_fast8_t>(1)); }
2039 constexpr auto operator!=(const uintwide_t& other) const -> bool { return (compare(other) != static_cast<std::int_fast8_t>(0)); }
2040 constexpr auto operator<=(const uintwide_t& other) const -> bool { return (compare(other) <= static_cast<std::int_fast8_t>(0)); }
2041 constexpr auto operator>=(const uintwide_t& other) const -> bool { return (compare(other) >= static_cast<std::int_fast8_t>(0)); }
2042
2043 // Helper functions for supporting std::numeric_limits<>.
2044 static constexpr auto limits_helper_max(bool is_signed) -> uintwide_t
2045 {
2046 return
2047 (!is_signed)
2048 ? from_rep
2049 (
2050 representation_type
2051 (
2052 number_of_limbs, (std::numeric_limits<limb_type>::max)()
2053 )
2054 )
2055 : from_rep
2056 (
2057 representation_type
2058 (
2059 number_of_limbs, (std::numeric_limits<limb_type>::max)()
2060 )
2061 ) ^ (uintwide_t(1U) << (my_width2 - 1))
2062 ;
2063 }
2064
2065 static constexpr auto limits_helper_min(bool is_signed) -> uintwide_t
2066 {
2067 return
2068 (!is_signed)
2069 ? from_rep
2070 (
2071 representation_type
2072 (
2073 number_of_limbs, static_cast<limb_type>(0U)
2074 )
2075 )
2076 : from_rep
2077 (
2078 representation_type
2079 (
2080 number_of_limbs, static_cast<limb_type>(0U)
2081 )
2082 ) | (uintwide_t(1U) << (my_width2 - 1))
2083 ;
2084 }
2085
2086 static constexpr auto limits_helper_min() -> uintwide_t
2087 {
2088 return uintwide_t(representation_type(number_of_limbs, static_cast<limb_type>(0U)));
2089 }
2090
2091 static constexpr auto limits_helper_lowest(bool is_signed) -> uintwide_t
2092 {
2093 return
2094 (!is_signed)
2095 ? from_rep
2096 (
2097 representation_type
2098 (
2099 number_of_limbs, static_cast<limb_type>(0U)
2100 )
2101 )
2102 : from_rep
2103 (
2104 representation_type
2105 (
2106 number_of_limbs, static_cast<limb_type>(0U)
2107 )
2108 ) | (uintwide_t(1U) << (my_width2 - 1))
2109 ;
2110 }
2111
2112 // Define the maximum buffer sizes for extracting
2113 // octal, decimal and hexadecimal string representations.
2114 static constexpr auto wr_string_max_buffer_size_oct =
2115 static_cast<size_t>
2116 (
2117 (
2118 8U
2119 + (((my_width2 % 3U) != 0U) ? 1U : 0U)
2120 + (my_width2 / 3U)
2121 )
2122 );
2123
2124 static constexpr auto wr_string_max_buffer_size_hex =
2125 static_cast<size_t>
2126 (
2127 (
2128 8U
2129 + (((my_width2 % 4U) != 0U) ? 1U : 0U)
2130 + (my_width2 / 4U)
2131 )
2132 );
2133
2134 static constexpr auto wr_string_max_buffer_size_dec =
2135 static_cast<size_t>
2136 (
2137 (
2138 10U
2139 + static_cast<size_t>((static_cast<std::uintmax_t>(my_width2) * UINTMAX_C(301)) / UINTMAX_C(1000))
2140 )
2141 );
2142
2143 // Write string function.
2144 WIDE_INTEGER_CONSTEXPR auto wr_string(char* str_result, // NOLINT(readability-function-cognitive-complexity)
2145 const std::uint_fast8_t base_rep = 0x10U,
2146 const bool show_base = true,
2147 const bool show_pos = false,
2148 const bool is_uppercase = true,
2149 unsigned_fast_type field_width = 0U,
2150 const char fill_char = static_cast<char>('0')) const -> bool
2151 {
2152 bool wr_string_is_ok = true;
2153
2154 if (base_rep == UINT8_C(8))
2155 {
2156 uintwide_t t(*this);
2157
2158 const auto mask = static_cast<limb_type>(static_cast<std::uint8_t>(0x7U));
2159
2160 using string_storage_oct_type =
2161 typename std::conditional
2162 <my_width2 <= static_cast<size_t>(UINT32_C(2048)),
2163 detail::fixed_static_array <char,
2164 wr_string_max_buffer_size_oct>,
2165 detail::fixed_dynamic_array<char,
2166 wr_string_max_buffer_size_oct,
2167 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
2168 std::allocator<void>,
2169 AllocatorType>::type>::template rebind_alloc<limb_type>>
2170 >::type;
2171
2172 string_storage_oct_type str_temp;
2173
2174 auto pos = static_cast<unsigned_fast_type>(str_temp.size() - 1U);
2175
2176 if (t.is_zero())
2177 {
2178 --pos;
2179
2180 str_temp[static_cast<typename string_storage_oct_type::size_type>(pos)] = static_cast<char>('0');
2181 }
2182 else
2183 {
2184 if (!is_neg(t))
2185 {
2186 while (!t.is_zero())
2187 {
2188 auto c = static_cast<char>(*t.values.cbegin() & mask);
2189
2190 if (c <= static_cast<char>(INT8_C(8))) { c = static_cast<char>(c + static_cast<char>(INT8_C(0x30))); }
2191
2192 --pos;
2193
2194 str_temp[static_cast<typename string_storage_oct_type::size_type>(pos)] = c;
2195
2196 t >>= 3;
2197 }
2198 }
2199 else
2200 {
2201 uintwide_t<my_width2, limb_type, AllocatorType, false> tu(t);
2202
2203 while (!tu.is_zero()) // NOLINT(altera-id-dependent-backward-branch)
2204 {
2205 auto c = static_cast<char>(*tu.values.cbegin() & mask);
2206
2207 if (c <= static_cast<char>(INT8_C(8))) { c = static_cast<char>(c + static_cast<char>(INT8_C(0x30))); }
2208
2209 --pos;
2210
2211 str_temp[static_cast<typename string_storage_oct_type::size_type>(pos)] = c;
2212
2213 tu >>= 3;
2214 }
2215 }
2216 }
2217
2218 if (show_base)
2219 {
2220 --pos;
2221
2222 str_temp[static_cast<typename string_storage_oct_type::size_type>(pos)] = static_cast<char>('0');
2223 }
2224
2225 if (show_pos)
2226 {
2227 --pos;
2228
2229 str_temp[static_cast<typename string_storage_oct_type::size_type>(pos)] = static_cast<char>('+');
2230 }
2231
2232 if (field_width != 0U)
2233 {
2234 field_width = (std::min)(field_width, static_cast<unsigned_fast_type>(str_temp.size() - 1U));
2235
2236 while (static_cast<signed_fast_type>(pos) > static_cast<signed_fast_type>((str_temp.size() - 1U) - field_width)) // NOLINT(altera-id-dependent-backward-branch)
2237 {
2238 --pos;
2239
2240 str_temp[static_cast<typename string_storage_oct_type::size_type>(pos)] = fill_char;
2241 }
2242 }
2243
2244 str_temp[static_cast<typename string_storage_oct_type::size_type>(str_temp.size() - 1U)] = static_cast<char>('\0');
2245
2246 detail::strcpy_unsafe(str_result, str_temp.data() + pos);
2247 }
2248 else if (base_rep == UINT8_C(10))
2249 {
2250 uintwide_t t(*this);
2251
2252 const bool str_has_neg_sign = is_neg(t);
2253
2254 if (str_has_neg_sign)
2255 {
2256 t.negate();
2257 }
2258
2259 using string_storage_dec_type =
2260 typename std::conditional
2261 <my_width2 <= static_cast<size_t>(UINT32_C(2048)),
2262 detail::fixed_static_array <char,
2263 wr_string_max_buffer_size_dec>,
2264 detail::fixed_dynamic_array<char,
2265 wr_string_max_buffer_size_dec,
2266 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
2267 std::allocator<void>,
2268 AllocatorType>::type>::template rebind_alloc<limb_type>>
2269 >::type;
2270
2271 string_storage_dec_type str_temp;
2272
2273 auto pos = static_cast<unsigned_fast_type>(str_temp.size() - 1U);
2274
2275 if (t.is_zero())
2276 {
2277 --pos;
2278
2279 str_temp[static_cast<typename string_storage_dec_type::size_type>(pos)] = static_cast<char>('0');
2280 }
2281 else
2282 {
2283 while (!t.is_zero())
2284 {
2285 const uintwide_t tmp(t);
2286
2287 t.eval_divide_by_single_limb(static_cast<limb_type>(UINT8_C(10)), 0U, nullptr);
2288
2289 --pos;
2290
2291 str_temp[static_cast<typename string_storage_dec_type::size_type>(pos)] =
2292 static_cast<char>
2293 (
2294 static_cast<limb_type>
2295 (
2296 tmp - (uintwide_t(t).mul_by_limb(static_cast<limb_type>(UINT8_C(10))))
2297 )
2298 + UINT8_C(0x30)
2299 );
2300 }
2301 }
2302
2303 if (show_pos && (!str_has_neg_sign))
2304 {
2305 --pos;
2306
2307 str_temp[static_cast<typename string_storage_dec_type::size_type>(pos)] = static_cast<char>('+');
2308 }
2309 else if (str_has_neg_sign)
2310 {
2311 --pos;
2312
2313 str_temp[static_cast<typename string_storage_dec_type::size_type>(pos)] = static_cast<char>('-');
2314 }
2315
2316 if (field_width != 0U)
2317 {
2318 field_width = (std::min)(field_width, static_cast<unsigned_fast_type>(str_temp.size() - 1U));
2319
2320 while (static_cast<signed_fast_type>(pos) > static_cast<signed_fast_type>((str_temp.size() - 1U) - field_width)) // NOLINT(altera-id-dependent-backward-branch)
2321 {
2322 --pos;
2323
2324 str_temp[static_cast<typename string_storage_dec_type::size_type>(pos)] = fill_char;
2325 }
2326 }
2327
2328 str_temp[static_cast<typename string_storage_dec_type::size_type>(str_temp.size() - 1U)] = static_cast<char>('\0');
2329
2330 detail::strcpy_unsafe(str_result, str_temp.data() + pos);
2331 }
2332 else if (base_rep == UINT8_C(16))
2333 {
2334 uintwide_t t(*this);
2335
2336 const auto mask = static_cast<limb_type>(static_cast<std::uint8_t>(0xFU));
2337
2338 using string_storage_hex_type =
2339 typename std::conditional
2340 <my_width2 <= static_cast<size_t>(UINT32_C(2048)),
2341 detail::fixed_static_array <char,
2342 wr_string_max_buffer_size_hex>,
2343 detail::fixed_dynamic_array<char,
2344 wr_string_max_buffer_size_hex,
2345 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
2346 std::allocator<void>,
2347 AllocatorType>::type>::template rebind_alloc<limb_type>>
2348 >::type;
2349
2350 string_storage_hex_type str_temp;
2351
2352 auto pos = static_cast<unsigned_fast_type>(str_temp.size() - 1U);
2353
2354 if (t.is_zero())
2355 {
2356 --pos;
2357
2358 str_temp[static_cast<typename string_storage_hex_type::size_type>(pos)] = static_cast<char>('0');
2359 }
2360 else
2361 {
2362 if (!is_neg(t))
2363 {
2364 while (!t.is_zero())
2365 {
2366 char c(*t.values.cbegin() & mask);
2367
2368 if (c <= static_cast<char>(INT8_C(9))) { c = static_cast<char>(c + static_cast<char>(INT8_C(0x30))); }
2369 else if ((c >= static_cast<char>(INT8_C(0xA))) && (c <= static_cast<char>(INT8_C(0xF)))) { c = static_cast<char>(c + (is_uppercase ? static_cast<char>(INT8_C(55)) : static_cast<char>(INT8_C(87)))); }
2370
2371 --pos;
2372
2373 str_temp[static_cast<typename string_storage_hex_type::size_type>(pos)] = c;
2374
2375 t >>= 4;
2376 }
2377 }
2378 else
2379 {
2380 uintwide_t<my_width2, limb_type, AllocatorType, false> tu(t);
2381
2382 while (!tu.is_zero()) // NOLINT(altera-id-dependent-backward-branch)
2383 {
2384 char c(*tu.values.cbegin() & mask);
2385
2386 if (c <= static_cast<char>(INT8_C(9))) { c = static_cast<char>(c + static_cast<char>(INT8_C(0x30))); }
2387 else if ((c >= static_cast<char>(INT8_C(0xA))) && (c <= static_cast<char>(INT8_C(0xF)))) { c = static_cast<char>(c + (is_uppercase ? static_cast<char>(INT8_C(55)) : static_cast<char>(INT8_C(87)))); }
2388
2389 --pos;
2390
2391 str_temp[static_cast<typename string_storage_hex_type::size_type>(pos)] = c;
2392
2393 tu >>= 4;
2394 }
2395 }
2396 }
2397
2398 if (show_base)
2399 {
2400 --pos;
2401
2402 str_temp[static_cast<typename string_storage_hex_type::size_type>(pos)] = (is_uppercase ? static_cast<char>('X') : static_cast<char>('x'));
2403
2404 --pos;
2405
2406 str_temp[static_cast<typename string_storage_hex_type::size_type>(pos)] = static_cast<char>('0');
2407 }
2408
2409 if (show_pos)
2410 {
2411 --pos;
2412
2413 str_temp[static_cast<typename string_storage_hex_type::size_type>(pos)] = static_cast<char>('+');
2414 }
2415
2416 if (field_width != 0U)
2417 {
2418 field_width = (std::min)(field_width, static_cast<unsigned_fast_type>(str_temp.size() - 1U));
2419
2420 while (static_cast<signed_fast_type>(pos) > static_cast<signed_fast_type>((str_temp.size() - 1U) - field_width)) // NOLINT(altera-id-dependent-backward-branch)
2421 {
2422 --pos;
2423
2424 str_temp[static_cast<typename string_storage_hex_type::size_type>(pos)] = fill_char;
2425 }
2426 }
2427
2428 str_temp[static_cast<typename string_storage_hex_type::size_type>(str_temp.size() - 1U)] = static_cast<char>('\0');
2429
2430 detail::strcpy_unsafe(str_result, str_temp.data() + pos);
2431 }
2432 else
2433 {
2434 wr_string_is_ok = false;
2435 }
2436
2437 return wr_string_is_ok;
2438 }
2439
2440 template<const bool RePhraseIsSigned = IsSigned,
2441 typename std::enable_if<(!RePhraseIsSigned)>::type const* = nullptr>
2442 WIDE_INTEGER_NODISCARD WIDE_INTEGER_CONSTEXPR auto compare(const uintwide_t<Width2, LimbType, AllocatorType, RePhraseIsSigned> & other) const -> std::int_fast8_t
2443 {
2444 return compare_ranges(values.data(),
2445 other.values.data(),
2446 uintwide_t<Width2, LimbType, AllocatorType, RePhraseIsSigned>::number_of_limbs);
2447 }
2448
2449 template<const bool RePhraseIsSigned = IsSigned,
2450 typename std::enable_if<(RePhraseIsSigned)>::type const* = nullptr>
2451 WIDE_INTEGER_NODISCARD WIDE_INTEGER_CONSTEXPR auto compare(const uintwide_t<Width2, LimbType, AllocatorType, RePhraseIsSigned> & other) const -> std::int_fast8_t
2452 {
2453 const bool other_is_neg = is_neg(other);
2454
2455 return
2456 is_neg(*this)
2457 ? (other_is_neg ? compare_ranges(values.data(), other.values.data(), uintwide_t<Width2, LimbType, AllocatorType, RePhraseIsSigned>::number_of_limbs)
2458 : INT8_C(-1))
2459 : (other_is_neg ? INT8_C(1)
2460 : compare_ranges(values.data(), other.values.data(), uintwide_t<Width2, LimbType, AllocatorType, RePhraseIsSigned>::number_of_limbs))
2461 ;
2462 }
2463
2464 WIDE_INTEGER_CONSTEXPR void negate()
2465 {
2466 bitwise_not();
2467
2468 preincrement();
2469 }
2470
2471 WIDE_INTEGER_CONSTEXPR void eval_divide_by_single_limb(const limb_type short_denominator,
2472 const unsigned_fast_type u_offset,
2473 uintwide_t* remainder)
2474 {
2475 // The denominator has one single limb.
2476 // Use a one-dimensional division algorithm.
2477
2478 auto long_numerator = static_cast<double_limb_type>(0U);
2479
2480 auto hi_part = static_cast<limb_type>(0U);
2481
2482 for (auto i = static_cast<signed_fast_type>(static_cast<unsigned_fast_type>(number_of_limbs - 1U) - u_offset); static_cast<signed_fast_type>(i) >= 0; --i) // NOLINT(altera-id-dependent-backward-branch)
2483 {
2484 long_numerator =
2485 static_cast<double_limb_type>
2486 (
2487 static_cast<double_limb_type>(*(values.cbegin() + static_cast<size_t>(i)))
2488 + static_cast<double_limb_type>(static_cast<double_limb_type>(long_numerator - static_cast<double_limb_type>(static_cast<double_limb_type>(short_denominator) * hi_part)) << static_cast<unsigned>(std::numeric_limits<limb_type>::digits))
2489 );
2490
2491 *(values.begin() + static_cast<size_t>(i)) =
2492 detail::make_lo<limb_type>(static_cast<double_limb_type>(long_numerator / short_denominator));
2493
2494 hi_part = *(values.cbegin() + static_cast<size_t>(i));
2495 }
2496
2497 if (remainder != nullptr)
2498 {
2499 long_numerator =
2500 static_cast<double_limb_type>
2501 (
2502 static_cast<double_limb_type>(*values.cbegin())
2503 + static_cast<double_limb_type>(static_cast<double_limb_type>(long_numerator - static_cast<double_limb_type>(static_cast<double_limb_type>(short_denominator) * hi_part)) << static_cast<unsigned>(std::numeric_limits<limb_type>::digits))
2504 );
2505
2506 *remainder = static_cast<limb_type>(long_numerator >> static_cast<unsigned>(std::numeric_limits<limb_type>::digits));
2507 }
2508 }
2509
2510 WIDE_INTEGER_NODISCARD WIDE_INTEGER_CONSTEXPR auto is_zero() const -> bool
2511 {
2512 auto it = values.cbegin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto)
2513
2514 while ((it != values.cend()) && (*it == static_cast<limb_type>(0U))) // NOLINT(altera-id-dependent-backward-branch)
2515 {
2516 ++it;
2517 }
2518
2519 return (it == values.cend());
2520 }
2521
2522 template<const bool RePhraseIsSigned = IsSigned,
2523 typename std::enable_if<(!RePhraseIsSigned)>::type const* = nullptr>
2524 static constexpr auto is_neg(uintwide_t<Width2, LimbType, AllocatorType, RePhraseIsSigned>) -> bool // NOLINT(hicpp-named-parameter,readability-named-parameter)
2525 {
2526 return false;
2527 }
2528
2529 template<const bool RePhraseIsSigned = IsSigned,
2530 typename std::enable_if<(RePhraseIsSigned)>::type const* = nullptr>
2531 static constexpr auto is_neg(uintwide_t<Width2, LimbType, AllocatorType, RePhraseIsSigned> a) -> bool
2532 {
2533 return (static_cast<std::uint_fast8_t>(static_cast<std::uint_fast8_t>(a.values.back() >> static_cast<size_t>(std::numeric_limits<typename uintwide_t<Width2, LimbType, AllocatorType, RePhraseIsSigned>::limb_type>::digits - 1)) & 1U) != 0U);
2534 }
2535
2536 static constexpr auto from_rep(const representation_type& other_rep) -> uintwide_t
2537 {
2538 // Create a factory-like object from the internal data representation.
2539 return uintwide_t(static_cast<const representation_type&>(other_rep));
2540 }
2541
2542 static constexpr auto from_rep(representation_type&& other_rep) -> uintwide_t
2543 {
2544 // Create a factory-like object from the internal data representation.
2545 return uintwide_t(static_cast<representation_type&&>(other_rep));
2546 }
2547
2548 private:
2549 representation_type values{ }; // NOLINT(readability-identifier-naming)
2550
2551 explicit constexpr uintwide_t(const representation_type& other_rep)
2552 : values(static_cast<const representation_type&>(other_rep)) { }
2553
2554 explicit constexpr uintwide_t(representation_type&& other_rep)
2555 : values(static_cast<representation_type&&>(other_rep)) { }
2556
2557 template<typename InputIteratorLeftType,
2558 typename InputIteratorRightType>
2559 static WIDE_INTEGER_CONSTEXPR auto compare_ranges(InputIteratorLeftType a,
2560 InputIteratorRightType b,
2561 const unsigned_fast_type count) -> std::int_fast8_t
2562 {
2563 std::int_fast8_t n_return = 0;
2564
2565 std::reverse_iterator<InputIteratorLeftType> pa(a + count);
2566 std::reverse_iterator<InputIteratorRightType> pb(b + count);
2567
2568 for (; pa != std::reverse_iterator<InputIteratorLeftType>(a); ++pa, ++pb) // NOLINT(altera-id-dependent-backward-branch)
2569 {
2570 using value_left_type =
2571 typename std::iterator_traits<InputIteratorLeftType>::value_type;
2572
2573 if (*pa > static_cast<value_left_type>(*pb)) { n_return = 1; break; }
2574 if (*pa < static_cast<value_left_type>(*pb)) { n_return = -1; break; }
2575 }
2576
2577 return n_return;
2578 }
2579
2580 template<typename UnknownBuiltInIntegralType>
2581 struct digits_ratio
2582 {
2583 using local_unknown_builtin_integral_type = UnknownBuiltInIntegralType;
2584
2585 using local_unsigned_conversion_type =
2586 typename detail::uint_type_helper<
2587 std::numeric_limits<local_unknown_builtin_integral_type>::is_signed
2588 ? static_cast<size_t>(std::numeric_limits<local_unknown_builtin_integral_type>::digits + 1)
2589 : static_cast<size_t>(std::numeric_limits<local_unknown_builtin_integral_type>::digits + 0)>::exact_unsigned_type;
2590
2591 static constexpr unsigned_fast_type value =
2592 static_cast<unsigned_fast_type>(std::numeric_limits<local_unsigned_conversion_type>::digits
2593 / std::numeric_limits<limb_type>::digits);
2594
2595 template<typename InputIteratorLeft>
2596 static WIDE_INTEGER_CONSTEXPR auto extract(InputIteratorLeft p_limb, unsigned_fast_type limb_count) -> local_unknown_builtin_integral_type
2597 {
2598 using local_limb_type = typename std::iterator_traits<InputIteratorLeft>::value_type;
2599 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
2600
2601 auto u = static_cast<local_unsigned_conversion_type>(0U);
2602
2603 for (auto i = static_cast<unsigned_fast_type>(0U); i < limb_count; ++i)
2604 {
2605 u =
2606 static_cast<local_unsigned_conversion_type>
2607 (
2608 u
2609 | static_cast<local_unsigned_conversion_type>(static_cast<local_unsigned_conversion_type>(*(p_limb + static_cast<left_difference_type>(i))) << static_cast<unsigned>(std::numeric_limits<local_limb_type>::digits * static_cast<int>(i)))
2610 );
2611 }
2612
2613 return static_cast<local_unknown_builtin_integral_type>(u);
2614 }
2615 };
2616
2617 // Implement a function that extracts any built-in signed or unsigned integral type.
2618 template<typename UnknownBuiltInIntegralType,
2619 typename = typename std::enable_if<std::is_integral<UnknownBuiltInIntegralType>::value>::type>
2620 WIDE_INTEGER_NODISCARD WIDE_INTEGER_CONSTEXPR auto extract_builtin_integral_type() const -> UnknownBuiltInIntegralType
2621 {
2622 using local_unknown_integral_type = UnknownBuiltInIntegralType;
2623 using digits_ratio_type = digits_ratio<local_unknown_integral_type>;
2624
2625 const unsigned_fast_type ilim = (std::min)(static_cast<unsigned_fast_type>(digits_ratio_type::value),
2626 static_cast<unsigned_fast_type>(values.size()));
2627
2628 // Handle cases for which the input parameter is less wide
2629 // or equally as wide as the limb width or wider than the limb width.
2630 return ((digits_ratio_type::value < 2U)
2631 ? static_cast<local_unknown_integral_type>(*values.cbegin())
2632 : digits_ratio_type::extract(values.data(), ilim));
2633 }
2634
2635#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
2636 // Implement a function that extracts any built-in floating-point type.
2637 template<typename FloatingPointType,
2638 typename = typename std::enable_if<std::is_floating_point<FloatingPointType>::value>::type>
2639 WIDE_INTEGER_NODISCARD WIDE_INTEGER_CONSTEXPR auto extract_builtin_floating_point_type() const -> FloatingPointType
2640 {
2641 using local_unsigned_wide_integer_type = uintwide_t<Width2, limb_type, AllocatorType, false>;
2642 using local_builtin_float_type = FloatingPointType;
2643
2644 const bool u_is_neg = is_neg(*this);
2645
2646 const local_unsigned_wide_integer_type u((!u_is_neg) ? *this : -*this);
2647
2648 const auto my_msb = static_cast<size_t>(msb(u));
2649 const auto ilim = static_cast<size_t>
2650 (
2651 static_cast<size_t>(static_cast<size_t>(my_msb + 1U) / static_cast<size_t>(std::numeric_limits<limb_type>::digits))
2652 + static_cast<size_t>(((static_cast<size_t>(my_msb + 1U) % static_cast<size_t>(std::numeric_limits<limb_type>::digits)) != 0U) ? static_cast<size_t>(1U) : static_cast<size_t>(0U))
2653 );
2654
2655 auto a = static_cast<local_builtin_float_type>(0.0F);
2656
2657 constexpr long double one_ldbl(1.0L);
2658
2659 long double ldexp_runner(one_ldbl);
2660
2661 for (auto i = static_cast<size_t>(0U); i < ilim; ++i) // NOLINT(altera-id-dependent-backward-branch)
2662 {
2663 auto ld = static_cast<long double>(0.0L);
2664 auto lm_mask = static_cast<limb_type>(1ULL);
2665
2666 for (auto j = static_cast<size_t>(0U); j < static_cast<size_t>(std::numeric_limits<limb_type>::digits); ++j)
2667 {
2668 if (static_cast<limb_type>(*(u.values.cbegin() + static_cast<size_t>(i)) & lm_mask) != static_cast<limb_type>(0U))
2669 {
2670 ld = static_cast<long double>(ld + ldexp_runner);
2671 }
2672
2673 constexpr long double two_ldbl(2.0L);
2674
2675 lm_mask = static_cast<limb_type> (lm_mask << 1U);
2676 ldexp_runner = static_cast<long double>(ldexp_runner * two_ldbl);
2677 }
2678
2679 a += static_cast<local_builtin_float_type>(ld);
2680 }
2681
2682 return static_cast<local_builtin_float_type>((!u_is_neg) ? a : -a);
2683 }
2684#endif
2685
2686 template<const size_t OtherWidth2>
2687 static WIDE_INTEGER_CONSTEXPR void eval_mul_unary(uintwide_t<OtherWidth2, LimbType, AllocatorType, IsSigned>& u,
2688 const uintwide_t<OtherWidth2, LimbType, AllocatorType, IsSigned>& v,
2689 typename std::enable_if<((OtherWidth2 / std::numeric_limits<LimbType>::digits) < number_of_limbs_karatsuba_threshold)>::type* p_nullparam = nullptr)
2690 {
2691 static_cast<void>(p_nullparam == nullptr);
2692
2693 // Unary multiplication function using schoolbook multiplication,
2694 // but we only need to retain the low half of the n*n algorithm.
2695 // In other words, this is an n*n->n bit multiplication.
2696
2697 constexpr size_t local_number_of_limbs =
2698 uintwide_t<OtherWidth2, LimbType, AllocatorType, IsSigned>::number_of_limbs;
2699
2700 representation_type result{ };
2701
2702 eval_multiply_n_by_n_to_lo_part(result.data(),
2703 u.values.data(),
2704 v.values.data(),
2705 local_number_of_limbs);
2706
2707 std::copy(result.cbegin(),
2708 result.cbegin() + local_number_of_limbs,
2709 u.values.begin());
2710 }
2711
2712 template<const size_t OtherWidth2>
2713 static WIDE_INTEGER_CONSTEXPR void eval_mul_unary(uintwide_t<OtherWidth2, LimbType, AllocatorType, IsSigned>& u,
2714 const uintwide_t<OtherWidth2, LimbType, AllocatorType, IsSigned>& v,
2715 typename std::enable_if<((OtherWidth2 / std::numeric_limits<LimbType>::digits) >= number_of_limbs_karatsuba_threshold)>::type* p_nullparam = nullptr)
2716 {
2717 static_cast<void>(p_nullparam == nullptr);
2718
2719 // Unary multiplication function using Karatsuba multiplication.
2720
2721 constexpr size_t local_number_of_limbs =
2722 uintwide_t<OtherWidth2, LimbType, AllocatorType, IsSigned>::number_of_limbs;
2723
2724 // TBD: Can use specialized allocator or memory pool for these arrays.
2725 // Good examples for this (both threaded as well as non-threaded)
2726 // can be found in the wide_decimal project.
2727 using result_array_type =
2728 typename std::conditional<std::is_same<AllocatorType, void>::value,
2729 detail::fixed_static_array <limb_type, number_of_limbs * 2U>,
2730 detail::fixed_dynamic_array<limb_type,
2731 number_of_limbs * 2U,
2732 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
2733 std::allocator<void>,
2734 AllocatorType>::type>::template rebind_alloc<limb_type>>>::type;
2735
2736 using storage_array_type =
2737 typename std::conditional<std::is_same<AllocatorType, void>::value,
2738 detail::fixed_static_array <limb_type, number_of_limbs * 4U>,
2739 detail::fixed_dynamic_array<limb_type,
2740 number_of_limbs * 4U,
2741 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
2742 std::allocator<void>,
2743 AllocatorType>::type>::template rebind_alloc<limb_type>>>::type;
2744
2745 result_array_type result;
2746 storage_array_type t;
2747
2748 eval_multiply_kara_n_by_n_to_2n(result.data(),
2749 u.values.data(),
2750 v.values.data(),
2751 local_number_of_limbs,
2752 t.data());
2753
2754 std::copy(result.cbegin(),
2755 result.cbegin() + local_number_of_limbs,
2756 u.values.begin());
2757 }
2758
2759 template<typename ResultIterator,
2760 typename InputIteratorLeft,
2761 typename InputIteratorRight>
2762 static WIDE_INTEGER_CONSTEXPR auto eval_add_n(ResultIterator r,
2763 InputIteratorLeft u,
2764 InputIteratorRight v,
2765 const unsigned_fast_type count,
2766 const limb_type carry_in = static_cast<limb_type>(0U)) -> limb_type
2767 {
2768 auto carry_out = static_cast<std::uint_fast8_t>(carry_in);
2769
2770 static_assert
2771 (
2772 (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorLeft>::value_type>::digits)
2773 && (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorRight>::value_type>::digits),
2774 "Error: Internals require same widths for left-right-result limb_types at the moment"
2775 );
2776
2777 using local_limb_type = typename std::iterator_traits<ResultIterator>::value_type;
2778
2779 using local_double_limb_type =
2780 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_limb_type>::digits * 2)>::exact_unsigned_type;
2781
2782 using result_difference_type = typename std::iterator_traits<ResultIterator>::difference_type;
2783 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
2784 using right_difference_type = typename std::iterator_traits<InputIteratorRight>::difference_type;
2785
2786 for (auto i = static_cast<unsigned_fast_type>(0U); i < count; ++i)
2787 {
2788 const auto uv_as_ularge =
2789 static_cast<local_double_limb_type>(static_cast<local_double_limb_type>(static_cast<local_double_limb_type>(*(u + static_cast<left_difference_type>(i))) + *(v + static_cast<right_difference_type>(i))) + carry_out);
2790
2791 carry_out = static_cast<std::uint_fast8_t>(detail::make_hi<local_limb_type>(uv_as_ularge));
2792
2793 *(r + static_cast<result_difference_type>(i)) = static_cast<local_limb_type>(uv_as_ularge);
2794 }
2795
2796 return static_cast<limb_type>(carry_out);
2797 }
2798
2799 template<typename ResultIterator,
2800 typename InputIteratorLeft,
2801 typename InputIteratorRight>
2802 static WIDE_INTEGER_CONSTEXPR auto eval_subtract_n(ResultIterator r,
2803 InputIteratorLeft u,
2804 InputIteratorRight v,
2805 const unsigned_fast_type count,
2806 const bool has_borrow_in = false) -> bool
2807 {
2808 std::uint_fast8_t has_borrow_out = (has_borrow_in ? 1U : 0U);
2809
2810 static_assert
2811 (
2812 (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorLeft>::value_type>::digits)
2813 && (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorRight>::value_type>::digits),
2814 "Error: Internals require same widths for left-right-result limb_types at the moment"
2815 );
2816
2817 using local_limb_type = typename std::iterator_traits<ResultIterator>::value_type;
2818
2819 using local_double_limb_type =
2820 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_limb_type>::digits * 2)>::exact_unsigned_type;
2821
2822 using result_difference_type = typename std::iterator_traits<ResultIterator>::difference_type;
2823 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
2824 using right_difference_type = typename std::iterator_traits<InputIteratorRight>::difference_type;
2825
2826 for (auto i = static_cast<unsigned_fast_type>(0U); i < count; ++i)
2827 {
2828 const auto uv_as_ularge = static_cast<local_double_limb_type>(static_cast<local_double_limb_type>(static_cast<local_double_limb_type>(*(u + static_cast<left_difference_type>(i))) - *(v + static_cast<right_difference_type>(i))) - has_borrow_out);
2829
2830 has_borrow_out = (detail::make_hi<local_limb_type>(uv_as_ularge) != static_cast<local_limb_type>(0U)) ? 1U : 0U;
2831
2832 *(r + static_cast<result_difference_type>(i)) = static_cast<local_limb_type>(uv_as_ularge);
2833 }
2834
2835 return (has_borrow_out != 0U);
2836 }
2837
2838 template<typename ResultIterator,
2839 typename InputIteratorLeft,
2840 typename InputIteratorRight,
2841 const size_t RePhraseWidth2 = Width2,
2842 typename std::enable_if<(uintwide_t<RePhraseWidth2, LimbType, AllocatorType, IsSigned>::number_of_limbs == 4U)>::type const* = nullptr>
2843 static WIDE_INTEGER_CONSTEXPR void eval_multiply_n_by_n_to_lo_part(ResultIterator r,
2844 InputIteratorLeft a,
2845 InputIteratorRight b,
2846 const unsigned_fast_type count)
2847 {
2848 static_cast<void>(count);
2849
2850 static_assert
2851 (
2852 (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorLeft>::value_type>::digits)
2853 && (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorRight>::value_type>::digits),
2854 "Error: Internals require same widths for left-right-result limb_types at the moment"
2855 );
2856
2857 using local_limb_type = typename std::iterator_traits<ResultIterator>::value_type;
2858
2859 using local_double_limb_type =
2860 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_limb_type>::digits * 2)>::exact_unsigned_type;
2861
2862 using result_difference_type = typename std::iterator_traits<ResultIterator>::difference_type;
2863 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
2864 using right_difference_type = typename std::iterator_traits<InputIteratorRight>::difference_type;
2865 using result_value_type = typename std::iterator_traits<ResultIterator>::value_type;
2866
2867 // The algorithm has been derived from the polynomial multiplication.
2868 // After the multiplication terms of equal order are grouped
2869 // together and retained up to order(3). The carries from the
2870 // multiplications are included when adding up the terms.
2871 // The results of the intermediate multiplications are stored
2872 // in local variables in memory.
2873
2874 // Column[CoefficientList[Expand[(a0 + a1 x + a2 x^2 + a3 x^3) (b0 + b1 x + b2 x^2 + b3 x^3)], x]]
2875 // a0b0
2876 // a1b0 + a0b1
2877 // a2b0 + a1b1 + a0b2
2878 // a3b0 + a2b1 + a1b2 + a0b3
2879
2880 // See also Wolfram Alpha at:
2881 // https://www.wolframalpha.com/input/?i=Column%5BCoefficientList%5B+++Expand%5B%28a0+%2B+a1+x+%2B+a2+x%5E2+%2B+a3+x%5E3%29+%28b0+%2B+b1+x+%2B+b2+x%5E2+%2B+b3+x%5E3%29%5D%2C++++x%5D%5D
2882 // ... and take the upper half of the pyramid.
2883
2884 // Performance improvement:
2885 // (old) kops_per_sec: 33173.50
2886 // (new) kops_per_sec: 95069.43
2887
2888 local_double_limb_type r1;
2889 local_double_limb_type r2;
2890
2891 const auto a0b0 = static_cast<local_double_limb_type>(*(a + static_cast<left_difference_type>(0)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(0))));
2892 const auto a0b1 = static_cast<local_double_limb_type>(*(a + static_cast<left_difference_type>(0)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(1))));
2893 const auto a1b0 = static_cast<local_double_limb_type>(*(a + static_cast<left_difference_type>(1)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(0))));
2894 const auto a1b1 = static_cast<local_double_limb_type>(*(a + static_cast<left_difference_type>(1)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(1))));
2895
2896 // One special case is considered, the case of multiplication
2897 // of the form BITS/2 * BITS/2 = BITS. In this case, the algorithm
2898 // can be significantly simplified by using only the 'lower-halves'
2899 // of the data.
2900 if ((*(a + static_cast<left_difference_type>(2)) == 0U) && (*(b + static_cast<right_difference_type>(2)) == 0U)
2901 && (*(a + static_cast<left_difference_type>(3)) == 0U) && (*(b + static_cast<right_difference_type>(3)) == 0U))
2902 {
2903 r1 = static_cast<local_double_limb_type>
2904 (
2905 static_cast<local_double_limb_type>
2906 (
2907 detail::make_hi<local_limb_type>(a0b0)
2908 )
2909 + detail::make_lo<local_limb_type>(a1b0)
2910 + detail::make_lo<local_limb_type>(a0b1)
2911 )
2912 ;
2913 r2 = static_cast<local_double_limb_type>
2914 (
2915 static_cast<local_double_limb_type>
2916 (
2917 detail::make_hi<local_limb_type>(r1)
2918 )
2919 + detail::make_lo<local_limb_type>(a1b1)
2920 + detail::make_hi<local_limb_type>(a0b1)
2921 + detail::make_hi<local_limb_type>(a1b0)
2922 )
2923 ;
2924 *(r + static_cast<result_difference_type>(3))
2925 = static_cast<result_value_type>
2926 (
2927 detail::make_hi<local_limb_type>(r2)
2928 + detail::make_hi<local_limb_type>(a1b1)
2929 )
2930 ;
2931 }
2932 else
2933 {
2934 const auto a0b2 = static_cast<local_double_limb_type>(*(a + static_cast<left_difference_type>(0)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(2))));
2935 const auto a2b0 = static_cast<local_double_limb_type>(*(a + static_cast<left_difference_type>(2)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(0))));
2936
2937 r1 = static_cast<local_double_limb_type>
2938 (
2939 static_cast<local_double_limb_type>
2940 (
2941 detail::make_hi<local_limb_type>(a0b0)
2942 )
2943 + detail::make_lo<local_limb_type>(a1b0)
2944 + detail::make_lo<local_limb_type>(a0b1)
2945 )
2946 ;
2947 r2 = static_cast<local_double_limb_type>
2948 (
2949 static_cast<local_double_limb_type>
2950 (
2951 detail::make_hi<local_limb_type>(r1)
2952 )
2953 + detail::make_lo<local_limb_type>(a2b0)
2954 + detail::make_lo<local_limb_type>(a1b1)
2955 + detail::make_lo<local_limb_type>(a0b2)
2956 + detail::make_hi<local_limb_type>(a1b0)
2957 + detail::make_hi<local_limb_type>(a0b1)
2958 )
2959 ;
2960 *(r + static_cast<result_difference_type>(3))
2961 = static_cast<result_value_type>
2962 (
2963 detail::make_hi<local_limb_type>(r2)
2964 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(3)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(0))))
2965 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(2)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(1))))
2966 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(1)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(2))))
2967 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(0)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(3))))
2968 + detail::make_hi<local_limb_type>(a2b0)
2969 + detail::make_hi<local_limb_type>(a1b1)
2970 + detail::make_hi<local_limb_type>(a0b2)
2971 )
2972 ;
2973 }
2974
2975 *(r + static_cast<result_difference_type>(0)) = static_cast<local_limb_type>(a0b0);
2976 *(r + static_cast<result_difference_type>(1)) = static_cast<local_limb_type>(r1);
2977 *(r + static_cast<result_difference_type>(2)) = static_cast<local_limb_type>(r2);
2978 }
2979
2980#if defined(WIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL)
2981 template<typename ResultIterator,
2982 typename InputIteratorLeft,
2983 typename InputIteratorRight,
2984 const size_t RePhraseWidth2 = Width2,
2985 typename std::enable_if<(uintwide_t<RePhraseWidth2, LimbType, AllocatorType, IsSigned>::number_of_limbs == static_cast<size_t>(UINT32_C(8)))>::type const* = nullptr>
2986 static WIDE_INTEGER_CONSTEXPR void eval_multiply_n_by_n_to_lo_part(ResultIterator r,
2987 InputIteratorLeft a,
2988 InputIteratorRight b,
2989 const unsigned_fast_type count)
2990 {
2991 static_cast<void>(count);
2992
2993 static_assert
2994 (
2995 (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorLeft>::value_type>::digits)
2996 && (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorRight>::value_type>::digits),
2997 "Error: Internals require same widths for left-right-result limb_types at the moment"
2998 );
2999
3000 using local_limb_type = typename std::iterator_traits<ResultIterator>::value_type;
3001
3002 using local_double_limb_type =
3003 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_limb_type>::digits * 2)>::exact_unsigned_type;
3004
3005 using result_difference_type = typename std::iterator_traits<ResultIterator>::difference_type;
3006 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
3007 using right_difference_type = typename std::iterator_traits<InputIteratorRight>::difference_type;
3008
3009 // The algorithm has been derived from the polynomial multiplication.
3010 // After the multiplication terms of equal order are grouped
3011 // together and retained up to order(3). The carries from the
3012 // multiplications are included when adding up the terms.
3013 // The results of the intermediate multiplications are stored
3014 // in local variables in memory.
3015
3016 // Column[CoefficientList[Expand[(a0 + a1 x + a2 x^2 + a3 x^3 + a4 x^4 + a5 x^5 + a6 x^6 + a7 x^7) (b0 + b1 x + b2 x^2 + b3 x^3 + b4 x^4 + b5 x^5 + b6 x^6 + b7 x^7)], x]]
3017 // a0b0
3018 // a1b0 + a0b1
3019 // a2b0 + a1b1 + a0b2
3020 // a3b0 + a2b1 + a1b2 + a0b3
3021 // a4b0 + a3b1 + a2b2 + a1b3 + a0b4
3022 // a5b0 + a4b1 + a3b2 + a2b3 + a1b4 + a0b5
3023 // a6b0 + a5b1 + a4b2 + a3b3 + a2b4 + a1b5 + a0b6
3024 // a7b0 + a6b1 + a5b2 + a4b3 + a3b4 + a2b5 + a1b6 + a0b7
3025
3026 // See also Wolfram Alpha at:
3027 // https://www.wolframalpha.com/input/?i=Column%5BCoefficientList%5B+++Expand%5B%28a0+%2B+a1+x+%2B+a2+x%5E2+%2B+a3+x%5E3%29+%28b0+%2B+b1+x+%2B+b2+x%5E2+%2B+b3+x%5E3%29%5D%2C++++x%5D%5D
3028 // ... and take the upper half of the pyramid.
3029
3030 const local_double_limb_type a0b0 = *(a + static_cast<left_difference_type>(0)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(0)));
3031
3032 const local_double_limb_type a1b0 = *(a + static_cast<left_difference_type>(1)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(0)));
3033 const local_double_limb_type a0b1 = *(a + static_cast<left_difference_type>(0)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(1)));
3034
3035 const local_double_limb_type a2b0 = *(a + static_cast<left_difference_type>(2)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(0)));
3036 const local_double_limb_type a1b1 = *(a + static_cast<left_difference_type>(1)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(1)));
3037 const local_double_limb_type a0b2 = *(a + static_cast<left_difference_type>(0)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(2)));
3038
3039 const local_double_limb_type a3b0 = *(a + static_cast<left_difference_type>(3)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(0)));
3040 const local_double_limb_type a2b1 = *(a + static_cast<left_difference_type>(2)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(1)));
3041 const local_double_limb_type a1b2 = *(a + static_cast<left_difference_type>(1)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(2)));
3042 const local_double_limb_type a0b3 = *(a + static_cast<left_difference_type>(0)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(3)));
3043
3044 const local_double_limb_type a3b1 = *(a + static_cast<left_difference_type>(3)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(1)));
3045 const local_double_limb_type a2b2 = *(a + static_cast<left_difference_type>(2)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(2)));
3046 const local_double_limb_type a1b3 = *(a + static_cast<left_difference_type>(1)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(3)));
3047
3048 const local_double_limb_type a3b2 = *(a + static_cast<left_difference_type>(3)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(2)));
3049 const local_double_limb_type a2b3 = *(a + static_cast<left_difference_type>(2)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(3)));
3050
3051 const local_double_limb_type a3b3 = *(a + static_cast<left_difference_type>(3)) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(3)));
3052
3053 local_double_limb_type rd1;
3054 local_double_limb_type rd2;
3055 local_double_limb_type rd3;
3056 local_double_limb_type rd4;
3057 local_double_limb_type rd5;
3058 local_double_limb_type rd6;
3059
3060 // One special case is considered, the case of multiplication
3061 // of the form BITS/2 * BITS/2 = BITS. In this case, the algorithm
3062 // can be significantly simplified by using only the 'lower-halves'
3063 // of the data.
3064 if ((*(a + static_cast<left_difference_type>(INT32_C(7))) == 0U) && (*(b + static_cast<right_difference_type>(INT32_C(7))) == 0U)
3065 && (*(a + static_cast<left_difference_type>(INT32_C(6))) == 0U) && (*(b + static_cast<right_difference_type>(INT32_C(6))) == 0U)
3066 && (*(a + static_cast<left_difference_type>(INT32_C(5))) == 0U) && (*(b + static_cast<right_difference_type>(INT32_C(5))) == 0U)
3067 && (*(a + static_cast<left_difference_type>(INT32_C(4))) == 0U) && (*(b + static_cast<right_difference_type>(INT32_C(4))) == 0U))
3068 {
3069 rd1 = static_cast<local_double_limb_type>
3070 (
3071 detail::make_hi<local_limb_type>(a0b0)
3072 )
3073 + detail::make_lo<local_limb_type>(a1b0)
3074 + detail::make_lo<local_limb_type>(a0b1)
3075 ;
3076
3077 rd2 = static_cast<local_double_limb_type>
3078 (
3079 detail::make_hi<local_limb_type>(rd1)
3080 )
3081 + detail::make_lo<local_limb_type>(a2b0)
3082 + detail::make_lo<local_limb_type>(a1b1)
3083 + detail::make_lo<local_limb_type>(a0b2)
3084 + detail::make_hi<local_limb_type>(a1b0)
3085 + detail::make_hi<local_limb_type>(a0b1)
3086 ;
3087
3088 rd3 = static_cast<local_double_limb_type>
3089 (
3090 detail::make_hi<local_limb_type>(rd2)
3091 )
3092 + detail::make_lo<local_limb_type>(a3b0)
3093 + detail::make_lo<local_limb_type>(a2b1)
3094 + detail::make_lo<local_limb_type>(a1b2)
3095 + detail::make_lo<local_limb_type>(a0b3)
3096 + detail::make_hi<local_limb_type>(a2b0)
3097 + detail::make_hi<local_limb_type>(a1b1)
3098 + detail::make_hi<local_limb_type>(a0b2)
3099 ;
3100
3101 rd4 = static_cast<local_double_limb_type>
3102 (
3103 detail::make_hi<local_limb_type>(rd3)
3104 )
3105 + detail::make_lo<local_limb_type>(a3b1)
3106 + detail::make_lo<local_limb_type>(a2b2)
3107 + detail::make_lo<local_limb_type>(a1b3)
3108 + detail::make_hi<local_limb_type>(a3b0)
3109 + detail::make_hi<local_limb_type>(a2b1)
3110 + detail::make_hi<local_limb_type>(a1b2)
3111 + detail::make_hi<local_limb_type>(a0b3)
3112 ;
3113
3114 rd5 = static_cast<local_double_limb_type>
3115 (
3116 detail::make_hi<local_limb_type>(rd4)
3117 )
3118 + detail::make_lo<local_limb_type>(a3b2)
3119 + detail::make_lo<local_limb_type>(a2b3)
3120 + detail::make_hi<local_limb_type>(a3b1)
3121 + detail::make_hi<local_limb_type>(a2b2)
3122 + detail::make_hi<local_limb_type>(a1b3)
3123 ;
3124
3125 rd6 = static_cast<local_double_limb_type>
3126 (
3127 detail::make_hi<local_limb_type>(rd5)
3128 )
3129 + detail::make_lo<local_limb_type>(a3b3)
3130 + detail::make_hi<local_limb_type>(a3b2)
3131 + detail::make_hi<local_limb_type>(a2b3)
3132 ;
3133
3134 *(r + static_cast<result_difference_type>(INT32_C(7)))
3135 = static_cast<local_limb_type>
3136 (
3137 detail::make_hi<local_limb_type>(rd6)
3138 + detail::make_hi<local_limb_type>(a3b3)
3139 )
3140 ;
3141 }
3142 else
3143 {
3144 const local_double_limb_type a4b0 = *(a + static_cast<left_difference_type>(INT32_C(4))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(0))));
3145 const local_double_limb_type a0b4 = *(a + static_cast<left_difference_type>(INT32_C(0))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(4))));
3146
3147 const local_double_limb_type a5b0 = *(a + static_cast<left_difference_type>(INT32_C(5))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(0))));
3148 const local_double_limb_type a4b1 = *(a + static_cast<left_difference_type>(INT32_C(4))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(1))));
3149
3150 const local_double_limb_type a1b4 = *(a + static_cast<left_difference_type>(INT32_C(1))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(4))));
3151 const local_double_limb_type a0b5 = *(a + static_cast<left_difference_type>(INT32_C(0))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(5))));
3152
3153 const local_double_limb_type a6b0 = *(a + static_cast<left_difference_type>(INT32_C(6))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(0))));
3154 const local_double_limb_type a5b1 = *(a + static_cast<left_difference_type>(INT32_C(5))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(1))));
3155
3156 const local_double_limb_type a4b2 = *(a + static_cast<left_difference_type>(INT32_C(4))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(2))));
3157 const local_double_limb_type a2b4 = *(a + static_cast<left_difference_type>(INT32_C(2))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(4))));
3158
3159 const local_double_limb_type a1b5 = *(a + static_cast<left_difference_type>(INT32_C(1))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(5))));
3160 const local_double_limb_type a0b6 = *(a + static_cast<left_difference_type>(INT32_C(0))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(6))));
3161
3162 rd1 = static_cast<local_double_limb_type>
3163 (
3164 detail::make_hi<local_limb_type>(a0b0)
3165 )
3166 + detail::make_lo<local_limb_type>(a1b0)
3167 + detail::make_lo<local_limb_type>(a0b1)
3168 ;
3169
3170 rd2 = static_cast<local_double_limb_type>
3171 (
3172 detail::make_hi<local_limb_type>(rd1)
3173 )
3174 + detail::make_lo<local_limb_type>(a2b0)
3175 + detail::make_lo<local_limb_type>(a1b1)
3176 + detail::make_lo<local_limb_type>(a0b2)
3177 + detail::make_hi<local_limb_type>(a1b0)
3178 + detail::make_hi<local_limb_type>(a0b1)
3179 ;
3180
3181 rd3 = static_cast<local_double_limb_type>
3182 (
3183 detail::make_hi<local_limb_type>(rd2)
3184 )
3185 + detail::make_lo<local_limb_type>(a3b0)
3186 + detail::make_lo<local_limb_type>(a2b1)
3187 + detail::make_lo<local_limb_type>(a1b2)
3188 + detail::make_lo<local_limb_type>(a0b3)
3189 + detail::make_hi<local_limb_type>(a2b0)
3190 + detail::make_hi<local_limb_type>(a1b1)
3191 + detail::make_hi<local_limb_type>(a0b2)
3192 ;
3193
3194 rd4 = static_cast<local_double_limb_type>
3195 (
3196 detail::make_hi<local_limb_type>(rd3)
3197 )
3198 + detail::make_lo<local_limb_type>(a4b0)
3199 + detail::make_lo<local_limb_type>(a3b1)
3200 + detail::make_lo<local_limb_type>(a2b2)
3201 + detail::make_lo<local_limb_type>(a1b3)
3202 + detail::make_lo<local_limb_type>(a0b4)
3203 + detail::make_hi<local_limb_type>(a3b0)
3204 + detail::make_hi<local_limb_type>(a2b1)
3205 + detail::make_hi<local_limb_type>(a1b2)
3206 + detail::make_hi<local_limb_type>(a0b3)
3207 ;
3208
3209 rd5 = static_cast<local_double_limb_type>
3210 (
3211 detail::make_hi<local_limb_type>(rd4)
3212 )
3213 + detail::make_lo<local_limb_type>(a5b0)
3214 + detail::make_lo<local_limb_type>(a4b1)
3215 + detail::make_lo<local_limb_type>(a3b2)
3216 + detail::make_lo<local_limb_type>(a2b3)
3217 + detail::make_lo<local_limb_type>(a1b4)
3218 + detail::make_lo<local_limb_type>(a0b5)
3219 + detail::make_hi<local_limb_type>(a4b0)
3220 + detail::make_hi<local_limb_type>(a3b1)
3221 + detail::make_hi<local_limb_type>(a2b2)
3222 + detail::make_hi<local_limb_type>(a1b3)
3223 + detail::make_hi<local_limb_type>(a0b4)
3224 ;
3225
3226 rd6 = static_cast<local_double_limb_type>
3227 (
3228 detail::make_hi<local_limb_type>(rd5)
3229 )
3230 + detail::make_lo<local_limb_type>(a6b0)
3231 + detail::make_lo<local_limb_type>(a5b1)
3232 + detail::make_lo<local_limb_type>(a4b2)
3233 + detail::make_lo<local_limb_type>(a3b3)
3234 + detail::make_lo<local_limb_type>(a2b4)
3235 + detail::make_lo<local_limb_type>(a1b5)
3236 + detail::make_lo<local_limb_type>(a0b6)
3237 + detail::make_hi<local_limb_type>(a5b0)
3238 + detail::make_hi<local_limb_type>(a4b1)
3239 + detail::make_hi<local_limb_type>(a3b2)
3240 + detail::make_hi<local_limb_type>(a2b3)
3241 + detail::make_hi<local_limb_type>(a1b4)
3242 + detail::make_hi<local_limb_type>(a0b5)
3243 ;
3244
3245 *(r + static_cast<result_difference_type>(INT32_C(7)))
3246 = static_cast<local_limb_type>
3247 (
3248 detail::make_hi<local_limb_type>(rd6)
3249 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(INT32_C(7))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(0)))))
3250 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(INT32_C(6))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(1)))))
3251 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(INT32_C(5))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(2)))))
3252 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(INT32_C(4))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(3)))))
3253 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(INT32_C(3))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(4)))))
3254 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(INT32_C(2))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(5)))))
3255 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(INT32_C(1))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(6)))))
3256 + static_cast<local_limb_type> (*(a + static_cast<left_difference_type>(INT32_C(0))) * static_cast<local_double_limb_type>(*(b + static_cast<right_difference_type>(INT32_C(7)))))
3257 + detail::make_hi<local_limb_type>(a6b0)
3258 + detail::make_hi<local_limb_type>(a5b1)
3259 + detail::make_hi<local_limb_type>(a4b2)
3260 + detail::make_hi<local_limb_type>(a3b3)
3261 + detail::make_hi<local_limb_type>(a2b4)
3262 + detail::make_hi<local_limb_type>(a1b5)
3263 + detail::make_hi<local_limb_type>(a0b6)
3264 )
3265 ;
3266 }
3267
3268 *(r + static_cast<result_difference_type>(INT32_C(0))) = static_cast<local_limb_type>(a0b0);
3269 *(r + static_cast<result_difference_type>(INT32_C(1))) = static_cast<local_limb_type>(rd1);
3270 *(r + static_cast<result_difference_type>(INT32_C(2))) = static_cast<local_limb_type>(rd2);
3271 *(r + static_cast<result_difference_type>(INT32_C(3))) = static_cast<local_limb_type>(rd3);
3272 *(r + static_cast<result_difference_type>(INT32_C(4))) = static_cast<local_limb_type>(rd4);
3273 *(r + static_cast<result_difference_type>(INT32_C(5))) = static_cast<local_limb_type>(rd5);
3274 *(r + static_cast<result_difference_type>(INT32_C(6))) = static_cast<local_limb_type>(rd6);
3275 }
3276#endif
3277
3278 template<typename ResultIterator,
3279 typename InputIteratorLeft,
3280 typename InputIteratorRight,
3281 const size_t RePhraseWidth2 = Width2,
3282 typename std::enable_if<((uintwide_t<RePhraseWidth2, LimbType, AllocatorType>::number_of_limbs != static_cast<size_t>(UINT32_C(4)))
3283#if defined(WIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL)
3284 && (uintwide_t<RePhraseWidth2, LimbType, AllocatorType>::number_of_limbs != static_cast<size_t>(UINT32_C(8)))
3285#endif
3286 )>::type const* = nullptr>
3287 static WIDE_INTEGER_CONSTEXPR void eval_multiply_n_by_n_to_lo_part(ResultIterator r,
3288 InputIteratorLeft a,
3289 InputIteratorRight b,
3290 const unsigned_fast_type count)
3291 {
3292 static_assert
3293 (
3294 (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorLeft>::value_type>::digits)
3295 && (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorRight>::value_type>::digits),
3296 "Error: Internals require same widths for left-right-result limb_types at the moment"
3297 );
3298
3299 using local_limb_type = typename std::iterator_traits<ResultIterator>::value_type;
3300
3301 using local_double_limb_type =
3302 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_limb_type>::digits * 2)>::exact_unsigned_type;
3303
3304 using result_difference_type = typename std::iterator_traits<ResultIterator>::difference_type;
3305 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
3306 using right_difference_type = typename std::iterator_traits<InputIteratorRight>::difference_type;
3307
3308 std::fill_n(r, count, static_cast<local_limb_type>(0U));
3309
3310 for (auto i = static_cast<unsigned_fast_type>(0U); i < count; ++i)
3311 {
3312 if (*(a + static_cast<left_difference_type>(i)) != static_cast<local_limb_type>(0U))
3313 {
3314 local_double_limb_type carry = 0U;
3315
3316 for (auto j = static_cast<unsigned_fast_type>(0U); j < static_cast<unsigned_fast_type>(count - i); ++j)
3317 {
3318 carry = static_cast<local_double_limb_type>(carry + static_cast<local_double_limb_type>(static_cast<local_double_limb_type>(*(a + static_cast<left_difference_type>(i))) * *(b + static_cast<right_difference_type>(j))));
3319 carry = static_cast<local_double_limb_type>(carry + *(r + static_cast<result_difference_type>(i + j)));
3320
3321 *(r + static_cast<result_difference_type>(i + j)) = static_cast<local_limb_type>(carry);
3322 carry = detail::make_hi<local_limb_type>(carry);
3323 }
3324 }
3325 }
3326 }
3327
3328 template<typename ResultIterator,
3329 typename InputIteratorLeft,
3330 typename InputIteratorRight>
3331 static WIDE_INTEGER_CONSTEXPR void eval_multiply_n_by_n_to_2n(ResultIterator r,
3332 InputIteratorLeft a,
3333 InputIteratorRight b,
3334 const unsigned_fast_type count)
3335 {
3336 static_assert
3337 (
3338 (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorLeft>::value_type>::digits)
3339 && (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorRight>::value_type>::digits),
3340 "Error: Internals require same widths for left-right-result limb_types at the moment"
3341 );
3342
3343 using local_limb_type = typename std::iterator_traits<ResultIterator>::value_type;
3344
3345 using local_double_limb_type =
3346 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_limb_type>::digits * 2)>::exact_unsigned_type;
3347
3348 using result_difference_type = typename std::iterator_traits<ResultIterator>::difference_type;
3349 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
3350 using right_difference_type = typename std::iterator_traits<InputIteratorRight>::difference_type;
3351
3352 std::fill_n(r, (count * 2U), static_cast<local_limb_type>(0U));
3353
3354 for (auto i = static_cast<unsigned_fast_type>(0U); i < count; ++i)
3355 {
3356 if (*(a + static_cast<left_difference_type>(i)) != static_cast<local_limb_type>(0U))
3357 {
3358 unsigned_fast_type j = 0U;
3359
3360 local_double_limb_type carry = 0U;
3361
3362 for (; j < count; ++j)
3363 {
3364 carry = static_cast<local_double_limb_type>(carry + static_cast<local_double_limb_type>(static_cast<local_double_limb_type>(*(a + static_cast<left_difference_type>(i))) * *(b + static_cast<right_difference_type>(j))));
3365 carry = static_cast<local_double_limb_type>(carry + *(r + static_cast<result_difference_type>(i + j)));
3366
3367 *(r + static_cast<result_difference_type>(i + j)) = static_cast<local_limb_type>(carry);
3368 carry = detail::make_hi<local_limb_type>(carry);
3369 }
3370
3371 *(r + static_cast<result_difference_type>(i + j)) = static_cast<local_limb_type>(carry);
3372 }
3373 }
3374 }
3375
3376 template<typename ResultIterator,
3377 typename InputIteratorLeft>
3378 static WIDE_INTEGER_CONSTEXPR auto eval_multiply_1d(ResultIterator r,
3379 InputIteratorLeft a,
3380 const typename std::iterator_traits<InputIteratorLeft>::value_type b,
3381 const unsigned_fast_type count) -> limb_type
3382 {
3383 static_assert
3384 (
3385 (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorLeft>::value_type>::digits),
3386 "Error: Internals require same widths for left-right-result limb_types at the moment"
3387 );
3388
3389 using local_limb_type = typename std::iterator_traits<ResultIterator>::value_type;
3390
3391 using local_double_limb_type =
3392 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_limb_type>::digits * 2)>::exact_unsigned_type;
3393
3394 using result_difference_type = typename std::iterator_traits<ResultIterator>::difference_type;
3395 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
3396
3397 local_double_limb_type carry = 0U;
3398
3399 if (b == 0U)
3400 {
3401 std::fill(r, r + count, static_cast<limb_type>(0U));
3402 }
3403 else
3404 {
3405 for (auto i = static_cast<unsigned_fast_type>(0U); i < count; ++i)
3406 {
3407 carry = static_cast<local_double_limb_type>(carry + static_cast<local_double_limb_type>(static_cast<local_double_limb_type>(*(a + static_cast<left_difference_type>(i))) * b));
3408
3409 *(r + static_cast<result_difference_type>(i)) = static_cast<local_limb_type>(carry);
3410 carry = detail::make_hi<local_limb_type>(carry);
3411 }
3412 }
3413
3414 return static_cast<local_limb_type>(carry);
3415 }
3416
3417 template<typename InputIteratorLeft>
3418 static WIDE_INTEGER_CONSTEXPR
3419 void eval_multiply_kara_propagate_carry(InputIteratorLeft t,
3420 const unsigned_fast_type n,
3421 const typename std::iterator_traits<InputIteratorLeft>::value_type carry)
3422 {
3423 using local_limb_type = typename std::iterator_traits<InputIteratorLeft>::value_type;
3424
3425 using local_double_limb_type =
3426 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_limb_type>::digits * 2)>::exact_unsigned_type;
3427
3428 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
3429
3430 unsigned_fast_type i = 0U;
3431
3432 local_limb_type carry_out = carry;
3433
3434 while ((i < n) && (carry_out != static_cast<local_limb_type>(0U))) // NOLINT(altera-id-dependent-backward-branch)
3435 {
3436 const local_double_limb_type uv_as_ularge = static_cast<local_double_limb_type>(*(t + static_cast<left_difference_type>(i))) + carry_out;
3437
3438 carry_out = detail::make_hi<local_limb_type>(uv_as_ularge);
3439
3440 *(t + static_cast<left_difference_type>(i)) = static_cast<local_limb_type>(uv_as_ularge);
3441
3442 ++i;
3443 }
3444 }
3445
3446 template<typename InputIteratorLeft>
3447 static WIDE_INTEGER_CONSTEXPR
3448 void eval_multiply_kara_propagate_borrow(InputIteratorLeft t,
3449 const unsigned_fast_type n,
3450 const bool has_borrow)
3451 {
3452 using local_limb_type = typename std::iterator_traits<InputIteratorLeft>::value_type;
3453
3454 using local_double_limb_type =
3455 typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_limb_type>::digits * 2)>::exact_unsigned_type;
3456
3457 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
3458
3459 unsigned_fast_type i = 0U;
3460
3461 bool has_borrow_out = has_borrow;
3462
3463 while ((i < n) && (has_borrow_out)) // NOLINT(altera-id-dependent-backward-branch)
3464 {
3465 auto uv_as_ularge = static_cast<local_double_limb_type>(*(t + static_cast<left_difference_type>(i)));
3466
3467 if (has_borrow_out)
3468 {
3469 --uv_as_ularge;
3470 }
3471
3472 has_borrow_out = (detail::make_hi<local_limb_type>(uv_as_ularge) != static_cast<local_limb_type>(0U));
3473
3474 *(t + static_cast<left_difference_type>(i)) = static_cast<local_limb_type>(uv_as_ularge);
3475
3476 ++i;
3477 }
3478 }
3479
3480 template<typename ResultIterator,
3481 typename InputIteratorLeft,
3482 typename InputIteratorRight,
3483 typename InputIteratorTemp>
3484 static WIDE_INTEGER_CONSTEXPR
3485 void eval_multiply_kara_n_by_n_to_2n(ResultIterator r, // NOLINT(misc-no-recursion)
3486 const InputIteratorLeft a,
3487 const InputIteratorRight b,
3488 const unsigned_fast_type n,
3489 InputIteratorTemp t)
3490 {
3491 if (n <= static_cast<unsigned_fast_type>(UINT32_C(48)))
3492 {
3493 static_cast<void>(t);
3494
3495 eval_multiply_n_by_n_to_2n(r, a, b, n);
3496 }
3497 else
3498 {
3499 static_assert
3500 (
3501 (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorLeft>::value_type>::digits)
3502 && (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorRight>::value_type>::digits)
3503 && (std::numeric_limits<typename std::iterator_traits<ResultIterator>::value_type>::digits == std::numeric_limits<typename std::iterator_traits<InputIteratorTemp>::value_type>::digits),
3504 "Error: Internals require same widths for left-right-result limb_types at the moment"
3505 );
3506
3507 using local_limb_type = typename std::iterator_traits<ResultIterator>::value_type;
3508
3509 using result_difference_type = typename std::iterator_traits<ResultIterator>::difference_type;
3510 using left_difference_type = typename std::iterator_traits<InputIteratorLeft>::difference_type;
3511 using right_difference_type = typename std::iterator_traits<InputIteratorRight>::difference_type;
3512 using temp_difference_type = typename std::iterator_traits<InputIteratorTemp>::difference_type;
3513
3514 // Based on "Algorithm 1.3 KaratsubaMultiply", Sect. 1.3.2, page 5
3515 // of R.P. Brent and P. Zimmermann, "Modern Computer Arithmetic",
3516 // Cambridge University Press (2011).
3517
3518 // The Karatsuba multipliation computes the product of u*v as:
3519 // [b^N + b^(N/2)] a1*b1 + [b^(N/2)](a1 - a0)(b0 - b1) + [b^(N/2) + 1] a0*b0
3520
3521 // Here we visualize u and v in two components 0,1 corresponding
3522 // to the high and low order parts, respectively.
3523
3524 // Step 1
3525 // Calculate a1*b1 and store it in the upper part of r.
3526 // Calculate a0*b0 and store it in the lower part of r.
3527 // copy r to t0.
3528
3529 // Step 2
3530 // Add a1*b1 (which is t2) to the middle two-quarters of r (which is r1)
3531 // Add a0*b0 (which is t0) to the middle two-quarters of r (which is r1)
3532
3533 // Step 3
3534 // Calculate |a1-a0| in t0 and note the sign (i.e., the borrow flag)
3535
3536 // Step 4
3537 // Calculate |b0-b1| in t1 and note the sign (i.e., the borrow flag)
3538
3539 // Step 5
3540 // Call kara mul to calculate |a1-a0|*|b0-b1| in (t2),
3541 // while using temporary storage in t4 along the way.
3542
3543 // Step 6
3544 // Check the borrow signs. If a1-a0 and b0-b1 have the same signs,
3545 // then add |a1-a0|*|b0-b1| to r1, otherwise subtract it from r1.
3546
3547 const unsigned_fast_type nh = n / 2U;
3548
3549 const InputIteratorLeft a0 = a + static_cast<left_difference_type>(0);
3550 const InputIteratorLeft a1 = a + static_cast<left_difference_type>(nh);
3551
3552 const InputIteratorRight b0 = b + static_cast<right_difference_type>(0);
3553 const InputIteratorRight b1 = b + static_cast<right_difference_type>(nh);
3554
3555 ResultIterator r0 = r + static_cast<result_difference_type>(0);
3556 ResultIterator r1 = r + static_cast<result_difference_type>(nh);
3557 ResultIterator r2 = r + static_cast<result_difference_type>(n);
3558 ResultIterator r3 = r + static_cast<result_difference_type>(n + nh);
3559
3560 InputIteratorTemp t0 = t + static_cast<temp_difference_type>(0);
3561 InputIteratorTemp t1 = t + static_cast<temp_difference_type>(nh);
3562 InputIteratorTemp t2 = t + static_cast<temp_difference_type>(n);
3563 InputIteratorTemp t4 = t + static_cast<temp_difference_type>(n + n);
3564
3565 // Step 1
3566 // a1*b1 -> r2
3567 // a0*b0 -> r0
3568 // r -> t0
3569 eval_multiply_kara_n_by_n_to_2n(r2, a1, b1, nh, t0);
3570 eval_multiply_kara_n_by_n_to_2n(r0, a0, b0, nh, t0);
3571 std::copy(r0, r0 + (2U * n), t0);
3572
3573 local_limb_type carry;
3574
3575 // Step 2
3576 // r1 += a1*b1
3577 // r1 += a0*b0
3578 carry = eval_add_n(r1, r1, t2, n);
3579 eval_multiply_kara_propagate_carry(r3, nh, carry);
3580 carry = eval_add_n(r1, r1, t0, n);
3581 eval_multiply_kara_propagate_carry(r3, nh, carry);
3582
3583 // Step 3
3584 // |a1-a0| -> t0
3585 const std::int_fast8_t cmp_result_a1a0 = compare_ranges(a1, a0, nh);
3586
3587 if (cmp_result_a1a0 == 1)
3588 {
3589 static_cast<void>(eval_subtract_n(t0, a1, a0, nh));
3590 }
3591 else if (cmp_result_a1a0 == -1)
3592 {
3593 static_cast<void>(eval_subtract_n(t0, a0, a1, nh));
3594 }
3595
3596 // Step 4
3597 // |b0-b1| -> t1
3598 const std::int_fast8_t cmp_result_b0b1 = compare_ranges(b0, b1, nh);
3599
3600 if (cmp_result_b0b1 == 1)
3601 {
3602 static_cast<void>(eval_subtract_n(t1, b0, b1, nh));
3603 }
3604 else if (cmp_result_b0b1 == -1)
3605 {
3606 static_cast<void>(eval_subtract_n(t1, b1, b0, nh));
3607 }
3608
3609 // Step 5
3610 // |a1-a0|*|b0-b1| -> t2
3611 eval_multiply_kara_n_by_n_to_2n(t2, t0, t1, nh, t4);
3612
3613 // Step 6
3614 // either r1 += |a1-a0|*|b0-b1|
3615 // or r1 -= |a1-a0|*|b0-b1|
3616 if ((cmp_result_a1a0 * cmp_result_b0b1) == 1)
3617 {
3618 carry = eval_add_n(r1, r1, t2, n);
3619
3620 eval_multiply_kara_propagate_carry(r3, nh, carry);
3621 }
3622 else if ((cmp_result_a1a0 * cmp_result_b0b1) == -1)
3623 {
3624 const bool has_borrow = eval_subtract_n(r1, r1, t2, n);
3625
3626 eval_multiply_kara_propagate_borrow(r3, nh, has_borrow);
3627 }
3628 }
3629 }
3630
3631 WIDE_INTEGER_CONSTEXPR void eval_divide_knuth(const uintwide_t& other, // NOLINT(readability-function-cognitive-complexity)
3632 uintwide_t* remainder)
3633 {
3634 // Use Knuth's long division algorithm.
3635 // The loop-ordering of indices in Knuth's original
3636 // algorithm has been reversed due to the data format
3637 // used here. Several optimizations and combinations
3638 // of logic have been carried out in the source code.
3639
3640 // See also:
3641 // D.E. Knuth, "The Art of Computer Programming, Volume 2:
3642 // Seminumerical Algorithms", Addison-Wesley (1998),
3643 // Section 4.3.1 Algorithm D and Exercise 16.
3644
3645 using local_uint_index_type = unsigned_fast_type;
3646
3647 auto u_offset = static_cast<local_uint_index_type>(0U);
3648 auto v_offset = static_cast<local_uint_index_type>(0U);
3649
3650 // Compute the offsets for u and v.
3651 for (auto i = static_cast<local_uint_index_type>(0U); (i < number_of_limbs) && (*(values.cbegin() + static_cast<size_t>(static_cast<local_uint_index_type>(number_of_limbs - 1U) - i)) == static_cast<limb_type>(0U)); ++i) { ++u_offset; } // NOLINT(altera-id-dependent-backward-branch)
3652 for (auto i = static_cast<local_uint_index_type>(0U); (i < number_of_limbs) && (*(other.values.cbegin() + static_cast<size_t>(static_cast<local_uint_index_type>(number_of_limbs - 1U) - i)) == static_cast<limb_type>(0U)); ++i) { ++v_offset; } // NOLINT(altera-id-dependent-backward-branch)
3653
3654 if (v_offset == static_cast<local_uint_index_type>(number_of_limbs))
3655 {
3656 // The denominator is zero. Set the maximum value and return.
3657 // This also catches (0 / 0) and sets the maximum value for it.
3658 operator=(limits_helper_max(IsSigned));
3659
3660 if (remainder != nullptr)
3661 {
3662 *remainder = uintwide_t(static_cast<std::uint8_t>(0U));
3663 }
3664 }
3665 else if (u_offset == static_cast<local_uint_index_type>(number_of_limbs))
3666 {
3667 // The numerator is zero. Do nothing and return.
3668
3669 if (remainder != nullptr)
3670 {
3671 *remainder = uintwide_t(static_cast<std::uint8_t>(0U));
3672 }
3673 }
3674 else
3675 {
3676 const auto result_of_compare_left_with_right = compare(other);
3677
3678 const bool left_is_less_than_right = (result_of_compare_left_with_right == INT8_C(-1));
3679 const bool left_is_equal_to_right = (result_of_compare_left_with_right == INT8_C(0));
3680
3681 if (left_is_less_than_right)
3682 {
3683 // If the denominator is larger than the numerator,
3684 // then the result of the division is zero.
3685 if (remainder != nullptr)
3686 {
3687 *remainder = *this;
3688 }
3689
3690 operator=(static_cast<std::uint8_t>(0U));
3691 }
3692 else if (left_is_equal_to_right)
3693 {
3694 // If the denominator is equal to the numerator,
3695 // then the result of the division is one.
3696 operator=(static_cast<std::uint8_t>(1U));
3697
3698 if (remainder != nullptr)
3699 {
3700 *remainder = uintwide_t(static_cast<std::uint8_t>(0U));
3701 }
3702 }
3703 else if (v_offset == static_cast<local_uint_index_type>(number_of_limbs - 1U))
3704 {
3705 // The denominator has one single limb.
3706 // Use a one-dimensional division algorithm.
3707 const limb_type short_denominator = *other.values.cbegin();
3708
3709 eval_divide_by_single_limb(short_denominator, u_offset, remainder);
3710 }
3711 else
3712 {
3713 // We will now use the Knuth long division algorithm.
3714
3715 // Compute the normalization factor d.
3716 const auto d =
3717 static_cast<limb_type>(static_cast<double_limb_type>(static_cast<double_limb_type>(static_cast<double_limb_type>(1U) << static_cast<unsigned>(std::numeric_limits<limb_type>::digits))
3718 / static_cast<double_limb_type>(static_cast<double_limb_type>(*(other.values.cbegin() + static_cast<size_t>(static_cast<local_uint_index_type>(number_of_limbs - 1U) - v_offset))) + static_cast<limb_type>(1U))));
3719
3720 // Step D1(b), normalize u -> u * d = uu.
3721 // Step D1(c): normalize v -> v * d = vv.
3722
3723 using uu_array_type =
3724 typename std::conditional<std::is_same<AllocatorType, void>::value,
3725 detail::fixed_static_array <limb_type, number_of_limbs + 1U>,
3726 detail::fixed_dynamic_array<limb_type,
3727 number_of_limbs + 1U,
3728 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
3729 std::allocator<void>,
3730 AllocatorType>::type>::template rebind_alloc<limb_type>>>::type;
3731
3732 uu_array_type uu;
3733 representation_type vv;
3734
3735 if (d > static_cast<limb_type>(1U))
3736 {
3737 *(uu.begin() + static_cast<size_t>(static_cast<local_uint_index_type>(number_of_limbs) - u_offset)) =
3738 eval_multiply_1d(uu.data(), values.data(), d, number_of_limbs - u_offset);
3739
3740 static_cast<void>(eval_multiply_1d(vv.data(), other.values.data(), d, number_of_limbs - v_offset));
3741 }
3742 else
3743 {
3744 std::copy(values.cbegin(), values.cend(), uu.begin());
3745
3746 *(uu.begin() + static_cast<size_t>(static_cast<local_uint_index_type>(number_of_limbs) - u_offset)) = static_cast<limb_type>(0U);
3747
3748 vv = other.values;
3749 }
3750
3751 // Step D2: Initialize j.
3752 // Step D7: Loop on j from m to 0.
3753
3754 const auto n = static_cast<local_uint_index_type> (number_of_limbs - v_offset);
3755 const auto m = static_cast<local_uint_index_type> (number_of_limbs - u_offset) - n;
3756 const auto vj0 = static_cast<local_uint_index_type>((number_of_limbs - 1U) - v_offset);
3757
3758 for (auto j = static_cast<local_uint_index_type>(0U); j <= m; ++j) // NOLINT(altera-id-dependent-backward-branch)
3759 {
3760 // Step D3 [Calculate q_hat].
3761 // if u[j] == v[j0]
3762 // set q_hat = b - 1
3763 // else
3764 // set q_hat = (u[j] * b + u[j + 1]) / v[1]
3765
3766 const auto uj = static_cast<local_uint_index_type>(static_cast<local_uint_index_type>(static_cast<local_uint_index_type>(static_cast<local_uint_index_type>(number_of_limbs + 1U) - 1U) - u_offset) - j);
3767 const auto u_j_j1 = static_cast<double_limb_type>(static_cast<double_limb_type>(static_cast<double_limb_type>(*(uu.cbegin() + static_cast<size_t>(uj))) << static_cast<unsigned>(std::numeric_limits<limb_type>::digits)) + *(uu.cbegin() + static_cast<size_t>(uj - 1U)));
3768
3769 limb_type q_hat = ((*(uu.cbegin() + static_cast<size_t>(uj)) == *(vv.cbegin() + static_cast<size_t>(vj0)))
3770 ? (std::numeric_limits<limb_type>::max)()
3771 : static_cast<limb_type>(u_j_j1 / *(vv.cbegin() + static_cast<size_t>(vj0))));
3772
3773 // Decrease q_hat if necessary.
3774 // This means that q_hat must be decreased if the
3775 // expression [(u[uj] * b + u[uj - 1] - q_hat * v[vj0 - 1]) * b]
3776 // exceeds the range of uintwide_t.
3777
3778 for (auto t = static_cast<double_limb_type>(u_j_j1 - static_cast<double_limb_type>(q_hat * static_cast<double_limb_type>(*(vv.cbegin() + static_cast<size_t>(vj0))))); ; --q_hat, t = static_cast<double_limb_type>(t + *(vv.cbegin() + static_cast<size_t>(vj0))))
3779 {
3780 if ((detail::make_hi<limb_type>(t) != static_cast<limb_type>(0U))
3781 || (static_cast<double_limb_type>(static_cast<double_limb_type>(*(vv.cbegin() + static_cast<size_t>(vj0 - 1U))) * q_hat)
3782 <= static_cast<double_limb_type>(static_cast<double_limb_type>(t << static_cast<unsigned>(std::numeric_limits<limb_type>::digits)) + *(uu.cbegin() + static_cast<size_t>(uj - 2U)))))
3783 {
3784 break;
3785 }
3786 }
3787
3788 // Step D4: Multiply and subtract.
3789 // Replace u[j, ... j + n] by u[j, ... j + n] - q_hat * v[1, ... n].
3790
3791 // Set nv = q_hat * (v[1, ... n]).
3792 uu_array_type nv;
3793
3794 *(nv.begin() + static_cast<size_t>(n)) = eval_multiply_1d(nv.data(), vv.data(), q_hat, n);
3795
3796 const bool has_borrow =
3797 eval_subtract_n(uu.data() + static_cast<size_t>(static_cast<local_uint_index_type>(uj - n)),
3798 uu.data() + static_cast<size_t>(static_cast<local_uint_index_type>(uj - n)),
3799 nv.data(),
3800 n + 1U);
3801
3802
3803 // Get the result data.
3804 *(values.begin() + static_cast<size_t>(m - j)) = static_cast<limb_type>(q_hat - (has_borrow ? 1U : 0U));
3805
3806 // Step D5: Test the remainder.
3807 // Set the result value: Set result.m_data[m - j] = q_hat.
3808 // Use the condition (u[j] < 0), in other words if the borrow
3809 // is non-zero, then step D6 needs to be carried out.
3810
3811 if (has_borrow)
3812 {
3813 // Step D6: Add back.
3814 // Add v[1, ... n] back to u[j, ... j + n],
3815 // and decrease the result by 1.
3816
3817 static_cast<void>(eval_add_n(uu.data() + static_cast<size_t>(static_cast<local_uint_index_type>(uj - n)),
3818 uu.data() + static_cast<size_t>(static_cast<local_uint_index_type>(uj - n)),
3819 vv.data(),
3820 n));
3821 }
3822 }
3823
3824 // Clear the data elements that have not
3825 // been computed in the division algorithm.
3826 std::fill(values.begin() + static_cast<local_uint_index_type>(m + 1U), values.end(), static_cast<limb_type>(0U));
3827
3828 if (remainder != nullptr)
3829 {
3830 if (d == 1U)
3831 {
3832 std::copy(uu.cbegin(),
3833 uu.cbegin() + static_cast<size_t>(static_cast<local_uint_index_type>(number_of_limbs - v_offset)),
3834 remainder->values.begin());
3835 }
3836 else
3837 {
3838 auto previous_u = static_cast<limb_type>(0U);
3839
3840 for (auto rl = static_cast<signed_fast_type>(n - 1U), ul = static_cast<signed_fast_type>(number_of_limbs - (v_offset + 1U)); rl >= 0; --rl, --ul) // NOLINT(altera-id-dependent-backward-branch)
3841 {
3842 const auto t =
3843 static_cast<double_limb_type>(*(uu.cbegin() + static_cast<size_t>(ul))
3844 + static_cast<double_limb_type>(static_cast<double_limb_type>(previous_u) << static_cast<unsigned>(std::numeric_limits<limb_type>::digits)));
3845
3846 *(remainder->values.begin() + static_cast<size_t>(rl)) = static_cast<limb_type>(static_cast<double_limb_type>(t / d));
3847 previous_u = static_cast<limb_type>(static_cast<double_limb_type>(t - static_cast<double_limb_type>(static_cast<double_limb_type>(d) * *(remainder->values.cbegin() + static_cast<size_t>(rl)))));
3848 }
3849 }
3850
3851 std::fill(remainder->values.begin() + static_cast<size_t>(n),
3852 remainder->values.end(),
3853 static_cast<limb_type>(0U));
3854 }
3855 }
3856 }
3857 }
3858
3859 WIDE_INTEGER_CONSTEXPR void shl(const unsigned_fast_type offset, // NOLINT(bugprone-easily-swappable-parameters)
3860 const std::uint_fast16_t left_shift_amount)
3861 {
3862 if (offset > 0U)
3863 {
3864 std::copy_backward(values.data(),
3865 values.data() + static_cast<size_t>(number_of_limbs - offset),
3866 values.data() + static_cast<size_t>(number_of_limbs));
3867
3868 std::fill(values.begin(), values.begin() + static_cast<size_t>(offset), static_cast<limb_type>(0U));
3869 }
3870
3871 using local_integral_type = unsigned_fast_type;
3872
3873 if (left_shift_amount != static_cast<local_integral_type>(0U))
3874 {
3875 auto part_from_previous_value = static_cast<limb_type>(0U);
3876
3877 for (unsigned_fast_type i = offset; i < static_cast<unsigned_fast_type>(number_of_limbs); ++i) // NOLINT(altera-id-dependent-backward-branch)
3878 {
3879 const limb_type t = *(values.cbegin() + static_cast<size_t>(i));
3880
3881 *(values.begin() + static_cast<size_t>(i)) =
3882 static_cast<limb_type>(static_cast<limb_type>(t << static_cast<local_integral_type>(left_shift_amount)) | part_from_previous_value);
3883
3884 part_from_previous_value =
3885 static_cast<limb_type>(t >> static_cast<local_integral_type>(static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits - left_shift_amount)));
3886 }
3887 }
3888 }
3889
3890 WIDE_INTEGER_CONSTEXPR void shr(const unsigned_fast_type offset, // NOLINT(bugprone-easily-swappable-parameters)
3891 const std::uint_fast16_t right_shift_amount)
3892 {
3893 if (offset > 0U)
3894 {
3895 std::copy(values.begin() + static_cast<size_t>(offset),
3896 values.begin() + static_cast<size_t>(number_of_limbs),
3897 values.begin());
3898
3899 std::fill(values.end() - static_cast<size_t>(offset),
3900 values.end(),
3901 (!is_neg(*this)) ? static_cast<limb_type>(0U) : static_cast<limb_type>((std::numeric_limits<limb_type>::max)()));
3902 }
3903
3904 using local_integral_type = unsigned_fast_type;
3905
3906 if (right_shift_amount != static_cast<local_integral_type>(0U))
3907 {
3908 limb_type part_from_previous_value =
3909 (!is_neg(*this))
3910 ? static_cast<limb_type>(0U)
3911 : static_cast<limb_type>((std::numeric_limits<limb_type>::max)() << static_cast<std::uint_fast16_t>(static_cast<std::uint_fast16_t>(std::numeric_limits<limb_type>::digits) - right_shift_amount));
3912
3913 for (auto i = static_cast<signed_fast_type>((number_of_limbs - 1U) - offset); i >= static_cast<signed_fast_type>(0); --i) // NOLINT(altera-id-dependent-backward-branch)
3914 {
3915 const limb_type t = *(values.cbegin() + static_cast<size_t>(i));
3916
3917 *(values.begin() + static_cast<size_t>(i)) = static_cast<limb_type>(static_cast<limb_type>(t >> static_cast<local_integral_type>(right_shift_amount)) | part_from_previous_value);
3918
3919 part_from_previous_value = static_cast<limb_type>(t << static_cast<local_integral_type>(static_cast<unsigned_fast_type>(std::numeric_limits<limb_type>::digits - right_shift_amount)));
3920 }
3921 }
3922 }
3923
3924 // Read string function.
3925 WIDE_INTEGER_CONSTEXPR auto rd_string(const char* str_input) -> bool // NOLINT(readability-function-cognitive-complexity)
3926 {
3927 std::fill(values.begin(), values.end(), static_cast<limb_type>(0U));
3928
3929 const unsigned_fast_type str_length = detail::strlen_unsafe(str_input);
3930
3931 std::uint_fast8_t base = UINT8_C(10);
3932
3933 unsigned_fast_type pos = 0U;
3934
3935 // Detect: Is there a plus sign?
3936 // And if there is a plus sign, skip over the plus sign.
3937 if ((str_length > 0U) && (str_input[0U] == static_cast<char>('+'))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3938 {
3939 ++pos;
3940 }
3941
3942 bool str_has_neg_sign = false;
3943
3944 // Detect: Is there a minus sign?
3945 // And if there is a minus sign, skip over the minus sign.
3946 if ((str_length > 0U) && (str_input[0U] == static_cast<char>('-'))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3947 {
3948 str_has_neg_sign = true;
3949
3950 ++pos;
3951 }
3952
3953 // Perform a dynamic detection of the base.
3954 if (str_length > (pos + 0U))
3955 {
3956 const bool might_be_oct_or_hex = ((str_input[pos + 0U] == static_cast<char>('0')) && (str_length > (pos + 1U))); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3957
3958 if (might_be_oct_or_hex)
3959 {
3960 if ((str_input[pos + 1U] >= static_cast<char>('0')) && (str_input[pos + 1U] <= static_cast<char>('8'))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3961 {
3962 // The input format is octal.
3963 base = UINT8_C(8);
3964
3965 pos += 1U;
3966 }
3967 else if ((str_input[pos + 1U] == static_cast<char>('x')) || (str_input[pos + 1U] == static_cast<char>('X'))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3968 {
3969 // The input format is hexadecimal.
3970 base = UINT8_C(16);
3971
3972 pos += 2U;
3973 }
3974 }
3975 else if ((str_input[pos + 0U] >= static_cast<char>('0')) && (str_input[pos + 0U] <= static_cast<char>('9'))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3976 {
3977 // The input format is decimal.
3978 ;
3979 }
3980 }
3981
3982 bool char_is_valid = true;
3983
3984 for (; ((pos < str_length) && char_is_valid); ++pos) // NOLINT(altera-id-dependent-backward-branch)
3985 {
3986 const auto c = static_cast<std::uint8_t>(str_input[pos]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3987
3988 // TBD: Handle other digit delimiters in addition to apostrophe.
3989 const bool char_is_apostrophe = (c == static_cast<char>(39));
3990
3991 if (!char_is_apostrophe)
3992 {
3993 if (base == UINT8_C(8))
3994 {
3995 std::uint8_t uc_oct{ };
3996
3997 if ((c >= static_cast<char>('0')) && (c <= static_cast<char>('8'))) { uc_oct = static_cast<std::uint8_t>(c - static_cast<std::uint8_t>(UINT8_C(0x30))); }
3998 else { uc_oct = static_cast<std::uint8_t>('\0'); char_is_valid = false; }
3999
4000 if (char_is_valid)
4001 {
4002 operator<<=(3);
4003
4004 *values.begin() = static_cast<limb_type>(*values.begin() | uc_oct);
4005 }
4006 }
4007 else if (base == UINT8_C(10))
4008 {
4009 std::uint8_t uc_dec{ };
4010
4011 if ((c >= static_cast<std::uint8_t>('0')) && (c <= static_cast<std::uint8_t>('9'))) { uc_dec = static_cast<std::uint8_t>(c - static_cast<std::uint8_t>(UINT8_C(0x30))); }
4012 else { uc_dec = static_cast<std::uint8_t>('\0'); char_is_valid = false; }
4013
4014 if (char_is_valid)
4015 {
4016 mul_by_limb(static_cast<limb_type>(UINT8_C(10)));
4017
4018 operator+=(uc_dec);
4019 }
4020 }
4021 else if (base == UINT8_C(16))
4022 {
4023 std::uint8_t uc_hex{ };
4024
4025 if ((c >= static_cast<std::uint8_t>('a')) && (c <= static_cast<std::uint8_t>('f'))) { uc_hex = static_cast<std::uint8_t>(c - static_cast<std::uint8_t>(UINT8_C(87))); }
4026 else if ((c >= static_cast<std::uint8_t>('A')) && (c <= static_cast<std::uint8_t>('F'))) { uc_hex = static_cast<std::uint8_t>(c - static_cast<std::uint8_t>(UINT8_C(55))); }
4027 else if ((c >= static_cast<std::uint8_t>('0')) && (c <= static_cast<std::uint8_t>('9'))) { uc_hex = static_cast<std::uint8_t>(c - static_cast<std::uint8_t>(UINT8_C(0x30))); }
4028 else { uc_hex = static_cast<std::uint8_t>('\0'); char_is_valid = false; }
4029
4030 if (char_is_valid)
4031 {
4032 operator<<=(4);
4033
4034 *values.begin() = static_cast<limb_type>(*values.begin() | uc_hex);
4035 }
4036 }
4037 }
4038 }
4039
4040 if (str_has_neg_sign)
4041 {
4042 negate();
4043 }
4044
4045 return char_is_valid;
4046 }
4047
4048 WIDE_INTEGER_CONSTEXPR void bitwise_not()
4049 {
4050 for (auto i = static_cast<unsigned_fast_type>(0U); i < number_of_limbs; ++i)
4051 {
4052 *(values.begin() + static_cast<size_t>(i)) = static_cast<limb_type>(~(*(values.cbegin() + static_cast<size_t>(i))));
4053 }
4054 }
4055
4056 WIDE_INTEGER_CONSTEXPR void preincrement()
4057 {
4058 // Implement pre-increment.
4059 unsigned_fast_type i = 0U;
4060
4061 for (; (i < static_cast<unsigned_fast_type>(values.size() - 1U)) && (++(*(values.begin() + static_cast<size_t>(i))) == static_cast<limb_type>(0U)); ++i) // NOLINT(altera-id-dependent-backward-branch)
4062 {
4063 ;
4064 }
4065
4066 if (i == static_cast<unsigned_fast_type>(values.size() - 1U))
4067 {
4068 ++(*(values.begin() + static_cast<size_t>(i)));
4069 }
4070 }
4071
4072 WIDE_INTEGER_CONSTEXPR void predecrement()
4073 {
4074 // Implement pre-decrement.
4075 unsigned_fast_type i = 0U;
4076
4077 for (; (i < static_cast<unsigned_fast_type>(values.size() - 1U)) && ((*(values.begin() + static_cast<size_t>(i)))-- == static_cast<limb_type>(0U)); ++i) // NOLINT(altera-id-dependent-backward-branch)
4078 {
4079 ;
4080 }
4081
4082 if (i == static_cast<unsigned_fast_type>(values.size() - 1U))
4083 {
4084 --(*(values.begin() + static_cast<size_t>(i)));
4085 }
4086 }
4087 };
4088
4089 // Define some convenient unsigned wide integer types.
4090 using uint64_t = uintwide_t<static_cast<size_t>(UINT32_C(64)), std::uint16_t>;
4091 using uint128_t = uintwide_t<static_cast<size_t>(UINT32_C(128)), std::uint32_t>;
4092 using uint256_t = uintwide_t<static_cast<size_t>(UINT32_C(256)), std::uint32_t>;
4093 using uint512_t = uintwide_t<static_cast<size_t>(UINT32_C(512)), std::uint32_t>;
4094 using uint1024_t = uintwide_t<static_cast<size_t>(UINT32_C(1024)), std::uint32_t>;
4095 using uint2048_t = uintwide_t<static_cast<size_t>(UINT32_C(2048)), std::uint32_t>;
4096 using uint4096_t = uintwide_t<static_cast<size_t>(UINT32_C(4096)), std::uint32_t>;
4097 using uint8192_t = uintwide_t<static_cast<size_t>(UINT32_C(8192)), std::uint32_t>;
4098 using uint16384_t = uintwide_t<static_cast<size_t>(UINT32_C(16384)), std::uint32_t>;
4099 using uint32768_t = uintwide_t<static_cast<size_t>(UINT32_C(32768)), std::uint32_t>;
4100 using uint65536_t = uintwide_t<static_cast<size_t>(UINT32_C(65536)), std::uint32_t>;
4101
4102#if !defined(WIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS)
4103 static_assert(std::is_trivially_copyable<uint64_t >::value, "uintwide_t must be trivially copyable.");
4104 static_assert(std::is_trivially_copyable<uint128_t >::value, "uintwide_t must be trivially copyable.");
4105 static_assert(std::is_trivially_copyable<uint256_t >::value, "uintwide_t must be trivially copyable.");
4106 static_assert(std::is_trivially_copyable<uint512_t >::value, "uintwide_t must be trivially copyable.");
4107 static_assert(std::is_trivially_copyable<uint1024_t >::value, "uintwide_t must be trivially copyable.");
4108 static_assert(std::is_trivially_copyable<uint2048_t >::value, "uintwide_t must be trivially copyable.");
4109 static_assert(std::is_trivially_copyable<uint4096_t >::value, "uintwide_t must be trivially copyable.");
4110 static_assert(std::is_trivially_copyable<uint8192_t >::value, "uintwide_t must be trivially copyable.");
4111 static_assert(std::is_trivially_copyable<uint16384_t>::value, "uintwide_t must be trivially copyable.");
4112 static_assert(std::is_trivially_copyable<uint32768_t>::value, "uintwide_t must be trivially copyable.");
4113 static_assert(std::is_trivially_copyable<uint65536_t>::value, "uintwide_t must be trivially copyable.");
4114
4115 static_assert(std::is_standard_layout<uint64_t >::value, "uintwide_t must have standard layout.");
4116 static_assert(std::is_standard_layout<uint128_t >::value, "uintwide_t must have standard layout.");
4117 static_assert(std::is_standard_layout<uint256_t >::value, "uintwide_t must have standard layout.");
4118 static_assert(std::is_standard_layout<uint512_t >::value, "uintwide_t must have standard layout.");
4119 static_assert(std::is_standard_layout<uint1024_t >::value, "uintwide_t must have standard layout.");
4120 static_assert(std::is_standard_layout<uint2048_t >::value, "uintwide_t must have standard layout.");
4121 static_assert(std::is_standard_layout<uint4096_t >::value, "uintwide_t must have standard layout.");
4122 static_assert(std::is_standard_layout<uint8192_t >::value, "uintwide_t must have standard layout.");
4123 static_assert(std::is_standard_layout<uint16384_t>::value, "uintwide_t must have standard layout.");
4124 static_assert(std::is_standard_layout<uint32768_t>::value, "uintwide_t must have standard layout.");
4125 static_assert(std::is_standard_layout<uint65536_t>::value, "uintwide_t must have standard layout.");
4126#endif
4127
4128 using int64_t = uintwide_t<static_cast<size_t>(UINT32_C(64)), std::uint16_t, void, true>;
4129 using int128_t = uintwide_t<static_cast<size_t>(UINT32_C(128)), std::uint32_t, void, true>;
4130 using int256_t = uintwide_t<static_cast<size_t>(UINT32_C(256)), std::uint32_t, void, true>;
4131 using int512_t = uintwide_t<static_cast<size_t>(UINT32_C(512)), std::uint32_t, void, true>;
4132 using int1024_t = uintwide_t<static_cast<size_t>(UINT32_C(1024)), std::uint32_t, void, true>;
4133 using int2048_t = uintwide_t<static_cast<size_t>(UINT32_C(2048)), std::uint32_t, void, true>;
4134 using int4096_t = uintwide_t<static_cast<size_t>(UINT32_C(4096)), std::uint32_t, void, true>;
4135 using int8192_t = uintwide_t<static_cast<size_t>(UINT32_C(8192)), std::uint32_t, void, true>;
4136 using int16384_t = uintwide_t<static_cast<size_t>(UINT32_C(16384)), std::uint32_t, void, true>;
4137 using int32768_t = uintwide_t<static_cast<size_t>(UINT32_C(32768)), std::uint32_t, void, true>;
4138 using int65536_t = uintwide_t<static_cast<size_t>(UINT32_C(65536)), std::uint32_t, void, true>;
4139
4140#if !defined(WIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS)
4141 static_assert(std::is_trivially_copyable<int64_t >::value, "uintwide_t must be trivially copyable.");
4142 static_assert(std::is_trivially_copyable<int128_t >::value, "uintwide_t must be trivially copyable.");
4143 static_assert(std::is_trivially_copyable<int256_t >::value, "uintwide_t must be trivially copyable.");
4144 static_assert(std::is_trivially_copyable<int512_t >::value, "uintwide_t must be trivially copyable.");
4145 static_assert(std::is_trivially_copyable<int1024_t >::value, "uintwide_t must be trivially copyable.");
4146 static_assert(std::is_trivially_copyable<int2048_t >::value, "uintwide_t must be trivially copyable.");
4147 static_assert(std::is_trivially_copyable<int4096_t >::value, "uintwide_t must be trivially copyable.");
4148 static_assert(std::is_trivially_copyable<int8192_t >::value, "uintwide_t must be trivially copyable.");
4149 static_assert(std::is_trivially_copyable<int16384_t>::value, "uintwide_t must be trivially copyable.");
4150 static_assert(std::is_trivially_copyable<int32768_t>::value, "uintwide_t must be trivially copyable.");
4151 static_assert(std::is_trivially_copyable<int65536_t>::value, "uintwide_t must be trivially copyable.");
4152
4153 static_assert(std::is_standard_layout<int64_t >::value, "uintwide_t must have standard layout.");
4154 static_assert(std::is_standard_layout<int128_t >::value, "uintwide_t must have standard layout.");
4155 static_assert(std::is_standard_layout<int256_t >::value, "uintwide_t must have standard layout.");
4156 static_assert(std::is_standard_layout<int512_t >::value, "uintwide_t must have standard layout.");
4157 static_assert(std::is_standard_layout<int1024_t >::value, "uintwide_t must have standard layout.");
4158 static_assert(std::is_standard_layout<int2048_t >::value, "uintwide_t must have standard layout.");
4159 static_assert(std::is_standard_layout<int4096_t >::value, "uintwide_t must have standard layout.");
4160 static_assert(std::is_standard_layout<int8192_t >::value, "uintwide_t must have standard layout.");
4161 static_assert(std::is_standard_layout<int16384_t>::value, "uintwide_t must have standard layout.");
4162 static_assert(std::is_standard_layout<int32768_t>::value, "uintwide_t must have standard layout.");
4163 static_assert(std::is_standard_layout<int65536_t>::value, "uintwide_t must have standard layout.");
4164#endif
4165
4166 // Insert a base class for numeric_limits<> support.
4167 // This class inherits from std::numeric_limits<unsigned int>
4168 // in order to provide limits for a non-specific unsigned type.
4169
4170 template<const size_t Width2,
4171 typename LimbType,
4172 typename AllocatorType,
4173 const bool IsSigned>
4174 WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits_uintwide_t_base
4175 : public std::numeric_limits<typename std::conditional<(!IsSigned), unsigned int, signed int>::type>
4176 {
4177 private:
4178 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4179
4180 public:
4181 static constexpr int digits = (!IsSigned)
4182 ? static_cast<int>(local_wide_integer_type::my_width2)
4183 : static_cast<int>(local_wide_integer_type::my_width2 - 1U);
4184
4185 static constexpr int digits10 = static_cast<int>((static_cast<std::uintmax_t>(digits) * UINTMAX_C(75257499)) / UINTMAX_C(250000000));
4186 static constexpr int max_digits10 = digits10;
4187 static constexpr int max_exponent = digits;
4188 static constexpr int max_exponent10 = static_cast<int>((static_cast<std::uintmax_t>(max_exponent) * UINTMAX_C(75257499)) / UINTMAX_C(250000000));
4189
4190 static constexpr auto (max)() -> local_wide_integer_type { return local_wide_integer_type::limits_helper_max(IsSigned); }
4191 static constexpr auto (min)() -> local_wide_integer_type { return local_wide_integer_type::limits_helper_min(IsSigned); }
4192 static constexpr auto lowest() -> local_wide_integer_type { return local_wide_integer_type::limits_helper_lowest(IsSigned); }
4193 };
4194
4195 template<class T>
4196 struct is_integral : public std::is_integral<T> { };
4197
4198 template<const size_t Width2,
4199 typename LimbType,
4200 typename AllocatorType,
4201 const bool IsSigned>
4202 struct is_integral<math::wide_integer::uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>
4203 : public std::integral_constant<bool, true> { };
4204
4205#if(__cplusplus >= 201703L)
4206 } // namespace math::wide_integer
4207#else
4208} // namespace wide_integer
4209} // namespace math
4210#endif
4211
4212WIDE_INTEGER_NAMESPACE_END
4213
4214namespace std
4215{
4216 // Specialization of std::numeric_limits<uintwide_t>.
4217#if defined(WIDE_INTEGER_NAMESPACE)
4218 template<const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t Width2,
4219 typename LimbType,
4220 typename AllocatorType,
4221 const bool IsSigned>
4222 WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits<WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>
4223 : public WIDE_INTEGER_NAMESPACE::math::wide_integer::numeric_limits_uintwide_t_base<Width2, LimbType, AllocatorType, IsSigned>{ };
4224#else
4225 template<const ::math::wide_integer::size_t Width2,
4226 typename LimbType,
4227 typename AllocatorType,
4228 const bool IsSigned>
4229 WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits<::math::wide_integer::uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>
4230 : public ::math::wide_integer::numeric_limits_uintwide_t_base<Width2, LimbType, AllocatorType, IsSigned>{ };
4231#endif
4232} // namespace std
4233
4234WIDE_INTEGER_NAMESPACE_BEGIN
4235
4236#if(__cplusplus >= 201703L)
4237namespace math::wide_integer {
4238#else
4239namespace math {
4240 namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces)
4241#endif
4242
4243// Non-member binary add, sub, mul, div, mod of (uintwide_t op uintwide_t).
4244 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+ (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned> { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator+=(v); }
4245 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator- (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned> { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator-=(v); }
4246 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator* (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned> { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator*=(v); }
4247 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/ (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned> { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator/=(v); }
4248 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator% (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned> { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator%=(v); }
4249
4250 // Non-member binary logic operations of (uintwide_t op uintwide_t).
4251 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator| (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned> { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator|=(v); }
4252 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator^ (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned> { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator^=(v); }
4253 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator& (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned> { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator&=(v); }
4254
4255 // Non-member binary add, sub, mul, div, mod of (uintwide_t op IntegralType).
4256 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator+=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4257 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator-(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator-=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4258 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator*(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator*=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4259 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator/=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4260
4261 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned>
4262 constexpr auto operator%(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<((std::is_integral<IntegralType>::value)
4263 && (!std::is_unsigned<IntegralType>::value)),
4264 uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type
4265 { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator%=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4266
4267 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned>
4268 WIDE_INTEGER_CONSTEXPR auto operator%(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<((std::is_integral<IntegralType>::value)
4269 && (std::is_unsigned<IntegralType>::value)
4270 && (std::numeric_limits<IntegralType>::digits <= std::numeric_limits<LimbType>::digits)),
4271 typename uintwide_t<Width2, LimbType, AllocatorType, IsSigned>::limb_type>::type
4272 {
4273 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4274
4275 const bool u_is_neg = local_wide_integer_type::is_neg(u);
4276
4277 local_wide_integer_type remainder;
4278
4279 local_wide_integer_type((!u_is_neg) ? u : -u).eval_divide_by_single_limb(v, 0U, &remainder);
4280
4281 using local_limb_type = typename local_wide_integer_type::limb_type;
4282
4283 auto u_rem = static_cast<local_limb_type>(remainder);
4284
4285 return ((!u_is_neg) ? u_rem : static_cast<local_limb_type>(static_cast<local_limb_type>(~u_rem) + 1U));
4286 }
4287
4288 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned>
4289 constexpr auto operator%(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<((std::is_integral<IntegralType>::value)
4290 && (std::is_unsigned<IntegralType>::value)
4291 && (std::numeric_limits<IntegralType>::digits > std::numeric_limits<LimbType>::digits)),
4292 uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type
4293 { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator%=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4294
4295 // Non-member binary add, sub, mul, div, mod of (IntegralType op uintwide_t).
4296 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator+=(v); }
4297 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator-(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator-=(v); }
4298 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator*(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator*=(v); }
4299 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator/=(v); }
4300 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator%(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator%=(v); }
4301
4302#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
4303 // Non-member binary add, sub, mul, div, mod of (uintwide_t op FloatingPointType).
4304 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator+=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4305 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator-(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator-=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4306 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator*(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator*=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4307 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator/=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4308 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator%(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator%=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4309
4310 // Non-member binary add, sub, mul, div, mod of (FloatingPointType op uintwide_t).
4311 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator+(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator+=(v); }
4312 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator-(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator-=(v); }
4313 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator*(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator*=(v); }
4314 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator/(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator/=(v); }
4315 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator%(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator%=(v); }
4316#endif
4317
4318 // Non-member binary logic operations of (uintwide_t op IntegralType).
4319 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator|(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator|=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4320 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator^(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator^=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4321 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator&(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator&=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4322
4323 // Non-member binary binary logic operations of (IntegralType op uintwide_t).
4324 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator|(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator|=(v); }
4325 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator^(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator^=(v); }
4326 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator&(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator&=(v); }
4327
4328 // Non-member shift functions of (uintwide_t shift IntegralType).
4329 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<<(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType n) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator<<=(n); }
4330 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>>(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType n) -> typename std::enable_if<std::is_integral<IntegralType>::value, uintwide_t<Width2, LimbType, AllocatorType, IsSigned>>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator>>=(n); }
4331
4332 // Non-member comparison functions of (uintwide_t cmp uintwide_t).
4333 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool { return u.operator==(v); }
4334 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool { return u.operator!=(v); }
4335 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool { return u.operator> (v); }
4336 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool { return u.operator< (v); }
4337 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool { return u.operator>=(v); }
4338 template<const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> bool { return u.operator<=(v); }
4339
4340 // Non-member comparison functions of (uintwide_t cmp IntegralType).
4341 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return u.operator==(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4342 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return u.operator!=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4343 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return u.operator> (uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4344 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return u.operator< (uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4345 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return u.operator>=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4346 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const IntegralType& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return u.operator<=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(v)); }
4347
4348 // Non-member comparison functions of (IntegralType cmp uintwide_t).
4349 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator==(v); }
4350 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator!=(v); }
4351 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator> (v); }
4352 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator< (v); }
4353 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator>=(v); }
4354 template<typename IntegralType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const IntegralType& u, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(u).operator<=(v); }
4355
4356#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
4357 // Non-member comparison functions of (uintwide_t cmp FloatingPointType).
4358 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return u.operator==(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4359 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return u.operator!=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4360 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return u.operator> (uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4361 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return u.operator< (uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4362 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return u.operator>=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4363 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& u, const FloatingPointType& f) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return u.operator<=(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f)); }
4364
4365 // Non-member comparison functions of (FloatingPointType cmp uintwide_t).
4366 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator==(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator==(v); }
4367 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator!=(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator!=(v); }
4368 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator> (const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator> (v); }
4369 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator< (const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator< (v); }
4370 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator>=(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator>=(v); }
4371 template<typename FloatingPointType, const size_t Width2, typename LimbType, typename AllocatorType, const bool IsSigned> constexpr auto operator<=(const FloatingPointType& f, const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& v) -> typename std::enable_if<std::is_floating_point<FloatingPointType>::value, bool>::type { return uintwide_t<Width2, LimbType, AllocatorType, IsSigned>(f).operator<=(v); }
4372#endif // !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
4373
4374#if !defined(WIDE_INTEGER_DISABLE_IOSTREAM)
4375
4376 // I/O streaming functions.
4377 template<typename char_type,
4378 typename traits_type,
4379 const size_t Width2,
4380 typename LimbType,
4381 typename AllocatorType,
4382 const bool IsSigned>
4383 auto operator<<(std::basic_ostream<char_type, traits_type>& out,
4384 const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x) -> std::basic_ostream<char_type, traits_type> &
4385 {
4386 std::basic_ostringstream<char_type, traits_type> ostr;
4387
4388 const std::ios::fmtflags my_flags = out.flags();
4389
4390 const bool show_pos = ((my_flags & std::ios::showpos) == std::ios::showpos);
4391 const bool show_base = ((my_flags & std::ios::showbase) == std::ios::showbase);
4392 const bool is_uppercase = ((my_flags & std::ios::uppercase) == std::ios::uppercase);
4393
4394 std::uint_fast8_t base_rep{ };
4395
4396 if ((my_flags & std::ios::oct) == std::ios::oct) { base_rep = UINT8_C(8); }
4397 else if ((my_flags & std::ios::hex) == std::ios::hex) { base_rep = UINT8_C(16); }
4398 else { base_rep = UINT8_C(10); }
4399
4400 const auto field_width = static_cast<unsigned_fast_type>(out.width());
4401 const auto fill_char = static_cast<char>(out.fill());
4402
4403 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4404
4405 if (base_rep == UINT8_C(8))
4406 {
4407 using string_storage_oct_type =
4408 typename std::conditional
4409 <local_wide_integer_type::my_width2 <= static_cast<size_t>(UINT32_C(2048)),
4410 detail::fixed_static_array <char,
4411 local_wide_integer_type::wr_string_max_buffer_size_oct>,
4412 detail::fixed_dynamic_array<char,
4413 local_wide_integer_type::wr_string_max_buffer_size_oct,
4414 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
4415 std::allocator<void>,
4416 AllocatorType>::type>::template rebind_alloc<typename local_wide_integer_type::limb_type>>
4417 >::type;
4418
4419 // TBD: There is redundant storage of this kind both here
4420 // in this subroutine as well as in the wr_string method.
4421 string_storage_oct_type str_result;
4422
4423 str_result.fill(static_cast<char>('\0'));
4424
4425 x.wr_string(str_result.data(), base_rep, show_base, show_pos, is_uppercase, field_width, fill_char);
4426
4427 static_cast<void>(ostr << str_result.data());
4428 }
4429 else if (base_rep == UINT8_C(10))
4430 {
4431 using string_storage_dec_type =
4432 typename std::conditional
4433 <local_wide_integer_type::my_width2 <= static_cast<size_t>(UINT32_C(2048)),
4434 detail::fixed_static_array <char,
4435 local_wide_integer_type::wr_string_max_buffer_size_dec>,
4436 detail::fixed_dynamic_array<char,
4437 local_wide_integer_type::wr_string_max_buffer_size_dec,
4438 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
4439 std::allocator<void>,
4440 AllocatorType>::type>::template rebind_alloc<typename local_wide_integer_type::limb_type>>
4441 >::type;
4442
4443 // TBD: There is redundant storage of this kind both here
4444 // in this subroutine as well as in the wr_string method.
4445 string_storage_dec_type str_result;
4446
4447 str_result.fill(static_cast<char>('\0'));
4448
4449 x.wr_string(str_result.data(), base_rep, show_base, show_pos, is_uppercase, field_width, fill_char);
4450
4451 static_cast<void>(ostr << str_result.data());
4452 }
4453 else if (base_rep == UINT8_C(16))
4454 {
4455 using string_storage_hex_type =
4456 typename std::conditional
4457 <local_wide_integer_type::my_width2 <= static_cast<size_t>(UINT32_C(2048)),
4458 detail::fixed_static_array <char,
4459 local_wide_integer_type::wr_string_max_buffer_size_hex>,
4460 detail::fixed_dynamic_array<char,
4461 local_wide_integer_type::wr_string_max_buffer_size_hex,
4462 typename std::allocator_traits<typename std::conditional<std::is_same<AllocatorType, void>::value,
4463 std::allocator<void>,
4464 AllocatorType>::type>::template rebind_alloc<typename local_wide_integer_type::limb_type>>
4465 >::type;
4466
4467 // TBD: There is redundant storage of this kind both here
4468 // in this subroutine as well as in the wr_string method.
4469 string_storage_hex_type str_result;
4470
4471 str_result.fill(static_cast<char>('\0'));
4472
4473 x.wr_string(str_result.data(), base_rep, show_base, show_pos, is_uppercase, field_width, fill_char);
4474
4475 static_cast<void>(ostr << str_result.data());
4476 }
4477
4478 return (out << ostr.str());
4479 }
4480
4481 template<typename char_type,
4482 typename traits_type,
4483 const size_t Width2,
4484 typename LimbType,
4485 typename AllocatorType,
4486 const bool IsSigned>
4487 auto operator>>(std::basic_istream<char_type, traits_type>& in,
4488 uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x) -> std::basic_istream<char_type, traits_type> &
4489 {
4490 std::string str_in;
4491
4492 in >> str_in;
4493
4494 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4495
4496 x = local_wide_integer_type(str_in.c_str());
4497
4498 return in;
4499 }
4500
4501#endif // !defined(WIDE_INTEGER_DISABLE_IOSTREAM)
4502
4503#if(__cplusplus >= 201703L)
4504 } // namespace math::wide_integer
4505#else
4506} // namespace wide_integer
4507} // namespace math
4508#endif
4509
4510// Implement various number-theoretical tools.
4511
4512#if(__cplusplus >= 201703L)
4513namespace math::wide_integer {
4514#else
4515namespace math {
4516 namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces)
4517#endif
4518
4519 namespace detail {
4520
4521#if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
4522 namespace my_own {
4523
4524 template<typename FloatingPointType> WIDE_INTEGER_CONSTEXPR auto frexp(FloatingPointType x, int* expptr) -> typename std::enable_if<((std::is_floating_point<FloatingPointType>::value) && (std::numeric_limits<FloatingPointType>::is_iec559)), FloatingPointType>::type
4525 {
4526 using local_floating_point_type = FloatingPointType;
4527
4528 const bool x_is_neg = (x < static_cast<local_floating_point_type>(0.0L));
4529
4530 local_floating_point_type f = (x_is_neg ? -x : x);
4531
4532 int e2 = 0;
4533
4534 constexpr long double two_pow32 =
4535 static_cast<long double>(0x10000) * static_cast<long double>(0x10000);
4536
4537 while (f >= static_cast<local_floating_point_type>(two_pow32)) // NOLINT(altera-id-dependent-backward-branch)
4538 {
4539 // TBD: Maybe optimize this exponent reduction
4540 // with a more clever kind of binary searching.
4541
4542 f = static_cast<local_floating_point_type>(f / static_cast<local_floating_point_type>(two_pow32));
4543 e2 += static_cast<int>(INT32_C(32));
4544 }
4545
4546 constexpr long double one_ldbl(1.0L);
4547
4548 while (f >= static_cast<local_floating_point_type>(one_ldbl)) // NOLINT(altera-id-dependent-backward-branch)
4549 {
4550 constexpr long double two_ldbl(2.0L);
4551
4552 f = static_cast<local_floating_point_type>(f / static_cast<local_floating_point_type>(two_ldbl));
4553
4554 ++e2;
4555 }
4556
4557 if (expptr != nullptr)
4558 {
4559 *expptr = e2;
4560 }
4561
4562 return ((!x_is_neg) ? f : -f);
4563 }
4564
4565 template<typename FloatingPointType> WIDE_INTEGER_CONSTEXPR auto frexp(FloatingPointType x, int* expptr) -> typename std::enable_if<((std::is_floating_point<FloatingPointType>::value) && (!std::numeric_limits<FloatingPointType>::is_iec559)), FloatingPointType>::type
4566 {
4567 using std::frexp;
4568
4569 return frexp(x, expptr);
4570 }
4571
4572 template<typename FloatingPointType> WIDE_INTEGER_CONSTEXPR auto isfinite(FloatingPointType x) -> typename std::enable_if<((std::is_floating_point<FloatingPointType>::value) && (std::numeric_limits<FloatingPointType>::is_iec559)), bool>::type
4573 {
4574 using local_floating_point_type = FloatingPointType;
4575
4576 bool x_is_finite = true;
4577
4578 const bool x_is_nan = (x != x);
4579
4580 if (x_is_nan)
4581 {
4582 x_is_finite = false;
4583 }
4584 else
4585 {
4586 const bool x_is_inf_pos = (x > (std::numeric_limits<local_floating_point_type>::max)());
4587 const bool x_is_inf_neg = (x < (std::numeric_limits<local_floating_point_type>::lowest)());
4588
4589 if (x_is_inf_pos || x_is_inf_neg)
4590 {
4591 x_is_finite = false;
4592 }
4593 }
4594
4595 return x_is_finite;
4596 }
4597
4598 template<typename FloatingPointType> WIDE_INTEGER_CONSTEXPR auto isfinite(FloatingPointType x) -> typename std::enable_if<((std::is_floating_point<FloatingPointType>::value) && (!std::numeric_limits<FloatingPointType>::is_iec559)), bool>::type
4599 {
4600 using std::isfinite;
4601
4602 return isfinite(x);
4603 }
4604 } // namespace my_own
4605#endif // !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP)
4606
4607 template<typename UnsignedIntegralType>
4608 inline WIDE_INTEGER_CONSTEXPR auto lsb_helper(const UnsignedIntegralType& u) -> unsigned_fast_type
4609 {
4610 // Compile-time checks.
4611 static_assert(((std::is_integral<UnsignedIntegralType>::value)
4612 && (std::is_unsigned<UnsignedIntegralType>::value)),
4613 "Error: Please check the characteristics of UnsignedIntegralType");
4614
4615 unsigned_fast_type result = 0U;
4616
4617 UnsignedIntegralType mask(u);
4618
4619 // This assumes that at least one bit is set.
4620 // Otherwise saturation of the index will occur.
4621
4622 // Naive and basic LSB search.
4623 // TBD: This could be improved with a binary search
4624 // on the lowest bit position of the fundamental type.
4625 while (static_cast<std::uint_fast8_t>(static_cast<std::uint_fast8_t>(mask) & UINT8_C(1)) == UINT8_C(0)) // NOLINT(hicpp-signed-bitwise,altera-id-dependent-backward-branch)
4626 {
4627 mask >>= 1U;
4628
4629 ++result;
4630 }
4631
4632 return result;
4633 }
4634
4635 template<typename UnsignedIntegralType>
4636 inline WIDE_INTEGER_CONSTEXPR auto msb_helper(const UnsignedIntegralType& u) -> unsigned_fast_type
4637 {
4638 // Compile-time checks.
4639 static_assert(((std::is_integral<UnsignedIntegralType>::value)
4640 && (std::is_unsigned<UnsignedIntegralType>::value)),
4641 "Error: Please check the characteristics of UnsignedIntegralType");
4642
4643 using local_unsigned_integral_type = UnsignedIntegralType;
4644
4645 signed_fast_type i{ };
4646
4647 // TBD: This could potentially be improved with a binary
4648 // search for the highest bit position in the type.
4649
4650 for (i = static_cast<signed_fast_type>(std::numeric_limits<local_unsigned_integral_type>::digits - 1); i >= 0; --i)
4651 {
4652 if ((u & static_cast<local_unsigned_integral_type>(static_cast<local_unsigned_integral_type>(1U) << i)) != 0U)
4653 {
4654 break;
4655 }
4656 }
4657
4658 return static_cast<unsigned_fast_type>((std::max)(static_cast<signed_fast_type>(0), i));
4659 }
4660
4661 template<>
4662 inline WIDE_INTEGER_CONSTEXPR auto msb_helper<std::uint32_t>(const std::uint32_t& u) -> unsigned_fast_type
4663 {
4664 auto r = static_cast<unsigned_fast_type>(0U);
4665 auto x = static_cast<std::uint_fast32_t>(u);
4666
4667 // Use O(log2[N]) binary-halving in an unrolled loop to find the msb.
4668 if ((x & UINT32_C(0xFFFF0000)) != UINT32_C(0)) { x = static_cast<std::uint_fast32_t>(x >> static_cast<unsigned>(UINT8_C(16))); r = static_cast<unsigned_fast_type>(r | UINT32_C(16)); }
4669 if ((x & UINT32_C(0x0000FF00)) != UINT32_C(0)) { x = static_cast<std::uint_fast32_t>(x >> static_cast<unsigned>(UINT8_C(8))); r = static_cast<unsigned_fast_type>(r | UINT32_C(8)); }
4670 if ((x & UINT32_C(0x000000F0)) != UINT32_C(0)) { x = static_cast<std::uint_fast32_t>(x >> static_cast<unsigned>(UINT8_C(4))); r = static_cast<unsigned_fast_type>(r | UINT32_C(4)); }
4671 if ((x & UINT32_C(0x0000000C)) != UINT32_C(0)) { x = static_cast<std::uint_fast32_t>(x >> static_cast<unsigned>(UINT8_C(2))); r = static_cast<unsigned_fast_type>(r | UINT32_C(2)); }
4672 if ((x & UINT32_C(0x00000002)) != UINT32_C(0)) { r = static_cast<unsigned_fast_type>(r | UINT32_C(1)); }
4673
4674 return r;
4675 }
4676
4677 template<>
4678 inline WIDE_INTEGER_CONSTEXPR auto msb_helper<std::uint16_t>(const std::uint16_t& u) -> unsigned_fast_type
4679 {
4680 auto r = static_cast<unsigned_fast_type>(0U);
4681 auto x = static_cast<std::uint_fast16_t>(u);
4682
4683 // Use O(log2[N]) binary-halving in an unrolled loop to find the msb.
4684 if (static_cast<std::uint_fast16_t>(static_cast<std::uint_fast32_t>(x) & UINT32_C(0xFF00)) != UINT16_C(0)) { x = static_cast<std::uint_fast16_t>(x >> static_cast<unsigned>(UINT8_C(8))); r = static_cast<unsigned_fast_type>(r | UINT32_C(8)); }
4685 if (static_cast<std::uint_fast16_t>(static_cast<std::uint_fast32_t>(x) & UINT32_C(0x00F0)) != UINT16_C(0)) { x = static_cast<std::uint_fast16_t>(x >> static_cast<unsigned>(UINT8_C(4))); r = static_cast<unsigned_fast_type>(r | UINT32_C(4)); }
4686 if (static_cast<std::uint_fast16_t>(static_cast<std::uint_fast32_t>(x) & UINT32_C(0x000C)) != UINT16_C(0)) { x = static_cast<std::uint_fast16_t>(x >> static_cast<unsigned>(UINT8_C(2))); r = static_cast<unsigned_fast_type>(r | UINT32_C(2)); }
4687 if (static_cast<std::uint_fast16_t>(static_cast<std::uint_fast32_t>(x) & UINT32_C(0x0002)) != UINT16_C(0)) { r = static_cast<unsigned_fast_type>(r | UINT32_C(1)); }
4688
4689 return r;
4690 }
4691
4692 template<>
4693 inline WIDE_INTEGER_CONSTEXPR auto msb_helper<std::uint8_t>(const std::uint8_t& u) -> unsigned_fast_type
4694 {
4695 auto r = static_cast<unsigned_fast_type>(0U);
4696 auto x = static_cast<std::uint_fast8_t>(u);
4697
4698 // Use O(log2[N]) binary-halving in an unrolled loop to find the msb.
4699 if (static_cast<std::uint_fast8_t>(static_cast<std::uint_fast32_t>(x) & UINT32_C(0xF0)) != UINT8_C(0)) { x = static_cast<std::uint_fast8_t>(x >> static_cast<unsigned>(UINT8_C(4))); r = static_cast<unsigned_fast_type>(r | UINT32_C(4)); }
4700 if (static_cast<std::uint_fast8_t>(static_cast<std::uint_fast32_t>(x) & UINT32_C(0x0C)) != UINT8_C(0)) { x = static_cast<std::uint_fast8_t>(x >> static_cast<unsigned>(UINT8_C(2))); r = static_cast<unsigned_fast_type>(r | UINT32_C(2)); }
4701 if (static_cast<std::uint_fast8_t>(static_cast<std::uint_fast32_t>(x) & UINT32_C(0x02)) != UINT8_C(0)) { r = static_cast<unsigned_fast_type>(r | UINT32_C(1)); }
4702
4703 return r;
4704 }
4705
4706 } // namespace detail
4707
4708 template<const size_t Width2,
4709 typename LimbType,
4710 typename AllocatorType,
4711 const bool IsSigned>
4712 WIDE_INTEGER_CONSTEXPR void swap(uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x,
4713 uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& y)
4714 {
4715 if (&x != &y)
4716 {
4717 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4718
4719 const local_wide_integer_type tmp_x(x);
4720
4721 x = y;
4722 y = tmp_x;
4723 }
4724 }
4725
4726 template<const size_t Width2,
4727 typename LimbType,
4728 typename AllocatorType,
4729 const bool IsSigned>
4730 inline WIDE_INTEGER_CONSTEXPR auto lsb(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x) -> unsigned_fast_type
4731 {
4732 // Calculate the position of the least-significant bit.
4733 // Use a linear search starting from the least significant limbs.
4734
4735 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4736 using local_value_type = typename local_wide_integer_type::representation_type::value_type;
4737
4738 auto bpos = static_cast<unsigned_fast_type>(0U);
4739 auto offset = static_cast<unsigned_fast_type>(0U);
4740
4741 for (auto it = x.crepresentation().cbegin(); it != x.crepresentation().cend(); ++it, ++offset) // NOLINT(llvm-qualified-auto,readability-qualified-auto,altera-id-dependent-backward-branch)
4742 {
4743 const auto vi = static_cast<local_value_type>(*it & (std::numeric_limits<local_value_type>::max)());
4744
4745 if (vi != static_cast<local_value_type>(0U))
4746 {
4747 bpos = static_cast<unsigned_fast_type>
4748 (
4749 detail::lsb_helper(*it)
4750 + static_cast<unsigned_fast_type>(static_cast<unsigned_fast_type>(std::numeric_limits<local_value_type>::digits) * offset)
4751 );
4752
4753 break;
4754 }
4755 }
4756
4757 return bpos;
4758 }
4759
4760 template<const size_t Width2,
4761 typename LimbType,
4762 typename AllocatorType,
4763 const bool IsSigned>
4764 WIDE_INTEGER_CONSTEXPR auto msb(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x) -> unsigned_fast_type
4765 {
4766 // Calculate the position of the most-significant bit.
4767 // Use a linear search starting from the most significant limbs.
4768
4769 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4770 using local_value_type = typename local_wide_integer_type::representation_type::value_type;
4771
4772 auto bpos = static_cast<unsigned_fast_type>(0U);
4773 auto offset = static_cast<unsigned_fast_type>(x.crepresentation().size() - 1U);
4774
4775 for (auto ri = x.crepresentation().crbegin(); ri != x.crepresentation().crend(); ++ri, --offset) // NOLINT(altera-id-dependent-backward-branch)
4776 {
4777 const auto vr = static_cast<local_value_type>(*ri & (std::numeric_limits<local_value_type>::max)());
4778
4779 if (vr != static_cast<local_value_type>(0U))
4780 {
4781 bpos = static_cast<unsigned_fast_type>
4782 (
4783 detail::msb_helper(*ri)
4784 + static_cast<unsigned_fast_type>(static_cast<unsigned_fast_type>(std::numeric_limits<local_value_type>::digits) * offset)
4785 );
4786
4787 break;
4788 }
4789 }
4790
4791 return bpos;
4792 }
4793
4794 template<const size_t Width2,
4795 typename LimbType,
4796 typename AllocatorType,
4797 const bool IsSigned>
4798 constexpr auto abs(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& x) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned>
4799 {
4800 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4801
4802 return ((!local_wide_integer_type::is_neg(x)) ? x : -x);
4803 }
4804
4805 template<const size_t Width2,
4806 typename LimbType,
4807 typename AllocatorType,
4808 const bool IsSigned>
4809 WIDE_INTEGER_CONSTEXPR auto sqrt(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& m) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned>
4810 {
4811 // Calculate the square root.
4812
4813 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4814
4815 local_wide_integer_type s;
4816
4817 if (m.is_zero() || local_wide_integer_type::is_neg(m))
4818 {
4819 s = local_wide_integer_type(static_cast<std::uint_fast8_t>(0U));
4820 }
4821 else
4822 {
4823 // Obtain the initial guess via algorithms
4824 // involving the position of the msb.
4825 const unsigned_fast_type msb_pos = msb(m);
4826
4827 // Obtain the initial value.
4828 const unsigned_fast_type left_shift_amount =
4829 ((static_cast<unsigned_fast_type>(msb_pos % 2U) == 0U)
4830 ? static_cast<unsigned_fast_type>(1U + static_cast<unsigned_fast_type>((msb_pos + 0U) / 2U))
4831 : static_cast<unsigned_fast_type>(1U + static_cast<unsigned_fast_type>((msb_pos + 1U) / 2U)));
4832
4833 local_wide_integer_type
4834 u
4835 (
4836 local_wide_integer_type(static_cast<std::uint_fast8_t>(1U)) << left_shift_amount
4837 );
4838
4839 // Perform the iteration for the square root.
4840 // See Algorithm 1.13 SqrtInt, Sect. 1.5.1
4841 // in R.P. Brent and Paul Zimmermann, "Modern Computer Arithmetic",
4842 // Cambridge University Press, 2011.
4843
4844 for (auto i = static_cast<unsigned_fast_type>(0U); i < static_cast<unsigned_fast_type>(UINT8_C(64)); ++i)
4845 {
4846 s = u;
4847
4848 u = (s + (m / s)) >> 1;
4849
4850 if (u >= s)
4851 {
4852 break;
4853 }
4854 }
4855 }
4856
4857 return s;
4858 }
4859
4860 template<const size_t Width2,
4861 typename LimbType,
4862 typename AllocatorType,
4863 const bool IsSigned>
4864 WIDE_INTEGER_CONSTEXPR auto cbrt(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& m) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned> // NOLINT(misc-no-recursion)
4865 {
4866 // Calculate the cube root.
4867
4868 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4869
4870 local_wide_integer_type s;
4871
4872 if (local_wide_integer_type::is_neg(m))
4873 {
4874 s = -cbrt(-m);
4875 }
4876 else if (m.is_zero())
4877 {
4878 s = local_wide_integer_type(static_cast<std::uint_fast8_t>(0U));
4879 }
4880 else
4881 {
4882 // Obtain the initial guess via algorithms
4883 // involving the position of the msb.
4884 const unsigned_fast_type msb_pos = msb(m);
4885
4886 // Obtain the initial value.
4887 const auto msb_pos_mod_3 = static_cast<unsigned_fast_type>(msb_pos % UINT8_C(3));
4888
4889 const unsigned_fast_type left_shift_amount =
4890 ((msb_pos_mod_3 == 0U)
4891 ? static_cast<unsigned_fast_type>(1U + static_cast<unsigned_fast_type>((msb_pos + 0U) / 3U))
4892 : static_cast<unsigned_fast_type>(1U + static_cast<unsigned_fast_type>((msb_pos + (3U - msb_pos_mod_3)) / 3U)));
4893
4894 local_wide_integer_type u(local_wide_integer_type(static_cast<std::uint_fast8_t>(1U)) << left_shift_amount);
4895
4896 // Perform the iteration for the k'th root.
4897 // See Algorithm 1.14 RootInt, Sect. 1.5.2
4898 // in R.P. Brent and Paul Zimmermann, "Modern Computer Arithmetic",
4899 // Cambridge University Press, 2011.
4900
4901 const auto three_minus_one = static_cast<unsigned_fast_type>(3U - 1U);
4902
4903 for (auto i = static_cast<unsigned_fast_type>(0U); i < static_cast<unsigned_fast_type>(UINT8_C(64)); ++i)
4904 {
4905 s = u;
4906
4907 local_wide_integer_type m_over_s_pow_3_minus_one = m;
4908
4909 for (unsigned_fast_type j = 0U; j < 3U - 1U; ++j)
4910 {
4911 // Use a loop here to divide by s^(3 - 1) because
4912 // without a loop, s^(3 - 1) is likely to overflow.
4913
4914 m_over_s_pow_3_minus_one /= s;
4915 }
4916
4917 u = ((s * three_minus_one) + m_over_s_pow_3_minus_one) / 3U;
4918
4919 if (u >= s)
4920 {
4921 break;
4922 }
4923 }
4924 }
4925
4926 return s;
4927 }
4928
4929 template<const size_t Width2,
4930 typename LimbType,
4931 typename AllocatorType,
4932 const bool IsSigned>
4933 WIDE_INTEGER_CONSTEXPR auto rootk(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& m, const std::uint_fast8_t k) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned>
4934 {
4935 // Calculate the k'th root.
4936
4937 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
4938
4939 local_wide_integer_type s;
4940
4941 if (k < 2U)
4942 {
4943 s = m;
4944 }
4945 else if (k == 2U)
4946 {
4947 s = sqrt(m);
4948 }
4949 else if (k == 3U)
4950 {
4951 s = cbrt(m);
4952 }
4953 else
4954 {
4955 if (m.is_zero() || local_wide_integer_type::is_neg(m))
4956 {
4957 s = local_wide_integer_type(static_cast<std::uint_fast8_t>(0U));
4958 }
4959 else
4960 {
4961 // Obtain the initial guess via algorithms
4962 // involving the position of the msb.
4963 const unsigned_fast_type msb_pos = msb(m);
4964
4965 // Obtain the initial value.
4966 const unsigned_fast_type msb_pos_mod_k = msb_pos % k;
4967
4968 const unsigned_fast_type left_shift_amount =
4969 ((msb_pos_mod_k == 0U)
4970 ? 1U + static_cast<unsigned_fast_type>((msb_pos + 0U) / k)
4971 : 1U + static_cast<unsigned_fast_type>((msb_pos + (k - msb_pos_mod_k)) / k));
4972
4973 local_wide_integer_type u(local_wide_integer_type(static_cast<std::uint_fast8_t>(1U)) << left_shift_amount);
4974
4975 // Perform the iteration for the k'th root.
4976 // See Algorithm 1.14 RootInt, Sect. 1.5.2
4977 // in R.P. Brent and Paul Zimmermann, "Modern Computer Arithmetic",
4978 // Cambridge University Press, 2011.
4979
4980 const unsigned_fast_type k_minus_one(k - 1U);
4981
4982 for (auto i = static_cast<unsigned_fast_type>(0U); i < static_cast<unsigned_fast_type>(UINT8_C(64)); ++i)
4983 {
4984 s = u;
4985
4986 local_wide_integer_type m_over_s_pow_k_minus_one = m;
4987
4988 for (unsigned_fast_type j = 0U; j < k - 1U; ++j)
4989 {
4990 // Use a loop here to divide by s^(k - 1) because
4991 // without a loop, s^(k - 1) is likely to overflow.
4992
4993 m_over_s_pow_k_minus_one /= s;
4994 }
4995
4996 u = ((s * k_minus_one) + m_over_s_pow_k_minus_one) / k;
4997
4998 if (u >= s)
4999 {
5000 break;
5001 }
5002 }
5003 }
5004 }
5005
5006 return s;
5007 }
5008
5009 template<typename OtherIntegralTypeP,
5010 const size_t Width2,
5011 typename LimbType,
5012 typename AllocatorType,
5013 const bool IsSigned>
5014 WIDE_INTEGER_CONSTEXPR auto pow(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& b, const OtherIntegralTypeP& p) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned>
5015 {
5016 // Calculate (b ^ p).
5017 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
5018 using local_limb_type = typename local_wide_integer_type::limb_type;
5019
5020 local_wide_integer_type result;
5021 auto p0(static_cast<local_limb_type>(p));
5022
5023 if ((p0 == 0U) && (p == OtherIntegralTypeP(0)))
5024 {
5025 result = local_wide_integer_type(static_cast<std::uint8_t>(1U));
5026 }
5027 else if ((p0 == 1U) && (p == OtherIntegralTypeP(1)))
5028 {
5029 result = b;
5030 }
5031 else if ((p0 == 2U) && (p == OtherIntegralTypeP(2)))
5032 {
5033 result = b;
5034 result *= b;
5035 }
5036 else
5037 {
5038 result = local_wide_integer_type(static_cast<std::uint8_t>(1U));
5039
5040 local_wide_integer_type y(b);
5041 local_wide_integer_type p_local(p);
5042
5043 while (((p0 = static_cast<local_limb_type>(p_local)) != 0U) || (p_local != 0U)) // NOLINT(altera-id-dependent-backward-branch)
5044 {
5045 if ((p0 & 1U) != 0U)
5046 {
5047 result *= y;
5048 }
5049
5050 y *= y;
5051
5052 p_local >>= 1;
5053 }
5054 }
5055
5056 return result;
5057 }
5058
5059 template<typename OtherIntegralTypeP,
5060 typename OtherIntegralTypeM,
5061 const size_t Width2,
5062 typename LimbType,
5063 typename AllocatorType,
5064 const bool IsSigned>
5065 WIDE_INTEGER_CONSTEXPR auto powm(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& b,
5066 const OtherIntegralTypeP& p,
5067 const OtherIntegralTypeM& m) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned>
5068 {
5069 // Calculate (b ^ p) % m.
5070
5071 using local_normal_width_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
5072 using local_double_width_type = typename local_normal_width_type::double_width_type;
5073 using local_limb_type = typename local_normal_width_type::limb_type;
5074
5075 local_normal_width_type result;
5076 local_double_width_type y(b);
5077 const local_double_width_type m_local(m);
5078 auto p0(static_cast<local_limb_type>(p));
5079
5080 if ((p0 == 0U) && (p == OtherIntegralTypeP(0)))
5081 {
5082 result = local_normal_width_type((m != 1U) ? static_cast<std::uint8_t>(1U) : static_cast<std::uint8_t>(0U));
5083 }
5084 else if ((p0 == 1U) && (p == OtherIntegralTypeP(1)))
5085 {
5086 result = b % m;
5087 }
5088 else if ((p0 == 2U) && (p == OtherIntegralTypeP(2)))
5089 {
5090 y *= y;
5091 y %= m_local;
5092
5093 result = local_normal_width_type(y);
5094 }
5095 else
5096 {
5097 local_double_width_type x(static_cast<std::uint8_t>(1U));
5098 OtherIntegralTypeP p_local(p);
5099
5100 while (((p0 = static_cast<local_limb_type>(p_local)) != 0U) || (p_local != 0U)) // NOLINT(altera-id-dependent-backward-branch)
5101 {
5102 if ((p0 & 1U) != 0U)
5103 {
5104 x *= y;
5105 x %= m_local;
5106 }
5107
5108 y *= y;
5109 y %= m_local;
5110
5111 p_local >>= 1U; // NOLINT(hicpp-signed-bitwise)
5112 }
5113
5114 result = local_normal_width_type(x);
5115 }
5116
5117 return result;
5118 }
5119
5120 namespace detail {
5121
5122 template<typename UnsignedShortType>
5123 WIDE_INTEGER_CONSTEXPR auto integer_gcd_reduce_short(UnsignedShortType u, UnsignedShortType v) -> UnsignedShortType
5124 {
5125 // This implementation of GCD reduction is based on an
5126 // adaptation of existing code from Boost.Multiprecision.
5127
5128 for (;;)
5129 {
5130 if (u > v)
5131 {
5132 std::swap(u, v);
5133 }
5134
5135 if (u == v)
5136 {
5137 break;
5138 }
5139
5140 v -= u;
5141 v >>= detail::lsb_helper(v);
5142 }
5143
5144 return u;
5145 }
5146
5147 template<typename UnsignedLargeType>
5148 WIDE_INTEGER_CONSTEXPR auto integer_gcd_reduce_large(UnsignedLargeType u, UnsignedLargeType v) -> UnsignedLargeType
5149 {
5150 // This implementation of GCD reduction is based on an
5151 // adaptation of existing code from Boost.Multiprecision.
5152
5153 using local_ularge_type = UnsignedLargeType;
5154 using local_ushort_type = typename detail::uint_type_helper<static_cast<size_t>(std::numeric_limits<local_ularge_type>::digits / 2)>::exact_unsigned_type;
5155
5156 for (;;)
5157 {
5158 if (u > v)
5159 {
5160 std::swap(u, v);
5161 }
5162
5163 if (u == v)
5164 {
5165 break;
5166 }
5167
5168 if (v <= static_cast<local_ularge_type>((std::numeric_limits<local_ushort_type>::max)()))
5169 {
5170 u = integer_gcd_reduce_short(static_cast<local_ushort_type>(v),
5171 static_cast<local_ushort_type>(u));
5172
5173 break;
5174 }
5175
5176 v -= u;
5177
5178 while (static_cast<std::uint_fast8_t>(static_cast<std::uint_fast8_t>(v) & UINT8_C(1)) == UINT8_C(0)) // NOLINT(hicpp-signed-bitwise,altera-id-dependent-backward-branch)
5179 {
5180 v >>= 1U;
5181 }
5182 }
5183
5184 return u;
5185 }
5186
5187 } // namespace detail
5188
5189 template<const size_t Width2,
5190 typename LimbType,
5191 typename AllocatorType,
5192 const bool IsSigned>
5193 WIDE_INTEGER_CONSTEXPR auto gcd(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& a, // NOLINT(readability-function-cognitive-complexity,bugprone-easily-swappable-parameters)
5194 const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& b) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned>
5195 {
5196 // This implementation of GCD is an adaptation
5197 // of existing code from Boost.Multiprecision.
5198
5199 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
5200 using local_ushort_type = typename local_wide_integer_type::limb_type;
5201 using local_ularge_type = typename local_wide_integer_type::double_limb_type;
5202
5203 const bool u_is_neg = local_wide_integer_type::is_neg(a);
5204 const bool v_is_neg = local_wide_integer_type::is_neg(b);
5205
5206 local_wide_integer_type u((!u_is_neg) ? a : -a);
5207 local_wide_integer_type v((!v_is_neg) ? b : -b);
5208
5209 local_wide_integer_type result;
5210
5211 if (u == v)
5212 {
5213 // This handles cases having (u = v) and also (u = v = 0).
5214 result = u;
5215 }
5216
5217 if ((static_cast<local_ushort_type>(v) == 0U) && (v == 0U))
5218 {
5219 // This handles cases having (v = 0) with (u != 0).
5220 result = u;
5221 }
5222
5223 if ((static_cast<local_ushort_type>(u) == 0U) && (u == 0U))
5224 {
5225 // This handles cases having (u = 0) with (v != 0).
5226 result = v;
5227 }
5228 else
5229 {
5230 // Now we handle cases having (u != 0) and (v != 0).
5231
5232 // Let shift := lg K, where K is the greatest
5233 // power of 2 dividing both u and v.
5234
5235 const unsigned_fast_type u_shift = lsb(u);
5236 const unsigned_fast_type v_shift = lsb(v);
5237
5238 const unsigned_fast_type left_shift_amount = (std::min)(u_shift, v_shift);
5239
5240 u >>= u_shift;
5241 v >>= v_shift;
5242
5243 for (;;)
5244 {
5245 // Now u and v are both odd, so diff(u, v) is even.
5246 // Let u = min(u, v), v = diff(u, v) / 2.
5247
5248 if (u > v)
5249 {
5250 swap(u, v);
5251 }
5252
5253 if (u == v)
5254 {
5255 break;
5256 }
5257
5258 if (v <= (std::numeric_limits<local_ularge_type>::max)())
5259 {
5260 if (v <= (std::numeric_limits<local_ushort_type>::max)())
5261 {
5262 u = detail::integer_gcd_reduce_short(*(v.crepresentation().cbegin() + 0U),
5263 *(u.crepresentation().cbegin() + 0U));
5264 }
5265 else
5266 {
5267 const auto my_v_hi =
5268 static_cast<local_ushort_type>
5269 (
5270 (v.crepresentation().size() >= static_cast<typename local_wide_integer_type::representation_type::size_type>(2U))
5271 ? static_cast<local_ushort_type>(*(v.crepresentation().cbegin() + 1U))
5272 : static_cast<local_ushort_type>(0U)
5273 );
5274
5275 const auto my_u_hi =
5276 static_cast<local_ushort_type>
5277 (
5278 (u.crepresentation().size() >= static_cast<typename local_wide_integer_type::representation_type::size_type>(2U))
5279 ? static_cast<local_ushort_type>(*(u.crepresentation().cbegin() + 1U))
5280 : static_cast<local_ushort_type>(0U)
5281 );
5282
5283 const local_ularge_type v_large = detail::make_large(*(v.crepresentation().cbegin() + 0U), my_v_hi);
5284 const local_ularge_type u_large = detail::make_large(*(u.crepresentation().cbegin() + 0U), my_u_hi);
5285
5286 u = detail::integer_gcd_reduce_large(v_large, u_large);
5287 }
5288
5289 break;
5290 }
5291
5292 v -= u;
5293 v >>= lsb(v);
5294 }
5295
5296 result = (u << left_shift_amount);
5297 }
5298
5299 return ((u_is_neg == v_is_neg) ? result : -result);
5300 }
5301
5302 template<typename UnsignedShortType>
5303 WIDE_INTEGER_CONSTEXPR auto gcd(const UnsignedShortType& u, const UnsignedShortType& v) -> typename std::enable_if<((std::is_integral<UnsignedShortType>::value)
5304 && (std::is_unsigned<UnsignedShortType>::value)), UnsignedShortType>::type
5305 {
5306 UnsignedShortType result;
5307
5308 if (u > v)
5309 {
5310 result = gcd(v, u);
5311 }
5312
5313 if (u == v)
5314 {
5315 // This handles cases having (u = v) and also (u = v = 0).
5316 result = u;
5317 }
5318
5319 if (v == 0U)
5320 {
5321 // This handles cases having (v = 0) with (u != 0).
5322 result = u;
5323 }
5324
5325 if (u == 0U)
5326 {
5327 // This handles cases having (u = 0) with (v != 0).
5328 result = v;
5329 }
5330 else
5331 {
5332 result = detail::integer_gcd_reduce_short(u, v);
5333 }
5334
5335 return result;
5336 }
5337
5338 namespace detail {
5339
5340 template<typename IntegerType>
5341 WIDE_INTEGER_CONSTEXPR auto lcm_impl(const IntegerType& a, const IntegerType& b) -> IntegerType
5342 {
5343 using local_integer_type = IntegerType;
5344
5345 using std::abs;
5346
5347 const local_integer_type ap = abs(a);
5348 const local_integer_type bp = abs(b);
5349
5350 const bool a_is_greater_than_b = (ap > bp);
5351
5352 const local_integer_type gcd_of_ab = gcd(a, b);
5353
5354 return (a_is_greater_than_b ? ap * (bp / gcd_of_ab)
5355 : bp * (ap / gcd_of_ab));
5356 }
5357
5358 } // namespace detail
5359
5360 template<const size_t Width2,
5361 typename LimbType,
5362 typename AllocatorType,
5363 const bool IsSigned>
5364 WIDE_INTEGER_CONSTEXPR auto lcm(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& a,
5365 const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& b) -> uintwide_t<Width2, LimbType, AllocatorType, IsSigned>
5366 {
5367 return detail::lcm_impl(a, b);
5368 }
5369
5370 template<typename UnsignedShortType>
5371 WIDE_INTEGER_CONSTEXPR auto lcm(const UnsignedShortType& a, const UnsignedShortType& b) -> typename std::enable_if<((std::is_integral<UnsignedShortType>::value)
5372 && (std::is_unsigned<UnsignedShortType>::value)), UnsignedShortType>::type
5373 {
5374 return detail::lcm_impl(a, b);
5375 }
5376
5377 template<const size_t Width2,
5378 typename LimbType,
5379 typename AllocatorType,
5380 const bool IsSigned>
5381 class uniform_int_distribution
5382 {
5383 public:
5384 using result_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
5385
5387 {
5388 public:
5389 explicit param_type(result_type p_a = (std::numeric_limits<result_type>::min)(),
5390 result_type p_b = (std::numeric_limits<result_type>::max)())
5391 : param_a(std::move(p_a)),
5392 param_b(std::move(p_b)) { }
5393
5394 ~param_type() = default;
5395
5396 param_type(const param_type& other_params) : param_a(other_params.param_a),
5397 param_b(other_params.param_b) { }
5398
5399 param_type(param_type&& other_params) noexcept : param_a(other_params.param_a),
5400 param_b(other_params.param_b) { }
5401
5402 auto operator=(const param_type& other_params) -> param_type &
5403 {
5404 if (this != &other_params)
5405 {
5406 param_a = other_params.param_a;
5407 param_b = other_params.param_b;
5408 }
5409
5410 return *this;
5411 }
5412
5413 auto operator=(param_type&& other_params) noexcept -> param_type &
5414 {
5415 param_a = other_params.param_a;
5416 param_b = other_params.param_b;
5417
5418 return *this;
5419 }
5420
5421 WIDE_INTEGER_NODISCARD constexpr auto get_a() const -> result_type { return param_a; }
5422 WIDE_INTEGER_NODISCARD constexpr auto get_b() const -> result_type { return param_b; }
5423
5424 void set_a(const result_type& p_a) { param_a = p_a; }
5425 void set_b(const result_type& p_b) { param_b = p_b; }
5426
5427 private:
5428 result_type param_a; // NOLINT(readability-identifier-naming)
5429 result_type param_b; // NOLINT(readability-identifier-naming)
5430
5431 friend inline constexpr auto operator==(const param_type& lhs,
5432 const param_type& rhs) -> bool
5433 {
5434 return ((lhs.param_a == rhs.param_a)
5435 && (lhs.param_b == rhs.param_b));
5436 }
5437
5438 friend inline constexpr auto operator!=(const param_type& lhs,
5439 const param_type& rhs) -> bool
5440 {
5441 return ((lhs.param_a != rhs.param_a)
5442 || (lhs.param_b != rhs.param_b));
5443 }
5444 };
5445
5446 uniform_int_distribution() : my_params() { }
5447
5448 explicit uniform_int_distribution(const result_type& p_a,
5449 const result_type& p_b = (std::numeric_limits<result_type>::max)())
5450 : my_params(param_type(p_a, p_b)) { }
5451
5452 explicit uniform_int_distribution(const param_type& other_params)
5453 : my_params(other_params) { }
5454
5455 uniform_int_distribution(const uniform_int_distribution& other_distribution) = delete;
5456
5457 uniform_int_distribution(uniform_int_distribution&& other) noexcept : my_params(other.my_params) { }
5458
5459 ~uniform_int_distribution() = default;
5460
5461 auto operator=(const uniform_int_distribution& other) -> uniform_int_distribution &
5462 {
5463 if (this != &other)
5464 {
5465 my_params = other.my_params;
5466 }
5467
5468 return *this;
5469 }
5470
5471 auto operator=(uniform_int_distribution&& other) noexcept -> uniform_int_distribution &
5472 {
5473 my_params = other.my_params;
5474
5475 return *this;
5476 }
5477
5478 void param(const param_type& new_params)
5479 {
5480 my_params = new_params;
5481 }
5482
5483 WIDE_INTEGER_NODISCARD auto param() const -> const param_type & { return my_params; }
5484
5485 WIDE_INTEGER_NODISCARD auto a() const -> result_type { return my_params.get_a(); }
5486 WIDE_INTEGER_NODISCARD auto b() const -> result_type { return my_params.get_b(); }
5487
5488 template<typename GeneratorType,
5489 const int GeneratorResultBits = std::numeric_limits<typename GeneratorType::result_type>::digits>
5490 WIDE_INTEGER_CONSTEXPR auto operator()(GeneratorType & generator) -> result_type
5491 {
5492 return generate<GeneratorType, GeneratorResultBits>
5493 (
5494 generator,
5495 my_params
5496 );
5497 }
5498
5499 template<typename GeneratorType,
5500 const int GeneratorResultBits = std::numeric_limits<typename GeneratorType::result_type>::digits>
5501 WIDE_INTEGER_CONSTEXPR auto operator()(GeneratorType & input_generator,
5502 const param_type & input_params) -> result_type
5503 {
5504 return generate<GeneratorType, GeneratorResultBits>
5505 (
5506 input_generator,
5507 input_params
5508 );
5509 }
5510
5511 private:
5512 param_type my_params; // NOLINT(readability-identifier-naming)
5513
5514 template<typename GeneratorType,
5515 const int GeneratorResultBits = std::numeric_limits<typename GeneratorType::result_type>::digits>
5516 WIDE_INTEGER_CONSTEXPR auto generate(GeneratorType & input_generator,
5517 const param_type & input_params) const -> result_type
5518 {
5519 // Generate random numbers r, where a <= r <= b.
5520
5521 auto result = static_cast<result_type>(static_cast<std::uint8_t>(0U));
5522
5523 using local_limb_type = typename result_type::limb_type;
5524
5525 using generator_result_type = typename GeneratorType::result_type;
5526
5527 constexpr auto digits_generator_result_type = static_cast<std::uint32_t>(GeneratorResultBits);
5528
5529 static_assert((digits_generator_result_type % UINT32_C(8)) == UINT32_C(0),
5530 "Error: Generator result type must have a multiple of 8 bits.");
5531
5532 constexpr auto digits_limb_ratio =
5533 static_cast<std::uint32_t>(std::numeric_limits<local_limb_type>::digits / 8U);
5534
5535 constexpr auto digits_gtor_ratio = static_cast<std::uint32_t>(digits_generator_result_type / 8U);
5536
5537 generator_result_type value = generator_result_type();
5538
5539 auto it = result.representation().begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto)
5540
5541 unsigned_fast_type j = 0U;
5542
5543 while (it != result.representation().end()) // NOLINT(altera-id-dependent-backward-branch)
5544 {
5545 if ((j % digits_gtor_ratio) == 0U)
5546 {
5547 value = input_generator();
5548 }
5549
5550 const auto next_byte =
5551 static_cast<std::uint8_t>(value >> static_cast<unsigned>(static_cast<unsigned_fast_type>(j % digits_gtor_ratio) * static_cast<unsigned_fast_type>(UINT8_C(8))));
5552
5553 *it =
5554 static_cast<typename result_type::limb_type>
5555 (
5556 *it | static_cast<local_limb_type>(static_cast<local_limb_type>(next_byte) << static_cast<unsigned>(static_cast<unsigned_fast_type>(j % digits_limb_ratio) * static_cast<unsigned_fast_type>(UINT8_C(8))))
5557 );
5558
5559 ++j;
5560
5561 if (static_cast<unsigned_fast_type>(j % digits_limb_ratio) == static_cast<unsigned_fast_type>(0U))
5562 {
5563 ++it;
5564 }
5565 }
5566
5567 if ((input_params.get_a() != (std::numeric_limits<result_type>::min)())
5568 || (input_params.get_b() != (std::numeric_limits<result_type>::max)()))
5569 {
5570 // Note that this restricts the range r to:
5571 // r = {[input_generator() % ((b - a) + 1)] + a}
5572
5573 result_type range(input_params.get_b() - input_params.get_a());
5574
5575 ++range;
5576
5577 result %= range;
5578 result += input_params.get_a();
5579 }
5580
5581 return result;
5582 }
5583 };
5584
5585 template<const size_t Width2,
5586 typename LimbType,
5587 typename AllocatorType,
5588 const bool IsSigned>
5589 constexpr auto operator==(const uniform_int_distribution<Width2, LimbType, AllocatorType, IsSigned>& lhs,
5590 const uniform_int_distribution<Width2, LimbType, AllocatorType, IsSigned>& rhs) -> bool
5591 {
5592 return (lhs.param() == rhs.param());
5593 }
5594
5595 template<const size_t Width2,
5596 typename LimbType,
5597 typename AllocatorType,
5598 const bool IsSigned>
5599 constexpr auto operator!=(const uniform_int_distribution<Width2, LimbType, AllocatorType, IsSigned>& lhs,
5600 const uniform_int_distribution<Width2, LimbType, AllocatorType, IsSigned>& rhs) -> bool
5601 {
5602 return (lhs.param() != rhs.param());
5603 }
5604
5605 template<typename DistributionType,
5606 typename GeneratorType,
5607 const size_t Width2,
5608 typename LimbType,
5609 typename AllocatorType,
5610 const bool IsSigned>
5611 auto miller_rabin(const uintwide_t<Width2, LimbType, AllocatorType, IsSigned>& n, // NOLINT(readability-function-cognitive-complexity)
5612 const unsigned_fast_type number_of_trials,
5613 DistributionType& distribution,
5614 GeneratorType& generator) -> bool
5615 {
5616 // This Miller-Rabin primality test is loosely based on
5617 // an adaptation of some code from Boost.Multiprecision.
5618 // The Boost.Multiprecision code can be found here:
5619 // https://www.boost.org/doc/libs/1_76_0/libs/multiprecision/doc/html/boost_multiprecision/tut/primetest.html
5620
5621 // Note: Some comments in this subroutine use the Wolfram Language(TM).
5622 // These can be exercised at the web links to WolframAlpha(R) provided
5623
5624 using local_wide_integer_type = uintwide_t<Width2, LimbType, AllocatorType, IsSigned>;
5625 using local_limb_type = typename local_wide_integer_type::limb_type;
5626
5627 const local_wide_integer_type np((!local_wide_integer_type::is_neg(n)) ? n : -n);
5628
5629 {
5630 const auto n0 = static_cast<local_limb_type>(np);
5631
5632 if ((n0 & 1U) == 0U)
5633 {
5634 // Not prime because n is even.
5635 return false;
5636 }
5637
5638 if ((n0 <= static_cast<local_limb_type>(UINT8_C(227))) && (np <= static_cast<local_limb_type>(UINT8_C(227))))
5639 {
5640 if ((n0 == static_cast<local_limb_type>(UINT8_C(2))) && (np == static_cast<local_limb_type>(UINT8_C(2))))
5641 {
5642 // Trivial special case of (n = 2).
5643 return true;
5644 }
5645
5646 // Exclude pure small primes from 3...227.
5647 // Table[Prime[i], {i, 2, 49}] =
5648 // {
5649 // 3, 5, 7, 11, 13, 17, 19, 23,
5650 // 29, 31, 37, 41, 43, 47, 53, 59,
5651 // 61, 67, 71, 73, 79, 83, 89, 97,
5652 // 101, 103, 107, 109, 113, 127, 131, 137,
5653 // 139, 149, 151, 157, 163, 167, 173, 179,
5654 // 181, 191, 193, 197, 199, 211, 223, 227
5655 // }
5656 // See also:
5657 // https://www.wolframalpha.com/input/?i=Table%5BPrime%5Bi%5D%2C+%7Bi%2C+2%2C+49%7D%5D
5658
5659 constexpr std::array<local_limb_type, 48U> small_primes =
5660 { {
5661 UINT8_C(3), UINT8_C(5), UINT8_C(7), UINT8_C(11), UINT8_C(13), UINT8_C(17), UINT8_C(19), UINT8_C(23),
5662 UINT8_C(29), UINT8_C(31), UINT8_C(37), UINT8_C(41), UINT8_C(43), UINT8_C(47), UINT8_C(53), UINT8_C(59),
5663 UINT8_C(61), UINT8_C(67), UINT8_C(71), UINT8_C(73), UINT8_C(79), UINT8_C(83), UINT8_C(89), UINT8_C(97),
5664 UINT8_C(101), UINT8_C(103), UINT8_C(107), UINT8_C(109), UINT8_C(113), UINT8_C(127), UINT8_C(131), UINT8_C(137),
5665 UINT8_C(139), UINT8_C(149), UINT8_C(151), UINT8_C(157), UINT8_C(163), UINT8_C(167), UINT8_C(173), UINT8_C(179),
5666 UINT8_C(181), UINT8_C(191), UINT8_C(193), UINT8_C(197), UINT8_C(199), UINT8_C(211), UINT8_C(223), UINT8_C(227)
5667 } };
5668
5669 return std::binary_search(small_primes.cbegin(),
5670 small_primes.cend(),
5671 n0);
5672 }
5673 }
5674
5675 // Check small factors.
5676
5677 // Exclude small prime factors from { 3 ... 53 }.
5678 // Product[Prime[i], {i, 2, 16}] = 16294579238595022365
5679 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+2%2C+16%7D%5D
5680 {
5681 constexpr std::uint64_t pp0 = UINT64_C(16294579238595022365);
5682
5683 const auto m0 = static_cast<std::uint64_t>(np % pp0);
5684
5685 if (detail::integer_gcd_reduce_large(m0, pp0) != 1U)
5686 {
5687 return false;
5688 }
5689 }
5690
5691 // Exclude small prime factors from { 59 ... 101 }.
5692 // Product[Prime[i], {i, 17, 26}] = 7145393598349078859
5693 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+17%2C+26%7D%5D
5694 {
5695 constexpr std::uint64_t pp1 = UINT64_C(7145393598349078859);
5696
5697 const auto m1 = static_cast<std::uint64_t>(np % pp1);
5698
5699 if (detail::integer_gcd_reduce_large(m1, pp1) != 1U)
5700 {
5701 return false;
5702 }
5703 }
5704
5705 // Exclude small prime factors from { 103 ... 149 }.
5706 // Product[Prime[i], {i, 27, 35}] = 6408001374760705163
5707 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+27%2C+35%7D%5D
5708 {
5709 constexpr std::uint64_t pp2 = UINT64_C(6408001374760705163);
5710
5711 const auto m2 = static_cast<std::uint64_t>(np % pp2);
5712
5713 if (detail::integer_gcd_reduce_large(m2, pp2) != 1U)
5714 {
5715 return false;
5716 }
5717 }
5718
5719 // Exclude small prime factors from { 151 ... 191 }.
5720 // Product[Prime[i], {i, 36, 43}] = 690862709424854779
5721 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+36%2C+43%7D%5D
5722 {
5723 constexpr std::uint64_t pp3 = UINT64_C(690862709424854779);
5724
5725 const auto m3 = static_cast<std::uint64_t>(np % pp3);
5726
5727 if (detail::integer_gcd_reduce_large(m3, pp3) != 1U)
5728 {
5729 return false;
5730 }
5731 }
5732
5733 // Exclude small prime factors from { 193 ... 227 }.
5734 // Product[Prime[i], {i, 44, 49}] = 80814592450549
5735 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+44%2C+49%7D%5D
5736 {
5737 constexpr std::uint64_t pp4 = UINT64_C(80814592450549);
5738
5739 const auto m4 = static_cast<std::uint64_t>(np % pp4);
5740
5741 if (detail::integer_gcd_reduce_large(m4, pp4) != 1U)
5742 {
5743 return false;
5744 }
5745 }
5746
5747 const local_wide_integer_type nm1(np - 1U);
5748
5749 // Since we have already excluded all small factors
5750 // up to and including 227, n is greater than 227.
5751
5752 {
5753 // Perform a single Fermat test which will
5754 // exclude many non-prime candidates.
5755
5756 const local_wide_integer_type fn = powm(local_wide_integer_type(static_cast<local_limb_type>(228U)), nm1, np);
5757
5758 const auto fn0 = static_cast<local_limb_type>(fn);
5759
5760 if ((fn0 != 1U) && (fn != 1U))
5761 {
5762 return false;
5763 }
5764 }
5765
5766 const unsigned_fast_type k = lsb(nm1);
5767
5768 const local_wide_integer_type q = nm1 >> k;
5769
5770 using local_param_type = typename DistributionType::param_type;
5771
5772 const local_param_type params(local_wide_integer_type(2U), np - 2U);
5773
5774 bool is_probably_prime = true;
5775
5776 auto i = static_cast<unsigned_fast_type>(0U);
5777
5778 local_wide_integer_type x;
5779 local_wide_integer_type y;
5780
5781 // Execute the random trials.
5782 do
5783 {
5784 x = distribution(generator, params);
5785 y = powm(x, q, np);
5786
5787 auto j = static_cast<unsigned_fast_type>(0U);
5788
5789 while (y != nm1) // NOLINT(altera-id-dependent-backward-branch)
5790 {
5791 const local_limb_type y0(y);
5792
5793 if ((y0 == 1U) && (y == 1U))
5794 {
5795 if (j != 0U)
5796 {
5797 is_probably_prime = false;
5798 }
5799 else
5800 {
5801 break;
5802 }
5803 }
5804 else
5805 {
5806 ++j;
5807
5808 if (j == k)
5809 {
5810 is_probably_prime = false;
5811 }
5812 else
5813 {
5814 y = powm(y, 2U, np);
5815 }
5816 }
5817 }
5818
5819 ++i;
5820 } while ((i < number_of_trials) && is_probably_prime);
5821
5822 // The prime candidate is probably prime in the sense
5823 // of the very high probability resulting from Miller-Rabin.
5824 return is_probably_prime;
5825 }
5826
5827#if(__cplusplus >= 201703L)
5828 } // namespace math::wide_integer
5829#else
5830} // namespace wide_integer
5831} // namespace math
5832#endif
5833
5834WIDE_INTEGER_NAMESPACE_END
5835
5836#endif // UINTWIDE_T_2018_10_02_H
bool operator==(const Immediate &imm1, const Immediate &imm2)
Compares two Immediate.
std::ostream & operator<<(std::ostream &stream, BasicBlock &block)
Displays an BasicBlock.
bool operator!=(const Immediate &imm1, const Immediate &imm2)
Compares two Immediate.
bool operator<(const Immediate &imm1, const Immediate &imm2)
Compares two Immediate (needed for std::map)