• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stillwater-sc / universal / 30660486273

31 Jul 2026 07:48PM UTC coverage: 85.249% (+0.02%) from 85.229%
30660486273

push

github

web-flow
fix(integer): clear -Wsign-conversion in integer/primes/lns (#1283) (#1284)

* fix(integer): clear -Wsign-conversion in integer/primes/lns (#1283)

Sub-issue of Epic #1279 (-Wsign-conversion cleanup). All fixes are
value-preserving; each casts a value already proven non-negative /
in-range at the site, or replaces a signedness-changing literal.

integer_impl.hpp (shift operators <<=/>>=):
- guard the block-shift index arithmetic where int bitsToShift/blockShift
  mixes with unsigned bitsInBlock/nbits/MSU; bitsToShift is > 0 past the
  guards, so static_cast<unsigned> is exact
- upper-block mask now uses the shared bit_high_mask<bt>(#1261) helper,
  which also states the truncation explicitly (was a raw 64-bit literal
  shift that narrowed implicitly)
- assign(int64_t): low-bit test v & 0x1ull -> (v & 1) != 0; masking with a
  signed 1 keeps the operation in int64 (correct for negative v) instead
  of promoting v to uint64
- operator<<: width padding casts std::streamsize width (guarded
  width > s.size(), so positive) before subtracting the string size

primes.hpp: printPrimes column counter int -> size_t (compared against
size_t COL_WIDTH/PAGE_WIDTH).

lns_impl.hpp: setbit(i + shiftLeft) with shiftLeft used as a left-shift
count (>= 0 on this path) -> cast to unsigned.

Verified -Wsign-conversion clean for all three headers on gcc and clang;
no new -Wconversion introduced. integer shift_left/shift_right/division/
remainder and lns conversion regressions PASS on both compilers.

Relates to #1279

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(integer): address CodeRabbit review on #1283

- revert the unsigned-path low-bit test (convert_unsigned) to its original
  `v & 0x1ull`: `v` is uint64_t there, so it never triggered
  -Wsign-conversion; a global sed had changed it and attached a comment
  that (correctly, per review) described the signed path
- keep only the signed-path change (int64_t v) where the comment is accurate... (continued)

14 of 16 new or added lines in 2 files covered. (87.5%)

41698 of 48913 relevant lines covered (85.25%)

7267429.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.04
/include/sw/universal/number/integer/integer_impl.hpp
1
#pragma once
2
// integer_impl.hpp: implementation of a fixed-size arbitrary precision integer number
3
//
4
// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc.
5
//
6
// This file is part of the universal numbers project, which is released under an MIT Open Source license.
7
#include <string>
8
#include <sstream>
9
#include <iostream>
10
#include <iomanip>
11
#include <algorithm>
12
#include <string_view>
13
#include <type_traits>  // for std::is_constant_evaluated() dispatch around mul128/addcarry
14
#include <vector>
15

16
// supporting types and functions
17
#include <universal/number/shared/specific_value_encoding.hpp>
18
#include <universal/number/shared/blocktype.hpp>
19
#include <universal/native/integers.hpp> // just for printing native integers in binary form
20
#include <universal/internal/blocktype/carry.hpp> // carry-detection intrinsics for uint64_t limbs
21
#include <universal/utility/string_parse.hpp>   // shared constexpr scan_prefix / scan_sign / char classifiers
22

23
/*
24
the integer arithmetic can be configured to:
25
- throw exceptions on overflow
26
- throw exceptions on arithmetic
27
- throw exceptions on encoding errors for Whole and Natural Numbers
28

29
you need the exception types defined, but you have the option to throw them
30
 */
31
#include <universal/number/integer/exceptions.hpp>
32

33
 // composition types used by integer
34
#include <universal/number/support/decimal.hpp>
35
#include <universal/internal/blocktriple/blocktriple.hpp>
36

37
#include <universal/internal/bit_manipulation.hpp>
38

39
namespace sw { namespace universal {
40

41
enum class IntegerNumberType {
42
        IntegerNumber = 0,  // { ...,-3,-2,-1,0,1,2,3,... }
43
        WholeNumber   = 1,  // {              0,1,2,3,... }
44
        NaturalNumber = 2   // {                1,2,3,... }
45
};
46

47
constexpr IntegerNumberType IntegerNumber = IntegerNumberType::IntegerNumber;
48
constexpr IntegerNumberType WholeNumber = IntegerNumberType::WholeNumber;
49
constexpr IntegerNumberType NaturalNumber = IntegerNumberType::NaturalNumber;
50

51
// scale calculate the power of 2 exponent that would capture an approximation of a normalized real value
52
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
53
inline long scale(const integer<nbits, BlockType, NumberType>& i) {
128✔
54
        integer<nbits, BlockType, NumberType> v(i);
128✔
55
        if (i.sign()) { // special case handling
128✔
56
                v.twosComplement();
1✔
57
                if (v == i) {  // special case of 10000..... largest negative number in 2's complement encoding
1✔
58
                        return long(nbits - 1);
×
59
                }
60
        }
61
        // calculate scale
62
        long scale = 0;
128✔
63
        while (v > 1) {
8,256✔
64
                ++scale;
8,128✔
65
                v >>= 1;
8,128✔
66
        }
67
        return scale;
128✔
68
}
69

70
// signed integer conversion
71
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
72
inline constexpr integer<nbits, BlockType, NumberType>& convert(int64_t v, integer<nbits, BlockType, NumberType>& result) {        return result.convert(v); }
73
// unsigned integer conversion
74
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
75
inline constexpr integer<nbits, BlockType, NumberType>& convert(uint64_t v, integer<nbits, BlockType, NumberType>& result) { return result.convert(v); }
76

77
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
78
bool parse(const std::string& number, integer<nbits, BlockType, NumberType>& v);
79

80
// idiv_t for integer<nbits, BlockType, NumberType> to capture quotient and remainder during long division
81
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
82
struct idiv_t {
83
        constexpr idiv_t() : quot{ 0 }, rem{ 0 } {};
×
84
        integer<nbits, BlockType, NumberType> quot; // quotient
85
        integer<nbits, BlockType, NumberType> rem;  // remainder
86
};
87

88
/*
89
The rules for detecting overflow in a two's complement sum are simple:
90
 - If the sum of two positive numbers yields a negative result, the sum has overflowed.
91
 - If the sum of two negative numbers yields a positive result, the sum has overflowed.
92
 - Otherwise, the sum has not overflowed.
93
It is important to note the overflow and carry out can each occur without the other. 
94
In unsigned numbers, carry out is equivalent to overflow. In two's complement, carry out tells 
95
you nothing about overflow.
96

97
The reason for the rules is that overflow in two's complement occurs, not when a bit is carried out 
98
out of the left column, but when one is carried into it. That is, when there is a carry into the sign. 
99
The rules detect this error by examining the sign of the result. A negative and positive added together 
100
cannot overflow, because the sum is between the addends. Since both of the addends fit within the
101
allowable range of numbers, and their sum is between them, it must fit as well.
102

103
When implementing addition/subtraction on chuncks the overflow condition must be deduced from the 
104
chunk values. The chunks need to be interpreted as unsigned binary segments.
105
*/
106

107
// integer is an arbitrary fixed-sized 2's complement integer
108
template<unsigned _nbits, typename bt = std::uint8_t, IntegerNumberType _NumberType = IntegerNumberType::IntegerNumber>
109
class integer {
110
public:
111
        // cache template parameters
112
        static constexpr unsigned nbits = _nbits;
113
        typedef bt BlockType;
114
        static constexpr IntegerNumberType NumberType = _NumberType;
115
        // derive other parameters
116
        static constexpr unsigned bitsInByte = 8ull;
117
        static constexpr unsigned bitsInBlock = sizeof(bt) * bitsInByte;
118
        static constexpr unsigned nrBlocks = 1ull + ((nbits - 1ull) / bitsInBlock);
119
        static constexpr unsigned MSU = nrBlocks - 1ull;
120
        static constexpr bt       ALL_ONES = bt(~0); // block type specific all 1's value
121
        static constexpr unsigned bitSurplus = (nrBlocks * bitsInBlock - nbits);
122
        static constexpr unsigned bitsInMSU = bitsInBlock - bitSurplus;
123
        static constexpr bool     EXACT_FIT = (bitSurplus == 0);
124
        static constexpr unsigned signBitShift = (EXACT_FIT ? (bitsInBlock - 1) : bitsInMSU - 1);
125
        static constexpr bt       SIGN_BIT_MASK = bt(1ull << signBitShift);
126
        static constexpr bt       MSU_MASK = bt(ALL_ONES >> bitSurplus);
127
        static constexpr bt       SIGN_EXTENTION_BITS = static_cast<bt>(~MSU_MASK);
128
        static constexpr uint64_t storageMask = (uint64_t(~0) >> (64u - bitsInBlock));
129
        static constexpr uint64_t BASE = (ALL_ONES + 1ull);
130

131
        /// trivial constructor
132
        constexpr integer() noexcept = default;
133

134
        /// Construct a new integer from another, sign extend when necessary, BlockTypes must be the same
135
        template<unsigned srcbits>
136
        constexpr integer(const integer<srcbits, BlockType, NumberType>& a) {
2,128,154✔
137
//                static_assert(srcbits > nbits, "Source integer is bigger than target: potential loss of precision"); // TODO: do we want this?
138
                bitcopy(a);
2,128,154✔
139
                if constexpr (srcbits < nbits && NumberType == IntegerNumberType::IntegerNumber) {
140
                        if (a.sign()) { // sign extend
709,271✔
141
                                for (unsigned i = srcbits; i < nbits; ++i) {
523,734✔
142
                                        setbit(i);
261,867✔
143
                                }
144
                        }
145
                }
146
        }
2,128,154✔
147

148
        // initializers for native types
149
        constexpr integer(signed char initial_value)        noexcept { *this = initial_value; }
150
        constexpr integer(short initial_value)              noexcept { *this = initial_value; }
151
        constexpr integer(int initial_value)                noexcept { *this = initial_value; }
175,268,749✔
152
        constexpr integer(long initial_value)               noexcept { *this = initial_value; }
851,742✔
153
        constexpr integer(long long initial_value)          noexcept { *this = initial_value; }
37,526,865✔
154
        constexpr integer(char initial_value)               noexcept { *this = initial_value; }
155
        constexpr integer(unsigned short initial_value)     noexcept { *this = initial_value; }
156
        constexpr integer(unsigned int initial_value)       noexcept { *this = initial_value; }
104✔
157
        constexpr integer(unsigned long initial_value)      noexcept { *this = initial_value; }
368✔
158
        constexpr integer(unsigned long long initial_value) noexcept { *this = initial_value; }
12✔
159
        constexpr integer(float initial_value)              noexcept { *this = initial_value; }
20✔
160
        constexpr integer(double initial_value)             noexcept { *this = initial_value; }
100✔
161
        constexpr integer(long double initial_value)        noexcept { *this = initial_value; }
162

163
        // specific value constructors
164
        constexpr integer(const std::string& s) noexcept { assign(s); }
1✔
165
        constexpr integer(const SpecificValue code) noexcept
166
                : _block{ 0 } {
167
                switch (code) {
168
                case SpecificValue::maxpos:
169
                        maxpos();
170
                        break;
171
                case SpecificValue::minpos:
172
                        minpos();
173
                        break;
174
                case SpecificValue::zero:
175
                default:
176
                        zero();
177
                        break;
178
                case SpecificValue::minneg:
179
                        minneg();
180
                        break;
181
                case SpecificValue::maxneg:
182
                        maxneg();
183
                        break;
184
                case SpecificValue::infneg:
185
                case SpecificValue::infpos:
186
                case SpecificValue::qnan:
187
                case SpecificValue::snan:
188
                case SpecificValue::nar:
189
                        zero();
190
                        break;
191
                }
192
        }
193

194
        // access operator for bits
195
        // this needs a proxy to be able to create l-values
196
        // bool operator[](const unsigned int i) const //
197

198
        // simpler interface for now, using at(i) and set(i)/reset(i)
199

200
        // assignment operators for native types
201
        constexpr integer& operator=(signed char rhs)        { return convert_signed(rhs); }
202
        constexpr integer& operator=(short rhs)              { return convert_signed(rhs); }
203
        constexpr integer& operator=(int rhs)                { return convert_signed(rhs); }
180,485,119✔
204
        constexpr integer& operator=(long rhs)               { return convert_signed(rhs); }
2,788,399✔
205
        constexpr integer& operator=(long long rhs)          { return convert_signed(rhs); }
37,527,650✔
206
        constexpr integer& operator=(char rhs)               { return convert_unsigned(rhs); }
207
        constexpr integer& operator=(unsigned short rhs)     { return convert_unsigned(rhs); }
522,242✔
208
        constexpr integer& operator=(unsigned int rhs)       { return convert_unsigned(rhs); }
3,536✔
209
        constexpr integer& operator=(unsigned long rhs)      { return convert_unsigned(rhs); }
1,162✔
210
        constexpr integer& operator=(unsigned long long rhs) { return convert_unsigned(rhs); }
213✔
211
        constexpr integer& operator=(float rhs)              { return convert_ieee(rhs); }
24✔
212
        constexpr integer& operator=(double rhs)             { return convert_ieee(rhs); }
758✔
213
#if LONG_DOUBLE_SUPPORT
214
        constexpr integer& operator=(long double rhs)        { return convert_ieee(rhs); }
215
#endif
216

217
#ifdef ADAPTER_POSIT_AND_INTEGER
218
        // convenience assignment operator 
219
        template<unsigned nbits, unsigned es>
220
        integer& operator=(const posit<nbits, es>& rhs) {
221
                convert_p2i(rhs, *this);
222
                return *this;
223
        }
224
#endif // ADAPTER_POSIT_AND_INTEGER
225

226
        // prefix operators
227
        constexpr integer operator-() const {
667,396✔
228
                integer negated(*this);
667,396✔
229
                negated.flip();
667,396✔
230
                negated += 1;
667,396✔
231
                return negated;
667,396✔
232
        }
233
        // one's complement
234
        constexpr integer operator~() const {
235
                integer complement(*this);
236
                complement.flip();
237
                return complement;
238
        }
239
        // increment
240
        constexpr integer operator++(int) {
241
                integer tmp(*this);
242
                operator++();
243
                return tmp;
244
        }
245
        constexpr integer& operator++() {
95,956,076✔
246
                *this += integer(1);
95,956,076✔
247
                _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK); // assert precondition of properly nulled leading non-bits
95,956,076✔
248
                return *this;
95,956,076✔
249
        }
250
        // decrement
251
        constexpr integer operator--(int) {
252
                integer tmp(*this);
253
                operator--();
254
                return tmp;
255
        }
256
        constexpr integer& operator--() {
594✔
257
                *this -= integer(1);
594✔
258
                _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK); // assert precondition of properly nulled leading non-bits
594✔
259
                return *this;
594✔
260
        }
261

262
        // conversion operators
263
        explicit operator unsigned char()      const noexcept { return to_unsigned_integer<unsigned char>(); }
12✔
264
        explicit operator unsigned short()     const noexcept { return to_unsigned_integer<unsigned short>(); }
12✔
265
        explicit operator unsigned int()       const noexcept { return to_unsigned_integer<unsigned int>(); }
12✔
266
        explicit operator unsigned long()      const noexcept { return to_unsigned_integer<unsigned long>(); }
12✔
267
        explicit operator unsigned long long() const noexcept { return to_unsigned_integer<unsigned long long>(); }
268
        explicit operator signed char()        const noexcept { return to_integer<signed char>(); }
12✔
269
        explicit operator short()              const noexcept { return to_integer<short>(); }
12✔
270
        explicit operator int()                const noexcept { return to_integer<int>(); }
2,724,077✔
271
        explicit operator long()               const noexcept { return to_integer<long>(); }
2,341,023✔
272
        explicit operator long long()          const noexcept { return to_integer<long long>(); }
523✔
273
        explicit operator float()              const noexcept { return to_real<float>(); }
274
        explicit operator double()             const noexcept { return to_real<double>(); }
769✔
275
#if LONG_DOUBLE_SUPPORT
276
        explicit operator long double()        const noexcept { return to_real<long double>(); }
277
#endif
278

279
        // arithmetic operators
280
        constexpr integer& operator+=(const integer& rhs) {
301,681,208✔
281
                if constexpr (nrBlocks == 1) {
282
                        _block[0] = static_cast<bt>(_block[0] + rhs.block(0));
35,384,409✔
283
                        // null any leading bits that fall outside of nbits
284
                        _block[MSU] = static_cast<bt>(MSU_MASK & _block[MSU]);
35,384,409✔
285
                }
286
                else if constexpr (bitsInBlock == 64) {
287
                        // uint64_t limbs: addcarry uses platform intrinsics (not constexpr on MSVC).
288
                        // Dispatch to a portable carry path in constant-evaluated context.
289
                        integer<nbits, BlockType, NumberType> sum;
290
                        if (std::is_constant_evaluated()) {
1,165,996✔
291
                                uint64_t carry = 0;
×
292
                                for (unsigned i = 0; i < nrBlocks; ++i) {
×
293
                                        uint64_t a = _block[i];
×
294
                                        uint64_t b = rhs._block[i];
×
295
                                        uint64_t s1 = a + carry;
×
296
                                        uint64_t c1 = (s1 < a) ? 1ull : 0ull;
×
297
                                        uint64_t r  = s1 + b;
×
298
                                        uint64_t c2 = (r < s1) ? 1ull : 0ull;
×
299
                                        sum._block[i] = r;
×
300
                                        carry = c1 + c2;
×
301
                                }
302
                        }
303
                        else {
304
                                uint64_t carry = 0;
1,165,996✔
305
                                for (unsigned i = 0; i < nrBlocks; ++i) {
20,987,416✔
306
                                        sum._block[i] = addcarry(_block[i], rhs._block[i], carry, carry);
19,821,420✔
307
                                }
308
                        }
309
                        // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
310
                        sum._block[MSU] = static_cast<bt>(MSU_MASK & sum._block[MSU]);
1,165,996✔
311
                        *this = sum;
1,165,996✔
312
                }
313
                else {
314
                        // Multi-limb path for bt = uint8_t/uint16_t/uint32_t.
315
                        // Index-based loop (constexpr-friendly; pointer arithmetic on stack
316
                        // arrays is forbidden in constexpr).
317
                        integer<nbits, BlockType, NumberType> sum;
318
                        std::uint64_t carry = 0;
265,130,803✔
319
                        for (unsigned i = 0; i < nrBlocks; ++i) {
2,147,483,647✔
320
                                carry += static_cast<std::uint64_t>(_block[i]) + static_cast<std::uint64_t>(rhs._block[i]);
2,147,483,647✔
321
                                sum._block[i] = static_cast<bt>(carry);
2,147,483,647✔
322
                                carry >>= bitsInBlock;
2,147,483,647✔
323
                        }
324
                        // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
325
                        sum._block[MSU] = static_cast<bt>(MSU_MASK & sum._block[MSU]);
265,130,803✔
326
        #if INTEGER_THROW_ARITHMETIC_EXCEPTION
327
                        // TODO: what is the real overflow condition?
328
                        // it is not carry == 1 as  say 1 + -1 sets the carry but is 0
329
                //                if (carry) throw integer_overflow();
330
        #endif
331
                        *this = sum;
265,130,803✔
332
                }
333
                return *this;
301,681,208✔
334
        }
335
        constexpr integer& operator-=(const integer& rhs) {
92,448,752✔
336
                if constexpr (NumberType == WholeNumber || NumberType == NaturalNumber) {
337
                        // Both modes are unsigned-domain. The semantic preconditions
338
                        // (WholeNumber: result must be >= 1; NaturalNumber: result >= 0)
339
                        // are checked only when INTEGER_THROW_ARITHMETIC_EXCEPTION is on
340
                        // -- matching the convention used by operator/= and convert_*.
341
                        //
342
                        // Under THROW=0 (the default) the magnitude subtractor runs
343
                        // unconditionally. This is necessary because internal algorithms
344
                        // (long division at line 1598/1632, decimal conversion via the
345
                        // quotient/remainder loop) call -= with operands that may be
346
                        // equal or that may produce an out-of-domain modular result;
347
                        // throwing in those paths would break printing and division.
348
                        // Out-of-domain user code under THROW=0 gets defined modular
349
                        // wraparound, the same convention IntegerNumber uses.
350
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
351
                        if (*this < rhs) {
2✔
352
                                throw integer_wholenumber_cannot_be_negative{};
2✔
353
                        }
354
                        if constexpr (NumberType == WholeNumber) {
355
                                if (*this == rhs) {
×
356
                                        throw integer_wholenumber_cannot_be_zero{};
×
357
                                }
358
                        }
359
#endif
360
                        // Magnitude subtraction with limb-wise borrow propagation.
361
                        // constexpr-safe: only bt-typed integer arithmetic.
362
                        //
363
                        // Borrow-out logic per limb:
364
                        //   incoming borrow == 0: borrow-out iff a < b
365
                        //   incoming borrow == 1: borrow-out iff a <= b  (a - b - 1 wraps when a == b too)
366
                        // This formulation works uniformly for bt = uint8/16/32/64 without
367
                        // overflow concerns from widening b + borrow at the largest limb size.
368
                        unsigned borrow = 0;
7✔
369
                        for (unsigned i = 0; i < nrBlocks; ++i) {
35✔
370
                                bt a = _block[i];
28✔
371
                                bt b = rhs._block[i];
28✔
372
                                bt diff = static_cast<bt>(a - b - borrow);
28✔
373
                                borrow = (borrow == 0) ? (a < b ? 1u : 0u)
30✔
374
                                                       : (a <= b ? 1u : 0u);
2✔
375
                                _block[i] = diff;
28✔
376
                        }
377
                        // Clear bits above nbits in the most significant unit.
378
                        _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK);
7✔
379
                }
380
                else {
381
                        integer twos(rhs);
92,448,743✔
382
                        operator+=(twos.twosComplement());
92,448,743✔
383
                }
384
                return *this;
92,448,750✔
385
        }
386
        constexpr integer& operator*=(const integer& rhs) {
3,735,069✔
387
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
388
                        if constexpr (nrBlocks == 1) {
389
                                _block[0] = static_cast<bt>(_block[0] * rhs.block(0));
3,644,088✔
390
                        }
391
                        else if constexpr (bitsInBlock == 64) {
392
                                // uint64_t limbs: mul128/addcarry use platform intrinsics that are
393
                                // not constexpr on MSVC. In constant-evaluated context, fall back
394
                                // to a portable double-loop using the index-loop formulation
395
                                // (same as the bt < 64 branch below). At runtime we keep the
396
                                // intrinsic path for performance.
397
                                integer<nbits + 1, BlockType, NumberType> base(*this);
201✔
398
                                integer<nbits + 1, BlockType, NumberType> multiplicant(rhs);
201✔
399
                                bool resultIsNeg = (base.isneg() ^ multiplicant.isneg());
201✔
400
                                if (base.isneg()) {
201✔
401
                                        base.twosComplement();
×
402
                                }
403
                                if (multiplicant.isneg()) {
201✔
404
                                        multiplicant.twosComplement();
×
405
                                }
406
                                clear();
201✔
407
                                if (std::is_constant_evaluated()) {
201✔
408
                                        // Constexpr-safe 64x64 -> 128 mul + carry propagation. Uses
409
                                        // __int128 on gcc/clang (where it is constexpr-friendly).
410
                                        // On MSVC (no __int128), constexpr eval of integer<N, uint64_t>
411
                                        // is unsupported -- callers can use uint32_t limbs there.
412
#if defined(__SIZEOF_INT128__)
413
                                        for (unsigned i = 0; i < nrBlocks; ++i) {
×
414
                                                uint128_t carry = 0;
×
415
                                                for (unsigned j = 0; j < nrBlocks; ++j) {
×
416
                                                        if (i + j < nrBlocks) {
×
417
                                                                uint128_t product = static_cast<uint128_t>(base.block(i)) * multiplicant.block(j);
×
418
                                                                uint128_t sum = product + _block[i + j] + carry;
×
419
                                                                _block[i + j] = static_cast<bt>(sum);
×
420
                                                                carry = sum >> 64;
×
421
                                                        }
422
                                                }
423
                                        }
424
#else
425
                                        // MSVC fallback (or any platform without __int128): truncating
426
                                        // fallback. Documented limitation: uint64-limb integer<>
427
                                        // constexpr arithmetic loses high-half of partial products.
428
                                        for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
429
                                                std::uint64_t segment(0);
430
                                                for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
431
                                                        segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
432
                                                        if (i + j < static_cast<unsigned>(nrBlocks)) {
433
                                                                segment += _block[i + j];
434
                                                                _block[i + j] = static_cast<bt>(segment);
435
                                                                segment = 0;
436
                                                        }
437
                                                }
438
                                        }
439
#endif
440
                                }
441
                                else {
442
                                        for (unsigned i = 0; i < nrBlocks; ++i) {
3,403✔
443
                                                uint64_t carry = 0;
3,202✔
444
                                                for (unsigned j = 0; j < nrBlocks; ++j) {
54,406✔
445
                                                        if (i + j < nrBlocks) {
51,204✔
446
                                                                uint64_t lo, hi;
447
                                                                mul128(base.block(i), multiplicant.block(j), lo, hi);
27,203✔
448
                                                                uint64_t c1 = 0;
27,203✔
449
                                                                uint64_t sum = addcarry(_block[i + j], lo, carry, c1);
27,203✔
450
                                                                _block[i + j] = sum;
27,203✔
451
                                                                carry = hi + c1;
27,203✔
452
                                                        }
453
                                                }
454
                                        }
455
                                }
456
                                if (resultIsNeg) twosComplement();
201✔
457
                        }
458
                        else {
459
                                // is there a better way than upconverting to deal with maxneg in a 2's complement encoding?
460
                                integer<nbits + 1, BlockType, NumberType> base(*this);
90,780✔
461
                                integer<nbits + 1, BlockType, NumberType> multiplicant(rhs);
90,780✔
462
                                bool resultIsNeg = (base.isneg() ^ multiplicant.isneg());
90,780✔
463
                                if (base.isneg()) {
90,780✔
464
                                        base.twosComplement();
64✔
465
                                }
466
                                if (multiplicant.isneg()) {
90,780✔
467
                                        multiplicant.twosComplement();
×
468
                                }
469
                                clear();
90,780✔
470
                                for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
14,196,663✔
471
                                        std::uint64_t segment(0);
14,105,883✔
472
                                        for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
2,147,483,647✔
473
                                                segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
2,147,483,647✔
474

475
                                                if (i + j < static_cast<unsigned>(nrBlocks)) {
2,147,483,647✔
476
                                                        segment += _block[i + j];
2,147,483,647✔
477
                                                        _block[i + j] = static_cast<bt>(segment);
2,147,483,647✔
478
                                                        segment >>= bitsInBlock;
2,147,483,647✔
479
                                                }
480
                                        }
481
                                }
482
                                if (resultIsNeg) twosComplement();
90,780✔
483
                        }
