xref: /netbsd-src/external/gpl3/gcc.old/dist/libphobos/src/std/bigint.d (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1*627f7eb2Smrg /** Arbitrary-precision ('bignum') arithmetic.
2*627f7eb2Smrg  *
3*627f7eb2Smrg  * Performance is optimized for numbers below ~1000 decimal digits.
4*627f7eb2Smrg  * For X86 machines, highly optimised assembly routines are used.
5*627f7eb2Smrg  *
6*627f7eb2Smrg  * The following algorithms are currently implemented:
7*627f7eb2Smrg  * $(UL
8*627f7eb2Smrg  * $(LI Karatsuba multiplication)
9*627f7eb2Smrg  * $(LI Squaring is optimized independently of multiplication)
10*627f7eb2Smrg  * $(LI Divide-and-conquer division)
11*627f7eb2Smrg  * $(LI Binary exponentiation)
12*627f7eb2Smrg  * )
13*627f7eb2Smrg  *
14*627f7eb2Smrg  * For very large numbers, consider using the $(HTTP gmplib.org, GMP library) instead.
15*627f7eb2Smrg  *
16*627f7eb2Smrg  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
17*627f7eb2Smrg  * Authors:   Don Clugston
18*627f7eb2Smrg  * Source: $(PHOBOSSRC std/_bigint.d)
19*627f7eb2Smrg  */
20*627f7eb2Smrg /*          Copyright Don Clugston 2008 - 2010.
21*627f7eb2Smrg  * Distributed under the Boost Software License, Version 1.0.
22*627f7eb2Smrg  *    (See accompanying file LICENSE_1_0.txt or copy at
23*627f7eb2Smrg  *          http://www.boost.org/LICENSE_1_0.txt)
24*627f7eb2Smrg  */
25*627f7eb2Smrg 
26*627f7eb2Smrg module std.bigint;
27*627f7eb2Smrg 
28*627f7eb2Smrg import std.conv : ConvException;
29*627f7eb2Smrg 
30*627f7eb2Smrg import std.format : FormatSpec, FormatException;
31*627f7eb2Smrg import std.internal.math.biguintcore;
32*627f7eb2Smrg import std.range.primitives;
33*627f7eb2Smrg import std.traits;
34*627f7eb2Smrg 
35*627f7eb2Smrg /** A struct representing an arbitrary precision integer.
36*627f7eb2Smrg  *
37*627f7eb2Smrg  * All arithmetic operations are supported, except unsigned shift right (>>>).
38*627f7eb2Smrg  * Bitwise operations (|, &, ^, ~) are supported, and behave as if BigInt was
39*627f7eb2Smrg  * an infinite length 2's complement number.
40*627f7eb2Smrg  *
41*627f7eb2Smrg  * BigInt implements value semantics using copy-on-write. This means that
42*627f7eb2Smrg  * assignment is cheap, but operations such as x++ will cause heap
43*627f7eb2Smrg  * allocation. (But note that for most bigint operations, heap allocation is
44*627f7eb2Smrg  * inevitable anyway.)
45*627f7eb2Smrg  */
46*627f7eb2Smrg struct BigInt
47*627f7eb2Smrg {
48*627f7eb2Smrg private:
49*627f7eb2Smrg     BigUint data;     // BigInt adds signed arithmetic to BigUint.
50*627f7eb2Smrg     bool sign = false;
51*627f7eb2Smrg public:
52*627f7eb2Smrg     /**
53*627f7eb2Smrg      * Construct a BigInt from a decimal or hexadecimal string. The number must
54*627f7eb2Smrg      * be in the form of a decimal or hex literal. It may have a leading `+`
55*627f7eb2Smrg      * or `-` sign, followed by `0x` or `0X` if hexadecimal. Underscores are
56*627f7eb2Smrg      * permitted in any location after the `0x` and/or the sign of the number.
57*627f7eb2Smrg      *
58*627f7eb2Smrg      * Params:
59*627f7eb2Smrg      *     s = a finite bidirectional range of any character type
60*627f7eb2Smrg      *
61*627f7eb2Smrg      * Throws:
62*627f7eb2Smrg      *     $(REF ConvException, std,conv) if the string doesn't represent a valid number
63*627f7eb2Smrg      */
64*627f7eb2Smrg     this(Range)(Range s) if (
65*627f7eb2Smrg         isBidirectionalRange!Range &&
66*627f7eb2Smrg         isSomeChar!(ElementType!Range) &&
67*627f7eb2Smrg         !isInfinite!Range &&
68*627f7eb2Smrg         !isSomeString!Range)
69*627f7eb2Smrg     {
70*627f7eb2Smrg         import std.algorithm.iteration : filterBidirectional;
71*627f7eb2Smrg         import std.algorithm.searching : startsWith;
72*627f7eb2Smrg         import std.conv : ConvException;
73*627f7eb2Smrg         import std.exception : enforce;
74*627f7eb2Smrg         import std.utf : byChar;
75*627f7eb2Smrg 
76*627f7eb2Smrg         enforce!ConvException(!s.empty, "Can't initialize BigInt with an empty range");
77*627f7eb2Smrg 
78*627f7eb2Smrg         bool neg = false;
79*627f7eb2Smrg         bool ok;
80*627f7eb2Smrg 
81*627f7eb2Smrg         data = 0UL;
82*627f7eb2Smrg 
83*627f7eb2Smrg         // check for signs and if the string is a hex value
84*627f7eb2Smrg         if (s.front == '+')
85*627f7eb2Smrg         {
86*627f7eb2Smrg             s.popFront(); // skip '+'
87*627f7eb2Smrg         }
88*627f7eb2Smrg         else if (s.front == '-')
89*627f7eb2Smrg         {
90*627f7eb2Smrg             neg = true;
91*627f7eb2Smrg             s.popFront();
92*627f7eb2Smrg         }
93*627f7eb2Smrg 
94*627f7eb2Smrg         if (s.save.startsWith("0x".byChar) ||
95*627f7eb2Smrg             s.save.startsWith("0X".byChar))
96*627f7eb2Smrg         {
97*627f7eb2Smrg             s.popFront;
98*627f7eb2Smrg             s.popFront;
99*627f7eb2Smrg 
100*627f7eb2Smrg             if (!s.empty)
101*627f7eb2Smrg                 ok = data.fromHexString(s.filterBidirectional!(a => a != '_'));
102*627f7eb2Smrg             else
103*627f7eb2Smrg                 ok = false;
104*627f7eb2Smrg         }
105*627f7eb2Smrg         else
106*627f7eb2Smrg         {
107*627f7eb2Smrg             ok = data.fromDecimalString(s.filterBidirectional!(a => a != '_'));
108*627f7eb2Smrg         }
109*627f7eb2Smrg 
110*627f7eb2Smrg         enforce!ConvException(ok, "Not a valid numerical string");
111*627f7eb2Smrg 
112*627f7eb2Smrg         if (isZero())
113*627f7eb2Smrg             neg = false;
114*627f7eb2Smrg 
115*627f7eb2Smrg         sign = neg;
116*627f7eb2Smrg     }
117*627f7eb2Smrg 
118*627f7eb2Smrg     /// ditto
119*627f7eb2Smrg     this(Range)(Range s) pure if (isSomeString!Range)
120*627f7eb2Smrg     {
121*627f7eb2Smrg         import std.utf : byCodeUnit;
122*627f7eb2Smrg         this(s.byCodeUnit);
123*627f7eb2Smrg     }
124*627f7eb2Smrg 
125*627f7eb2Smrg     @system unittest
126*627f7eb2Smrg     {
127*627f7eb2Smrg         // system because of the dummy ranges eventually call std.array!string
128*627f7eb2Smrg         import std.exception : assertThrown;
129*627f7eb2Smrg         import std.internal.test.dummyrange;
130*627f7eb2Smrg 
131*627f7eb2Smrg         auto r1 = new ReferenceBidirectionalRange!dchar("101");
132*627f7eb2Smrg         auto big1 = BigInt(r1);
133*627f7eb2Smrg         assert(big1 == BigInt(101));
134*627f7eb2Smrg 
135*627f7eb2Smrg         auto r2 = new ReferenceBidirectionalRange!dchar("1_000");
136*627f7eb2Smrg         auto big2 = BigInt(r2);
137*627f7eb2Smrg         assert(big2 == BigInt(1000));
138*627f7eb2Smrg 
139*627f7eb2Smrg         auto r3 = new ReferenceBidirectionalRange!dchar("0x0");
140*627f7eb2Smrg         auto big3 = BigInt(r3);
141*627f7eb2Smrg         assert(big3 == BigInt(0));
142*627f7eb2Smrg 
143*627f7eb2Smrg         auto r4 = new ReferenceBidirectionalRange!dchar("0x");
144*627f7eb2Smrg         assertThrown!ConvException(BigInt(r4));
145*627f7eb2Smrg     }
146*627f7eb2Smrg 
147*627f7eb2Smrg     /// Construct a BigInt from a built-in integral type.
148*627f7eb2Smrg     this(T)(T x) pure nothrow if (isIntegral!T)
149*627f7eb2Smrg     {
150*627f7eb2Smrg         data = data.init; // @@@: Workaround for compiler bug
151*627f7eb2Smrg         opAssign(x);
152*627f7eb2Smrg     }
153*627f7eb2Smrg 
154*627f7eb2Smrg     ///
155*627f7eb2Smrg     @system unittest
156*627f7eb2Smrg     {
157*627f7eb2Smrg         // @system due to failure in FreeBSD32
158*627f7eb2Smrg         ulong data = 1_000_000_000_000;
159*627f7eb2Smrg         auto bigData = BigInt(data);
160*627f7eb2Smrg         assert(data == BigInt("1_000_000_000_000"));
161*627f7eb2Smrg     }
162*627f7eb2Smrg 
163*627f7eb2Smrg     /// Construct a BigInt from another BigInt.
164*627f7eb2Smrg     this(T)(T x) pure nothrow if (is(Unqual!T == BigInt))
165*627f7eb2Smrg     {
166*627f7eb2Smrg         opAssign(x);
167*627f7eb2Smrg     }
168*627f7eb2Smrg 
169*627f7eb2Smrg     ///
170*627f7eb2Smrg     @system unittest
171*627f7eb2Smrg     {
172*627f7eb2Smrg         const(BigInt) b1 = BigInt("1_234_567_890");
173*627f7eb2Smrg         BigInt b2 = BigInt(b1);
174*627f7eb2Smrg         assert(b2 == BigInt("1_234_567_890"));
175*627f7eb2Smrg     }
176*627f7eb2Smrg 
177*627f7eb2Smrg     /// Assignment from built-in integer types.
178*627f7eb2Smrg     BigInt opAssign(T)(T x) pure nothrow if (isIntegral!T)
179*627f7eb2Smrg     {
180*627f7eb2Smrg         data = cast(ulong) absUnsign(x);
181*627f7eb2Smrg         sign = (x < 0);
182*627f7eb2Smrg         return this;
183*627f7eb2Smrg     }
184*627f7eb2Smrg 
185*627f7eb2Smrg     ///
186*627f7eb2Smrg     @system unittest
187*627f7eb2Smrg     {
188*627f7eb2Smrg         auto b = BigInt("123");
189*627f7eb2Smrg         b = 456;
190*627f7eb2Smrg         assert(b == BigInt("456"));
191*627f7eb2Smrg     }
192*627f7eb2Smrg 
193*627f7eb2Smrg     /// Assignment from another BigInt.
194*627f7eb2Smrg     BigInt opAssign(T:BigInt)(T x) pure @nogc
195*627f7eb2Smrg     {
196*627f7eb2Smrg         data = x.data;
197*627f7eb2Smrg         sign = x.sign;
198*627f7eb2Smrg         return this;
199*627f7eb2Smrg     }
200*627f7eb2Smrg 
201*627f7eb2Smrg     ///
202*627f7eb2Smrg     @system unittest
203*627f7eb2Smrg     {
204*627f7eb2Smrg         auto b1 = BigInt("123");
205*627f7eb2Smrg         auto b2 = BigInt("456");
206*627f7eb2Smrg         b2 = b1;
207*627f7eb2Smrg         assert(b2 == BigInt("123"));
208*627f7eb2Smrg     }
209*627f7eb2Smrg 
210*627f7eb2Smrg     /**
211*627f7eb2Smrg      * Implements assignment operators from built-in integers of the form
212*627f7eb2Smrg      * $(D BigInt op= integer).
213*627f7eb2Smrg      */
214*627f7eb2Smrg     BigInt opOpAssign(string op, T)(T y) pure nothrow
215*627f7eb2Smrg         if ((op=="+" || op=="-" || op=="*" || op=="/" || op=="%"
216*627f7eb2Smrg           || op==">>" || op=="<<" || op=="^^" || op=="|" || op=="&" || op=="^") && isIntegral!T)
217*627f7eb2Smrg     {
218*627f7eb2Smrg         ulong u = absUnsign(y);
219*627f7eb2Smrg 
220*627f7eb2Smrg         static if (op=="+")
221*627f7eb2Smrg         {
222*627f7eb2Smrg             data = BigUint.addOrSubInt(data, u, sign != (y<0), sign);
223*627f7eb2Smrg         }
224*627f7eb2Smrg         else static if (op=="-")
225*627f7eb2Smrg         {
226*627f7eb2Smrg             data = BigUint.addOrSubInt(data, u, sign == (y<0), sign);
227*627f7eb2Smrg         }
228*627f7eb2Smrg         else static if (op=="*")
229*627f7eb2Smrg         {
230*627f7eb2Smrg             if (y == 0)
231*627f7eb2Smrg             {
232*627f7eb2Smrg                 sign = false;
233*627f7eb2Smrg                 data = 0UL;
234*627f7eb2Smrg             }
235*627f7eb2Smrg             else
236*627f7eb2Smrg             {
237*627f7eb2Smrg                 sign = ( sign != (y<0) );
238*627f7eb2Smrg                 data = BigUint.mulInt(data, u);
239*627f7eb2Smrg             }
240*627f7eb2Smrg         }
241*627f7eb2Smrg         else static if (op=="/")
242*627f7eb2Smrg         {
243*627f7eb2Smrg             assert(y != 0, "Division by zero");
244*627f7eb2Smrg             static if (T.sizeof <= uint.sizeof)
245*627f7eb2Smrg             {
246*627f7eb2Smrg                 data = BigUint.divInt(data, cast(uint) u);
247*627f7eb2Smrg             }
248*627f7eb2Smrg             else
249*627f7eb2Smrg             {
250*627f7eb2Smrg                 data = BigUint.divInt(data, u);
251*627f7eb2Smrg             }
252*627f7eb2Smrg             sign = data.isZero() ? false : sign ^ (y < 0);
253*627f7eb2Smrg         }
254*627f7eb2Smrg         else static if (op=="%")
255*627f7eb2Smrg         {
256*627f7eb2Smrg             assert(y != 0, "Division by zero");
257*627f7eb2Smrg             static if (is(immutable(T) == immutable(long)) || is( immutable(T) == immutable(ulong) ))
258*627f7eb2Smrg             {
259*627f7eb2Smrg                 this %= BigInt(y);
260*627f7eb2Smrg             }
261*627f7eb2Smrg             else
262*627f7eb2Smrg             {
263*627f7eb2Smrg                 data = cast(ulong) BigUint.modInt(data, cast(uint) u);
264*627f7eb2Smrg                 if (data.isZero())
265*627f7eb2Smrg                     sign = false;
266*627f7eb2Smrg             }
267*627f7eb2Smrg             // x%y always has the same sign as x.
268*627f7eb2Smrg             // This is not the same as mathematical mod.
269*627f7eb2Smrg         }
270*627f7eb2Smrg         else static if (op==">>" || op=="<<")
271*627f7eb2Smrg         {
272*627f7eb2Smrg             // Do a left shift if y>0 and <<, or
273*627f7eb2Smrg             // if y<0 and >>; else do a right shift.
274*627f7eb2Smrg             if (y == 0)
275*627f7eb2Smrg                 return this;
276*627f7eb2Smrg             else if ((y > 0) == (op=="<<"))
277*627f7eb2Smrg             {
278*627f7eb2Smrg                 // Sign never changes during left shift
279*627f7eb2Smrg                 data = data.opShl(u);
280*627f7eb2Smrg             } else
281*627f7eb2Smrg             {
282*627f7eb2Smrg                 data = data.opShr(u);
283*627f7eb2Smrg                 if (data.isZero())
284*627f7eb2Smrg                     sign = false;
285*627f7eb2Smrg             }
286*627f7eb2Smrg         }
287*627f7eb2Smrg         else static if (op=="^^")
288*627f7eb2Smrg         {
289*627f7eb2Smrg             sign = (y & 1) ? sign : false;
290*627f7eb2Smrg             data = BigUint.pow(data, u);
291*627f7eb2Smrg         }
292*627f7eb2Smrg         else static if (op=="|" || op=="&" || op=="^")
293*627f7eb2Smrg         {
294*627f7eb2Smrg             BigInt b = y;
295*627f7eb2Smrg             opOpAssign!op(b);
296*627f7eb2Smrg         }
297*627f7eb2Smrg         else static assert(0, "BigInt " ~ op[0..$-1] ~ "= " ~ T.stringof ~ " is not supported");
298*627f7eb2Smrg         return this;
299*627f7eb2Smrg     }
300*627f7eb2Smrg 
301*627f7eb2Smrg     ///
302*627f7eb2Smrg     @system unittest
303*627f7eb2Smrg     {
304*627f7eb2Smrg         //@system because opOpAssign is @system
305*627f7eb2Smrg         auto b = BigInt("1_000_000_000");
306*627f7eb2Smrg 
307*627f7eb2Smrg         b += 12345;
308*627f7eb2Smrg         assert(b == BigInt("1_000_012_345"));
309*627f7eb2Smrg 
310*627f7eb2Smrg         b /= 5;
311*627f7eb2Smrg         assert(b == BigInt("200_002_469"));
312*627f7eb2Smrg     }
313*627f7eb2Smrg 
314*627f7eb2Smrg     /**
315*627f7eb2Smrg      * Implements assignment operators of the form $(D BigInt op= BigInt).
316*627f7eb2Smrg      */
317*627f7eb2Smrg     BigInt opOpAssign(string op, T)(T y) pure nothrow
318*627f7eb2Smrg         if ((op=="+" || op== "-" || op=="*" || op=="|" || op=="&" || op=="^" || op=="/" || op=="%")
319*627f7eb2Smrg             && is (T: BigInt))
320*627f7eb2Smrg     {
321*627f7eb2Smrg         static if (op == "+")
322*627f7eb2Smrg         {
323*627f7eb2Smrg             data = BigUint.addOrSub(data, y.data, sign != y.sign, &sign);
324*627f7eb2Smrg         }
325*627f7eb2Smrg         else static if (op == "-")
326*627f7eb2Smrg         {
327*627f7eb2Smrg             data = BigUint.addOrSub(data, y.data, sign == y.sign, &sign);
328*627f7eb2Smrg         }
329*627f7eb2Smrg         else static if (op == "*")
330*627f7eb2Smrg         {
331*627f7eb2Smrg             data = BigUint.mul(data, y.data);
332*627f7eb2Smrg             sign = isZero() ? false : sign ^ y.sign;
333*627f7eb2Smrg         }
334*627f7eb2Smrg         else static if (op == "/")
335*627f7eb2Smrg         {
336*627f7eb2Smrg             y.checkDivByZero();
337*627f7eb2Smrg             if (!isZero())
338*627f7eb2Smrg             {
339*627f7eb2Smrg                 data = BigUint.div(data, y.data);
340*627f7eb2Smrg                 sign = isZero() ? false : sign ^ y.sign;
341*627f7eb2Smrg             }
342*627f7eb2Smrg         }
343*627f7eb2Smrg         else static if (op == "%")
344*627f7eb2Smrg         {
345*627f7eb2Smrg             y.checkDivByZero();
346*627f7eb2Smrg             if (!isZero())
347*627f7eb2Smrg             {
348*627f7eb2Smrg                 data = BigUint.mod(data, y.data);
349*627f7eb2Smrg                 // x%y always has the same sign as x.
350*627f7eb2Smrg                 if (isZero())
351*627f7eb2Smrg                     sign = false;
352*627f7eb2Smrg             }
353*627f7eb2Smrg         }
354*627f7eb2Smrg         else static if (op == "|" || op == "&" || op == "^")
355*627f7eb2Smrg         {
356*627f7eb2Smrg             data = BigUint.bitwiseOp!op(data, y.data, sign, y.sign, sign);
357*627f7eb2Smrg         }
358*627f7eb2Smrg         else static assert(0, "BigInt " ~ op[0..$-1] ~ "= " ~
359*627f7eb2Smrg             T.stringof ~ " is not supported");
360*627f7eb2Smrg         return this;
361*627f7eb2Smrg     }
362*627f7eb2Smrg 
363*627f7eb2Smrg     ///
364*627f7eb2Smrg     @system unittest
365*627f7eb2Smrg     {
366*627f7eb2Smrg         // @system because opOpAssign is @system
367*627f7eb2Smrg         auto x = BigInt("123");
368*627f7eb2Smrg         auto y = BigInt("321");
369*627f7eb2Smrg         x += y;
370*627f7eb2Smrg         assert(x == BigInt("444"));
371*627f7eb2Smrg     }
372*627f7eb2Smrg 
373*627f7eb2Smrg     /**
374*627f7eb2Smrg      * Implements binary operators between BigInts.
375*627f7eb2Smrg      */
376*627f7eb2Smrg     BigInt opBinary(string op, T)(T y) pure nothrow const
377*627f7eb2Smrg         if ((op=="+" || op == "*" || op=="-" || op=="|" || op=="&" || op=="^" ||
378*627f7eb2Smrg             op=="/" || op=="%")
379*627f7eb2Smrg             && is (T: BigInt))
380*627f7eb2Smrg     {
381*627f7eb2Smrg         BigInt r = this;
382*627f7eb2Smrg         return r.opOpAssign!(op)(y);
383*627f7eb2Smrg     }
384*627f7eb2Smrg 
385*627f7eb2Smrg     ///
386*627f7eb2Smrg     @system unittest
387*627f7eb2Smrg     {
388*627f7eb2Smrg         auto x = BigInt("123");
389*627f7eb2Smrg         auto y = BigInt("456");
390*627f7eb2Smrg         BigInt z = x * y;
391*627f7eb2Smrg         assert(z == BigInt("56088"));
392*627f7eb2Smrg     }
393*627f7eb2Smrg 
394*627f7eb2Smrg     /**
395*627f7eb2Smrg      * Implements binary operators between BigInt's and built-in integers.
396*627f7eb2Smrg      */
397*627f7eb2Smrg     BigInt opBinary(string op, T)(T y) pure nothrow const
398*627f7eb2Smrg         if ((op=="+" || op == "*" || op=="-" || op=="/" || op=="|" || op=="&" ||
399*627f7eb2Smrg             op=="^"|| op==">>" || op=="<<" || op=="^^")
400*627f7eb2Smrg             && isIntegral!T)
401*627f7eb2Smrg     {
402*627f7eb2Smrg         BigInt r = this;
403*627f7eb2Smrg         return r.opOpAssign!(op)(y);
404*627f7eb2Smrg     }
405*627f7eb2Smrg 
406*627f7eb2Smrg     ///
407*627f7eb2Smrg     @system unittest
408*627f7eb2Smrg     {
409*627f7eb2Smrg         auto x = BigInt("123");
410*627f7eb2Smrg         x *= 300;
411*627f7eb2Smrg         assert(x == BigInt("36900"));
412*627f7eb2Smrg     }
413*627f7eb2Smrg 
414*627f7eb2Smrg     /**
415*627f7eb2Smrg         Implements a narrowing remainder operation with built-in integer types.
416*627f7eb2Smrg 
417*627f7eb2Smrg         This binary operator returns a narrower, built-in integer type
418*627f7eb2Smrg         where applicable, according to the following table.
419*627f7eb2Smrg 
420*627f7eb2Smrg         $(TABLE ,
421*627f7eb2Smrg         $(TR $(TD `BigInt`) $(TD $(CODE_PERCENT)) $(TD `long`) $(TD $(RARR)) $(TD `long`))
422*627f7eb2Smrg         $(TR $(TD `BigInt`) $(TD $(CODE_PERCENT)) $(TD `ulong`) $(TD $(RARR)) $(TD `BigInt`))
423*627f7eb2Smrg         $(TR $(TD `BigInt`) $(TD $(CODE_PERCENT)) $(TD other type) $(TD $(RARR)) $(TD `int`))
424*627f7eb2Smrg         )
425*627f7eb2Smrg      */
426*627f7eb2Smrg     auto opBinary(string op, T)(T y) pure nothrow const
427*627f7eb2Smrg         if (op == "%" && isIntegral!T)
428*627f7eb2Smrg     {
429*627f7eb2Smrg         assert(y != 0);
430*627f7eb2Smrg 
431*627f7eb2Smrg         // BigInt % long => long
432*627f7eb2Smrg         // BigInt % ulong => BigInt
433*627f7eb2Smrg         // BigInt % other_type => int
434*627f7eb2Smrg         static if (is(Unqual!T == long) || is(Unqual!T == ulong))
435*627f7eb2Smrg         {
436*627f7eb2Smrg             auto r = this % BigInt(y);
437*627f7eb2Smrg 
438*627f7eb2Smrg             static if (is(Unqual!T == long))
439*627f7eb2Smrg             {
440*627f7eb2Smrg                 return r.toLong();
441*627f7eb2Smrg             }
442*627f7eb2Smrg             else
443*627f7eb2Smrg             {
444*627f7eb2Smrg                 // return as-is to avoid overflow
445*627f7eb2Smrg                 return r;
446*627f7eb2Smrg             }
447*627f7eb2Smrg         }
448*627f7eb2Smrg         else
449*627f7eb2Smrg         {
450*627f7eb2Smrg             immutable uint u = absUnsign(y);
451*627f7eb2Smrg             int rem = BigUint.modInt(data, u);
452*627f7eb2Smrg             // x%y always has the same sign as x.
453*627f7eb2Smrg             // This is not the same as mathematical mod.
454*627f7eb2Smrg             return sign ? -rem : rem;
455*627f7eb2Smrg         }
456*627f7eb2Smrg     }
457*627f7eb2Smrg 
458*627f7eb2Smrg     ///
459*627f7eb2Smrg     @system unittest
460*627f7eb2Smrg     {
461*627f7eb2Smrg         auto  x  = BigInt("1_000_000_500");
462*627f7eb2Smrg         long  l  = 1_000_000L;
463*627f7eb2Smrg         ulong ul = 2_000_000UL;
464*627f7eb2Smrg         int   i  = 500_000;
465*627f7eb2Smrg         short s  = 30_000;
466*627f7eb2Smrg 
467*627f7eb2Smrg         assert(is(typeof(x % l)  == long)   && x % l  == 500L);
468*627f7eb2Smrg         assert(is(typeof(x % ul) == BigInt) && x % ul == BigInt(500));
469*627f7eb2Smrg         assert(is(typeof(x % i)  == int)    && x % i  == 500);
470*627f7eb2Smrg         assert(is(typeof(x % s)  == int)    && x % s  == 10500);
471*627f7eb2Smrg     }
472*627f7eb2Smrg 
473*627f7eb2Smrg     /**
474*627f7eb2Smrg         Implements operators with built-in integers on the left-hand side and
475*627f7eb2Smrg         BigInt on the right-hand side.
476*627f7eb2Smrg      */
477*627f7eb2Smrg     BigInt opBinaryRight(string op, T)(T y) pure nothrow const
478*627f7eb2Smrg         if ((op=="+" || op=="*" || op=="|" || op=="&" || op=="^") && isIntegral!T)
479*627f7eb2Smrg     {
480*627f7eb2Smrg         return opBinary!(op)(y);
481*627f7eb2Smrg     }
482*627f7eb2Smrg 
483*627f7eb2Smrg     ///
484*627f7eb2Smrg     @system unittest
485*627f7eb2Smrg     {
486*627f7eb2Smrg         auto x = BigInt("100");
487*627f7eb2Smrg         BigInt y = 123 + x;
488*627f7eb2Smrg         assert(y == BigInt("223"));
489*627f7eb2Smrg 
490*627f7eb2Smrg         BigInt z = 123 - x;
491*627f7eb2Smrg         assert(z == BigInt("23"));
492*627f7eb2Smrg 
493*627f7eb2Smrg         // Dividing a built-in integer type by BigInt always results in
494*627f7eb2Smrg         // something that fits in a built-in type, so the built-in type is
495*627f7eb2Smrg         // returned, not BigInt.
496*627f7eb2Smrg         assert(is(typeof(1000 / x) == int));
497*627f7eb2Smrg         assert(1000 / x == 10);
498*627f7eb2Smrg     }
499*627f7eb2Smrg 
500*627f7eb2Smrg     //  BigInt = integer op BigInt
501*627f7eb2Smrg     /// ditto
502*627f7eb2Smrg     BigInt opBinaryRight(string op, T)(T y) pure nothrow const
503*627f7eb2Smrg         if (op == "-" && isIntegral!T)
504*627f7eb2Smrg     {
505*627f7eb2Smrg         ulong u = absUnsign(y);
506*627f7eb2Smrg         BigInt r;
507*627f7eb2Smrg         static if (op == "-")
508*627f7eb2Smrg         {
509*627f7eb2Smrg             r.sign = sign;
510*627f7eb2Smrg             r.data = BigUint.addOrSubInt(data, u, sign == (y<0), r.sign);
511*627f7eb2Smrg             r.negate();
512*627f7eb2Smrg         }
513*627f7eb2Smrg         return r;
514*627f7eb2Smrg     }
515*627f7eb2Smrg 
516*627f7eb2Smrg     //  integer = integer op BigInt
517*627f7eb2Smrg     /// ditto
518*627f7eb2Smrg     T opBinaryRight(string op, T)(T x) pure nothrow const
519*627f7eb2Smrg         if ((op=="%" || op=="/") && isIntegral!T)
520*627f7eb2Smrg     {
521*627f7eb2Smrg         checkDivByZero();
522*627f7eb2Smrg 
523*627f7eb2Smrg         static if (op == "%")
524*627f7eb2Smrg         {
525*627f7eb2Smrg             // x%y always has the same sign as x.
526*627f7eb2Smrg             if (data.ulongLength > 1)
527*627f7eb2Smrg                 return x;
528*627f7eb2Smrg             immutable u = absUnsign(x);
529*627f7eb2Smrg             immutable rem = u % data.peekUlong(0);
530*627f7eb2Smrg             // x%y always has the same sign as x.
531*627f7eb2Smrg             return cast(T)((x<0) ? -rem : rem);
532*627f7eb2Smrg         }
533*627f7eb2Smrg         else static if (op == "/")
534*627f7eb2Smrg         {
535*627f7eb2Smrg             if (data.ulongLength > 1)
536*627f7eb2Smrg                 return 0;
537*627f7eb2Smrg             return cast(T)(x / data.peekUlong(0));
538*627f7eb2Smrg         }
539*627f7eb2Smrg     }
540*627f7eb2Smrg 
541*627f7eb2Smrg     // const unary operations
542*627f7eb2Smrg     /**
543*627f7eb2Smrg         Implements BigInt unary operators.
544*627f7eb2Smrg      */
545*627f7eb2Smrg     BigInt opUnary(string op)() pure nothrow const if (op=="+" || op=="-" || op=="~")
546*627f7eb2Smrg     {
547*627f7eb2Smrg        static if (op=="-")
548*627f7eb2Smrg        {
549*627f7eb2Smrg             BigInt r = this;
550*627f7eb2Smrg             r.negate();
551*627f7eb2Smrg             return r;
552*627f7eb2Smrg         }
553*627f7eb2Smrg         else static if (op=="~")
554*627f7eb2Smrg         {
555*627f7eb2Smrg             return -(this+1);
556*627f7eb2Smrg         }
557*627f7eb2Smrg         else static if (op=="+")
558*627f7eb2Smrg            return this;
559*627f7eb2Smrg     }
560*627f7eb2Smrg 
561*627f7eb2Smrg     // non-const unary operations
562*627f7eb2Smrg     /// ditto
563*627f7eb2Smrg     BigInt opUnary(string op)() pure nothrow if (op=="++" || op=="--")
564*627f7eb2Smrg     {
565*627f7eb2Smrg         static if (op=="++")
566*627f7eb2Smrg         {
567*627f7eb2Smrg             data = BigUint.addOrSubInt(data, 1UL, sign, sign);
568*627f7eb2Smrg             return this;
569*627f7eb2Smrg         }
570*627f7eb2Smrg         else static if (op=="--")
571*627f7eb2Smrg         {
572*627f7eb2Smrg             data = BigUint.addOrSubInt(data, 1UL, !sign, sign);
573*627f7eb2Smrg             return this;
574*627f7eb2Smrg         }
575*627f7eb2Smrg     }
576*627f7eb2Smrg 
577*627f7eb2Smrg     ///
578*627f7eb2Smrg     @system unittest
579*627f7eb2Smrg     {
580*627f7eb2Smrg         auto x = BigInt("1234");
581*627f7eb2Smrg         assert(-x == BigInt("-1234"));
582*627f7eb2Smrg 
583*627f7eb2Smrg         ++x;
584*627f7eb2Smrg         assert(x == BigInt("1235"));
585*627f7eb2Smrg     }
586*627f7eb2Smrg 
587*627f7eb2Smrg     /**
588*627f7eb2Smrg         Implements BigInt equality test with other BigInt's and built-in
589*627f7eb2Smrg         integer types.
590*627f7eb2Smrg      */
opEqualsBigInt591*627f7eb2Smrg     bool opEquals()(auto ref const BigInt y) const pure @nogc
592*627f7eb2Smrg     {
593*627f7eb2Smrg        return sign == y.sign && y.data == data;
594*627f7eb2Smrg     }
595*627f7eb2Smrg 
596*627f7eb2Smrg     /// ditto
597*627f7eb2Smrg     bool opEquals(T)(T y) const pure nothrow @nogc if (isIntegral!T)
598*627f7eb2Smrg     {
599*627f7eb2Smrg         if (sign != (y<0))
600*627f7eb2Smrg             return 0;
601*627f7eb2Smrg         return data.opEquals(cast(ulong) absUnsign(y));
602*627f7eb2Smrg     }
603*627f7eb2Smrg 
604*627f7eb2Smrg     ///
605*627f7eb2Smrg     @system unittest
606*627f7eb2Smrg     {
607*627f7eb2Smrg         auto x = BigInt("12345");
608*627f7eb2Smrg         auto y = BigInt("12340");
609*627f7eb2Smrg         int z = 12345;
610*627f7eb2Smrg         int w = 54321;
611*627f7eb2Smrg 
612*627f7eb2Smrg         assert(x == x);
613*627f7eb2Smrg         assert(x != y);
614*627f7eb2Smrg         assert(x == y + 5);
615*627f7eb2Smrg         assert(x == z);
616*627f7eb2Smrg         assert(x != w);
617*627f7eb2Smrg     }
618*627f7eb2Smrg 
619*627f7eb2Smrg     /**
620*627f7eb2Smrg         Implements casting to bool.
621*627f7eb2Smrg      */
622*627f7eb2Smrg     T opCast(T:bool)() pure nothrow @nogc const
623*627f7eb2Smrg     {
624*627f7eb2Smrg         return !isZero();
625*627f7eb2Smrg     }
626*627f7eb2Smrg 
627*627f7eb2Smrg     ///
628*627f7eb2Smrg     @system unittest
629*627f7eb2Smrg     {
630*627f7eb2Smrg         // Non-zero values are regarded as true
631*627f7eb2Smrg         auto x = BigInt("1");
632*627f7eb2Smrg         auto y = BigInt("10");
633*627f7eb2Smrg         assert(x);
634*627f7eb2Smrg         assert(y);
635*627f7eb2Smrg 
636*627f7eb2Smrg         // Zero value is regarded as false
637*627f7eb2Smrg         auto z = BigInt("0");
638*627f7eb2Smrg         assert(!z);
639*627f7eb2Smrg     }
640*627f7eb2Smrg 
641*627f7eb2Smrg     /**
642*627f7eb2Smrg         Implements casting to integer types.
643*627f7eb2Smrg 
644*627f7eb2Smrg         Throws: $(REF ConvOverflowException, std,conv) if the number exceeds
645*627f7eb2Smrg         the target type's range.
646*627f7eb2Smrg      */
647*627f7eb2Smrg     T opCast(T:ulong)() /*pure*/ const
648*627f7eb2Smrg     {
649*627f7eb2Smrg         if (isUnsigned!T && sign)
650*627f7eb2Smrg             { /* throw */ }
651*627f7eb2Smrg         else
652*627f7eb2Smrg         if (data.ulongLength == 1)
653*627f7eb2Smrg         {
654*627f7eb2Smrg             ulong l = data.peekUlong(0);
655*627f7eb2Smrg             if (isUnsigned!T || !sign)
656*627f7eb2Smrg             {
657*627f7eb2Smrg                 if (l <= T.max)
658*627f7eb2Smrg                     return cast(T) l;
659*627f7eb2Smrg             }
660*627f7eb2Smrg             else
661*627f7eb2Smrg             {
662*627f7eb2Smrg                 if (l <= ulong(T.max)+1)
663*627f7eb2Smrg                     return cast(T)-long(l); // -long.min == long.min
664*627f7eb2Smrg             }
665*627f7eb2Smrg         }
666*627f7eb2Smrg 
667*627f7eb2Smrg         import std.conv : ConvOverflowException;
668*627f7eb2Smrg         import std.string : format;
669*627f7eb2Smrg         throw new ConvOverflowException(
670*627f7eb2Smrg             "BigInt(%d) cannot be represented as a %s"
671*627f7eb2Smrg             .format(this, T.stringof));
672*627f7eb2Smrg     }
673*627f7eb2Smrg 
674*627f7eb2Smrg     ///
675*627f7eb2Smrg     @system unittest
676*627f7eb2Smrg     {
677*627f7eb2Smrg         import std.conv : to, ConvOverflowException;
678*627f7eb2Smrg         import std.exception : assertThrown;
679*627f7eb2Smrg 
680*627f7eb2Smrg         assert(BigInt("0").to!int == 0);
681*627f7eb2Smrg 
682*627f7eb2Smrg         assert(BigInt("0").to!ubyte == 0);
683*627f7eb2Smrg         assert(BigInt("255").to!ubyte == 255);
684*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("256").to!ubyte);
685*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("-1").to!ubyte);
686*627f7eb2Smrg     }
687*627f7eb2Smrg 
688*627f7eb2Smrg     @system unittest
689*627f7eb2Smrg     {
690*627f7eb2Smrg         import std.conv : to, ConvOverflowException;
691*627f7eb2Smrg         import std.exception : assertThrown;
692*627f7eb2Smrg 
693*627f7eb2Smrg         assert(BigInt("-1").to!byte == -1);
694*627f7eb2Smrg         assert(BigInt("-128").to!byte == -128);
695*627f7eb2Smrg         assert(BigInt("127").to!byte == 127);
696*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("-129").to!byte);
697*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("128").to!byte);
698*627f7eb2Smrg 
699*627f7eb2Smrg         assert(BigInt("0").to!uint == 0);
700*627f7eb2Smrg         assert(BigInt("4294967295").to!uint == uint.max);
701*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("4294967296").to!uint);
702*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("-1").to!uint);
703*627f7eb2Smrg 
704*627f7eb2Smrg         assert(BigInt("-1").to!int == -1);
705*627f7eb2Smrg         assert(BigInt("-2147483648").to!int == int.min);
706*627f7eb2Smrg         assert(BigInt("2147483647").to!int == int.max);
707*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("-2147483649").to!int);
708*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("2147483648").to!int);
709*627f7eb2Smrg 
710*627f7eb2Smrg         assert(BigInt("0").to!ulong == 0);
711*627f7eb2Smrg         assert(BigInt("18446744073709551615").to!ulong == ulong.max);
712*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("18446744073709551616").to!ulong);
713*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("-1").to!ulong);
714*627f7eb2Smrg 
715*627f7eb2Smrg         assert(BigInt("-1").to!long == -1);
716*627f7eb2Smrg         assert(BigInt("-9223372036854775808").to!long == long.min);
717*627f7eb2Smrg         assert(BigInt("9223372036854775807").to!long == long.max);
718*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("-9223372036854775809").to!long);
719*627f7eb2Smrg         assertThrown!ConvOverflowException(BigInt("9223372036854775808").to!long);
720*627f7eb2Smrg     }
721*627f7eb2Smrg 
722*627f7eb2Smrg     /**
723*627f7eb2Smrg         Implements casting to/from qualified BigInt's.
724*627f7eb2Smrg 
725*627f7eb2Smrg         Warning: Casting to/from $(D const) or $(D immutable) may break type
726*627f7eb2Smrg         system guarantees. Use with care.
727*627f7eb2Smrg      */
728*627f7eb2Smrg     T opCast(T)() pure nothrow @nogc const
729*627f7eb2Smrg     if (is(Unqual!T == BigInt))
730*627f7eb2Smrg     {
731*627f7eb2Smrg         return this;
732*627f7eb2Smrg     }
733*627f7eb2Smrg 
734*627f7eb2Smrg     ///
735*627f7eb2Smrg     @system unittest
736*627f7eb2Smrg     {
737*627f7eb2Smrg         const(BigInt) x = BigInt("123");
738*627f7eb2Smrg         BigInt y = cast() x;    // cast away const
739*627f7eb2Smrg         assert(y == x);
740*627f7eb2Smrg     }
741*627f7eb2Smrg 
742*627f7eb2Smrg     // Hack to make BigInt's typeinfo.compare work properly.
743*627f7eb2Smrg     // Note that this must appear before the other opCmp overloads, otherwise
744*627f7eb2Smrg     // DMD won't find it.
745*627f7eb2Smrg     /**
746*627f7eb2Smrg         Implements 3-way comparisons of BigInt with BigInt or BigInt with
747*627f7eb2Smrg         built-in integers.
748*627f7eb2Smrg      */
opCmpBigInt749*627f7eb2Smrg     int opCmp(ref const BigInt y) pure nothrow @nogc const
750*627f7eb2Smrg     {
751*627f7eb2Smrg         // Simply redirect to the "real" opCmp implementation.
752*627f7eb2Smrg         return this.opCmp!BigInt(y);
753*627f7eb2Smrg     }
754*627f7eb2Smrg 
755*627f7eb2Smrg     /// ditto
756*627f7eb2Smrg     int opCmp(T)(T y) pure nothrow @nogc const if (isIntegral!T)
757*627f7eb2Smrg     {
758*627f7eb2Smrg         if (sign != (y<0) )
759*627f7eb2Smrg             return sign ? -1 : 1;
760*627f7eb2Smrg         int cmp = data.opCmp(cast(ulong) absUnsign(y));
761*627f7eb2Smrg         return sign? -cmp: cmp;
762*627f7eb2Smrg     }
763*627f7eb2Smrg     /// ditto
764*627f7eb2Smrg     int opCmp(T:BigInt)(const T y) pure nothrow @nogc const
765*627f7eb2Smrg     {
766*627f7eb2Smrg         if (sign != y.sign)
767*627f7eb2Smrg             return sign ? -1 : 1;
768*627f7eb2Smrg         immutable cmp = data.opCmp(y.data);
769*627f7eb2Smrg         return sign? -cmp: cmp;
770*627f7eb2Smrg     }
771*627f7eb2Smrg 
772*627f7eb2Smrg     ///
773*627f7eb2Smrg     @system unittest
774*627f7eb2Smrg     {
775*627f7eb2Smrg         auto x = BigInt("100");
776*627f7eb2Smrg         auto y = BigInt("10");
777*627f7eb2Smrg         int z = 50;
778*627f7eb2Smrg         const int w = 200;
779*627f7eb2Smrg 
780*627f7eb2Smrg         assert(y < x);
781*627f7eb2Smrg         assert(x > z);
782*627f7eb2Smrg         assert(z > y);
783*627f7eb2Smrg         assert(x < w);
784*627f7eb2Smrg     }
785*627f7eb2Smrg 
786*627f7eb2Smrg     /**
787*627f7eb2Smrg         Returns: The value of this BigInt as a long, or +/- long.max if outside
788*627f7eb2Smrg         the representable range.
789*627f7eb2Smrg      */
toLongBigInt790*627f7eb2Smrg     long toLong() @safe pure nothrow const @nogc
791*627f7eb2Smrg     {
792*627f7eb2Smrg         return (sign ? -1 : 1) *
793*627f7eb2Smrg           (data.ulongLength == 1  && (data.peekUlong(0) <= sign+cast(ulong)(long.max)) // 1+long.max = |long.min|
794*627f7eb2Smrg           ? cast(long)(data.peekUlong(0))
795*627f7eb2Smrg           : long.max);
796*627f7eb2Smrg     }
797*627f7eb2Smrg 
798*627f7eb2Smrg     ///
799*627f7eb2Smrg     @system unittest
800*627f7eb2Smrg     {
801*627f7eb2Smrg         auto b = BigInt("12345");
802*627f7eb2Smrg         long l = b.toLong();
803*627f7eb2Smrg         assert(l == 12345);
804*627f7eb2Smrg     }
805*627f7eb2Smrg 
806*627f7eb2Smrg     /**
807*627f7eb2Smrg         Returns: The value of this BigInt as an int, or +/- int.max if outside
808*627f7eb2Smrg         the representable range.
809*627f7eb2Smrg      */
toIntBigInt810*627f7eb2Smrg     int toInt() @safe pure nothrow @nogc const
811*627f7eb2Smrg     {
812*627f7eb2Smrg         return (sign ? -1 : 1) *
813*627f7eb2Smrg           (data.uintLength == 1  && (data.peekUint(0) <= sign+cast(uint)(int.max)) // 1+int.max = |int.min|
814*627f7eb2Smrg           ? cast(int)(data.peekUint(0))
815*627f7eb2Smrg           : int.max);
816*627f7eb2Smrg     }
817*627f7eb2Smrg 
818*627f7eb2Smrg     ///
819*627f7eb2Smrg     @system unittest
820*627f7eb2Smrg     {
821*627f7eb2Smrg         auto big = BigInt("5_000_000");
822*627f7eb2Smrg         auto i = big.toInt();
823*627f7eb2Smrg         assert(i == 5_000_000);
824*627f7eb2Smrg 
825*627f7eb2Smrg         // Numbers that are too big to fit into an int will be clamped to int.max.
826*627f7eb2Smrg         auto tooBig = BigInt("5_000_000_000");
827*627f7eb2Smrg         i = tooBig.toInt();
828*627f7eb2Smrg         assert(i == int.max);
829*627f7eb2Smrg     }
830*627f7eb2Smrg 
831*627f7eb2Smrg     /// Number of significant uints which are used in storing this number.
832*627f7eb2Smrg     /// The absolute value of this BigInt is always &lt; 2$(SUPERSCRIPT 32*uintLength)
uintLengthBigInt833*627f7eb2Smrg     @property size_t uintLength() @safe pure nothrow @nogc const
834*627f7eb2Smrg     {
835*627f7eb2Smrg         return data.uintLength;
836*627f7eb2Smrg     }
837*627f7eb2Smrg 
838*627f7eb2Smrg     /// Number of significant ulongs which are used in storing this number.
839*627f7eb2Smrg     /// The absolute value of this BigInt is always &lt; 2$(SUPERSCRIPT 64*ulongLength)
ulongLengthBigInt840*627f7eb2Smrg     @property size_t ulongLength() @safe pure nothrow @nogc const
841*627f7eb2Smrg     {
842*627f7eb2Smrg         return data.ulongLength;
843*627f7eb2Smrg     }
844*627f7eb2Smrg 
845*627f7eb2Smrg     /** Convert the BigInt to string, passing it to the given sink.
846*627f7eb2Smrg      *
847*627f7eb2Smrg      * Params:
848*627f7eb2Smrg      *  sink = A delegate for accepting possibly piecewise segments of the
849*627f7eb2Smrg      *      formatted string.
850*627f7eb2Smrg      *  formatString = A format string specifying the output format.
851*627f7eb2Smrg      *
852*627f7eb2Smrg      * $(TABLE  Available output formats:,
853*627f7eb2Smrg      * $(TR $(TD "d") $(TD  Decimal))
854*627f7eb2Smrg      * $(TR $(TD "o") $(TD  Octal))
855*627f7eb2Smrg      * $(TR $(TD "x") $(TD  Hexadecimal, lower case))
856*627f7eb2Smrg      * $(TR $(TD "X") $(TD  Hexadecimal, upper case))
857*627f7eb2Smrg      * $(TR $(TD "s") $(TD  Default formatting (same as "d") ))
858*627f7eb2Smrg      * $(TR $(TD null) $(TD Default formatting (same as "d") ))
859*627f7eb2Smrg      * )
860*627f7eb2Smrg      */
toStringBigInt861*627f7eb2Smrg     void toString(scope void delegate(const (char)[]) sink, string formatString) const
862*627f7eb2Smrg     {
863*627f7eb2Smrg         auto f = FormatSpec!char(formatString);
864*627f7eb2Smrg         f.writeUpToNextSpec(sink);
865*627f7eb2Smrg         toString(sink, f);
866*627f7eb2Smrg     }
867*627f7eb2Smrg 
868*627f7eb2Smrg     /// ditto
869*627f7eb2Smrg     void toString(scope void delegate(const(char)[]) sink, ref FormatSpec!char f) const
870*627f7eb2Smrg     {
871*627f7eb2Smrg         immutable hex = (f.spec == 'x' || f.spec == 'X');
872*627f7eb2Smrg         if (!(f.spec == 's' || f.spec == 'd' || f.spec =='o' || hex))
873*627f7eb2Smrg             throw new FormatException("Format specifier not understood: %" ~ f.spec);
874*627f7eb2Smrg 
875*627f7eb2Smrg         char[] buff;
876*627f7eb2Smrg         if (f.spec == 'X')
877*627f7eb2Smrg         {
878*627f7eb2Smrg             buff = data.toHexString(0, '_', 0, f.flZero ? '0' : ' ', LetterCase.upper);
879*627f7eb2Smrg         }
880*627f7eb2Smrg         else if (f.spec == 'x')
881*627f7eb2Smrg         {
882*627f7eb2Smrg             buff = data.toHexString(0, '_', 0, f.flZero ? '0' : ' ', LetterCase.lower);
883*627f7eb2Smrg         }
884*627f7eb2Smrg         else if (f.spec == 'o')
885*627f7eb2Smrg         {
886*627f7eb2Smrg             buff = data.toOctalString();
887*627f7eb2Smrg         }
888*627f7eb2Smrg         else
889*627f7eb2Smrg         {
890*627f7eb2Smrg             buff = data.toDecimalString(0);
891*627f7eb2Smrg         }
892*627f7eb2Smrg         assert(buff.length > 0);
893*627f7eb2Smrg 
894*627f7eb2Smrg         char signChar = isNegative() ? '-' : 0;
895*627f7eb2Smrg         auto minw = buff.length + (signChar ? 1 : 0);
896*627f7eb2Smrg 
897*627f7eb2Smrg         if (!hex && !signChar && (f.width == 0 || minw < f.width))
898*627f7eb2Smrg         {
899*627f7eb2Smrg             if (f.flPlus)
900*627f7eb2Smrg             {
901*627f7eb2Smrg                 signChar = '+';
902*627f7eb2Smrg                 ++minw;
903*627f7eb2Smrg             }
904*627f7eb2Smrg             else if (f.flSpace)
905*627f7eb2Smrg             {
906*627f7eb2Smrg                 signChar = ' ';
907*627f7eb2Smrg                 ++minw;
908*627f7eb2Smrg             }
909*627f7eb2Smrg         }
910*627f7eb2Smrg 
911*627f7eb2Smrg         immutable maxw = minw < f.width ? f.width : minw;
912*627f7eb2Smrg         immutable difw = maxw - minw;
913*627f7eb2Smrg 
914*627f7eb2Smrg         if (!f.flDash && !f.flZero)
915*627f7eb2Smrg             foreach (i; 0 .. difw)
916*627f7eb2Smrg                 sink(" ");
917*627f7eb2Smrg 
918*627f7eb2Smrg         if (signChar)
919*627f7eb2Smrg             sink((&signChar)[0 .. 1]);
920*627f7eb2Smrg 
921*627f7eb2Smrg         if (!f.flDash && f.flZero)
922*627f7eb2Smrg             foreach (i; 0 .. difw)
923*627f7eb2Smrg                 sink("0");
924*627f7eb2Smrg 
925*627f7eb2Smrg         sink(buff);
926*627f7eb2Smrg 
927*627f7eb2Smrg         if (f.flDash)
928*627f7eb2Smrg             foreach (i; 0 .. difw)
929*627f7eb2Smrg                 sink(" ");
930*627f7eb2Smrg     }
931*627f7eb2Smrg 
932*627f7eb2Smrg     /**
933*627f7eb2Smrg         $(D toString) is rarely directly invoked; the usual way of using it is via
934*627f7eb2Smrg         $(REF format, std, format):
935*627f7eb2Smrg      */
936*627f7eb2Smrg     @system unittest
937*627f7eb2Smrg     {
938*627f7eb2Smrg         import std.format : format;
939*627f7eb2Smrg 
940*627f7eb2Smrg         auto x = BigInt("1_000_000");
941*627f7eb2Smrg         x *= 12345;
942*627f7eb2Smrg 
943*627f7eb2Smrg         assert(format("%d", x) == "12345000000");
944*627f7eb2Smrg         assert(format("%x", x) == "2_dfd1c040");
945*627f7eb2Smrg         assert(format("%X", x) == "2_DFD1C040");
946*627f7eb2Smrg         assert(format("%o", x) == "133764340100");
947*627f7eb2Smrg     }
948*627f7eb2Smrg 
949*627f7eb2Smrg     // Implement toHash so that BigInt works properly as an AA key.
950*627f7eb2Smrg     /**
951*627f7eb2Smrg         Returns: A unique hash of the BigInt's value suitable for use in a hash
952*627f7eb2Smrg         table.
953*627f7eb2Smrg      */
toHashBigInt954*627f7eb2Smrg     size_t toHash() const @safe nothrow
955*627f7eb2Smrg     {
956*627f7eb2Smrg         return data.toHash() + sign;
957*627f7eb2Smrg     }
958*627f7eb2Smrg 
959*627f7eb2Smrg     /**
960*627f7eb2Smrg         $(D toHash) is rarely directly invoked; it is implicitly used when
961*627f7eb2Smrg         BigInt is used as the key of an associative array.
962*627f7eb2Smrg      */
963*627f7eb2Smrg     @safe unittest
964*627f7eb2Smrg     {
965*627f7eb2Smrg         string[BigInt] aa;
966*627f7eb2Smrg         aa[BigInt(123)] = "abc";
967*627f7eb2Smrg         aa[BigInt(456)] = "def";
968*627f7eb2Smrg 
969*627f7eb2Smrg         assert(aa[BigInt(123)] == "abc");
970*627f7eb2Smrg         assert(aa[BigInt(456)] == "def");
971*627f7eb2Smrg     }
972*627f7eb2Smrg 
973*627f7eb2Smrg private:
negateBigInt974*627f7eb2Smrg     void negate() @safe pure nothrow @nogc
975*627f7eb2Smrg     {
976*627f7eb2Smrg         if (!data.isZero())
977*627f7eb2Smrg             sign = !sign;
978*627f7eb2Smrg     }
isZeroBigInt979*627f7eb2Smrg     bool isZero() pure const nothrow @nogc @safe
980*627f7eb2Smrg     {
981*627f7eb2Smrg         return data.isZero();
982*627f7eb2Smrg     }
isNegativeBigInt983*627f7eb2Smrg     bool isNegative() pure const nothrow @nogc @safe
984*627f7eb2Smrg     {
985*627f7eb2Smrg         return sign;
986*627f7eb2Smrg     }
987*627f7eb2Smrg 
988*627f7eb2Smrg     // Generate a runtime error if division by zero occurs
checkDivByZeroBigInt989*627f7eb2Smrg     void checkDivByZero() pure const nothrow @safe
990*627f7eb2Smrg     {
991*627f7eb2Smrg         if (isZero())
992*627f7eb2Smrg             throw new Error("BigInt division by zero");
993*627f7eb2Smrg     }
994*627f7eb2Smrg }
995*627f7eb2Smrg 
996*627f7eb2Smrg ///
997*627f7eb2Smrg @system unittest
998*627f7eb2Smrg {
999*627f7eb2Smrg     BigInt a = "9588669891916142";
1000*627f7eb2Smrg     BigInt b = "7452469135154800";
1001*627f7eb2Smrg     auto c = a * b;
1002*627f7eb2Smrg     assert(c == BigInt("71459266416693160362545788781600"));
1003*627f7eb2Smrg     auto d = b * a;
1004*627f7eb2Smrg     assert(d == BigInt("71459266416693160362545788781600"));
1005*627f7eb2Smrg     assert(d == c);
1006*627f7eb2Smrg     d = c * BigInt("794628672112");
1007*627f7eb2Smrg     assert(d == BigInt("56783581982794522489042432639320434378739200"));
1008*627f7eb2Smrg     auto e = c + d;
1009*627f7eb2Smrg     assert(e == BigInt("56783581982865981755459125799682980167520800"));
1010*627f7eb2Smrg     auto f = d + c;
1011*627f7eb2Smrg     assert(f == e);
1012*627f7eb2Smrg     auto g = f - c;
1013*627f7eb2Smrg     assert(g == d);
1014*627f7eb2Smrg     g = f - d;
1015*627f7eb2Smrg     assert(g == c);
1016*627f7eb2Smrg     e = 12345678;
1017*627f7eb2Smrg     g = c + e;
1018*627f7eb2Smrg     auto h = g / b;
1019*627f7eb2Smrg     auto i = g % b;
1020*627f7eb2Smrg     assert(h == a);
1021*627f7eb2Smrg     assert(i == e);
1022*627f7eb2Smrg     BigInt j = "-0x9A56_57f4_7B83_AB78";
1023*627f7eb2Smrg     j ^^= 11;
1024*627f7eb2Smrg }
1025*627f7eb2Smrg 
1026*627f7eb2Smrg /**
1027*627f7eb2Smrg Params:
1028*627f7eb2Smrg     x = The $(D BigInt) to convert to a decimal $(D string).
1029*627f7eb2Smrg 
1030*627f7eb2Smrg Returns:
1031*627f7eb2Smrg     A $(D string) that represents the $(D BigInt) as a decimal number.
1032*627f7eb2Smrg 
1033*627f7eb2Smrg */
toDecimalString(const (BigInt)x)1034*627f7eb2Smrg string toDecimalString(const(BigInt) x)
1035*627f7eb2Smrg {
1036*627f7eb2Smrg     string outbuff="";
1037*627f7eb2Smrg     void sink(const(char)[] s) { outbuff ~= s; }
1038*627f7eb2Smrg     x.toString(&sink, "%d");
1039*627f7eb2Smrg     return outbuff;
1040*627f7eb2Smrg }
1041*627f7eb2Smrg 
1042*627f7eb2Smrg ///
1043*627f7eb2Smrg @system unittest
1044*627f7eb2Smrg {
1045*627f7eb2Smrg     auto x = BigInt("123");
1046*627f7eb2Smrg     x *= 1000;
1047*627f7eb2Smrg     x += 456;
1048*627f7eb2Smrg 
1049*627f7eb2Smrg     auto xstr = x.toDecimalString();
1050*627f7eb2Smrg     assert(xstr == "123456");
1051*627f7eb2Smrg }
1052*627f7eb2Smrg 
1053*627f7eb2Smrg /**
1054*627f7eb2Smrg Params:
1055*627f7eb2Smrg     x = The $(D BigInt) to convert to a hexadecimal $(D string).
1056*627f7eb2Smrg 
1057*627f7eb2Smrg Returns:
1058*627f7eb2Smrg     A $(D string) that represents the $(D BigInt) as a hexadecimal (base 16)
1059*627f7eb2Smrg     number in upper case.
1060*627f7eb2Smrg 
1061*627f7eb2Smrg */
toHex(const (BigInt)x)1062*627f7eb2Smrg string toHex(const(BigInt) x)
1063*627f7eb2Smrg {
1064*627f7eb2Smrg     string outbuff="";
1065*627f7eb2Smrg     void sink(const(char)[] s) { outbuff ~= s; }
1066*627f7eb2Smrg     x.toString(&sink, "%X");
1067*627f7eb2Smrg     return outbuff;
1068*627f7eb2Smrg }
1069*627f7eb2Smrg 
1070*627f7eb2Smrg ///
1071*627f7eb2Smrg @system unittest
1072*627f7eb2Smrg {
1073*627f7eb2Smrg     auto x = BigInt("123");
1074*627f7eb2Smrg     x *= 1000;
1075*627f7eb2Smrg     x += 456;
1076*627f7eb2Smrg 
1077*627f7eb2Smrg     auto xstr = x.toHex();
1078*627f7eb2Smrg     assert(xstr == "1E240");
1079*627f7eb2Smrg }
1080*627f7eb2Smrg 
1081*627f7eb2Smrg /** Returns the absolute value of x converted to the corresponding unsigned
1082*627f7eb2Smrg type.
1083*627f7eb2Smrg 
1084*627f7eb2Smrg Params:
1085*627f7eb2Smrg     x = The integral value to return the absolute value of.
1086*627f7eb2Smrg 
1087*627f7eb2Smrg Returns:
1088*627f7eb2Smrg     The absolute value of x.
1089*627f7eb2Smrg 
1090*627f7eb2Smrg */
1091*627f7eb2Smrg Unsigned!T absUnsign(T)(T x)
1092*627f7eb2Smrg if (isIntegral!T)
1093*627f7eb2Smrg {
1094*627f7eb2Smrg     static if (isSigned!T)
1095*627f7eb2Smrg     {
1096*627f7eb2Smrg         import std.conv : unsigned;
1097*627f7eb2Smrg         /* This returns the correct result even when x = T.min
1098*627f7eb2Smrg          * on two's complement machines because unsigned(T.min) = |T.min|
1099*627f7eb2Smrg          * even though -T.min = T.min.
1100*627f7eb2Smrg          */
1101*627f7eb2Smrg         return unsigned((x < 0) ? cast(T)(0-x) : x);
1102*627f7eb2Smrg     }
1103*627f7eb2Smrg     else
1104*627f7eb2Smrg     {
1105*627f7eb2Smrg         return x;
1106*627f7eb2Smrg     }
1107*627f7eb2Smrg }
1108*627f7eb2Smrg 
1109*627f7eb2Smrg ///
1110*627f7eb2Smrg nothrow pure @system
1111*627f7eb2Smrg unittest
1112*627f7eb2Smrg {
1113*627f7eb2Smrg     assert((-1).absUnsign == 1);
1114*627f7eb2Smrg     assert(1.absUnsign == 1);
1115*627f7eb2Smrg }
1116*627f7eb2Smrg 
1117*627f7eb2Smrg nothrow pure @system
1118*627f7eb2Smrg unittest
1119*627f7eb2Smrg {
1120*627f7eb2Smrg     BigInt a, b;
1121*627f7eb2Smrg     a = 1;
1122*627f7eb2Smrg     b = 2;
1123*627f7eb2Smrg     auto c = a + b;
1124*627f7eb2Smrg }
1125*627f7eb2Smrg 
1126*627f7eb2Smrg nothrow pure @system
1127*627f7eb2Smrg unittest
1128*627f7eb2Smrg {
1129*627f7eb2Smrg     long a;
1130*627f7eb2Smrg     BigInt b;
1131*627f7eb2Smrg     auto c = a + b;
1132*627f7eb2Smrg     auto d = b + a;
1133*627f7eb2Smrg }
1134*627f7eb2Smrg 
1135*627f7eb2Smrg nothrow pure @system
1136*627f7eb2Smrg unittest
1137*627f7eb2Smrg {
1138*627f7eb2Smrg     BigInt x = 1, y = 2;
1139*627f7eb2Smrg     assert(x <  y);
1140*627f7eb2Smrg     assert(x <= y);
1141*627f7eb2Smrg     assert(y >= x);
1142*627f7eb2Smrg     assert(y >  x);
1143*627f7eb2Smrg     assert(x != y);
1144*627f7eb2Smrg 
1145*627f7eb2Smrg     long r1 = x.toLong;
1146*627f7eb2Smrg     assert(r1 == 1);
1147*627f7eb2Smrg 
1148*627f7eb2Smrg     BigInt r2 = 10 % x;
1149*627f7eb2Smrg     assert(r2 == 0);
1150*627f7eb2Smrg 
1151*627f7eb2Smrg     BigInt r3 = 10 / y;
1152*627f7eb2Smrg     assert(r3 == 5);
1153*627f7eb2Smrg 
1154*627f7eb2Smrg     BigInt[] arr = [BigInt(1)];
1155*627f7eb2Smrg     auto incr = arr[0]++;
1156*627f7eb2Smrg     assert(arr == [BigInt(2)]);
1157*627f7eb2Smrg     assert(incr == BigInt(1));
1158*627f7eb2Smrg }
1159*627f7eb2Smrg 
1160*627f7eb2Smrg @system unittest
1161*627f7eb2Smrg {
1162*627f7eb2Smrg     // Radix conversion
1163*627f7eb2Smrg     assert( toDecimalString(BigInt("-1_234_567_890_123_456_789"))
1164*627f7eb2Smrg         == "-1234567890123456789");
1165*627f7eb2Smrg     assert( toHex(BigInt("0x1234567890123456789")) == "123_45678901_23456789");
1166*627f7eb2Smrg     assert( toHex(BigInt("0x00000000000000000000000000000000000A234567890123456789"))
1167*627f7eb2Smrg         == "A23_45678901_23456789");
1168*627f7eb2Smrg     assert( toHex(BigInt("0x000_00_000000_000_000_000000000000_000000_")) == "0");
1169*627f7eb2Smrg 
1170*627f7eb2Smrg     assert(BigInt(-0x12345678).toInt() == -0x12345678);
1171*627f7eb2Smrg     assert(BigInt(-0x12345678).toLong() == -0x12345678);
1172*627f7eb2Smrg     assert(BigInt(0x1234_5678_9ABC_5A5AL).ulongLength == 1);
1173*627f7eb2Smrg     assert(BigInt(0x1234_5678_9ABC_5A5AL).toLong() == 0x1234_5678_9ABC_5A5AL);
1174*627f7eb2Smrg     assert(BigInt(-0x1234_5678_9ABC_5A5AL).toLong() == -0x1234_5678_9ABC_5A5AL);
1175*627f7eb2Smrg     assert(BigInt(0xF234_5678_9ABC_5A5AL).toLong() == long.max);
1176*627f7eb2Smrg     assert(BigInt(-0x123456789ABCL).toInt() == -int.max);
1177*627f7eb2Smrg     char[] s1 = "123".dup; // bug 8164
1178*627f7eb2Smrg     assert(BigInt(s1) == 123);
1179*627f7eb2Smrg     char[] s2 = "0xABC".dup;
1180*627f7eb2Smrg     assert(BigInt(s2) == 2748);
1181*627f7eb2Smrg 
1182*627f7eb2Smrg     assert((BigInt(-2) + BigInt(1)) == BigInt(-1));
1183*627f7eb2Smrg     BigInt a = ulong.max - 5;
1184*627f7eb2Smrg     auto b = -long.max % a;
1185*627f7eb2Smrg     assert( b == -long.max % (ulong.max - 5));
1186*627f7eb2Smrg     b = long.max / a;
1187*627f7eb2Smrg     assert( b == long.max /(ulong.max - 5));
1188*627f7eb2Smrg     assert(BigInt(1) - 1 == 0);
1189*627f7eb2Smrg     assert((-4) % BigInt(5) == -4); // bug 5928
1190*627f7eb2Smrg     assert(BigInt(-4) % BigInt(5) == -4);
1191*627f7eb2Smrg     assert(BigInt(2)/BigInt(-3) == BigInt(0)); // bug 8022
1192*627f7eb2Smrg     assert(BigInt("-1") > long.min); // bug 9548
1193*627f7eb2Smrg 
1194*627f7eb2Smrg     assert(toDecimalString(BigInt("0000000000000000000000000000000000000000001234567"))
1195*627f7eb2Smrg         == "1234567");
1196*627f7eb2Smrg }
1197*627f7eb2Smrg 
1198*627f7eb2Smrg @system unittest // Minimum signed value bug tests.
1199*627f7eb2Smrg {
1200*627f7eb2Smrg     assert(BigInt("-0x8000000000000000") == BigInt(long.min));
1201*627f7eb2Smrg     assert(BigInt("-0x8000000000000000")+1 > BigInt(long.min));
1202*627f7eb2Smrg     assert(BigInt("-0x80000000") == BigInt(int.min));
1203*627f7eb2Smrg     assert(BigInt("-0x80000000")+1 > BigInt(int.min));
1204*627f7eb2Smrg     assert(BigInt(long.min).toLong() == long.min); // lossy toLong bug for long.min
1205*627f7eb2Smrg     assert(BigInt(int.min).toInt() == int.min); // lossy toInt bug for int.min
1206*627f7eb2Smrg     assert(BigInt(long.min).ulongLength == 1);
1207*627f7eb2Smrg     assert(BigInt(int.min).uintLength == 1); // cast/sign extend bug in opAssign
1208*627f7eb2Smrg     BigInt a;
1209*627f7eb2Smrg     a += int.min;
1210*627f7eb2Smrg     assert(a == BigInt(int.min));
1211*627f7eb2Smrg     a = int.min - BigInt(int.min);
1212*627f7eb2Smrg     assert(a == 0);
1213*627f7eb2Smrg     a = int.min;
1214*627f7eb2Smrg     assert(a == BigInt(int.min));
1215*627f7eb2Smrg     assert(int.min % (BigInt(int.min)-1) == int.min);
1216*627f7eb2Smrg     assert((BigInt(int.min)-1)%int.min == -1);
1217*627f7eb2Smrg }
1218*627f7eb2Smrg 
1219*627f7eb2Smrg @system unittest // Recursive division, bug 5568
1220*627f7eb2Smrg {
1221*627f7eb2Smrg     enum Z = 4843;
1222*627f7eb2Smrg     BigInt m = (BigInt(1) << (Z*8) ) - 1;
1223*627f7eb2Smrg     m -= (BigInt(1) << (Z*6)) - 1;
1224*627f7eb2Smrg     BigInt oldm = m;
1225*627f7eb2Smrg 
1226*627f7eb2Smrg     BigInt a = (BigInt(1) << (Z*4) )-1;
1227*627f7eb2Smrg     BigInt b = m % a;
1228*627f7eb2Smrg     m /= a;
1229*627f7eb2Smrg     m *= a;
1230*627f7eb2Smrg     assert( m + b == oldm);
1231*627f7eb2Smrg 
1232*627f7eb2Smrg     m = (BigInt(1) << (4846 + 4843) ) - 1;
1233*627f7eb2Smrg     a = (BigInt(1) << 4846 ) - 1;
1234*627f7eb2Smrg     b = (BigInt(1) << (4846*2 + 4843)) - 1;
1235*627f7eb2Smrg     BigInt c = (BigInt(1) << (4846*2 + 4843*2)) - 1;
1236*627f7eb2Smrg     BigInt w =  c - b + a;
1237*627f7eb2Smrg     assert(w % m == 0);
1238*627f7eb2Smrg 
1239*627f7eb2Smrg     // Bug 6819. ^^
1240*627f7eb2Smrg     BigInt z1 = BigInt(10)^^64;
1241*627f7eb2Smrg     BigInt w1 = BigInt(10)^^128;
1242*627f7eb2Smrg     assert(z1^^2 == w1);
1243*627f7eb2Smrg     BigInt z2 = BigInt(1)<<64;
1244*627f7eb2Smrg     BigInt w2 = BigInt(1)<<128;
1245*627f7eb2Smrg     assert(z2^^2 == w2);
1246*627f7eb2Smrg     // Bug 7993
1247*627f7eb2Smrg     BigInt n7793 = 10;
1248*627f7eb2Smrg     assert( n7793 / 1 == 10);
1249*627f7eb2Smrg     // Bug 7973
1250*627f7eb2Smrg     auto a7973 = 10_000_000_000_000_000;
1251*627f7eb2Smrg     const c7973 = 10_000_000_000_000_000;
1252*627f7eb2Smrg     immutable i7973 = 10_000_000_000_000_000;
1253*627f7eb2Smrg     BigInt v7973 = 2551700137;
1254*627f7eb2Smrg     v7973 %= a7973;
1255*627f7eb2Smrg     assert(v7973 == 2551700137);
1256*627f7eb2Smrg     v7973 %= c7973;
1257*627f7eb2Smrg     assert(v7973 == 2551700137);
1258*627f7eb2Smrg     v7973 %= i7973;
1259*627f7eb2Smrg     assert(v7973 == 2551700137);
1260*627f7eb2Smrg     // 8165
1261*627f7eb2Smrg     BigInt[2] a8165;
1262*627f7eb2Smrg     a8165[0] = a8165[1] = 1;
1263*627f7eb2Smrg }
1264*627f7eb2Smrg 
1265*627f7eb2Smrg @system unittest
1266*627f7eb2Smrg {
1267*627f7eb2Smrg     import std.array;
1268*627f7eb2Smrg     import std.format;
1269*627f7eb2Smrg 
1270*627f7eb2Smrg     immutable string[][] table = [
1271*627f7eb2Smrg     /*  fmt,        +10     -10 */
1272*627f7eb2Smrg         ["%d",      "10",   "-10"],
1273*627f7eb2Smrg         ["%+d",     "+10",  "-10"],
1274*627f7eb2Smrg         ["%-d",     "10",   "-10"],
1275*627f7eb2Smrg         ["%+-d",    "+10",  "-10"],
1276*627f7eb2Smrg 
1277*627f7eb2Smrg         ["%4d",     "  10", " -10"],
1278*627f7eb2Smrg         ["%+4d",    " +10", " -10"],
1279*627f7eb2Smrg         ["%-4d",    "10  ", "-10 "],
1280*627f7eb2Smrg         ["%+-4d",   "+10 ", "-10 "],
1281*627f7eb2Smrg 
1282*627f7eb2Smrg         ["%04d",    "0010", "-010"],
1283*627f7eb2Smrg         ["%+04d",   "+010", "-010"],
1284*627f7eb2Smrg         ["%-04d",   "10  ", "-10 "],
1285*627f7eb2Smrg         ["%+-04d",  "+10 ", "-10 "],
1286*627f7eb2Smrg 
1287*627f7eb2Smrg         ["% 04d",   " 010", "-010"],
1288*627f7eb2Smrg         ["%+ 04d",  "+010", "-010"],
1289*627f7eb2Smrg         ["%- 04d",  " 10 ", "-10 "],
1290*627f7eb2Smrg         ["%+- 04d", "+10 ", "-10 "],
1291*627f7eb2Smrg     ];
1292*627f7eb2Smrg 
1293*627f7eb2Smrg     auto w1 = appender!(char[])();
1294*627f7eb2Smrg     auto w2 = appender!(char[])();
1295*627f7eb2Smrg 
foreach(entry;table)1296*627f7eb2Smrg     foreach (entry; table)
1297*627f7eb2Smrg     {
1298*627f7eb2Smrg         immutable fmt = entry[0];
1299*627f7eb2Smrg 
1300*627f7eb2Smrg         formattedWrite(w1, fmt, BigInt(10));
1301*627f7eb2Smrg         formattedWrite(w2, fmt, 10);
1302*627f7eb2Smrg         assert(w1.data == w2.data);
1303*627f7eb2Smrg         assert(w1.data == entry[1]);
1304*627f7eb2Smrg         w1.clear();
1305*627f7eb2Smrg         w2.clear();
1306*627f7eb2Smrg 
1307*627f7eb2Smrg         formattedWrite(w1, fmt, BigInt(-10));
1308*627f7eb2Smrg         formattedWrite(w2, fmt, -10);
1309*627f7eb2Smrg         assert(w1.data == w2.data);
1310*627f7eb2Smrg         assert(w1.data == entry[2]);
1311*627f7eb2Smrg         w1.clear();
1312*627f7eb2Smrg         w2.clear();
1313*627f7eb2Smrg     }
1314*627f7eb2Smrg }
1315*627f7eb2Smrg 
1316*627f7eb2Smrg @system unittest
1317*627f7eb2Smrg {
1318*627f7eb2Smrg     import std.array;
1319*627f7eb2Smrg     import std.format;
1320*627f7eb2Smrg 
1321*627f7eb2Smrg     immutable string[][] table = [
1322*627f7eb2Smrg     /*  fmt,        +10     -10 */
1323*627f7eb2Smrg         ["%x",      "a",    "-a"],
1324*627f7eb2Smrg         ["%+x",     "a",    "-a"],
1325*627f7eb2Smrg         ["%-x",     "a",    "-a"],
1326*627f7eb2Smrg         ["%+-x",    "a",    "-a"],
1327*627f7eb2Smrg 
1328*627f7eb2Smrg         ["%4x",     "   a", "  -a"],
1329*627f7eb2Smrg         ["%+4x",    "   a", "  -a"],
1330*627f7eb2Smrg         ["%-4x",    "a   ", "-a  "],
1331*627f7eb2Smrg         ["%+-4x",   "a   ", "-a  "],
1332*627f7eb2Smrg 
1333*627f7eb2Smrg         ["%04x",    "000a", "-00a"],
1334*627f7eb2Smrg         ["%+04x",   "000a", "-00a"],
1335*627f7eb2Smrg         ["%-04x",   "a   ", "-a  "],
1336*627f7eb2Smrg         ["%+-04x",  "a   ", "-a  "],
1337*627f7eb2Smrg 
1338*627f7eb2Smrg         ["% 04x",   "000a", "-00a"],
1339*627f7eb2Smrg         ["%+ 04x",  "000a", "-00a"],
1340*627f7eb2Smrg         ["%- 04x",  "a   ", "-a  "],
1341*627f7eb2Smrg         ["%+- 04x", "a   ", "-a  "],
1342*627f7eb2Smrg     ];
1343*627f7eb2Smrg 
1344*627f7eb2Smrg     auto w1 = appender!(char[])();
1345*627f7eb2Smrg     auto w2 = appender!(char[])();
1346*627f7eb2Smrg 
foreach(entry;table)1347*627f7eb2Smrg     foreach (entry; table)
1348*627f7eb2Smrg     {
1349*627f7eb2Smrg         immutable fmt = entry[0];
1350*627f7eb2Smrg 
1351*627f7eb2Smrg         formattedWrite(w1, fmt, BigInt(10));
1352*627f7eb2Smrg         formattedWrite(w2, fmt, 10);
1353*627f7eb2Smrg         assert(w1.data == w2.data);     // Equal only positive BigInt
1354*627f7eb2Smrg         assert(w1.data == entry[1]);
1355*627f7eb2Smrg         w1.clear();
1356*627f7eb2Smrg         w2.clear();
1357*627f7eb2Smrg 
1358*627f7eb2Smrg         formattedWrite(w1, fmt, BigInt(-10));
1359*627f7eb2Smrg         //formattedWrite(w2, fmt, -10);
1360*627f7eb2Smrg         //assert(w1.data == w2.data);
1361*627f7eb2Smrg         assert(w1.data == entry[2]);
1362*627f7eb2Smrg         w1.clear();
1363*627f7eb2Smrg         //w2.clear();
1364*627f7eb2Smrg     }
1365*627f7eb2Smrg }
1366*627f7eb2Smrg 
1367*627f7eb2Smrg @system unittest
1368*627f7eb2Smrg {
1369*627f7eb2Smrg     import std.array;
1370*627f7eb2Smrg     import std.format;
1371*627f7eb2Smrg 
1372*627f7eb2Smrg     immutable string[][] table = [
1373*627f7eb2Smrg     /*  fmt,        +10     -10 */
1374*627f7eb2Smrg         ["%X",      "A",    "-A"],
1375*627f7eb2Smrg         ["%+X",     "A",    "-A"],
1376*627f7eb2Smrg         ["%-X",     "A",    "-A"],
1377*627f7eb2Smrg         ["%+-X",    "A",    "-A"],
1378*627f7eb2Smrg 
1379*627f7eb2Smrg         ["%4X",     "   A", "  -A"],
1380*627f7eb2Smrg         ["%+4X",    "   A", "  -A"],
1381*627f7eb2Smrg         ["%-4X",    "A   ", "-A  "],
1382*627f7eb2Smrg         ["%+-4X",   "A   ", "-A  "],
1383*627f7eb2Smrg 
1384*627f7eb2Smrg         ["%04X",    "000A", "-00A"],
1385*627f7eb2Smrg         ["%+04X",   "000A", "-00A"],
1386*627f7eb2Smrg         ["%-04X",   "A   ", "-A  "],
1387*627f7eb2Smrg         ["%+-04X",  "A   ", "-A  "],
1388*627f7eb2Smrg 
1389*627f7eb2Smrg         ["% 04X",   "000A", "-00A"],
1390*627f7eb2Smrg         ["%+ 04X",  "000A", "-00A"],
1391*627f7eb2Smrg         ["%- 04X",  "A   ", "-A  "],
1392*627f7eb2Smrg         ["%+- 04X", "A   ", "-A  "],
1393*627f7eb2Smrg     ];
1394*627f7eb2Smrg 
1395*627f7eb2Smrg     auto w1 = appender!(char[])();
1396*627f7eb2Smrg     auto w2 = appender!(char[])();
1397*627f7eb2Smrg 
foreach(entry;table)1398*627f7eb2Smrg     foreach (entry; table)
1399*627f7eb2Smrg     {
1400*627f7eb2Smrg         immutable fmt = entry[0];
1401*627f7eb2Smrg 
1402*627f7eb2Smrg         formattedWrite(w1, fmt, BigInt(10));
1403*627f7eb2Smrg         formattedWrite(w2, fmt, 10);
1404*627f7eb2Smrg         assert(w1.data == w2.data);     // Equal only positive BigInt
1405*627f7eb2Smrg         assert(w1.data == entry[1]);
1406*627f7eb2Smrg         w1.clear();
1407*627f7eb2Smrg         w2.clear();
1408*627f7eb2Smrg 
1409*627f7eb2Smrg         formattedWrite(w1, fmt, BigInt(-10));
1410*627f7eb2Smrg         //formattedWrite(w2, fmt, -10);
1411*627f7eb2Smrg         //assert(w1.data == w2.data);
1412*627f7eb2Smrg         assert(w1.data == entry[2]);
1413*627f7eb2Smrg         w1.clear();
1414*627f7eb2Smrg         //w2.clear();
1415*627f7eb2Smrg     }
1416*627f7eb2Smrg }
1417*627f7eb2Smrg 
1418*627f7eb2Smrg // 6448
1419*627f7eb2Smrg @system unittest
1420*627f7eb2Smrg {
1421*627f7eb2Smrg     import std.array;
1422*627f7eb2Smrg     import std.format;
1423*627f7eb2Smrg 
1424*627f7eb2Smrg     auto w1 = appender!string();
1425*627f7eb2Smrg     auto w2 = appender!string();
1426*627f7eb2Smrg 
1427*627f7eb2Smrg     int x = 100;
1428*627f7eb2Smrg     formattedWrite(w1, "%010d", x);
1429*627f7eb2Smrg     BigInt bx = x;
1430*627f7eb2Smrg     formattedWrite(w2, "%010d", bx);
1431*627f7eb2Smrg     assert(w1.data == w2.data);
1432*627f7eb2Smrg     //8011
1433*627f7eb2Smrg     BigInt y = -3;
1434*627f7eb2Smrg     ++y;
1435*627f7eb2Smrg     assert(y.toLong() == -2);
1436*627f7eb2Smrg     y = 1;
1437*627f7eb2Smrg     --y;
1438*627f7eb2Smrg     assert(y.toLong() == 0);
1439*627f7eb2Smrg     --y;
1440*627f7eb2Smrg     assert(y.toLong() == -1);
1441*627f7eb2Smrg     --y;
1442*627f7eb2Smrg     assert(y.toLong() == -2);
1443*627f7eb2Smrg }
1444*627f7eb2Smrg 
1445*627f7eb2Smrg @safe unittest
1446*627f7eb2Smrg {
1447*627f7eb2Smrg     import std.math : abs;
1448*627f7eb2Smrg     auto r = abs(BigInt(-1000)); // 6486
1449*627f7eb2Smrg     assert(r == 1000);
1450*627f7eb2Smrg 
1451*627f7eb2Smrg     auto r2 = abs(const(BigInt)(-500)); // 11188
1452*627f7eb2Smrg     assert(r2 == 500);
1453*627f7eb2Smrg     auto r3 = abs(immutable(BigInt)(-733)); // 11188
1454*627f7eb2Smrg     assert(r3 == 733);
1455*627f7eb2Smrg 
1456*627f7eb2Smrg     // opCast!bool
1457*627f7eb2Smrg     BigInt one = 1, zero;
1458*627f7eb2Smrg     assert(one && !zero);
1459*627f7eb2Smrg }
1460*627f7eb2Smrg 
1461*627f7eb2Smrg @system unittest // 6850
1462*627f7eb2Smrg {
pureTest()1463*627f7eb2Smrg     pure long pureTest() {
1464*627f7eb2Smrg         BigInt a = 1;
1465*627f7eb2Smrg         BigInt b = 1336;
1466*627f7eb2Smrg         a += b;
1467*627f7eb2Smrg         return a.toLong();
1468*627f7eb2Smrg     }
1469*627f7eb2Smrg 
1470*627f7eb2Smrg     assert(pureTest() == 1337);
1471*627f7eb2Smrg }
1472*627f7eb2Smrg 
1473*627f7eb2Smrg @system unittest // 8435 & 10118
1474*627f7eb2Smrg {
1475*627f7eb2Smrg     auto i = BigInt(100);
1476*627f7eb2Smrg     auto j = BigInt(100);
1477*627f7eb2Smrg 
1478*627f7eb2Smrg     // Two separate BigInt instances representing same value should have same
1479*627f7eb2Smrg     // hash.
1480*627f7eb2Smrg     assert(typeid(i).getHash(&i) == typeid(j).getHash(&j));
1481*627f7eb2Smrg     assert(typeid(i).compare(&i, &j) == 0);
1482*627f7eb2Smrg 
1483*627f7eb2Smrg     // BigInt AA keys should behave consistently.
1484*627f7eb2Smrg     int[BigInt] aa;
1485*627f7eb2Smrg     aa[BigInt(123)] = 123;
1486*627f7eb2Smrg     assert(BigInt(123) in aa);
1487*627f7eb2Smrg 
1488*627f7eb2Smrg     aa[BigInt(123)] = 321;
1489*627f7eb2Smrg     assert(aa[BigInt(123)] == 321);
1490*627f7eb2Smrg 
1491*627f7eb2Smrg     auto keys = aa.byKey;
1492*627f7eb2Smrg     assert(keys.front == BigInt(123));
1493*627f7eb2Smrg     keys.popFront();
1494*627f7eb2Smrg     assert(keys.empty);
1495*627f7eb2Smrg }
1496*627f7eb2Smrg 
1497*627f7eb2Smrg @system unittest // 11148
1498*627f7eb2Smrg {
foo(BigInt)1499*627f7eb2Smrg     void foo(BigInt) {}
1500*627f7eb2Smrg     const BigInt cbi = 3;
1501*627f7eb2Smrg     immutable BigInt ibi = 3;
1502*627f7eb2Smrg 
1503*627f7eb2Smrg     assert(__traits(compiles, foo(cbi)));
1504*627f7eb2Smrg     assert(__traits(compiles, foo(ibi)));
1505*627f7eb2Smrg 
1506*627f7eb2Smrg     import std.conv : to;
1507*627f7eb2Smrg     import std.meta : AliasSeq;
1508*627f7eb2Smrg 
1509*627f7eb2Smrg     foreach (T1; AliasSeq!(BigInt, const(BigInt), immutable(BigInt)))
1510*627f7eb2Smrg     {
1511*627f7eb2Smrg         foreach (T2; AliasSeq!(BigInt, const(BigInt), immutable(BigInt)))
1512*627f7eb2Smrg         {
1513*627f7eb2Smrg             T1 t1 = 2;
1514*627f7eb2Smrg             T2 t2 = t1;
1515*627f7eb2Smrg 
1516*627f7eb2Smrg             T2 t2_1 = to!T2(t1);
1517*627f7eb2Smrg             T2 t2_2 = cast(T2) t1;
1518*627f7eb2Smrg 
1519*627f7eb2Smrg             assert(t2 == t1);
1520*627f7eb2Smrg             assert(t2 == 2);
1521*627f7eb2Smrg 
1522*627f7eb2Smrg             assert(t2_1 == t1);
1523*627f7eb2Smrg             assert(t2_1 == 2);
1524*627f7eb2Smrg 
1525*627f7eb2Smrg             assert(t2_2 == t1);
1526*627f7eb2Smrg             assert(t2_2 == 2);
1527*627f7eb2Smrg         }
1528*627f7eb2Smrg     }
1529*627f7eb2Smrg 
1530*627f7eb2Smrg     BigInt n = 2;
1531*627f7eb2Smrg     n *= 2;
1532*627f7eb2Smrg }
1533*627f7eb2Smrg 
1534*627f7eb2Smrg @safe unittest // 8167
1535*627f7eb2Smrg {
1536*627f7eb2Smrg     BigInt a = BigInt(3);
1537*627f7eb2Smrg     BigInt b = BigInt(a);
1538*627f7eb2Smrg }
1539*627f7eb2Smrg 
1540*627f7eb2Smrg @safe unittest // 9061
1541*627f7eb2Smrg {
1542*627f7eb2Smrg     long l1 = 0x12345678_90ABCDEF;
1543*627f7eb2Smrg     long l2 = 0xFEDCBA09_87654321;
1544*627f7eb2Smrg     long l3 = l1 | l2;
1545*627f7eb2Smrg     long l4 = l1 & l2;
1546*627f7eb2Smrg     long l5 = l1 ^ l2;
1547*627f7eb2Smrg 
1548*627f7eb2Smrg     BigInt b1 = l1;
1549*627f7eb2Smrg     BigInt b2 = l2;
1550*627f7eb2Smrg     BigInt b3 = b1 | b2;
1551*627f7eb2Smrg     BigInt b4 = b1 & b2;
1552*627f7eb2Smrg     BigInt b5 = b1 ^ b2;
1553*627f7eb2Smrg 
1554*627f7eb2Smrg     assert(l3 == b3);
1555*627f7eb2Smrg     assert(l4 == b4);
1556*627f7eb2Smrg     assert(l5 == b5);
1557*627f7eb2Smrg }
1558*627f7eb2Smrg 
1559*627f7eb2Smrg @system unittest // 11600
1560*627f7eb2Smrg {
1561*627f7eb2Smrg     import std.conv;
1562*627f7eb2Smrg     import std.exception : assertThrown;
1563*627f7eb2Smrg 
1564*627f7eb2Smrg     // Original bug report
1565*627f7eb2Smrg     assertThrown!ConvException(to!BigInt("avadakedavra"));
1566*627f7eb2Smrg 
1567*627f7eb2Smrg     // Digit string lookalikes that are actually invalid
1568*627f7eb2Smrg     assertThrown!ConvException(to!BigInt("0123hellothere"));
1569*627f7eb2Smrg     assertThrown!ConvException(to!BigInt("-hihomarylowe"));
1570*627f7eb2Smrg     assertThrown!ConvException(to!BigInt("__reallynow__"));
1571*627f7eb2Smrg     assertThrown!ConvException(to!BigInt("-123four"));
1572*627f7eb2Smrg }
1573*627f7eb2Smrg 
1574*627f7eb2Smrg @safe unittest // 11583
1575*627f7eb2Smrg {
1576*627f7eb2Smrg     BigInt x = 0;
1577*627f7eb2Smrg     assert((x > 0) == false);
1578*627f7eb2Smrg }
1579*627f7eb2Smrg 
1580*627f7eb2Smrg @system unittest // 13391
1581*627f7eb2Smrg {
1582*627f7eb2Smrg     BigInt x1 = "123456789";
1583*627f7eb2Smrg     BigInt x2 = "123456789123456789";
1584*627f7eb2Smrg     BigInt x3 = "123456789123456789123456789";
1585*627f7eb2Smrg 
1586*627f7eb2Smrg     import std.meta : AliasSeq;
1587*627f7eb2Smrg     foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
1588*627f7eb2Smrg     {
1589*627f7eb2Smrg         assert((x1 * T.max) / T.max == x1);
1590*627f7eb2Smrg         assert((x2 * T.max) / T.max == x2);
1591*627f7eb2Smrg         assert((x3 * T.max) / T.max == x3);
1592*627f7eb2Smrg     }
1593*627f7eb2Smrg 
1594*627f7eb2Smrg     assert(x1 / -123456789 == -1);
1595*627f7eb2Smrg     assert(x1 / 123456789U == 1);
1596*627f7eb2Smrg     assert(x1 / -123456789L == -1);
1597*627f7eb2Smrg     assert(x1 / 123456789UL == 1);
1598*627f7eb2Smrg     assert(x2 / -123456789123456789L == -1);
1599*627f7eb2Smrg     assert(x2 / 123456789123456789UL == 1);
1600*627f7eb2Smrg 
1601*627f7eb2Smrg     assert(x1 / uint.max == 0);
1602*627f7eb2Smrg     assert(x1 / ulong.max == 0);
1603*627f7eb2Smrg     assert(x2 / ulong.max == 0);
1604*627f7eb2Smrg 
1605*627f7eb2Smrg     x1 /= 123456789UL;
1606*627f7eb2Smrg     assert(x1 == 1);
1607*627f7eb2Smrg     x2 /= 123456789123456789UL;
1608*627f7eb2Smrg     assert(x2 == 1);
1609*627f7eb2Smrg }
1610*627f7eb2Smrg 
1611*627f7eb2Smrg @system unittest // 13963
1612*627f7eb2Smrg {
1613*627f7eb2Smrg     BigInt x = 1;
1614*627f7eb2Smrg     import std.meta : AliasSeq;
1615*627f7eb2Smrg     foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint))
1616*627f7eb2Smrg     {
1617*627f7eb2Smrg         assert(is(typeof(x % Int(1)) == int));
1618*627f7eb2Smrg     }
1619*627f7eb2Smrg     assert(is(typeof(x % 1L) == long));
1620*627f7eb2Smrg     assert(is(typeof(x % 1UL) == BigInt));
1621*627f7eb2Smrg 
1622*627f7eb2Smrg     auto x1 = BigInt(8);
1623*627f7eb2Smrg     auto x2 = -BigInt(long.min) + 1;
1624*627f7eb2Smrg 
1625*627f7eb2Smrg     // long
1626*627f7eb2Smrg     assert(x1 % 2L == 0L);
1627*627f7eb2Smrg     assert(-x1 % 2L == 0L);
1628*627f7eb2Smrg 
1629*627f7eb2Smrg     assert(x1 % 3L == 2L);
1630*627f7eb2Smrg     assert(x1 % -3L == 2L);
1631*627f7eb2Smrg     assert(-x1 % 3L == -2L);
1632*627f7eb2Smrg     assert(-x1 % -3L == -2L);
1633*627f7eb2Smrg 
1634*627f7eb2Smrg     assert(x1 % 11L == 8L);
1635*627f7eb2Smrg     assert(x1 % -11L == 8L);
1636*627f7eb2Smrg     assert(-x1 % 11L == -8L);
1637*627f7eb2Smrg     assert(-x1 % -11L == -8L);
1638*627f7eb2Smrg 
1639*627f7eb2Smrg     // ulong
1640*627f7eb2Smrg     assert(x1 % 2UL == BigInt(0));
1641*627f7eb2Smrg     assert(-x1 % 2UL == BigInt(0));
1642*627f7eb2Smrg 
1643*627f7eb2Smrg     assert(x1 % 3UL == BigInt(2));
1644*627f7eb2Smrg     assert(-x1 % 3UL == -BigInt(2));
1645*627f7eb2Smrg 
1646*627f7eb2Smrg     assert(x1 % 11UL == BigInt(8));
1647*627f7eb2Smrg     assert(-x1 % 11UL == -BigInt(8));
1648*627f7eb2Smrg 
1649*627f7eb2Smrg     assert(x2 % ulong.max == x2);
1650*627f7eb2Smrg     assert(-x2 % ulong.max == -x2);
1651*627f7eb2Smrg }
1652*627f7eb2Smrg 
1653*627f7eb2Smrg @system unittest // 14124
1654*627f7eb2Smrg {
1655*627f7eb2Smrg     auto x = BigInt(-3);
1656*627f7eb2Smrg     x %= 3;
1657*627f7eb2Smrg     assert(!x.isNegative());
1658*627f7eb2Smrg     assert(x.isZero());
1659*627f7eb2Smrg 
1660*627f7eb2Smrg     x = BigInt(-3);
1661*627f7eb2Smrg     x %= cast(ushort) 3;
1662*627f7eb2Smrg     assert(!x.isNegative());
1663*627f7eb2Smrg     assert(x.isZero());
1664*627f7eb2Smrg 
1665*627f7eb2Smrg     x = BigInt(-3);
1666*627f7eb2Smrg     x %= 3L;
1667*627f7eb2Smrg     assert(!x.isNegative());
1668*627f7eb2Smrg     assert(x.isZero());
1669*627f7eb2Smrg 
1670*627f7eb2Smrg     x = BigInt(3);
1671*627f7eb2Smrg     x %= -3;
1672*627f7eb2Smrg     assert(!x.isNegative());
1673*627f7eb2Smrg     assert(x.isZero());
1674*627f7eb2Smrg }
1675*627f7eb2Smrg 
1676*627f7eb2Smrg // issue 15678
1677*627f7eb2Smrg @system unittest
1678*627f7eb2Smrg {
1679*627f7eb2Smrg     import std.exception : assertThrown;
1680*627f7eb2Smrg     assertThrown!ConvException(BigInt(""));
1681*627f7eb2Smrg     assertThrown!ConvException(BigInt("0x1234BARF"));
1682*627f7eb2Smrg     assertThrown!ConvException(BigInt("1234PUKE"));
1683*627f7eb2Smrg }
1684*627f7eb2Smrg 
1685*627f7eb2Smrg // Issue 6447
1686*627f7eb2Smrg @system unittest
1687*627f7eb2Smrg {
1688*627f7eb2Smrg     import std.algorithm.comparison : equal;
1689*627f7eb2Smrg     import std.range : iota;
1690*627f7eb2Smrg 
1691*627f7eb2Smrg     auto s = BigInt(1_000_000_000_000);
1692*627f7eb2Smrg     auto e = BigInt(1_000_000_000_003);
1693*627f7eb2Smrg     auto r = iota(s, e);
1694*627f7eb2Smrg     assert(r.equal([
1695*627f7eb2Smrg         BigInt(1_000_000_000_000),
1696*627f7eb2Smrg         BigInt(1_000_000_000_001),
1697*627f7eb2Smrg         BigInt(1_000_000_000_002)
1698*627f7eb2Smrg     ]));
1699*627f7eb2Smrg }
1700*627f7eb2Smrg 
1701*627f7eb2Smrg // Issue 17330
1702*627f7eb2Smrg @system unittest
1703*627f7eb2Smrg {
1704*627f7eb2Smrg     auto b = immutable BigInt("123");
1705*627f7eb2Smrg }
1706