484
                }
485
                else {  // whole and natural numbers are closed under multiplication (modulo)
486
                        if constexpr (nrBlocks == 1) {
487
                                _block[0] = static_cast<bt>(_block[0] * rhs.block(0));
488
                        }
489
                        else if constexpr (bitsInBlock == 64) {
490
                                // Same is_constant_evaluated dispatch as the IntegerNumber branch
491
                                // above to keep mul128/addcarry intrinsics out of constexpr context.
492
                                integer<nbits, BlockType, NumberType> base(*this), multiplicant(rhs);
493
                                clear();
494
                                if (std::is_constant_evaluated()) {
495
                                        // Same __int128 carry propagation as the IntegerNumber branch above
496
#if defined(__SIZEOF_INT128__)
497
                                        for (unsigned i = 0; i < nrBlocks; ++i) {
498
                                                uint128_t carry = 0;
499
                                                for (unsigned j = 0; j < nrBlocks; ++j) {
500
                                                        if (i + j < nrBlocks) {
501
                                                                uint128_t product = static_cast<uint128_t>(base.block(i)) * multiplicant.block(j);
502
                                                                uint128_t sum = product + _block[i + j] + carry;
503
                                                                _block[i + j] = static_cast<bt>(sum);
504
                                                                carry = sum >> 64;
505
                                                        }
506
                                                }
507
                                        }
508
#else
509
                                        for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
510
                                                std::uint64_t segment(0);
511
                                                for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
512
                                                        segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
513
                                                        if (i + j < static_cast<unsigned>(nrBlocks)) {
514
                                                                segment += _block[i + j];
515
                                                                _block[i + j] = static_cast<bt>(segment);
516
                                                                segment = 0;
517
                                                        }
518
                                                }
519
                                        }
520
#endif
521
                                }
522
                                else {
523
                                        for (unsigned i = 0; i < nrBlocks; ++i) {
524
                                                uint64_t carry = 0;
525
                                                for (unsigned j = 0; j < nrBlocks; ++j) {
526
                                                        if (i + j < nrBlocks) {
527
                                                                uint64_t lo, hi;
528
                                                                mul128(base.block(i), multiplicant.block(j), lo, hi);
529
                                                                uint64_t c1 = 0;
530
                                                                uint64_t sum = addcarry(_block[i + j], lo, carry, c1);
531
                                                                _block[i + j] = sum;
532
                                                                carry = hi + c1;
533
                                                        }
534
                                                }
535
                                        }
536
                                }
537
                        }
538
                        else {
539
                                integer<nbits, BlockType, NumberType> base(*this), multiplicant(rhs);
540
                                clear();
541
                                for (unsigned i = 0; i < static_cast<unsigned>(nrBlocks); ++i) {
542
                                        std::uint64_t segment(0);
543
                                        for (unsigned j = 0; j < static_cast<unsigned>(nrBlocks); ++j) {
544
                                                segment += static_cast<std::uint64_t>(base.block(i)) * static_cast<std::uint64_t>(multiplicant.block(j));
545

546
                                                if (i + j < static_cast<unsigned>(nrBlocks)) {
547
                                                        segment += _block[i + j];
548
                                                        _block[i + j] = static_cast<bt>(segment);
549
                                                        segment >>= bitsInBlock;
550
                                                }
551
                                        }
552
                                }
553
                        }
554
                }
555
                // null any leading bits that fall outside of nbits
556
                _block[MSU] = static_cast<bt>(MSU_MASK & _block[MSU]);
3,735,069✔
557
                return *this;
3,735,069✔
558
        }
559
        constexpr integer& operator*=(const BlockType& scale) noexcept {
88✔
560
                if constexpr (bitsInBlock == 64) {
561
                        // uint64_t limbs: same mul128/addcarry dispatch as operator*=
562
                        if (std::is_constant_evaluated()) {
563
#if defined(__SIZEOF_INT128__)
564
                                uint128_t carry = 0;
565
                                for (unsigned i = 0; i < nrBlocks; ++i) {
566
                                        uint128_t product = static_cast<uint128_t>(_block[i]) * scale + carry;
567
                                        _block[i] = static_cast<BlockType>(product);
568
                                        carry = product >> 64;
569
                                }
570
#else
571
                                std::uint64_t scaleFactor(scale), segment(0);
572
                                for (unsigned i = 0; i < nrBlocks; ++i) {
573
                                        segment += static_cast<std::uint64_t>(_block[i]) * scaleFactor;
574
                                        _block[i] = static_cast<BlockType>(segment);
575
                                        segment = 0;
576
                                }
577
#endif
578
                        }
579
                        else {
580
                                uint64_t carry = 0;
581
                                for (unsigned i = 0; i < nrBlocks; ++i) {
582
                                        uint64_t lo, hi;
583
                                        mul128(_block[i], static_cast<uint64_t>(scale), lo, hi);
584
                                        uint64_t c1 = 0;
585
                                        _block[i] = addcarry(lo, carry, uint64_t(0), c1);
586
                                        carry = hi + c1;
587
                                }
588
                        }
589
                }
590
                else {
591
                        std::uint64_t scaleFactor(scale), segment(0);
88✔
592
                        for (unsigned i = 0; i < nrBlocks; ++i) {
176✔
593
                                segment += static_cast<std::uint64_t>(_block[i]) * scaleFactor;
88✔
594
                                _block[i] = static_cast<BlockType>(segment);
88✔
595
                                segment >>= bitsInBlock;
88✔
596
                        }
597
                }
598
                return *this;
88✔
599
        }
600
        constexpr integer& operator/=(const integer& rhs) {
4,848,529✔
601
                if constexpr (EXACT_FIT && 1 == nrBlocks) {
602
                        if (rhs._block[0] == 0) {
3,215,160✔
603
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
604
                                throw integer_divide_by_zero{};
257✔
605
#else
606
                                // When exceptions are disabled we still must avoid the actual
607
                                // divide-by-zero below (UB at runtime; constexpr eval would
608
                                // be ill-formed). Set the result to 0 and bail out.
609
                                if (!std::is_constant_evaluated()) {
1✔
610
                                        std::cerr << "integer_divide_by_zero\n";
1✔
611
                                }
612
                                clear();
1✔
613
                                return *this;
1✔
614
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
615
                        }
616
                        if constexpr (NumberType == WholeNumber) {
617
                                if (*this < rhs) {
1✔
618
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
619
                                        throw integer_wholenumber_cannot_be_zero{};
1✔
620
#else
621
                                        if (!std::is_constant_evaluated()) {
622
                                                std::cerr << "whole number cannot be zero but division would yield 0\n";
623
                                        }
624
                                        clear();
625
                                        return *this;
626
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
627
                                }
628
                        }
629
                        if constexpr (sizeof(BlockType) == 1) {
630
                                _block[0] = static_cast<bt>(std::int8_t(_block[0]) / std::int8_t(rhs._block[0]));
1,117,748✔
631
                        }
632
                        else if constexpr (sizeof(BlockType) == 2) {
633
                                _block[0] = static_cast<bt>(std::int16_t(_block[0]) / std::int16_t(rhs._block[0]));
1,048,577✔
634
                        }
635
                        else if constexpr (sizeof(BlockType) == 4) {
636
                                _block[0] = static_cast<bt>(std::int32_t(_block[0]) / std::int32_t(rhs._block[0]));
524,288✔
637
                        }
638
                        else if constexpr (sizeof(BlockType) == 8) {
639
                                _block[0] = static_cast<bt>(std::int64_t(_block[0]) / std::int64_t(rhs._block[0]));                
524,288✔
640
                        }
641
                        _block[0] = static_cast<bt>(MSU_MASK & _block[0]);
3,214,901✔
642
                }
643
                else {
644
                        idiv_t<nbits, BlockType, NumberType> divresult = idiv<nbits, BlockType, NumberType>(*this, rhs);
1,633,369✔
645
                        *this = divresult.quot;
1,632,265✔
646
                }
647
                return *this;
4,847,166✔
648
        }
649
        constexpr integer& operator%=(const integer& rhs) {
3,271,634✔
650
                if constexpr (nbits == (sizeof(BlockType) * 8)) {
651
                        if (rhs._block[0] == 0) {
3,211,265✔
652
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
653
                                throw integer_divide_by_zero{};
256✔
654
#else
655
                                // When exceptions are disabled we still must avoid the actual
656
                                // modulo-by-zero below (UB at runtime; constexpr would be
657
                                // ill-formed). Set the result to 0 and bail out.
658
                                if (!std::is_constant_evaluated()) {
1✔
659
                                        std::cerr << "integer_divide_by_zero\n";
1✔
660
                                }
661
                                clear();
1✔
662
                                return *this;
1✔
663
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
664
                        }
665
                        if constexpr (sizeof(BlockType) == 1) {
666
                                _block[0] = static_cast<bt>(std::int8_t(_block[0]) % std::int8_t(rhs._block[0]));
1,113,856✔
667
                        }
668
                        else if constexpr (sizeof(BlockType) == 2) {
669
                                _block[0] = static_cast<bt>(std::int16_t(_block[0]) % std::int16_t(rhs._block[0]));
1,048,576✔
670
                        }
671
                        else if constexpr (sizeof(BlockType) == 4) {
672
                                _block[0] = static_cast<bt>(std::int32_t(_block[0]) % std::int32_t(rhs._block[0]));
524,288✔
673
                        }
674
                        else if constexpr (sizeof(BlockType) == 8) {
675
                                _block[0] = static_cast<bt>(std::int64_t(_block[0]) % std::int64_t(rhs._block[0]));
524,288✔
676
                        }
677
                        _block[0] = static_cast<bt>(MSU_MASK & _block[0]);
3,211,008✔
678
                }
679
                else {
680
                        idiv_t<nbits, BlockType, NumberType> divresult = idiv<nbits, BlockType, NumberType>(*this, rhs);
60,369✔
681
                        *this = divresult.rem;
60,289✔
682
                }
683

684
                return *this;
3,271,297✔
685
        }
686

687
        // arithmetic shift right operator
688
        constexpr integer& operator<<=(int bitsToShift) {
1,420,299✔
689
                if (bitsToShift == 0) return *this;
1,420,299✔
690
                if (bitsToShift < 0) return operator>>=(-bitsToShift);
280,511✔
691
                if (bitsToShift > static_cast<int>(nbits)) {
280,511✔
692
                        setzero();
×
693
                        return *this;
×
694
                }
695
                if (bitsToShift >= static_cast<int>(bitsInBlock)) {
280,511✔
696
                        int blockShift = bitsToShift / static_cast<int>(bitsInBlock);
95,118✔
697
                        for (int i = static_cast<int>(MSU); i >= blockShift; --i) {
863,105✔
698
                                _block[i] = bt(_block[i - blockShift]);
767,987✔
699
                        }
700
                        for (int i = blockShift - 1; i >= 0; --i) {
323,130✔
701
                                _block[i] = bt(0);
228,012✔
702
                        }
703
                        // adjust the shift
704
                        bitsToShift -= static_cast<int>(static_cast<unsigned>(blockShift) * bitsInBlock);
95,118✔
705
                        if (bitsToShift == 0) {
95,118✔
706
                                _block[MSU] &= MSU_MASK;
5,430✔
707
                                return *this;
5,430✔
708
                        }
709
                }
710
                if constexpr (MSU > 0) {
711
                        // construct the mask for the upper bits in the block that needs to move to the higher word
712
                        // bitsToShift is > 0 here (guarded above); the shared helper also states the
713
                        // mask truncation explicitly (bit_high_mask, #1261) and the cast removes the
714
                        // unsigned/int mixing in the index arithmetic (#1283).
715
                        bt mask = bit_high_mask<bt>(static_cast<unsigned>(bitsToShift), bitsInBlock);
185,336✔
716
                        for (unsigned i = MSU; i > 0; --i) {
1,222,142✔
717
                                _block[i] <<= bitsToShift;
1,036,806✔
718
                                // mix in the bits from the right
719
                                bt bits = bt(mask & _block[i - 1]);
1,036,806✔
720
                                _block[i] |= (bits >> (bitsInBlock - static_cast<unsigned>(bitsToShift)));
1,036,806✔
721
                        }
722
                }
723
                _block[0] <<= bitsToShift;        
275,081✔
724
                _block[MSU] &= MSU_MASK; // null any leading bits that fall outside of nbits
275,081✔
725
                return *this;
275,081✔
726
        }
727
        constexpr integer& operator>>=(int bitsToShift) {
4,797,386✔
728
                if (bitsToShift == 0) return *this;
4,797,386✔
729
                if (bitsToShift < 0) return operator<<=(-bitsToShift);
4,797,382✔
730
                if (bitsToShift >= static_cast<int>(nbits)) {
4,797,382✔
731
                        setzero();
4✔
732
                        return *this;
4✔
733
                }
734
                bool signext = sign();
4,797,378✔
735
                unsigned blockShift = 0;
4,797,378✔
736
                if (bitsToShift >= static_cast<int>(bitsInBlock)) {
4,797,378✔
737
                        blockShift = static_cast<unsigned>(bitsToShift) / bitsInBlock;
752✔
738
                        if (MSU >= blockShift) {
752✔
739
                                // shift by blocks
740
                                for (unsigned i = 0; i <= MSU - blockShift; ++i) {
49,546✔
741
                                        _block[i] = bt(_block[i + blockShift]);
48,794✔
742
                                }
743
                        }
744
                        // adjust the shift
745
                        bitsToShift -= static_cast<int>(blockShift * bitsInBlock);
752✔
746
                        if (bitsToShift == 0) {
752✔
747
                                // fix up the leading zeros if we have a negative number
748
                                if (signext) {
20✔
749
                                        // bitsToShift is guaranteed to be less than nbits
750
                                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
7✔
751
                                        for (unsigned i = nbits - static_cast<unsigned>(bitsToShift); i < nbits; ++i) {
119✔
752
                                                setbit(i);
112✔
753
                                        }
754
                                }
755
                                else {
756
                                        // clean up the blocks we have shifted clean
757
                                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
13✔
758
                                        for (unsigned i = nbits - static_cast<unsigned>(bitsToShift); i < nbits; ++i) {
1,197✔
759
                                                setbit(i, false);
1,184✔
760
                                        }
761
                                }
762
                                return *this;
20✔
763
                        }
764
                }
765
                if constexpr (MSU > 0) {
766
                        bt mask = ALL_ONES;
3,965,452✔
767
                        // mask for the lower bits in the block that need to move to the lower word
768
                        mask >>= (bitsInBlock - static_cast<unsigned>(bitsToShift));
3,965,452✔
769
                        // TODO: can this be improved? we should not have to work on the upper
770
                        // blocks in case we block shifted
771
                        for (unsigned i = 0; i < MSU; ++i) {
117,846,986✔
772
                                _block[i] >>= bitsToShift;
113,881,534✔
773
                                // mix in the bits from the left
774
                                bt bits = bt(mask & _block[i + 1]);
113,881,534✔
775
                                _block[i] |= (bits << (bitsInBlock - static_cast<unsigned>(bitsToShift)));
113,881,534✔
776
                        }
777
                }
778
                _block[MSU] >>= bitsToShift;
4,797,358✔
779

780
                // fix up the leading zeros if we have a negative number
781
                if (signext) {
4,797,358✔
782
                        // bitsToShift is guaranteed to be less than nbits
783
                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
61✔
784
                        for (unsigned i = nbits - static_cast<unsigned>(bitsToShift); i < nbits; ++i) {
742✔
785
                                setbit(i);
681✔
786
                        }
787
                }
788
                else {
789
                        // clean up the blocks we have shifted clean
790
                        bitsToShift += static_cast<int>(blockShift * bitsInBlock);
4,797,297✔
791
                        for (unsigned i = nbits - static_cast<unsigned>(bitsToShift); i < nbits; ++i) {
9,754,619✔
792
                                setbit(i, false);
4,957,322✔
793
                        }
794
                }
795

796
                // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
797
                _block[MSU] &= MSU_MASK;
4,797,358✔
798
                return *this;
4,797,358✔
799
        }
800
        constexpr integer& logicShiftRight(int shift) {
6✔
801
                if (shift == 0) return *this;
6✔
802
                if (shift < 0) {
6✔
803
                        return operator<<=(-shift);
×
804
                }
805
                if (nbits <= unsigned(shift)) {
6✔
806
                        clear();
×
807
                        return *this;
×
808
                }
809
                integer<nbits, BlockType, NumberType> target{};
6✔
810
                for (int i = nbits - 1; i >= shift; --i) {  // TODO: inefficient as it works at the bit level
6,144✔
811
                        target.setbit(static_cast<unsigned>(i - shift), at(static_cast<unsigned>(i)));
6,138✔
812
                }
813
                *this = target;
6✔
814
                return *this;
6✔
815
        }
816
        constexpr integer& operator&=(const integer& rhs) {
4✔
817
                for (unsigned i = 0; i < nrBlocks; ++i) {
36✔
818
                        _block[i] &= rhs._block[i];
32✔
819
                }
820
                _block[MSU] &= MSU_MASK;
4✔
821
                return *this;
4✔
822
        }
823
        constexpr integer& operator|=(const integer& rhs) {
824
                for (unsigned i = 0; i < nrBlocks; ++i) {
825
                        _block[i] |= rhs._block[i];
826
                }
827
                _block[MSU] &= MSU_MASK;
828
                return *this;
829
        }
830
        constexpr integer& operator^=(const integer& rhs) {
831
                for (unsigned i = 0; i < nrBlocks; ++i) {
832
                        _block[i] ^= rhs._block[i];
833
                }
834
                _block[MSU] &= MSU_MASK;
835
                return *this;
836
        }
837

838
        // modifiers
839
        constexpr void clear() noexcept { 
221,814,018✔
840
                bt* p = _block;
221,814,018✔
841
                if constexpr (0 == nrBlocks) {
842
                        return;
843
                }
844
                else if constexpr (1 == nrBlocks) {
845
                        *p = bt(0);
20,475,637✔
846
                }
847
                else if constexpr (2 == nrBlocks) {
848
                        *p++ = bt(0);
8,615,111✔
849
                        *p = bt(0);
8,615,111✔
850
                }
851
                else if constexpr (3 == nrBlocks) {
852
                        *p++ = bt(0);
72,870✔
853
                        *p++ = bt(0);
72,870✔
854
                        *p   = bt(0);
72,870✔
855
                }
856
                else if constexpr (4 == nrBlocks) {
857
                        *p++ = bt(0);
201,521✔
858
                        *p++ = bt(0);
201,521✔
859
                        *p++ = bt(0);
201,521✔
860
                        *p   = bt(0);
201,521✔
861
                }
862
                else {
863
                        for (unsigned i = 0; i < nrBlocks; ++i) {
2,000,138,056✔
864
                                *p++ = bt(0);
1,807,689,177✔
865
                        }
866
                }
867
        }
221,814,018✔
868
        constexpr void setzero() noexcept { clear(); }
5✔
869
        constexpr integer& maxpos() noexcept {
1✔
870
                clear();
1✔
871
                setbit(nbits - 1ull, true);
1✔
872
                flip();
1✔
873
                return *this;
1✔
874
        }
875
        constexpr integer& minpos() noexcept {
1✔
876
                clear();
1✔
877
                setbit(0, true);
1✔
878
                return *this;
1✔
879
        }
880
        constexpr integer& zero() noexcept {
881
                clear();
882
                return *this;
883
        }
884
        constexpr integer& minneg() noexcept {
1✔
885
                clear();
1✔
886
                flip();
1✔
887
                return *this;
1✔
888
        }
889
        constexpr integer& maxneg() noexcept {
1✔
890
                clear();
1✔
891
                setbit(nbits - 1ull, true);
1✔
892
                return *this;
1✔
893
        }
894
        constexpr void setbit(unsigned i, bool v = true) noexcept {
2,147,483,647✔
895
                unsigned blockIndex = i / bitsInBlock;
2,147,483,647✔
896
                if (blockIndex < nrBlocks) {
2,147,483,647✔
897
                        bt block = _block[blockIndex];
2,147,483,647✔
898
                        bt null = bit_clear_mask<bt>(i, bitsInBlock);
2,147,483,647✔
899
                        bt bit = bt(v ? 1 : 0);
2,147,483,647✔
900
                        bt mask = bt(bit << (i % bitsInBlock));
2,147,483,647✔
901
                        _block[blockIndex] = bt((block & null) | mask);
2,147,483,647✔
902
                }
903
                // nop if out of bounds
904
        }
2,147,483,647✔
905
        constexpr void setbyte(unsigned byteIndex, uint8_t data) {
906
                uint8_t mask = 0x1u;
907
                unsigned start = byteIndex * 8;
908
                unsigned end = start + 8;
909
                for (unsigned i = start; i < end; ++i) {
910
                        setbit(i, static_cast<bool>(mask & data));
911
                        mask <<= 1;
912
                }
913
        }
914
        constexpr void setblock(unsigned i, bt value) noexcept {
11✔
915
                if (i < nrBlocks) _block[i] = value;
11✔
916
        }
11✔
917
        // use un-interpreted raw bits to set the bits of the integer
918
        constexpr integer& setbits(uint64_t raw_bits) noexcept {
2,341,206✔
919
                if constexpr (0 == nrBlocks) {
920
                        return *this;
921
                }
922
                else if constexpr (1 == nrBlocks) {
923
                        _block[0] = raw_bits & storageMask;
1,290,402✔
924
                }
925
                else if constexpr (2 == nrBlocks) {
926
                        if constexpr (bitsInBlock < 64) {
927
                                _block[0] = raw_bits & storageMask;
1,050,640✔
928
                                raw_bits >>= bitsInBlock;
1,050,640✔
929
                                _block[1] = raw_bits & storageMask;
1,050,640✔
930
                        }
931
                        else {
932
                                _block[0] = raw_bits & storageMask;
933
                                _block[1] = 0;
934
                        }
935
                }
936
                else if constexpr (3 == nrBlocks) {
937
                        if constexpr (bitsInBlock < 64) {
938
                                _block[0] = raw_bits & storageMask;
20✔
939
                                raw_bits >>= bitsInBlock;
20✔
940
                                _block[1] = raw_bits & storageMask;
20✔
941
                                raw_bits >>= bitsInBlock;
20✔
942
                                _block[2] = raw_bits & storageMask;
20✔
943
                        }
944
                        else {
945
                                _block[0] = raw_bits & storageMask;
946
                                _block[1] = 0;
947
                                _block[2] = 0;
948
                        }
949
                }
950
                else if constexpr (4 == nrBlocks) {
951
                        if constexpr (bitsInBlock < 64) {
952
                                _block[0] = raw_bits & storageMask;
3✔
953
                                raw_bits >>= bitsInBlock;
3✔
954
                                _block[1] = raw_bits & storageMask;
3✔
955
                                raw_bits >>= bitsInBlock;
3✔
956
                                _block[2] = raw_bits & storageMask;
3✔
957
                                raw_bits >>= bitsInBlock;
3✔
958
                                _block[3] = raw_bits & storageMask;
3✔
959
                        }
960
                        else {
961
                                _block[0] = raw_bits & storageMask;
962
                                _block[1] = 0;
963
                                _block[2] = 0;
964
                                _block[3] = 0;
965
                        }
966
                }
967
                else {
968
                        if constexpr (bitsInBlock < 64) {
969
                                for (unsigned i = 0; i < nrBlocks; ++i) {
1,047✔
970
                                        _block[i] = raw_bits & storageMask;
906✔
971
                                        raw_bits >>= bitsInBlock;
906✔
972
                                }
973
                        }
974
                        else {
975
                                _block[0] = raw_bits & storageMask;
976
                                for (unsigned i = 1; i < nrBlocks; ++i) {
977
                                        _block[i] = 0;
978
                                }
979
                        }
980
                }
981
                _block[MSU] &= MSU_MASK; // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
2,341,206✔
982
                return *this;
2,341,206✔
983
        }
984
        integer& assign(const std::string& txt) noexcept {
2✔
985
                if (!parse(txt, *this)) {
2✔
986
                        std::cerr << "Unable to parse: " << txt << std::endl;
×
987
                }
988
                // enforce precondition for fast comparison by properly nulling bits that are outside of nbits
989
                _block[MSU] = static_cast<BlockType>(MSU_MASK & _block[MSU]);
2✔
990
                return *this;
2✔
991
        }
992
        // pure bit copy of source integer, no sign extension
993
        template<unsigned src_nbits>
994
        constexpr void bitcopy(const integer<src_nbits, BlockType, NumberType>& src) noexcept {
5,513,262✔
995
                // no need to clear as we are going to overwrite all blocks
996
                for (unsigned i = 0; i < nrBlocks; ++i) { // use nrBlocks of receiver even when src is smaller, src.block() will return 0 for blocks it doesn't have, nulling the receiver's blocks
44,814,027✔
997
                        _block[i] = src.block(i);
39,300,765✔
998
                }
999
                _block[MSU] &= MSU_MASK; // assert precondition of properly nulled leading non-bits
5,513,262✔
1000
        }
5,513,262✔
1001
        // in-place one's complement
1002
        constexpr integer& flip() {
93,576,981✔
1003
                for (unsigned i = 0; i < nrBlocks; ++i) {
923,555,931✔
1004
                        _block[i] = static_cast<bt>(~_block[i]);
829,978,950✔
1005
                }
1006
                _block[MSU] = static_cast<bt>(_block[MSU] & MSU_MASK); // assert precondition of properly nulled leading non-bits
93,576,981✔
1007
                return *this;
93,576,981✔
1008
        }
1009
        // in-place 2's complement
1010
        constexpr integer& twosComplement() {
92,776,210✔
1011
                flip();
92,776,210✔
1012
                return ++(*this);
92,776,210✔
1013
        }
1014

1015
        // selectors
1016
        constexpr bool iszero() const noexcept {
7,973,130✔
1017
                for (unsigned i = 0; i < nrBlocks; ++i) {
16,682,392✔
1018
                        if (_block[i] != 0) return false;
15,583,803✔
1019
                }
1020
                return true;
1,098,589✔
1021
        }
1022
        constexpr bool ispos()  const noexcept { if constexpr (NumberType == IntegerNumberType::IntegerNumber) return *this > 0; else return true; }
1023
        constexpr bool isneg()  const noexcept { if constexpr (NumberType == IntegerNumberType::IntegerNumber) return *this < 0; else return false; }
1,788,822✔
1024
        constexpr bool isone()  const noexcept {
305✔
1025
                for (unsigned i = 0; i < nrBlocks; ++i) {
307✔
1026
                        if (i == 0) {
305✔
1027
                                if (_block[0] != BlockType(1u)) return false;
305✔
1028
                        }
1029
                        else {
1030
                                if (_block[i] != BlockType(0u)) return false;
×
1031
                        }
1032
                }
1033
                return true;
2✔
1034
        }
1035
        constexpr bool isodd()  const noexcept  { return bool(_block[0] & 0x01); }
118✔
1036
        constexpr bool iseven() const noexcept { return !isodd(); }
112✔
1037
        constexpr bool sign()   const noexcept { return at(nbits - 1); }
235,507,330✔
1038
        constexpr bool at(unsigned bitIndex) const noexcept {
242,177,662✔
1039
                if (bitIndex < nbits) {
242,177,662✔
1040
                        bt word = _block[bitIndex / bitsInBlock];
242,177,662✔
1041
                        bt mask = bt(1ull << (bitIndex % bitsInBlock));
242,177,662✔
1042
                        return (word & mask);
242,177,662✔
1043
                }
1044
                return false;
×
1045
        }
1046
        constexpr bool test(unsigned i)  const noexcept { return at(i); }
10✔
1047
        constexpr bt   block(unsigned i) const noexcept { if (i < nrBlocks) return _block[i]; else return bt(0u); }
2,147,483,647✔
1048
        constexpr uint8_t nibble(unsigned n) const noexcept {
1049
                if (n < (1 + ((nbits - 1) >> 2))) {
1050
                        bt word = _block[(n * 4) / bitsInBlock];
1051
                        int nibbleIndexInWord = int(n % (bitsInBlock >> 2ull));
1052
                        bt mask = bt(0xF << (nibbleIndexInWord * 4));
1053
                        bt nibblebits = bt(mask & word);
1054
                        return uint8_t(nibblebits >> (nibbleIndexInWord * 4));
1055
                }
1056
                return 0;
1057
        }
1058
        // normalize: decompose integer value into a blocktriple<nbits-1, REP> for quire accumulation
1059
        template<typename TargetBlockType = BlockType>
1060
        void normalize(blocktriple<nbits - 1, BlockTripleOperator::REP, TargetBlockType>& tgt) const {
1061
                if (iszero()) { tgt.setzero(); return; }
1062
                tgt.setzero();
1063
                tgt.setnormal();
1064
                // For WholeNumber/NaturalNumber, sign() returns the raw MSB which is a data bit,
1065
                // not a sign indicator. Only IntegerNumber has a true sign bit.
1066
                const bool negative = (NumberType == IntegerNumberType::IntegerNumber) && sign();
1067
                tgt.setsign(negative);
1068
                // get magnitude
1069
                integer mag = negative ? -(*this) : *this;
1070
                signed msb = findMsb(mag);
1071
                tgt.setscale(msb);  // integer: scale = position of MSB
1072
                // copy magnitude bits into significand
1073
                constexpr unsigned f = nbits - 1;
1074
                tgt.setbit(f);  // hidden bit
1075
                for (signed i = msb - 1; i >= 0 && (msb - 1 - i) < static_cast<signed>(f); --i) {
1076
                        tgt.setbit(static_cast<unsigned>(f - 1 - (msb - 1 - i)), mag.at(static_cast<unsigned>(i)));
1077
                }
1078
        }
1079

1080
        // operators
1081
        // reduce returns the ratio and remainder of a and b in *this and r
1082
        void reduce(const integer& a, const integer& b, integer& r) {
594,176✔
1083
                if (b.iszero()) {
594,176✔
1084
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1085
                        throw integer_divide_by_zero{};
1,360✔
1086
#else
1087
                        std::cerr << "integer_divide_by_zero\n";
1088
                        return;
1089
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
1090
                }
1091

1092
                if (a.iszero()) {
592,816✔
1093
                        clear();
1,355✔
1094
                        r.clear();
1,355✔
1095
                        return;
1,355✔
1096
                }
1097
                if constexpr (nrBlocks == 1) { // completely reduce this to native div and rem
1098
                        BlockType _a = a._block[0];
330,340✔
1099
                        BlockType _b = b._block[0];
330,340✔
1100
                        if constexpr (NumberType == IntegerNumber) {
1101
                                bool sign_a = _a & SIGN_BIT_MASK;
330,340✔
1102
                                bool sign_b = _b & SIGN_BIT_MASK;
330,340✔
1103
                                if constexpr (8 == bitsInBlock) {
1104
                                        std::int8_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
69,219✔
1105
                                        std::int8_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
69,219✔
1106
                                        *this = static_cast<BlockType>(a0 / b0);
69,219✔
1107
                                        r = static_cast<BlockType>(a0 % b0);
69,219✔
1108
                                }
1109
                                else if constexpr (16 == bitsInBlock) {
1110
                                        std::int16_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
261,121✔
1111
                                        std::int16_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
261,121✔
1112
                                        *this = static_cast<BlockType>(a0 / b0);
261,121✔
1113
                                        r = static_cast<BlockType>(a0 % b0);
261,121✔
1114
                                }
1115
                                else if constexpr (32 == bitsInBlock) {
1116
                                        std::int32_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
1117
                                        std::int32_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
1118
                                        *this = static_cast<BlockType>(a0 / b0);
1119
                                        r = static_cast<BlockType>(a0 % b0);
1120
                                }
1121
                                else {
1122
                                        std::int64_t a0 = (sign_a ? SIGN_EXTENTION_BITS | _a : _a);
1123
                                        std::int64_t b0 = (sign_b ? SIGN_EXTENTION_BITS | _b : _b);
1124
                                        *this = static_cast<BlockType>(a0 / b0);
1125
                                        r = static_cast<BlockType>(a0 % b0);
1126
                                }
1127
                        }
1128
                        else {
1129
                                *this = static_cast<BlockType>(_a / _b);
1130
                                r = static_cast<BlockType>(_a % _b);
1131
                        }
1132
                }
1133
                else {
1134
                        clear();
261,121✔
1135
                        // no need to constexpr guard this for IntegerNumber as sign() will return false for Whole and Natural Numbers
1136
                        bool sign_a = a.sign();
261,121✔
1137
                        bool sign_b = b.sign();
261,121✔
1138
                        bool sign_q = sign_a ^ sign_b;
261,121✔
1139
                        using Integer = integer<nbits+1, BlockType, NumberType>; // nbits+1 to deal with maxneg
1140
                        Integer _a(a), _b(b);
261,121✔
1141
                        if (sign_a) _a.twosComplement();
261,121✔
1142
                        if (sign_b) _b.twosComplement();                        
261,121✔
1143
                        
1144
                        // filter out the easy stuff
1145
                        if (_a < _b) { r = a; clear(); return; }
392,191✔
1146

1147
                        // determine first non-zero limbs
1148
                        unsigned m{ 0 }, n{ 0 };
131,071✔
1149
                        for (unsigned i = nrBlocks; i > 0; --i) {
261,631✔
1150
                                if (_a.block(i - 1) != 0) {
261,631✔
1151
                                        m = static_cast<unsigned>(i);
131,071✔
1152
                                        break;
131,071✔
1153
                                }
1154
                        }
1155
                        for (unsigned i = nrBlocks; i > 0; --i) {
262,141✔
1156
                                if (_b.block(i - 1) != 0) {
262,141✔
1157
                                        n = static_cast<unsigned>(i);
131,071✔
1158
                                        break;
131,071✔
1159
                                }
1160
                        }
1161

1162
                        // single limb divisor
1163
                        if (n == 1) {
131,071✔
1164
                                std::uint64_t remainder{ 0 };
131,070✔
1165
                                auto divisor = _b.block(0);
131,070✔
1166
                                for (unsigned j = m; j > 0; --j) {
262,650✔
1167
                                        std::uint64_t dividend = remainder * BASE + _a.block(j - 1);
131,580✔
1168
                                        std::uint64_t limbQuotient = dividend / divisor;
131,580✔
1169
                                        _block[j - 1] = static_cast<BlockType>(limbQuotient);
131,580✔
1170
                                        remainder = dividend - limbQuotient * divisor;
131,580✔
1171
                                }
1172
                                r._block[0] = static_cast<BlockType>(remainder);
131,070✔
1173
                                if (sign_q) twosComplement();
131,070✔
1174
                                return;
131,070✔
1175
                        }
1176

1177
                        // Knuth's algorithm calculates a normalization factor d
1178
                        // that perfectly aligns b so that b0 >= floor(BASE/2),
1179
                        // a requirement for the relationship: (qHat - 2) <= q <= qHat
1180

1181
                        using OriginalInteger = integer<nbits, BlockType, NumberType>;
1182
                        using ExpandedInteger = integer<nbits + sizeof(BlockType) * 8, BlockType, NumberType>; // need room for overflow to receive the normalization bits
1183

1184
                        int shift = nlz(b.block(n - 1));
1✔
1185
                        ExpandedInteger normalized_a;
1186
                        normalized_a.setblock(m, static_cast<BlockType>((_a.block(m - 1) >> (bitsInBlock - shift))));
1✔
1187
                        for (unsigned i = m - 1; i > 0; --i) {
2✔
1188
                                normalized_a.setblock(i, static_cast<BlockType>((_a.block(i) << shift) | (_a.block(i - 1) >> (bitsInBlock - shift))));
1✔
1189
                        }
1190
                        normalized_a.setblock(0, static_cast<BlockType>(_a.block(0) << shift));
1✔
1191
                        // normalize b
1192
                        OriginalInteger normalized_b;
1193
                        unsigned n_minus_1 = n - 1;
1✔
1194
                        for (unsigned i = n_minus_1; i > 0; --i) {
2✔
1195
                                normalized_b.setblock(i, static_cast<BlockType>((_b.block(i) << shift) | (_b.block(i - 1) >> (bitsInBlock - shift))));
1✔
1196
                        }
1197
                        normalized_b.setblock(0, static_cast<BlockType>(_b.block(0) << shift));
1✔
1198

1199
//                        std::cout << "normalized a : " << normalized_a.showLimbs() << " : " << normalized_a.showLimbValues() << '\n';
1200
//                        std::cout << "normalized b :             " << normalized_b.showLimbs() << " : " << normalized_b.showLimbValues() << '\n';
1201

1202
                        // divide by limb
1203
                        std::uint64_t divisor = normalized_b._block[n - 1];
1✔
1204
                        std::uint64_t v_nminus2 = normalized_b._block[n - 2]; // n > 1 at this point
1✔
1205
                        for (int j = static_cast<int>(m - n); j >= 0; --j) {
2✔
1206
                                std::uint64_t dividend = normalized_a.block(j + n) * BASE + normalized_a.block(j + n - 1);
1✔
1207
                                std::uint64_t qhat = dividend / divisor;
1✔
1208
                                std::uint64_t rhat = dividend - qhat * divisor;
1✔
1209

1210
                                while (qhat >= BASE || qhat * v_nminus2 > BASE * rhat + normalized_a.block(j + n - 2)) {
1✔
1211
                                        --qhat;
×
1212
                                        rhat += divisor;
×
1213
                                        if (rhat < BASE) continue;
×
1214
                                }
1215
                                std::uint64_t borrow{ 0 };
1✔
1216
                                std::uint64_t diff{ 0 };
1✔
1217
                                for (unsigned i = 0; i < n; ++i) {
3✔
1218
                                        std::uint64_t p = qhat * normalized_b.block(i);
2✔
1219
                                        diff = normalized_a.block(i + j) - static_cast<BlockType>(p) - borrow;
2✔
1220
                                        normalized_a.setblock(i + j, static_cast<BlockType>(diff));
2✔
1221
                                        borrow = (p >> bitsInBlock) - (diff >> bitsInBlock);
2✔
1222
                                }
1223
                                std::int64_t signedBorrow = static_cast<int64_t>(normalized_a.block(j + n) - borrow);
1✔
1224
                                normalized_a.setblock(j + n, static_cast<BlockType>(signedBorrow));
1✔
1225

1226
//                                std::cout << "   updated a : " << normalized_a.showLimbs() << " : " << normalized_a.showLimbValues() << '\n';
1227

1228
                                setblock(static_cast<unsigned>(j), static_cast<BlockType>(qhat));
1✔
1229
                                if (signedBorrow < 0) { // subtracted too much, add back
1✔
1230
                                        std::cout << "subtracted too much, add back\n";
×
1231
                                        _block[j] -= 1;
×
1232
                                        std::uint64_t carry{ 0 };
×
1233
                                        for (unsigned i = 0; i < n; ++i) {
×
1234
                                                carry += static_cast<std::uint64_t>(normalized_a.block(i + j)) + static_cast<std::uint64_t>(normalized_b.block(i));
×
1235
                                                normalized_a.setblock(i + j, static_cast<BlockType>(carry));
×
1236
                                                carry >>= 32;
×
1237
                                        }
1238
                                        BlockType rectified = static_cast<BlockType>(normalized_a.block(j + n) + carry);
×
1239
                                        normalized_a.setblock(j + n, rectified);
×
1240
                                }
1241
//                                std::cout << "   updated a : " << normalized_a.showLimbs() << " : " << normalized_a.showLimbValues() << '\n';
1242
                        }
1243
                        if (sign_q) twosComplement();
1✔
1244

1245
                        // remainder needs to be normalized
1246
                        for (unsigned i = 0; i < n - 1; ++i) {
2✔
1247
                                std::uint64_t remainder = static_cast<uint64_t>(normalized_a.block(i) >> shift);
1✔
1248
                                remainder |= static_cast<uint64_t>(normalized_a.block(i + 1) << (32 - shift));
1✔
1249
                                r.setblock(i, static_cast<BlockType>(remainder));
1✔
1250
                        }
1251
                        r.setblock(n - 1, static_cast<BlockType>(normalized_a.block(n - 1) >> shift));
1✔
1252
                }
1253
        }
1254
        // signed integer conversion
1255
        template<typename SignedInt>
1256
        constexpr integer& convert_signed(SignedInt rhs) {
220,801,168✔
1257
                clear();
220,801,168✔
1258
                if (0 == rhs) {
220,801,168✔
1259
                        if constexpr (NumberType == WholeNumber) {
1260
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1261
                                throw integer_wholenumber_cannot_be_zero();
1✔
1262
#else
1263
                                return *this;
×
1264
#endif
1265
                        }
1266
                        else {
1267
                                return *this;
8,671,977✔
1268
                        }
1269
                }
1270
                if constexpr (NumberType == WholeNumber) {
1271
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1272
                        if (rhs < 0) throw integer_wholenumber_cannot_be_negative();
5✔
1273
#else
1274
                        if (rhs < 0) return *this;
3✔
1275
#endif
1276
                }
1277
                if constexpr (NumberType == NaturalNumber) {
1278
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1279
                        if (rhs < 0) throw integer_naturalnumber_cannot_be_negative();
5✔
1280
#else
1281
                        if (rhs < 0) return *this;
6✔
1282
#endif
1283
                }
1284

1285
                int64_t v = rhs;
212,129,188✔
1286
                for (unsigned i = 0; i < nbits && v != 0; ++i) {
2,147,483,647✔
1287
                        if ((v & 1) != 0) setbit(i);   // low-bit test; & with signed 1 avoids int64->uint64
2,147,483,647✔
1288
                        v >>= 1;
2,147,483,647✔
1289
                }
1290
                if constexpr (nbits > 64) {
1291
                        if (rhs < 0) {        // sign extend if negative
189,837,309✔
1292
                                for (unsigned i = 64; i < nbits; ++i) {
2,147,483,647✔
1293
                                        setbit(i);
2,147,483,647✔
1294
                                }
1295
                        }
1296
                }
1297
                return *this;
212,129,188✔
1298
        }
1299
        // unsigned integer conversion
1300
        template<typename UnsignedInt>
1301
        constexpr integer& convert_unsigned(UnsignedInt rhs) {
527,153✔
1302
                clear();
527,153✔
1303
                if (0 == rhs) {
527,153✔
1304
                        if constexpr (NumberType == WholeNumber) {
1305
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1306
                                throw integer_wholenumber_cannot_be_zero();
×
1307
#else
1308
                                return *this;
1309
#endif
1310
                        }
1311
                        else {
1312
                                return *this;
135,936✔
1313
                        }
1314
                }
1315
                uint64_t v = rhs;
391,217✔
1316
                constexpr unsigned argbits = sizeof(rhs);
391,217✔
1317
                unsigned upper = (nbits <= _nbits ? nbits : argbits);
391,217✔
1318
                for (unsigned i = 0; i < upper; ++i) {
4,363,390✔
1319
                        if (v & 0x1ull) setbit(i);
3,972,173✔
1320
                        v >>= 1;
3,972,173✔
1321
                }
1322
                return *this;
391,217✔
1323
        }
1324
        // native IEEE-754 conversion
1325
        // TODO: currently only supports integer values of 64bits or less
1326
        template<typename Real>
1327
        constexpr integer& convert_ieee(Real rhs) noexcept {
782✔
1328
                clear();
782✔
1329
                return *this = static_cast<long long>(rhs); // TODO: this clamps the IEEE range to +-2^63
782✔
1330
        }
1331

1332
        // show the binary encodings of the limbs
1333
        std::string showLimbs() const {
1334
                using Integer = sw::universal::integer<nbits, BlockType, NumberType>;
1335
                std::stringstream s;
1336
                unsigned i = Integer::MSU;
1337
                while (i > 0) {
1338
                        s << to_binary(_block[i], sizeof(BlockType) * 8, true) << ' ';
1339
                        --i;
1340
                }
1341
                s << to_binary(_block[0], sizeof(BlockType) * 8, true);
1342
                return s.str();
1343
        }
1344
        // show the values of the limbs as a radix-BlockType number
1345
        std::string showLimbValues() const {
1346
                using Integer = sw::universal::integer<nbits, BlockType, NumberType>;
1347
                std::stringstream s;
1348
                unsigned i = Integer::MSU;
1349
                while (i > 0) {
1350
                        s << std::setw(5) << unsigned(_block[i]) << ", ";
1351
                        --i;
1352
                }
1353
                s << std::setw(5) << unsigned(_block[0]);
1354
                return s.str();
1355
        }
1356

1357
protected:
1358
        // HELPER methods
1359

1360
        // to_integer converts to native signed integer
1361
        // TODO: enable_if this for integral types only
1362
        template<typename TargetInt>
1363
        TargetInt to_integer() const noexcept {
5,065,647✔
1364
                TargetInt v{ 0 };
5,065,647✔
1365
                if (iszero()) return v;  // this should only occur for Integer and Natural Numbers
5,065,647✔
1366

1367
                constexpr unsigned sizeoftarget   = 8 * sizeof(TargetInt);
3,976,809✔
1368
                constexpr unsigned upperTargetBlock = (sizeoftarget - 1ul) / bitsInBlock;
3,976,809✔
1369
                unsigned upperBlock = static_cast<unsigned>(std::min(MSU, upperTargetBlock));
3,976,809✔
1370
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1371
                        for (unsigned b = 0; b <= upperBlock; ++b) {
9,004,092✔
1372
                                std::uint64_t data = _block[b];
5,027,321✔
1373
                                v |= (data << (b * bitsInBlock));
5,027,321✔
1374
                        }
1375
                        unsigned upper = nbits;
3,976,771✔
1376
                        if (sign() && upper < sizeoftarget) { // sign extend
3,976,771✔
1377
                                uint64_t mask = (1ull << upper);
1,171,013✔
1378
                                for (unsigned i = upper; i < sizeoftarget; ++i) {
65,982,363✔
1379
                                        v |= mask;
64,811,350✔
1380
                                        mask <<= 1;
64,811,350✔
1381
                                }
1382
                        }
1383
                }
1384
                else {
1385
                        for (unsigned b = 0; b <= upperBlock; ++b) {
139✔
1386
                                std::uint64_t data = _block[b];
101✔
1387
                                v |= (data << (b * bitsInBlock));
101✔
1388
                        }
1389
                }
1390

1391
                return v;
3,976,809✔
1392
        }
1393

1394
        // to_unsigned_integer converts to native unsigned integer
1395
    // TODO: enable_if this for integral types only
1396
        template<typename TargetInt>
1397
        TargetInt to_unsigned_integer() const noexcept {
48✔
1398
                TargetInt v{ 0 };
48✔
1399
                if (iszero()) return v;  // this should only occur for Integer and Natural Numbers
48✔
1400

1401
                constexpr unsigned sizeoftarget = 8 * sizeof(TargetInt);
48✔
1402
                constexpr unsigned upperTargetBlock = (sizeoftarget - 1ul) / bitsInBlock;
48✔
1403
                unsigned upperBlock = std::min(MSU, upperTargetBlock);
48✔
1404
                for (unsigned b = 0; b <= upperBlock; ++b) {
159✔
1405
                        std::uint64_t data = _block[b];
111✔
1406
                        v |= (data << (b * bitsInBlock));
111✔
1407
                }
1408

1409
                return v;
48✔
1410
        }
1411

1412
        // TODO: enable_if this for native floating-point types only
1413
        template<typename Real>
1414
        constexpr Real to_real() const noexcept {
769✔
1415
                Real r = 0.0;
769✔
1416
                Real bitValue = static_cast<Real>(1.0);
769✔
1417
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1418
                        integer<nbits + 1, bt, NumberType> v{ *this }; // deal with maxneg in 2's complement
769✔
1419
                        if (isneg()) v = -v;
769✔
1420
                        for (unsigned i = 0; i < nbits; ++i) { // upper bound is nbits + 1 - 1 == nbits
35,249✔
1421
                                if (v.at(i)) r += bitValue;
34,480✔
1422
                                bitValue *= static_cast<Real>(2.0);
34,480✔
1423
                        }
1424
                        if (isneg()) r = -r;
769✔
1425
                }
1426
                else if constexpr (NumberType == IntegerNumberType::WholeNumber) {
1427
                        for (unsigned i = 0; i < nbits; ++i) {
1428
                                if (at(i)) r += bitValue;
1429
                                bitValue *= static_cast<Real>(2.0);
1430
                        }
1431
                }
1432
                else { // NaturalNumber
1433
                        if (iszero()) std::cerr << "internal error: natural number is set to 0\n";
1434
                        for (unsigned i = 0; i < nbits; ++i) {
1435
                                if (at(i)) r += bitValue;
1436
                                bitValue *= static_cast<Real>(2.0);
1437
                        }
1438
                }
1439

1440
                return r;
769✔
1441
        }
1442

1443
private:
1444
        bt _block[nrBlocks];
1445

1446
        // convert
1447
        template<unsigned nnbits, typename BBlockType, IntegerNumberType NNumberType>
1448
        friend std::string convert_to_decimal_string(const integer<nnbits, BBlockType, NNumberType>& value);
1449

1450
        // integer - integer logic comparisons
1451
        template<unsigned nnbits, typename BBlockType, IntegerNumberType NNumberType>
1452
        friend constexpr bool operator==(const integer<nnbits, BBlockType, NNumberType>& lhs, const integer<nnbits, BBlockType, NNumberType>& rhs);
1453

1454
        // find the most significant bit set
1455
        template<unsigned nnbits, typename BBlockType, IntegerNumberType NNumberType>
1456
        friend constexpr signed findMsb(const integer<nnbits, BBlockType, NNumberType>& v);
1457
};
1458

1459
////////////////////////    INTEGER functions   /////////////////////////////////
1460

1461
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1462
constexpr inline integer<nbits, BlockType, NumberType> abs(const integer<nbits, BlockType, NumberType>& a) {
1463
        integer<nbits, BlockType, NumberType> b(a);
1464
        return (a >= 0 ? b : b.twosComplement());
1465
}
1466

1467
// free function to create a 1's complement copy of an integer
1468
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1469
constexpr inline integer<nbits, BlockType, NumberType> onesComplement(const integer<nbits, BlockType, NumberType>& value) {
1✔
1470
        integer<nbits, BlockType, NumberType> ones(value);
1✔
1471
        return ones.flip();
1✔
1472
}
1473
// free function to create the 2's complement of an integer
1474
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1475
constexpr inline integer<nbits, BlockType, NumberType> twosComplement(const integer<nbits, BlockType, NumberType>& value) {
2✔
1476
        integer<nbits, BlockType, NumberType> twos(value);
2✔
1477
        return twos.twosComplement();;
4✔
1478
}
1479

1480
// convert integer to decimal string
1481
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1482
std::string convert_to_decimal_string(const integer<nbits, BlockType, NumberType>& value) {
3✔
1483
        if (value.iszero()) {
3✔
1484
                return std::string("0");
×
1485
        }
1486
        integer<nbits, BlockType, NumberType> number = value.sign() ? twosComplement(value) : value;
3✔
1487
        support::decimal partial, multiplier;
3✔
1488
        partial.setzero();
3✔
1489
        multiplier.setdigit(1);
3✔
1490
        // convert integer to decimal by adding and doubling multipliers
1491
        for (unsigned i = 0; i < nbits; ++i) {
579✔
1492
                if (number.at(i)) {
576✔
1493
                        support::add(partial, multiplier);
282✔
1494
                        // std::cout << partial << std::endl;
1495
                }
1496
                support::add(multiplier, multiplier);
576✔
1497
        }
1498
        std::stringstream str;
3✔
1499
        if (value.sign()) str << '-';
3✔
1500
        for (support::decimal::const_reverse_iterator rit = partial.rbegin(); rit != partial.rend(); ++rit) {
166✔
1501
                str << (int)*rit;
163✔
1502
        }
1503
        return str.str();
3✔
1504
}
3✔
1505

1506
// findMsb takes an integer<nbits, BlockType, NumberType> reference and returns the 0-based position of the most significant bit, -1 if v == 0
1507
// Index-based loop (constexpr-clean; pointer arithmetic on stack arrays is forbidden in constexpr).
1508
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1509
constexpr signed findMsb(const integer<nbits, BlockType, NumberType>& v) {
2,837,935✔
1510
        using IntegerT = integer<nbits, BlockType, NumberType>;
1511
        // Access static members via the type (clang requires this in constexpr context).
1512
        constexpr unsigned bitsInBlk = IntegerT::bitsInBlock;
2,837,935✔
1513
        constexpr unsigned nBlks = IntegerT::nrBlocks;
2,837,935✔
1514
        constexpr BlockType BlockMsb = BlockType(BlockType(1u) << (bitsInBlk - 1));
2,837,935✔
1515
        signed msb = static_cast<signed>(IntegerT::nbits - 1ull); // the case for an aligned MSB
2,837,935✔
1516
        constexpr unsigned rem = nbits % bitsInBlk;
2,837,935✔
1517

1518
        // little-endian: most significant block is at index nBlks - 1
1519
        unsigned blockIdx = nBlks - 1;
2,837,935✔
1520

1521
        // check if the blocks are aligned with the representation
1522
        if constexpr (rem > 0) {
1523
                // the top bits are unaligned: construct the right mask
1524
                BlockType mask = BlockType(BlockType(1u) << (rem - 1u));
2,837,935✔
1525
                while (mask != 0) {
47,428,894✔
1526
                        if (v._block[blockIdx] & mask) return msb;
45,910,926✔
1527
                        --msb;
44,590,959✔
1528
                        mask >>= 1;
44,590,959✔
1529
                }
1530
                if (msb < 0) return msb;
1,517,968✔
1531
                if (blockIdx == 0) return msb;
1,517,967✔
1532
                --blockIdx;
1,517,967✔
1533
        }
1534
        // invariant: msb is now aligned with the blocks
1535
        while (true) {
1,117,097✔
1536
                if (v._block[blockIdx] != 0) {
2,635,064✔
1537
                        BlockType mask = BlockMsb;
1,517,967✔
1538
                        while (mask != 0) {
35,503,476✔
1539
                                if (v._block[blockIdx] & mask) return msb;
35,503,476✔
1540
                                --msb;
33,985,509✔
1541
                                mask >>= 1;
33,985,509✔
1542
                        }
1543
                }
1544
                else {
1545
                        msb -= static_cast<signed>(bitsInBlk);
1,117,097✔
1546
                }
1547
                if (blockIdx == 0) break;
1,117,097✔
1548
                --blockIdx;
1,117,097✔
1549
        }
1550
        return msb; // == -1 if no significant bit found
×
1551
}
1552

1553
////////////////////////    INTEGER operators   /////////////////////////////////
1554

1555
// remainder returns a mod b in c
1556
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1557
void remainder(integer<nbits, BlockType, NumberType>& c, const integer<nbits, BlockType, NumberType>& a, const integer<nbits, BlockType, NumberType>& b) {
1558
        if (b == integer<nbits, BlockType, NumberType>(0)) {
1559
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1560
                throw integer_divide_by_zero{};
1561
#else
1562
                std::cerr << "integer_divide_by_zero\n";
1563
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
1564
        }
1565
        idiv_t<nbits, BlockType, NumberType> divresult = idiv<nbits, BlockType, NumberType>(a, b);
1566
        c = divresult.rem;
1567
}
1568

1569
// divide integer<nbits, BlockType, NumberType> a and b and return result argument
1570
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1571
constexpr idiv_t<nbits, BlockType, NumberType> idiv(const integer<nbits, BlockType, NumberType>& _a, const integer<nbits, BlockType, NumberType>& _b) {
1,693,738✔
1572
        if (_b.iszero()) {
1,693,738✔
1573
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1574
                throw integer_divide_by_zero{};
1,184✔
1575
#else
1576
                // When exceptions are disabled we still must avoid the actual
1577
                // long-division below (UB on integer div-by-zero; constexpr would
1578
                // be ill-formed). Return zeroed quot/rem and bail out.
1579
                if (!std::is_constant_evaluated()) {
×
1580
                        std::cerr << "integer_divide_by_zero\n";
×
1581
                }
1582
                idiv_t<nbits, BlockType, NumberType> zeroed;
×
1583
                return zeroed;
×
1584
#endif // INTEGER_THROW_ARITHMETIC_EXCEPTION
1585
        }
1586

1587
        idiv_t<nbits, BlockType, NumberType> divresult;
1,692,554✔
1588
        divresult.rem = 0;
1,692,554✔
1589
        divresult.quot = 0;
1,692,554✔
1590

1591
        // generate the absolute values to do long division
1592
        if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1593
                using Integer = integer<nbits+1, BlockType, NumberType>;
1594
                // 2's complement special case -max requires an signed int that is 1 bit bigger to represent abs()
1595
                bool a_negative = _a.sign();
1,692,554✔
1596
                bool b_negative = _b.sign();
1,692,554✔
1597
                bool result_negative = (a_negative ^ b_negative);
1,692,554✔
1598
                Integer a; a.bitcopy(a_negative ? -_a : _a);
1,692,554✔
1599
                Integer b; b.bitcopy(b_negative ? -_b : _b);
1,692,554✔
1600

1601
                if (a < b) {
1,692,554✔
1602
                        divresult.quot = 0; // a / b = 0
273,671✔
1603
                        divresult.rem = _a; // a % b = a when a / b = 0
273,671✔
1604
                        return divresult;
273,671✔
1605
                }
1606
                // initialize the long division
1607
                integer<nbits + 1, BlockType, NumberType> accumulator = a;
1,418,883✔
1608
                // prepare the subtractand
1609
                integer<nbits + 1, BlockType, NumberType> subtractand = b;
1,418,883✔
1610
                int msb_b = findMsb(b);
1,418,883✔
1611
                int msb_a = findMsb(a);
1,418,883✔
1612
                int shift = msb_a - msb_b;
1,418,883✔
1613
                subtractand <<= shift;
1,418,883✔
1614
                divresult.quot = 0;
1,418,883✔
1615
                // long division
1616
                for (int i = shift; i >= 0; --i) {
6,207,093✔
1617
                        if (subtractand <= accumulator) {
4,788,210✔
1618
                                accumulator -= subtractand;
2,846,317✔
1619
                                divresult.quot.setbit(static_cast<unsigned>(i));
2,846,317✔
1620
                        }
1621
                        else {
1622
                                divresult.quot.setbit(static_cast<unsigned>(i), false);
1,941,893✔
1623
                        }
1624
                        subtractand >>= 1;
4,788,210✔
1625
                        //                std::cout << "i = " << i << " subtractand : " << long(subtractand) << '\n';
1626
                }
1627
                if (result_negative) {  // take 2's complement
1,418,883✔
1628
                        divresult.quot.flip();
133,369✔
1629
                        divresult.quot += 1;
133,369✔
1630
                }
1631
                if (_a.isneg()) {
1,418,883✔
1632
                        divresult.rem = -accumulator;
133,961✔
1633
                }
1634
                else {
1635
                        divresult.rem = accumulator;
1,284,922✔
1636
                }
1637
        }
1638
        else {
1639
                if (_a < _b) {
×
1640
                        divresult.rem = _a; // a % b = a when a / b = 0
×
1641
                        return divresult; // a / b = 0 when b > a
×
1642
                }
1643
                using Integer = integer<nbits, BlockType, NumberType>;
1644
                Integer accumulator(_a), subtractand(_b);
×
1645
                int msb_b = findMsb(_b);
×
1646
                int msb_a = findMsb(_a);
×
1647
                int shift = msb_a - msb_b;
×
1648
                subtractand <<= shift;
×
1649
                // long division
1650
                for (int i = shift; i >= 0; --i) {
×
1651
                        if (subtractand <= accumulator) {
×
1652
                                accumulator -= subtractand;
×
1653
                                divresult.quot.setbit(static_cast<unsigned>(i));
×
1654
                        }
1655
                        else {
1656
                                divresult.quot.setbit(static_cast<unsigned>(i), false);
×
1657
                        }
1658
                        subtractand >>= 1;
×
1659
                        //                std::cout << "i = " << i << " subtractand : " << long(subtractand) << '\n';
1660
                }
1661
                divresult.rem = accumulator;
×
1662
        }
1663

1664
        return divresult;
1,418,883✔
1665
}
1666

1667
/// stream operators
1668

1669
// read an integer ASCII format and make a binary integer out of it
1670
//
1671
// Accepted syntax (Phase B1 of issue #835 -- shared string_parse foundation):
1672
//
1673
//   [+-]? ( 0[bB][01]+      |    // binary bit-pattern
1674
//           0[oO][0-7]+     |    // octal bit-pattern
1675
//           0[xX][0-9A-F']+ |    // hex bit-pattern (apostrophe allowed as digit separator)
1676
//           [0-9]+          )    // decimal integer
1677
//
1678
// Notes vs. the historical regex-based parser:
1679
//   - Octal now requires the explicit 0o/0O prefix (the previous code accepted
1680
//     C-style leading-zero octal but the conversion path was a `// TODO` that
1681
//     always returned false, so no real behavior change).
1682
//   - Binary 0b/0B is newly supported.
1683
//   - Decimal accepts a single optional leading +/- (the previous regex
1684
//     accepted multiple sign chars; functional difference is nil).
1685
//
1686
// All scanning is delegated to the constexpr primitives in
1687
// `<universal/utility/string_parse.hpp>`; the parser itself uses only
1688
// `integer`'s own arithmetic.
1689
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1690
bool parse(const std::string& number, integer<nbits, BlockType, NumberType>& value) {
41✔
1691
        namespace sp = sw::universal::string_parse;
1692
        using Int = integer<nbits, BlockType, NumberType>;
1693

1694
        // Build into a local temporary and only commit to `value` on a fully
1695
        // successful parse. This keeps malformed input from leaving the caller's
1696
        // object in a partially-mutated state.
1697
        Int tmp;
1698
        tmp.clear();
41✔
1699

1700
        std::string_view s{number};
41✔
1701

1702
        // Strip leading sign (if any).
1703
        auto sg = sp::scan_sign(s);
41✔
1704
        const bool negative = sg.negative;
41✔
1705
        s = sg.rest;
41✔
1706
        if (s.empty()) return false;
41✔
1707

1708
        // Detect base prefix; no prefix -> decimal.
1709
        auto pfx = sp::scan_prefix(s);
39✔
1710
        std::string_view body = pfx.body;
39✔
1711
        if (body.empty()) return false;
39✔
1712

1713
        // Track whether any real digit was consumed so payloads of only separators
1714
        // (e.g. "0x'") are rejected rather than silently yielding zero.
1715
        bool digit_found = false;
37✔
1716

1717
        switch (pfx.base) {
37✔
1718
        case sp::number_base::binary: {
7✔
1719
                // MSB-first: shift the accumulator left by 1 per character, OR in the bit.
1720
                for (char c : body) {
62✔
1721
                        if (!sp::is_binary_digit(c)) return false;
56✔
1722
                        tmp <<= 1;
55✔
1723
                        if (c == '1') tmp.setbit(0, true);
55✔
1724
                        digit_found = true;
55✔
1725
                }
1726
                if (!digit_found) return false;
6✔
1727
                break;
6✔
1728
        }
1729
        case sp::number_base::octal: {
5✔
1730
                // MSB-first: shift by 3, OR in the 3-bit digit.
1731
                for (char c : body) {
14✔
1732
                        if (!sp::is_octal_digit(c)) return false;
10✔
1733
                        tmp <<= 3;
9✔
1734
                        unsigned digit = static_cast<unsigned>(c - '0');
9✔
1735
                        for (unsigned b = 0; b < 3; ++b) {
36✔
1736
                                if ((digit >> b) & 1u) tmp.setbit(b, true);
27✔
1737
                        }
1738
                        digit_found = true;
9✔
1739
                }
1740
                if (!digit_found) return false;
4✔
1741
                break;
4✔
1742
        }
1743
        case sp::number_base::hex: {
12✔
1744
                // MSB-first: shift by 4, OR in the nibble. Apostrophe is a separator.
1745
                for (char c : body) {
46✔
1746
                        if (c == '\'') continue;
36✔
1747
                        if (!sp::is_hex_digit(c)) return false;
29✔
1748
                        tmp <<= 4;
27✔
1749
                        unsigned digit = sp::hex_digit_value(c);
27✔
1750
                        for (unsigned b = 0; b < 4; ++b) {
135✔
1751
                                if ((digit >> b) & 1u) tmp.setbit(b, true);
108✔
1752
                        }
1753
                        digit_found = true;
27✔
1754
                }
1755
                if (!digit_found) return false;
10✔
1756
                break;
7✔
1757
        }
1758
        case sp::number_base::decimal: {
13✔
1759
                // MSB-first: multiply accumulator by 10, add digit. is_decimal_digit
1760
                // gates the loop body so digit_found tracking is redundant here, but
1761
                // kept for symmetry.
1762
                Int ten{10};
13✔
1763
                for (char c : body) {
102✔
1764
                        if (!sp::is_decimal_digit(c)) return false;
91✔
1765
                        tmp *= ten;
89✔
1766
                        Int digit{static_cast<unsigned>(c - '0')};
89✔
1767
                        tmp += digit;
89✔
1768
                        digit_found = true;
89✔
1769
                }
1770
                if (!digit_found) return false;
11✔
1771
                break;
11✔
1772
        }
1773
        default:
×
1774
                return false;
×
1775
        }
1776

1777
        if (negative) tmp = -tmp;
28✔
1778
        value = tmp;
28✔
1779
        return true;
28✔
1780
}
1781

1782
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1783
std::string to_string(const integer<nbits, BlockType, NumberType>& n) {
2✔
1784
        return convert_to_decimal_string(n);
2✔
1785
}
1786

1787
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1788
std::string convert_to_string(std::ios_base::fmtflags flags, const integer<nbits, BlockType, NumberType>& n) {
4,186✔
1789
        using IntegerBase = integer<nbits, BlockType, NumberType>;
1790

1791
        // set the base of the target number system to convert to
1792
        int base = 10;
4,186✔
1793
        if ((flags & std::ios_base::oct) == std::ios_base::oct) base = 8;
4,186✔
1794
        if ((flags & std::ios_base::hex) == std::ios_base::hex) base = 16;
4,186✔
1795

1796
        std::string result;
4,186✔
1797
        if (base == 8 || base == 16) {
4,186✔
1798
                if (n.sign()) return std::string("negative value: ignored");
20✔
1799

1800
                BlockType shift = static_cast<BlockType>(base == 8 ? 3 : 4);
14✔
1801
                BlockType mask = static_cast<BlockType>((1u << shift) - 1);
14✔
1802
                IntegerBase t(n);
14✔
1803
                result.assign(nbits / shift + ((nbits % shift) ? 1 : 0), '0');
14✔
1804
                std::string::size_type pos = result.size() - 1u;
14✔
1805
                for (unsigned i = 0; i < nbits / static_cast<unsigned>(shift); ++i) {
42✔
1806
                        char c = '0' + static_cast<char>(t.block(0) & mask);
28✔
1807
                        if (c > '9')
28✔
1808
                                c += 'A' - '9' - static_cast<char>(1);
×
1809
                        result[pos--] = c;
28✔
1810
                        t >>= static_cast<int>(shift);
28✔
1811
                }
1812
                if (nbits % shift) {
14✔
1813
                        mask = static_cast<BlockType>((1u << (nbits % shift)) - 1);
7✔
1814
                        char c = '0' + static_cast<char>(t.block(0) & mask);
7✔
1815
                        if (c > '9')
7✔
1816
                                c += 'A' - '9';
×
1817
                        result[pos] = c;
7✔
1818
                }
1819
                //
1820
                // Get rid of leading zeros:
1821
                //
1822
                std::string::size_type fnz = result.find_first_not_of('0');
14✔
1823
                if (!result.empty() && (fnz == std::string::npos)) fnz = result.size() - 1;
14✔
1824
                result.erase(0, fnz);
14✔
1825
                if (flags & std::ios_base::showbase) {
14✔
1826
                        const char* pp = base == 8 ? "0" : "0x";
×
1827
                        result.insert(0ull, pp);
×
1828
                }
1829
        }
14✔
1830
        else {
1831
                using Integer = integer<nbits + 1, BlockType, NumberType>;  // nbits+1 to be able to represent maxneg in 2's complement form
1832

1833
                Integer t(n);
4,170✔
1834
                if constexpr (NumberType == IntegerNumberType::IntegerNumber) {
1835
                        if (t.sign()) t.twosComplement();
4,170✔
1836
                }
1837

1838
                Integer block10;
1839
                unsigned digits_in_block10 = 2;
4,170✔
1840
                if constexpr (IntegerBase::bitsInBlock == 8) {
1841
                        block10 = 100u;
3,428✔
1842
                        digits_in_block10 = 2;
3,428✔
1843
                }
1844
                else if constexpr (IntegerBase::bitsInBlock == 16) {
1845
                        block10 = 10'000u;
4✔
1846
                        digits_in_block10 = 4;
4✔
1847
                }
1848
                else if constexpr (IntegerBase::bitsInBlock == 32) {
1849
                        block10 = 1'000'000'000ul;
538✔
1850
                        digits_in_block10 = 9;
538✔
1851
                }
1852
                else if constexpr (IntegerBase::bitsInBlock == 64) {
1853
                        block10 = 1'000'000'000'000'000'000ull;
200✔
1854
                        digits_in_block10 = 18;
200✔
1855
                }
1856

1857
                result.assign(nbits / 3 + 1u, '0');
4,170✔
1858
                int pos = static_cast<int>(result.size() - 1u);
4,170✔
1859
                while (!t.iszero()) {
23,662✔
1860
                        Integer t2 = t / block10;
20,537✔
1861
                        Integer r  = t % block10;
20,537✔
1862
                        BlockType v = r.block(0);
20,537✔
1863
                        for (unsigned i = 0; i < digits_in_block10; ++i) {
92,855✔
1864
                                char c = '0' + static_cast<char>(v % 10);
73,363✔
1865
                                v /= 10;
73,363✔
1866
                                result[static_cast<unsigned>(pos)] = c;
73,363✔
1867
//                                std::cout << "result : " << result << " : pos : " << pos << '\n';
1868
                                if (pos-- == 0) break;
73,363✔
1869
                        }
1870
                        t = t2;
20,537✔
1871
                        if (pos < 0) break;
20,537✔
1872
                }
1873

1874
                std::string::size_type firstDigit = result.find_first_not_of('0');
4,170✔
1875
                result.erase(0, firstDigit);
4,170✔
1876
                if (result.empty())        result = std::string("0");
4,194✔
1877
                if (n.isneg()) { // no need to specialize as isneg() will return false for Natural and Whole Number types
4,170✔
1878
                        result.insert(static_cast<std::string::size_type>(0), 1, '-');
169✔
1879
                }
1880
                else if (flags & std::ios_base::showpos) {
4,001✔
1881
                        result.insert(static_cast<std::string::size_type>(0), 1, '+');
38✔
1882
                }
1883
        }
1884
        return result;
4,184✔
1885
}
4,186✔
1886

1887
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1888
inline std::ostream& operator<<(std::ostream& ostr, const integer<nbits, BlockType, NumberType>& i) {
4,186✔
1889
        std::string s = convert_to_string(ostr.flags(), i);
4,186✔
1890
        std::streamsize width = ostr.width();
4,186✔
1891
        if (width > static_cast<std::streamsize>(s.size())) {
4,186✔
1892
                char fill = ostr.fill();
216✔
1893
                // width > s.size() here, so the subtraction stays non-negative
1894
                std::string::size_type pad = static_cast<std::string::size_type>(width) - s.size();
216✔
1895
                if ((ostr.flags() & std::ios_base::left) == std::ios_base::left)
216✔
NEW
1896
                        s.append(pad, fill);
×
1897
                else
1898
                        s.insert(static_cast<std::string::size_type>(0), pad, fill);
216✔
1899
        }
1900
        return ostr << s;
8,372✔
1901
}
4,186✔
1902

1903
// read an ASCII integer format.
1904
// On parse failure: log a diagnostic to std::cerr AND set failbit on the stream
1905
// so callers (loops with `while (in >> x)`, etc.) can detect the error without
1906
// scraping stderr. Symmetric with fixpnt's operator>>.
1907
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1908
inline std::istream& operator>>(std::istream& istr, integer<nbits, BlockType, NumberType>& p) {
1909
        std::string txt;
1910
        istr >> txt;
1911
        if (!parse(txt, p)) {
1912
                std::cerr << "unable to parse -" << txt << "- into an integer value\n";
1913
                istr.setstate(std::ios::failbit);
1914
        }
1915
        return istr;
1916
}
1917

1918
////////////////// string operators
1919
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1920
inline std::string to_binary(const integer<nbits, BlockType, NumberType>& number, bool nibbleMarker = false) {
273✔
1921
        std::stringstream s;
273✔
1922
        s << "0b";
273✔
1923
        for (int i = nbits - 1; i >= 0; --i) {
10,043✔
1924
                s << (number.at(static_cast<unsigned>(i)) ? "1" : "0");
9,770✔
1925
                if (i > 0 && (i % 4) == 0 && nibbleMarker) s << '\'';
9,770✔
1926
        }
1927
        return s.str();
546✔
1928
}
273✔
1929

1930
// native semantic representation: radix-2, delegates to to_binary
1931
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1932
inline std::string to_native(const integer<nbits, BlockType, NumberType>& number, bool nibbleMarker = false) {
1933
        return to_binary(number, nibbleMarker);
1934
}
1935

1936
//////////////////////////////////////////////////////////////////////////////////////////////////////
1937
// integer - integer binary logic operators
1938

1939
// equal: precondition is that the storage is properly nulled in all arithmetic paths
1940
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1941
constexpr inline bool operator==(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
60,858,573✔
1942
        for (unsigned i = 0; i < lhs.nrBlocks; ++i) {
502,672,446✔
1943
                if (lhs._block[i] != rhs._block[i]) return false;
445,575,423✔
1944
        }
1945
        return true;
57,097,023✔
1946
}
1947
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1948
constexpr inline bool operator!=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2,434,917✔
1949
        return !operator==(lhs, rhs);
2,434,917✔
1950
}
1951
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1952
constexpr inline bool operator< (const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
74,806,765✔
1953
        if constexpr (NumberType == WholeNumber || NumberType == NaturalNumber) {
1954
                for (int i = static_cast<int>(lhs.nrBlocks) - 1; i >= 0; --i) {
3✔
1955
                        if (lhs.block(static_cast<unsigned>(i)) == rhs.block(static_cast<unsigned>(i))) continue;
3✔
1956
                        if (lhs.block(static_cast<unsigned>(i)) < rhs.block(static_cast<unsigned>(i))) return true;
3✔
1957
                }
1958
                return false;
×
1959
        }
1960
        else {
1961
                bool lhs_is_negative = lhs.sign();
74,806,762✔
1962
                bool rhs_is_negative = rhs.sign();
74,806,762✔
1963
                if (lhs_is_negative && !rhs_is_negative) return true;
74,806,762✔
1964
                if (rhs_is_negative && !lhs_is_negative) return false;
74,341,026✔
1965
                // arguments have the same sign
1966
                integer<nbits, BlockType, NumberType> diff;
1967
#if INTEGER_THROW_ARITHMETIC_EXCEPTION
1968
                // we need to catch and ignore the exception
1969
                try {
1970
                        diff = (lhs - rhs);
2,193,618✔
1971
                }
1972
                catch (const integer_overflow& e) {
×
1973
                        // all good as the arithmetic is modulo
1974
                        const char* p = e.what();
×
1975
                        if (p) --p;
×
1976
                }
1977
#else 
1978
                diff = (lhs - rhs);
70,305,098✔
1979
#endif
1980
                return diff.sign();
72,498,716✔
1981
        }
1982
}
1983
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1984
constexpr inline bool operator> (const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
23,456,443✔
1985
        return operator< (rhs, lhs);
23,456,443✔
1986
}
1987
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1988
constexpr inline bool operator<=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
5,337,132✔
1989
        return !operator> (lhs, rhs);
5,337,132✔
1990
}
1991
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
1992
constexpr inline bool operator>=(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
17,740,164✔
1993
        return !operator< (lhs, rhs);
17,740,164✔
1994
}
1995

1996
//////////////////////////////////////////////////////////////////////////////////////////////////////
1997
// integer - literal binary logic operators
1998
// equal: precondition is that the byte-storage is properly nulled in all arithmetic paths
1999
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2000
constexpr inline bool operator==(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
681,847✔
2001
        return operator==(lhs, integer<nbits, BlockType, NumberType>(rhs));
681,847✔
2002
}
2003
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2004
constexpr inline bool operator!=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
388✔
2005
        return !operator==(lhs, rhs);
388✔
2006
}
2007
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2008
constexpr inline bool operator< (const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
2,732,852✔
2009
        return operator<(lhs, integer<nbits, BlockType, NumberType>(rhs));
2,732,852✔
2010
}
2011
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2012
constexpr inline bool operator> (const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
8,267✔
2013
        return operator< (integer<nbits, BlockType, NumberType>(rhs), lhs);
8,267✔
2014
}
2015
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2016
constexpr inline bool operator<=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
12✔
2017
        return operator< (lhs, rhs) || operator==(lhs, rhs);
12✔
2018
}
2019
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType, typename IntType>
2020
constexpr inline bool operator>=(const integer<nbits, BlockType, NumberType>& lhs, IntType rhs) {
668✔
2021
        return !operator< (lhs, rhs);
668✔
2022
}
2023

2024
//////////////////////////////////////////////////////////////////////////////////////////////////////
2025
// literal - integer binary logic operators
2026
// precondition is that the byte-storage is properly nulled in all arithmetic paths
2027

2028
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2029
constexpr inline bool operator==(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
13✔
2030
        return operator==(integer<nbits, BlockType, NumberType>(lhs), rhs);
13✔
2031
}
2032
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2033
constexpr inline bool operator!=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2034
        return !operator==(lhs, rhs);
6✔
2035
}
2036
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2037
constexpr inline bool operator< (IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
18✔
2038
        return operator<(integer<nbits, BlockType, NumberType>(lhs), rhs);
18✔
2039
}
2040
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2041
constexpr inline bool operator> (IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2042
        return operator< (rhs, lhs);
6✔
2043
}
2044
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2045
constexpr inline bool operator<=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2046
        return operator< (lhs, rhs) || operator==(lhs, rhs);
6✔
2047
}
2048
template<typename IntType, unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2049
constexpr inline bool operator>=(IntType lhs, const integer<nbits, BlockType, NumberType>& rhs) {
6✔
2050
        return !operator< (lhs, rhs);
6✔
2051
}
2052

2053
//////////////////////////////////////////////////////////////////////////////////////////////////////
2054

2055
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2056
constexpr inline integer<nbits, BlockType, NumberType> operator<<(const integer<nbits, BlockType, NumberType>& lhs, int shift) {
182✔
2057
        integer<nbits, BlockType, NumberType> shifted(lhs);
182✔
2058
        return (shifted <<= shift);
364✔
2059
}
2060

2061
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2062
constexpr inline integer<nbits, BlockType, NumberType> operator>>(const integer<nbits, BlockType, NumberType>& lhs, int shift) {
76✔
2063
        integer<nbits, BlockType, NumberType> shifted(lhs);
76✔
2064
        return (shifted >>= shift);
152✔
2065
}
2066

2067
//////////////////////////////////////////////////////////////////////////////////////////////////////
2068
// integer - integer binary arithmetic operators
2069
// BINARY ADDITION
2070
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2071
constexpr inline integer<nbits, BlockType, NumberType> operator+(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
112,436,012✔
2072
        integer<nbits, BlockType, NumberType> sum(lhs);
112,436,012✔
2073
        sum += rhs;
112,436,012✔
2074
        return sum;
112,436,012✔
2075
}
2076
// BINARY SUBTRACTION
2077
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2078
constexpr inline integer<nbits, BlockType, NumberType> operator-(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
89,523,242✔
2079
        integer<nbits, BlockType, NumberType> diff(lhs);
89,523,242✔
2080
        diff -= rhs;
89,523,242✔
2081
        return diff;
89,523,240✔
2082
}
2083
// BINARY MULTIPLICATION
2084
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2085
constexpr inline integer<nbits, BlockType, NumberType> operator*(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
3,648,699✔
2086
        integer<nbits, BlockType, NumberType> mul(lhs);
3,648,699✔
2087
        mul *= rhs;
3,648,699✔
2088
        return mul;
3,648,699✔
2089
}
2090
// BINARY DIVISION
2091
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2092
constexpr inline integer<nbits, BlockType, NumberType> operator/(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4,847,491✔
2093
        integer<nbits, BlockType, NumberType> ratio(lhs);
4,847,491✔
2094
        ratio /= rhs;
4,847,491✔
2095
        return ratio;
4,846,129✔
2096
}
2097
// BINARY REMAINDER
2098
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2099
constexpr inline integer<nbits, BlockType, NumberType> operator%(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
3,270,727✔
2100
        integer<nbits, BlockType, NumberType> ratio(lhs);
3,270,727✔
2101
        ratio %= rhs;
3,270,727✔
2102
        return ratio;
3,270,391✔
2103
}
2104
// BINARY BIT-WISE AND
2105
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2106
constexpr inline integer<nbits, BlockType, NumberType> operator&(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4✔
2107
        integer<nbits, BlockType, NumberType> bitwise(lhs);
4✔
2108
        bitwise &= rhs;
4✔
2109
        return bitwise;
4✔
2110
}
2111
// BINARY BIT-WISE OR
2112
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2113
constexpr inline integer<nbits, BlockType, NumberType> operator|(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2114
        integer<nbits, BlockType, NumberType> bitwise(lhs);
2115
        bitwise |= rhs;
2116
        return bitwise;
2117
}
2118
// BINARY BIT-WISE XOR
2119
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2120
constexpr inline integer<nbits, BlockType, NumberType> operator^(const integer<nbits, BlockType, NumberType>& lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2121
        integer<nbits, BlockType, NumberType> bitwise(lhs);
2122
        bitwise ^= rhs;
2123
        return bitwise;
2124
}
2125

2126
//////////////////////////////////////////////////////////////////////////////////////////////////////
2127
// integer - literal binary arithmetic operators
2128
// BINARY ADDITION
2129
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2130
constexpr inline integer<nbits, BlockType, NumberType> operator+(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
30,360,511✔
2131
        return operator+(lhs, integer<nbits, BlockType, NumberType>(rhs));
30,360,511✔
2132
}
2133
// BINARY SUBTRACTION
2134
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2135
constexpr inline integer<nbits, BlockType, NumberType> operator-(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
7,159,787✔
2136
        return operator-(lhs, integer<nbits, BlockType, NumberType>(rhs));
7,159,787✔
2137
}
2138
// BINARY MULTIPLICATION
2139
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2140
constexpr inline integer<nbits, BlockType, NumberType> operator*(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
4,460✔
2141
        return operator*(lhs, integer<nbits, BlockType, NumberType>(rhs));
4,460✔
2142
}
2143
// BINARY DIVISION
2144
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2145
constexpr inline integer<nbits, BlockType, NumberType> operator/(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
1,513✔
2146
        return operator/(lhs, integer<nbits, BlockType, NumberType>(rhs));
1,513✔
2147
}
2148
// BINARY REMAINDER
2149
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2150
constexpr inline integer<nbits, BlockType, NumberType> operator%(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
6✔
2151
        return operator%(lhs, integer<nbits, BlockType, NumberType>(rhs));
6✔
2152
}
2153
// BINARY BIT-WISE AND
2154
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2155
constexpr inline integer<nbits, BlockType, NumberType> operator&(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2156
        return operator&(lhs, integer<nbits, BlockType, NumberType>(rhs));
2157
}
2158
// BINARY BIT-WISE OR
2159
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2160
constexpr inline integer<nbits, BlockType, NumberType> operator|(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2161
        return operator|(lhs, integer<nbits, BlockType, NumberType>(rhs));
2162
}
2163
// BINARY BIT-WISE XOR
2164
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2165
constexpr inline integer<nbits, BlockType, NumberType> operator^(const integer<nbits, BlockType, NumberType>& lhs, long long rhs) {
2166
        return operator^(lhs, integer<nbits, BlockType, NumberType>(rhs));
2167
}
2168
//////////////////////////////////////////////////////////////////////////////////////////////////////
2169
// literal - integer binary arithmetic operators
2170
// BINARY ADDITION
2171
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2172
constexpr inline integer<nbits, BlockType, NumberType> operator+(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
1✔
2173
        return operator+(integer<nbits, BlockType, NumberType>(lhs), rhs);
1✔
2174
}
2175
// BINARY SUBTRACTION
2176
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2177
constexpr inline integer<nbits, BlockType, NumberType> operator-(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
563✔
2178
        return operator-(integer<nbits, BlockType, NumberType>(lhs), rhs);
563✔
2179
}
2180
// BINARY MULTIPLICATION
2181
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2182
constexpr inline integer<nbits, BlockType, NumberType> operator*(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
4✔
2183
        return operator*(integer<nbits, BlockType, NumberType>(lhs), rhs);
4✔
2184
}
2185
// BINARY DIVISION
2186
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2187
constexpr inline integer<nbits, BlockType, NumberType> operator/(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2188
        return operator/(integer<nbits, BlockType, NumberType>(lhs), rhs);
2189
}
2190
// BINARY REMAINDER
2191
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2192
constexpr inline integer<nbits, BlockType, NumberType> operator%(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2193
        return operator%(integer<nbits, BlockType, NumberType>(lhs), rhs);
2194
}
2195
// BINARY BIT-WISE AND
2196
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2197
constexpr inline integer<nbits, BlockType, NumberType> operator&(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2198
        return operator&(integer<nbits, BlockType, NumberType>(lhs), rhs);
2199
}
2200
// BINARY BIT-WISE OR
2201
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2202
constexpr inline integer<nbits, BlockType, NumberType> operator|(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2203
        return operator|(integer<nbits, BlockType, NumberType>(lhs), rhs);
2204
}
2205
// BINARY BIT-WISE XOR
2206
template<unsigned nbits, typename BlockType, IntegerNumberType NumberType>
2207
constexpr inline integer<nbits, BlockType, NumberType> operator^(long long lhs, const integer<nbits, BlockType, NumberType>& rhs) {
2208
        return operator^(integer<nbits, BlockType, NumberType>(lhs), rhs);
2209
}
2210

2211
}} // namespace sw::universal
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc