1 /** High-level wrapper for GNU Multiple Precision (MP) library.
2 
3     TODO _ccc Make _ccc two => uint _initCCC and uint _opCCC, mutatingCallCount
4     return their sum. Use these counters to make more precise asserts on how
5     assignments and operators are lowered to calls to C __gmpz-calls
6 
7     TODO disallow construction and assignment from floating point? Check with
8     other GMP interfaces and std.bigint.
9 
10     TODO Should `in` operator be used for anything good?
11 
12     TODO Support operators
13           <<      >>      >>>
14           &= |= ^=
15 */
16 module gmp;
17 
18 debug import core.stdc.stdio : printf;
19 import std.typecons : Unsigned, Unqual;
20 import std.meta : AliasSeq;
21 import std.traits : isInstanceOf;
22 import std.algorithm.mutation : move, moveEmplace;
23 
24 /// Call unittests taking long to execute.
25 enum unittestLong = false;
26 
27 version(unittest)
28 {
29     version = ccc;              // do C mutation call count
30 }
31 
32 /** Is `true` iff `T` is a GNU MP arithmetic type (`long`, `ulong` or `double`). */
33 enum isGMPArithmetic(T) = is(T == long) && is(T == ulong) && is(T == double);
34 
35 /// Is `true` if type `T` can be evaluated to a `MpZ` value.
36 enum isMpZExpr(T) = (is(Unqual!(typeof(T.eval())) == MpZ)); // which returns an `MpZ`
37 /// Is `true` if type `T` is lazy (not yet evaluated) `MpZ`-expression.
38 enum isLazyMpZExpr(T) = (!is(Unqual!T == MpZ) &&            // exclude direct value
39                          isMpZExpr!T);
40 
41 version(unittest)
42 {
43     static assert(!isMpZExpr!int);
44 }
45 
46 // TODO use these imports instead of the ones below
47 // import deimos.gmp.gmp;
48 // import deimos.gmp.integer;
49 
50 /** Arbitrary (multi) precision signed integer (Z).
51     Wrapper for GNU MP (GMP)'s type `mpz_t` and functions `mpz_.*`.
52  */
53 struct MpZ
54 {
55     /// Default conversion base.
56     private enum defaultBase = 10;
57 
58     pure nothrow pragma(inline, true):
59 
60     /// Convert to `string` in base `base`.
61     string toString(uint base = defaultBase, bool upperCaseDigits = false) const @trusted
62     {
63         assert((base >= -2 && base <= -36) ||
64                (base >= 2 && base <= 62));
65 
66         immutable size = sizeInBase(base);
67 
68         string str = new string(size + 1); // one extra for minus sign
69         __gmpz_get_str(cast(char*)str.ptr, base, _ptr); // fill it
70 
71         if (upperCaseDigits)
72         {
73             foreach (ref e; cast(char[])str)
74             {
75                 import std.ascii : isLower, toUpper;
76                 if (e.isLower)
77                 {
78                     e = e.toUpper;
79                 }
80             }
81         }
82 
83         return str[0] == '-' ? str : str.ptr[0 .. size];
84     }
85 
86     // TODO toRCString wrapped in UniqueRange
87 
88     // Returns: A unique hash of the `MpZ` value suitable for use in a hash table.
89     size_t toHash() const
90     {
91         import core.internal.hash : hashOf;
92         typeof(return) hash = _limbCount;
93         foreach (immutable i; 0 .. _limbCount)
94         {
95             hash ^= _limbs[i].hashOf;
96         }
97         return hash;
98     }
99 
100     @nogc:
101 
102     /// No default construction.
103     @disable this();
104 
105     /// Construct empty (undefined) from explicit `null`.
106     this(typeof(null)) @trusted
107     {
108         initialize();             // TODO is there a faster way?
109         assert(this == MpZ.init); // if this is same as default
110     }
111 
112     /// Construct from expression `expr`.
113     this(Expr)(Expr expr)
114         if (isLazyMpZExpr!Expr)
115     {
116         // TODO ok to just assume zero-initialized contents at `_z` before...
117         this = expr;            // ...calling this.opAssign ?x
118     }
119 
120     /** Construct from `value`. */
121     this(T)(T value) @trusted
122         if (isArithmetic!T)
123     {
124         version(ccc) ++_ccc;
125         static      if (isUnsigned!T)
126             __gmpz_init_set_ui(_ptr, value);
127         else static if (isFloating!T)
128             __gmpz_init_set_d(_ptr, value);
129         else                    // isSigned integral
130             __gmpz_init_set_si(_ptr, value);
131     }
132 
133     /** Construct from `value` in base `base`.
134         If `base` is 0 it's guessed from contents of `value`.
135         */
136     pragma(inline, false)
137     this(in string value, uint base = 0) @trusted // TODO Use Optional/Nullable when value is nan, or inf
138     {
139         assert(base == 0 || (base >= 2 && base <= 62));
140         char* stringz = _allocStringzCopyOf(value);
141         immutable int status = __gmpz_init_set_str(_ptr, stringz, base); version(ccc) ++_ccc;
142         qualifiedFree(stringz);
143         assert(status == 0, "Parameter `value` does not contain an integer");
144     }
145 
146     /// Returns: the Mersenne prime, M(p) = 2 ^^ p - 1
147     static MpZ mersennePrime(Integral)(Integral p)
148         if (isIntegral!Integral)
149     {
150         return typeof(this).pow(2UL, p) - 1;
151     }
152 
153     /// Use copy construction.
154     enum useCopy = false;       // disable copy construction for now
155 
156     static if (useCopy)
157     {
158         /// Construct copy of `value`.
159         this(ref const MpZ value) @trusted
160         {
161             __gmpz_init_set(_ptr, value._ptr); version(ccc) ++_ccc;
162         }
163         /// Construct copy of `value`.
164         this(MpZ value) @trusted
165         {
166             moveEmplace(value, this); // fast
167         }
168     }
169     else
170     {
171         /// Disable copy construction.
172         @disable this(this);
173     }
174 
175     /** Initialize internal struct. */
176     private void initialize() @trusted // cannot be called `init` as that will override builtin type property
177     {
178         __gmpz_init(_ptr); version(ccc) ++_ccc;
179     }
180 
181     /// Swap content of `this` with `rhs`.
182     void swap(ref MpZ rhs) @safe
183     {
184         import std.algorithm.mutation : swap;
185         swap(this, rhs); // faster than __gmpz_swap(_ptr, rhs._ptr); version(ccc) ++_ccc;
186     }
187 
188     /// Returns: (duplicate) copy of `this`.
189     MpZ dup() const @trusted
190     {
191         typeof(return) y = void;
192         __gmpz_init_set(y._ptr, _ptr); ++y._ccc;
193         return y;
194     }
195 
196     /// Assign from `rhs`.
197     ref MpZ opAssign()(auto ref const MpZ rhs) return @trusted // TODO scope
198     {
199         __gmpz_set(_ptr, rhs._ptr); version(ccc) ++_ccc;
200         return this;
201     }
202     /// ditto
203     ref MpZ opAssign(Expr)(auto ref Expr rhs) return @trusted // TODO scope
204         if (isLazyMpZExpr!Expr)
205     {
206         static      if (isInstanceOf!(MpzAddExpr, Expr))
207         {
208             __gmpz_add(this._ptr,
209                        rhs.e1.eval()._ptr,
210                        rhs.e2.eval()._ptr); version(ccc) ++_ccc;
211         }
212         else static if (isInstanceOf!(MpzSubExpr, Expr))
213         {
214             __gmpz_sub(this._ptr,
215                        rhs.e1.eval()._ptr,
216                        rhs.e2.eval()._ptr); version(ccc) ++_ccc;
217         }
218         else static if (isInstanceOf!(MpzMulExpr, Expr))
219         {
220             __gmpz_mul(this._ptr,
221                        rhs.e1.eval()._ptr,
222                        rhs.e2.eval()._ptr); version(ccc) ++_ccc;
223         }
224         else static if (isInstanceOf!(MpzDivExpr, Expr))
225         {
226             __gmpz_tdiv_q(this._ptr,
227                           rhs.e1.eval()._ptr,
228                           rhs.e2.eval()._ptr); version(ccc) ++_ccc;
229         }
230         else static if (isInstanceOf!(MpzModExpr, Expr))
231         {
232             __gmpz_tdiv_r(this._ptr,
233                           rhs.e1.eval()._ptr,
234                           rhs.e2.eval()._ptr); version(ccc) ++_ccc;
235         }
236         else static if (isInstanceOf!(MpzNegExpr, Expr))
237         {
238             __gmpz_neg(this._ptr,
239                        rhs.e1.eval()._ptr); version(ccc) ++_ccc;
240         }
241         else
242         {
243             this = rhs.eval();     // evaluate and move
244         }
245         return this;
246     }
247     /// ditto
248     ref MpZ opAssign(T)(T rhs) return @trusted // TODO scope
249         if (isArithmetic!T)
250     {
251         static if      (isUnsigned!T)
252         {
253             __gmpz_set_ui(_ptr, rhs);
254         }
255         else static if (isFloating!T)
256         {
257             __gmpz_set_d(_ptr, rhs);
258         }
259         else static if (isSigned!T)
260         {
261             pragma(msg, T);
262             __gmpz_set_si(_ptr, rhs);
263         }
264         else
265         {
266             static assert(false);
267         }
268         version(ccc) ++_ccc;
269         return this;
270     }
271 
272     /** Assign `this` from `string` `rhs` interpreted in base `base`.
273         If `base` is 0 it's guessed from contents of `value`.
274     */
275     ref MpZ fromString(in string rhs, uint base = 0) return @trusted // TODO scope
276     {
277         assert(base == 0 || (base >= 2 && base <= 62));
278         char* stringz = _allocStringzCopyOf(rhs);
279         immutable int status = __gmpz_set_str(_ptr, stringz, base); version(ccc) ++_ccc;
280         qualifiedFree(stringz);
281         assert(status == 0, "Parameter `rhs` does not contain an integer");
282         return this;
283     }
284 
285     /// Destruct `this`.
286     ~this() @trusted
287     {
288         if (_ptr)
289         {
290             __gmpz_clear(_ptr); version(ccc) ++_ccc;
291         }
292     }
293 
294     /// Returns: `true` iff `this` equals `rhs`.
295     bool opEquals()(auto ref const MpZ rhs) const @trusted // TODO scope
296     {
297         if (_ptr == rhs._ptr)   // fast equality
298         {
299             return true;        // fast bailout
300         }
301         return __gmpz_cmp(_ptr, rhs._ptr) == 0;
302     }
303     /// ditto
304     bool opEquals(Rhs)(Rhs rhs) const @trusted // TODO scope
305         if (isArithmetic!Rhs)
306     {
307         if (rhs == 0)
308         {
309             return isZero;      // optimization
310         }
311         static      if (isUnsigned!Rhs)
312         {
313             return __gmpz_cmp_ui(_ptr, cast(ulong)rhs) == 0;
314         }
315         else static if (isFloating!Rhs)
316         {
317             return __gmpz_cmp_d(_ptr, cast(double)rhs) == 0; // TODO correct to do this cast here?
318         }
319         else                    // isSigned integral
320         {
321             return __gmpz_cmp_si(_ptr, cast(long)rhs) == 0;
322         }
323     }
324 
325     /// Compare `this` to `rhs`.
326     int opCmp()(auto ref const MpZ rhs) const @trusted // TODO scope
327     {
328         if (rhs == 0)
329         {
330             return sgn();       // optimization
331         }
332         return __gmpz_cmp(_ptr, rhs._ptr);
333     }
334 
335     /// ditto
336     int opCmp(T)(T rhs) const @trusted // TODO scope
337         if (isArithmetic!T)
338     {
339         if (rhs == 0)
340         {
341             return sgn();       // optimization
342         }
343         static      if (isUnsigned!T)
344         {
345             return __gmpz_cmp_ui(_ptr, rhs);
346         }
347         else static if (isFloating!T)
348         {
349             return __gmpz_cmp_d(_ptr, rhs);
350         }
351         else                    // isSigned integral
352         {
353             return __gmpz_cmp_si(_ptr, rhs);
354         }
355     }
356 
357     /// Cast to `bool`.
358     bool opCast(T : bool)() const // TODO scope
359     {
360         return !isZero;
361     }
362 
363     /// Cast to arithmetic type `T`.
364     T opCast(T)() const @trusted // TODO scope
365         if (isArithmetic!T)
366     {
367         static      if (isUnsigned!T)
368         {
369             return cast(T)__gmpz_get_ui(_ptr);
370         }
371         else static if (isFloating!T)
372         {
373             return cast(T)__gmpz_get_d(_ptr);
374         }
375         else                    // isSigned integral
376         {
377             return cast(T)__gmpz_get_si(_ptr);
378         }
379     }
380 
381     /** Returns: The value of this as a `long`, or +/- `long.max` if outside
382         the representable range.
383     */
384     long toLong() const @trusted
385     {
386         // TODO can probably be optimized
387         if (this <= long.min)
388         {
389             return long.min;
390         }
391         else if (this >= long.max)
392         {
393             return long.max;
394         }
395         else
396         {
397             return cast(long)__gmpz_get_si(_ptr);
398         }
399     }
400 
401     /** Returns: The value of this as a `int`, or +/- `int.max` if outside
402         the representable range.
403     */
404     int toInt() const @trusted
405     {
406         // TODO can probably be optimized
407         if (this <= int.min)
408         {
409             return int.min;
410         }
411         else if (this >= int.max)
412         {
413             return int.max;
414         }
415         else
416         {
417             return cast(int)__gmpz_get_si(_ptr);
418         }
419     }
420 
421     /** Returns: `this` `s` `rhs`. */
422     MpZ opBinary(string s)(auto ref const MpZ rhs) const @trusted // direct value
423         if ((s == "+" || s == "-" ||
424              s == "*" || s == "/" || s == "%" ||
425              s == "&" || s == "|" || s == "^"))
426     {
427         static if (!__traits(isRef, rhs)) // r-value `rhs`
428         {
429             MpZ* mut_rhs = (cast(MpZ*)(&rhs)); // @trusted because `MpZ` has no aliased indirections
430             static      if (s == "+")
431             {
432                 __gmpz_add(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
433             }
434             else static if (s == "-")
435             {
436                 __gmpz_sub(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
437             }
438             else static if (s == "*")
439             {
440                 __gmpz_mul(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
441             }
442             else static if (s == "/")
443             {
444                 assert(rhs != 0, "Divison by zero");
445                 __gmpz_tdiv_q(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
446             }
447             else static if (s == "%")
448             {
449                 assert(rhs != 0, "Divison by zero");
450                 __gmpz_tdiv_r(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
451             }
452             else static if (s == "&")
453             {
454                 __gmpz_and(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
455             }
456             else static if (s == "|")
457             {
458                 __gmpz_ior(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
459             }
460             else static if (s == "^")
461             {
462                 __gmpz_xor(mut_rhs._ptr, _ptr, rhs._ptr); version(ccc) ++mut_rhs._ccc;
463             }
464             else
465             {
466                 static assert(false);
467             }
468             return move(*mut_rhs); // TODO shouldn't have to call `move` here
469         }
470         else
471         {
472             typeof(return) y = null;
473             static      if (s == "+")
474             {
475                 __gmpz_add(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
476             }
477             else static if (s == "-")
478             {
479                 __gmpz_sub(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
480             }
481             else static if (s == "*")
482             {
483                 __gmpz_mul(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
484             }
485             else static if (s == "/")
486             {
487                 assert(rhs != 0, "Divison by zero");
488                 __gmpz_tdiv_q(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
489             }
490             else static if (s == "%")
491             {
492                 assert(rhs != 0, "Divison by zero");
493                 __gmpz_tdiv_r(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
494             }
495             else static if (s == "&")
496             {
497                 __gmpz_and(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
498             }
499             else static if (s == "|")
500             {
501                 __gmpz_ior(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
502             }
503             else static if (s == "^")
504             {
505                 __gmpz_xor(y._ptr, _ptr, rhs._ptr); version(ccc) ++y._ccc;
506             }
507             else
508             {
509                 static assert(false);
510             }
511             return y;
512         }
513     }
514 
515     /// ditto
516     MpZ opBinary(string s, Rhs)(auto ref const Rhs rhs) const
517         if (isLazyMpZExpr!Rhs && // lazy value
518             (s == "+" || s == "-" || s == "*" || s == "/" || s == "%"))
519     {
520         static assert(false, "TODO");
521     }
522 
523     MpZ opBinary(string s, Rhs)(Rhs rhs) const @trusted
524         if ((s == "+" || s == "-" || s == "*" || s == "/" || s == "^^") &&
525             isUnsigned!Rhs)
526     {
527         typeof(return) y = null;
528         version(ccc) ++y._ccc;
529         static      if (s == "+")
530         {
531             __gmpz_add_ui(y._ptr, _ptr, rhs);
532         }
533         else static if (s == "-")
534         {
535             __gmpz_sub_ui(y._ptr, _ptr, rhs);
536         }
537         else static if (s == "*")
538         {
539             __gmpz_mul_ui(y._ptr, _ptr, rhs);
540         }
541         else static if (s == "/")
542         {
543             assert(rhs != 0, "Divison by zero");
544             __gmpz_tdiv_q_ui(y._ptr, _ptr, rhs);
545         }
546         else static if (s == "^^")
547         {
548             __gmpz_pow_ui(y._ptr, _ptr, rhs);
549         }
550         else
551         {
552             static assert(false);
553         }
554         return y;
555     }
556 
557     MpZ opBinary(string s, Rhs)(Rhs rhs) const @trusted
558         if ((s == "+" || s == "-" || s == "*" || s == "/" || s == "^^") &&
559             isSigned!Rhs)
560     {
561         typeof(return) y = null;
562         version(ccc) ++y._ccc;
563         static      if (s == "+")
564         {
565             if (rhs < 0)        // TODO handle `rhs == rhs.min`
566             {
567                 immutable ulong pos_rhs = -rhs; // make it positive
568                 __gmpz_sub_ui(y._ptr, _ptr, pos_rhs);
569             }
570             else
571             {
572                 __gmpz_add_ui(y._ptr, _ptr, rhs);
573             }
574         }
575         else static if (s == "-")
576         {
577             if (rhs < 0)        // TODO handle `rhs == rhs.min`
578             {
579                 __gmpz_add_ui(y._ptr, _ptr, -rhs); // x - (-y) == x + y
580             }
581             else
582             {
583                 __gmpz_sub_ui(y._ptr, _ptr, rhs); // rhs is positive
584             }
585         }
586         else static if (s == "*")
587         {
588             __gmpz_mul_si(y._ptr, _ptr, rhs);
589         }
590         else static if (s == "/")
591         {
592             assert(rhs != 0, "Divison by zero");
593             if (rhs < 0)        // TODO handle `rhs == rhs.min`
594             {
595                 immutable ulong pos_rhs = -rhs; // make it positive
596                 __gmpz_tdiv_q_ui(y._ptr, _ptr, pos_rhs);
597                 y.negate();     // negate result
598             }
599             else
600             {
601                 __gmpz_tdiv_q_ui(y._ptr, _ptr, rhs);
602             }
603         }
604         else static if (s == "^^")
605         {
606             assert(rhs >= 0, "TODO Negative power exponent needs MpQ return");
607             __gmpz_pow_ui(y._ptr, _ptr, rhs);
608         }
609         else
610         {
611             static assert(false);
612         }
613         return y;
614     }
615 
616     /// Remainer propagates modulus type.
617     Unqual!Rhs opBinary(string s, Rhs)(Rhs rhs) const @trusted
618         if ((s == "%") &&
619             isIntegral!Rhs)
620     {
621         assert(rhs != 0, "Divison by zero");
622         MpZ y = null;
623         version(ccc) ++y._ccc;
624         static if (isSigned!Rhs)
625         {
626             if (rhs < 0)        // TODO handle `rhs == rhs.min`
627             {
628                 immutable ulong pos_rhs = -rhs; // make it positive
629                 return -cast(typeof(return))__gmpz_tdiv_r_ui(y._ptr, _ptr, pos_rhs);
630             }
631             else
632             {
633                 return cast(typeof(return))__gmpz_tdiv_r_ui(y._ptr, _ptr, rhs);
634             }
635         }
636         else static if (isUnsigned!Rhs)
637         {
638             return cast(typeof(return))__gmpz_tdiv_r_ui(y._ptr, _ptr, rhs);
639         }
640         else
641         {
642             static assert(false);
643         }
644     }
645 
646     /// Returns: an unsigned type `lhs` divided by `this`.
647     MpZ opBinaryRight(string s, Lhs)(Lhs lhs) const @trusted
648         if ((s == "+" || s == "-" || s == "*" || s == "%") &&
649             isUnsigned!Lhs)
650     {
651         typeof(return) y = null;
652         version(ccc) ++y._ccc;
653         static      if (s == "+")
654         {
655             __gmpz_add_ui(y._ptr, _ptr, lhs); // commutative
656         }
657         else static if (s == "-")
658         {
659             __gmpz_ui_sub(y._ptr, lhs, _ptr);
660         }
661         else static if (s == "*")
662         {
663             __gmpz_mul_ui(y._ptr, _ptr, lhs); // commutative
664         }
665         else static if (s == "%")
666         {
667             assert(this != 0, "Divison by zero");
668             __gmpz_tdiv_r(y._ptr, MpZ(lhs)._ptr, _ptr); // convert `lhs` to MpZ
669         }
670         else
671         {
672             static assert(false);
673         }
674         return y;
675     }
676 
677     /// Returns: a signed type `lhs` divided by `this`.
678     MpZ opBinaryRight(string s, Lhs)(Lhs lhs) const @trusted
679         if ((s == "+" || s == "-" || s == "*" || s == "%") &&
680             isSigned!Lhs)
681     {
682         static if (s == "+" || s == "*")
683         {
684             return opBinary!s(lhs); // commutative reuse
685         }
686         else static if (s == "-")
687         {
688             typeof(return) y = null;
689             version(ccc) ++y._ccc;
690             if (lhs < 0)        // TODO handle `lhs == lhs.min`
691             {
692                 immutable ulong pos_rhs = -lhs; // make it positive
693                 __gmpz_add_ui(y._ptr, _ptr, pos_rhs);
694             }
695             else
696             {
697                 __gmpz_sub_ui(y._ptr, _ptr, lhs);
698             }
699             y.negate();
700             return y;
701         }
702         else static if (s == "%")
703         {
704             typeof(return) y = null;
705             version(ccc) ++y._ccc;
706             assert(this != 0, "Divison by zero");
707             __gmpz_tdiv_r(y._ptr, MpZ(lhs)._ptr, _ptr); // convert `lhs` to MpZ
708             return y;
709         }
710         else
711         {
712             static assert(false);
713         }
714     }
715 
716     /// Dividend propagates quotient type to signed.
717     Unqual!Lhs opBinaryRight(string s, Lhs)(Lhs lhs) const @trusted
718         if ((s == "/") &&
719             isIntegral!Lhs)
720     {
721         MpZ y = null; // TODO avoid if !__traits(isRef, this)
722         version(ccc) ++y._ccc;
723         assert(this != 0, "Divison by zero");
724         __gmpz_tdiv_q(y._ptr, MpZ(lhs)._ptr, _ptr);
725         static      if (isSigned!Lhs)
726         {
727             return cast(typeof(return))y;
728         }
729         else static if (isUnsigned!Lhs)
730         {
731             import std.typecons : Signed;
732             return cast(Signed!(typeof(return)))y;
733         }
734         else
735         {
736             static assert(false);
737         }
738     }
739 
740     /// Exponentation.
741     MpZ opBinaryRight(string s, Base)(Base base) const
742         if ((s == "^^") &&
743             isIntegral!Base)
744     {
745         static assert(false, "Convert `this MpZ` exponent to `ulong` and calculate power via static method `pow()`");
746         // MpZ exp = null;
747         // __gmpz_pow();
748         // return exp;
749     }
750 
751     ref MpZ opOpAssign(string s)(auto ref const MpZ rhs) return @trusted // TODO scope
752         if ((s == "+" || s == "-" ||
753              s == "*" || s == "/" || s == "%" ||
754              s == "&" || s == "|" || s == "^"))
755     {
756         static      if (s == "+")
757         {
758             __gmpz_add(_ptr, _ptr, rhs._ptr); version(ccc) ++_ccc;
759         }
760         else static if (s == "-")
761         {
762             __gmpz_sub(_ptr, _ptr, rhs._ptr); version(ccc) ++_ccc;
763         }
764         else static if (s == "*")
765         {
766             if (rhs == -1)
767             {
768                 negate();
769             }
770             else
771             {
772                 __gmpz_mul(_ptr, _ptr, rhs._ptr); version(ccc) ++_ccc;
773             }
774         }
775         else static if (s == "/")
776         {
777             assert(rhs != 0, "Divison by zero");
778             if (rhs == -1)
779             {
780                 negate();
781             }
782             else
783             {
784                 __gmpz_tdiv_q(_ptr, _ptr, rhs._ptr); version(ccc) ++_ccc;
785             }
786         }
787         else static if (s == "%")
788         {
789             assert(rhs != 0, "Divison by zero");
790             __gmpz_tdiv_r(_ptr, _ptr, rhs._ptr); version(ccc) ++_ccc;
791         }
792         else static if (s == "&")
793         {
794             __gmpz_and(_ptr, _ptr, rhs._ptr); version(ccc) ++_ccc;
795         }
796         else static if (s == "|")
797         {
798             __gmpz_ior(_ptr, _ptr, rhs._ptr); version(ccc) ++_ccc;
799         }
800         else static if (s == "^")
801         {
802             __gmpz_xor(_ptr, _ptr, rhs._ptr); version(ccc) ++_ccc;
803         }
804         else
805         {
806             static assert(false);
807         }
808         return this;
809     }
810 
811     ref MpZ opOpAssign(string s, Rhs)(Rhs rhs) return @trusted // TODO scope
812         if ((s == "+" || s == "-" || s == "*" || s == "/" || s == "%" || s == "^^") &&
813             isUnsigned!Rhs)
814     {
815         static      if (s == "+")
816         {
817             __gmpz_add_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
818         }
819         else static if (s == "-")
820         {
821             __gmpz_sub_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
822         }
823         else static if (s == "*")
824         {
825             __gmpz_mul_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
826         }
827         else static if (s == "/")
828         {
829             assert(rhs != 0, "Divison by zero");
830             __gmpz_tdiv_q_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
831         }
832         else static if (s == "%")
833         {
834             assert(rhs != 0, "Divison by zero");
835             __gmpz_tdiv_r_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
836         }
837         else static if (s == "^^")
838         {
839             __gmpz_pow_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
840         }
841         else
842         {
843             static assert(false);
844         }
845         return this;
846     }
847 
848     ref MpZ opOpAssign(string s, Rhs)(Rhs rhs) return @trusted // TODO scope
849         if ((s == "+" || s == "-" || s == "*" || s == "/" || s == "%" || s == "^^") &&
850             isSigned!Rhs)
851     {
852         static      if (s == "+")
853         {
854             if (rhs < 0)        // TODO handle `rhs == rhs.min`
855             {
856                 assert(rhs != rhs.min);
857                 immutable ulong pos_rhs = -rhs; // make it positive
858                 __gmpz_sub_ui(_ptr, _ptr, pos_rhs); version(ccc) ++_ccc;
859             }
860             else
861             {
862                 __gmpz_add_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
863             }
864         }
865         else static if (s == "-")
866         {
867             if (rhs < 0)        // TODO handle `rhs == rhs.min`
868             {
869                 assert(rhs != rhs.min);
870                 immutable ulong pos_rhs = -rhs; // make it positive
871                 __gmpz_add_ui(_ptr, _ptr, pos_rhs); version(ccc) ++_ccc;
872             }
873             else
874             {
875                 __gmpz_sub_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
876             }
877         }
878         else static if (s == "*")
879         {
880             if (rhs == -1)
881             {
882                 negate();       // optimization
883             }
884             else
885             {
886                 __gmpz_mul_si(_ptr, _ptr, rhs); version(ccc) ++_ccc;
887             }
888         }
889         else static if (s == "/")
890         {
891             assert(rhs != 0, "Divison by zero");
892             if (rhs < 0)        // TODO handle `rhs == rhs.min`
893             {
894                 immutable ulong pos_rhs = -rhs; // make it positive
895                 __gmpz_tdiv_q_ui(_ptr, _ptr, pos_rhs); version(ccc) ++_ccc;
896                 negate();
897             }
898             else
899             {
900                 __gmpz_tdiv_q_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
901             }
902         }
903         else static if (s == "%")
904         {
905             assert(rhs != 0, "Divison by zero");
906             __gmpz_tdiv_r_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
907         }
908         else static if (s == "^^")
909         {
910             assert(rhs >= 0, "Negative power exponent");
911             __gmpz_pow_ui(_ptr, _ptr, rhs); version(ccc) ++_ccc;
912         }
913         else
914         {
915             static assert(false);
916         }
917         return this;
918     }
919 
920     /// Returns: `this`.
921     ref inout(MpZ) opUnary(string s)() inout
922         if (s == "+")
923     {
924         return this;
925     }
926 
927     /// Returns: negation of `this`.
928     MpZ opUnary(string s)() const
929         if (s == "-")
930     {
931         typeof(return) y = this.dup;
932         y.negate();
933         return y;
934     }
935 
936     /// Returns: negation of `this`.
937     MpZ unaryMinus() const @safe
938     {
939         pragma(msg, "memberFun:", __traits(isRef, this) ? "ref" : "non-ref", " this");
940         typeof(return) y = this.dup;
941         y.negate();
942         return y;
943     }
944 
945     /** Negate `this` in-place.
946         Returns: `void` to make it obvious `this` is mutated.
947      */
948     void negate() @safe
949     {
950         _z._mp_size = -_z._mp_size; // fast C macro `mpz_neg` in gmp.h
951     }
952 
953     /** Make `this` the absolute value of itself in-place.
954         Returns: `void` to make it obvious `this` is mutated.
955      */
956     void absolute() @trusted
957     {
958         __gmpz_abs(_ptr, _ptr); version(ccc) ++_ccc;
959     }
960 
961     /// Increase `this` by one.
962     ref MpZ opUnary(string s)() return @trusted // TODO scope
963         if (s == "++")
964     {
965         __gmpz_add_ui(_ptr, _ptr, 1); version(ccc) ++_ccc;
966         return this;
967     }
968 
969     /// Decrease `this` by one.
970     ref MpZ opUnary(string s)() return @trusted // TODO scope
971         if (s == "--")
972     {
973         __gmpz_sub_ui(_ptr, _ptr, 1); version(ccc) ++_ccc;
974         return this;
975     }
976 
977     /// Returns: `base` raised to the power of `exp`.
978     static typeof(this) pow(Base, Exp)(Base base, Exp exp) @trusted
979         if (isIntegral!Base &&
980             isIntegral!Exp)
981     {
982         static if (isSigned!Base)
983         {
984             immutable bool negate = base < 0;
985             immutable ubase = cast(ulong)(negate ? -base : base);
986         }
987         else
988         {
989             immutable bool negate = false;
990             immutable ubase = base;
991         }
992 
993         static if (isSigned!Exp)
994         {
995             assert(exp >= 0, "Negative power exponent"); // TODO return mpq?
996             immutable uexp = cast(ulong)exp;
997         }
998         else
999         {
1000             immutable uexp = exp;
1001         }
1002 
1003         typeof(return) y = null;
1004         __gmpz_ui_pow_ui(y._ptr, ubase, uexp); version(ccc) ++y._ccc;
1005         if (negate && exp & 1)  // if negative odd exponent
1006         {
1007             y.negate();
1008         }
1009 
1010         return y;
1011     }
1012 
1013     /// Returns: number of digits in base `base`.
1014     size_t sizeInBase(uint base) const @trusted
1015     {
1016         return __gmpz_sizeinbase(_ptr, base);
1017     }
1018 
1019     /// Returns: `true` iff `this` fits in a `T`.
1020     bool fitsIn(T)() const @trusted
1021         if (isIntegral!T)
1022     {
1023         static      if (is(T == ulong))  { return __gmpz_fits_ulong_p(_ptr) != 0; }
1024         else static if (is(T ==  long))  { return __gmpz_fits_slong_p(_ptr) != 0; }
1025         else static if (is(T ==  uint))  { return __gmpz_fits_uint_p(_ptr) != 0; }
1026         else static if (is(T ==   int))  { return __gmpz_fits_sint_p(_ptr) != 0; }
1027         else static if (is(T == ushort)) { return __gmpz_fits_ushort_p(_ptr) != 0; }
1028         else static if (is(T ==  short)) { return __gmpz_fits_sshort_p(_ptr) != 0; }
1029         else { static assert(false, "Unsupported type " ~ T.stringof); }
1030     }
1031 
1032     /// Check if `this` is zero.
1033     @property bool isZero() const @safe
1034     {
1035         return _z._mp_size == 0; // fast
1036     }
1037 
1038     /// Check if `this` is odd. TODO use as specialcase in: this & 1
1039     @property bool isOdd() const @safe
1040     {
1041         return (_z._mp_size != 0) & cast(int)(_z._mp_d[0]); // fast C macro `mpz_odd_p` in gmp.h
1042     }
1043 
1044     /// Check if `this` is odd.
1045     @property bool isEven() const @safe
1046     {
1047         return !isOdd;            // fast C macro `mpz_even_p` in gmp.h
1048     }
1049 
1050     /// Check if `this` is negative. TODO use as specialcase in opCmp
1051     @property bool isNegative() const @safe
1052     {
1053         return _z._mp_size < 0; // fast
1054     }
1055 
1056     /// Check if `this` is positive.
1057     @property bool isPositive() const @safe
1058     {
1059         return !isNegative;     // fast
1060     }
1061 
1062     /** Returns: sign as either
1063         - -1 (`this` < 0),
1064         -  0 (`this` == 0), or
1065         - +1 (`this` > 0).
1066      */
1067     @property int sgn() const @safe
1068     {
1069         return _z._mp_size < 0 ? -1 : _z._mp_size > 0; // fast C macro `mpz_sgn` in gmp.h
1070     }
1071 
1072     /// Number of significant `uint`s used for storing `this`.
1073     @property size_t uintLength() const
1074     {
1075         assert(false, "TODO use mpz_size");
1076     }
1077 
1078     /// Number of significant `ulong`s used for storing `this`.
1079     @property size_t uintLong() const
1080     {
1081         assert(false, "TODO use mpz_size");
1082     }
1083 
1084 private:
1085 
1086     /// Returns: evaluation of `this` expression which in this is a no-op.
1087     ref inout(MpZ) eval() @safe inout return { return this; }
1088 
1089     /// Type of limb in internal representation.
1090     alias Limb = __mp_limb_t;   // GNU MP alias
1091 
1092     /** Returns: limbs. */
1093     inout(Limb)[] _limbs() inout return @system // TODO scope
1094     {
1095         // import std.math : abs;
1096         return _z._mp_d[0 .. _limbCount];
1097     }
1098 
1099     /// Get number of limbs in internal representation.
1100     @property uint _limbCount() const @safe
1101     {
1102         return _integralAbs(_z._mp_size);
1103     }
1104 
1105     /// @nogc-variant of `toStringz` with heap allocation of null-terminated C-string `stringz`.
1106     char* _allocStringzCopyOf(const string value) @trusted @nogc
1107     {
1108         char* stringz = cast(char*)qualifiedMalloc(value.length + 1); // maximum this many characters
1109         size_t i = 0;
1110         foreach (immutable char ch; value[])
1111         {
1112             if (ch != '_')
1113             {
1114                 stringz[i] = ch;
1115                 i += 1;
1116             }
1117         }
1118         stringz[i] = '\0'; // set C null terminator
1119         return stringz;
1120     }
1121 
1122     /// Returns: pointer to internal GMP C struct.
1123     inout(__mpz_struct)* _ptr() inout return @system // TODO scope
1124     {
1125         return &_z;
1126     }
1127 
1128     __mpz_struct _z;            // internal libgmp C struct
1129 
1130     // qualified C memory managment
1131     static @safe
1132     {
1133         pragma(mangle, "malloc") void* qualifiedMalloc(size_t size);
1134         pragma(mangle, "free") void qualifiedFree(void* ptr);
1135     }
1136 
1137     /** Number of calls made to `__gmpz`--functions that construct or changes
1138         this value. Used to verify correct lowering and evaluation of template
1139         expressions.
1140 
1141         For instance the `x` in `x = y + z` should be assigned only once inside
1142         a call to `mpz_add`.
1143      */
1144     @property size_t mutatingCallCount() const @safe { return _ccc; }
1145 
1146     version(ccc) size_t _ccc;  // C mutation call count. number of calls to C GMP function calls that mutate this object
1147 }
1148 
1149 version(unittest) static assert(isMpZExpr!MpZ);
1150 
1151 pure nothrow pragma(inline, true):
1152 
1153 /** Instantiator for `MpZ`. */
1154 MpZ mpz(Args...)(Args args) @safe @nogc
1155 {
1156     return typeof(return)(args);
1157 }
1158 
1159 /// Swap contents of `x` with contents of `y`.
1160 void swap()(ref MpZ x,
1161             ref MpZ y) @nogc
1162 {
1163     import std.algorithm.mutation : swap;
1164     swap(x, y); // x.swap(y);
1165 }
1166 
1167 /// Returns: `x` as a `string` in decimal base.
1168 string toDecimalString()(auto ref const MpZ x) // for `std.bigint.BigInt` compatibility
1169 {
1170     return x.toString(10);
1171 }
1172 
1173 /// Returns: `x` as a uppercased `string` in hexadecimal base without any base prefix (0x).
1174 string toHex()(auto ref const MpZ x) // for `std.bigint.BigInt` compatibility
1175 {
1176     return x.toString(16, true);
1177 }
1178 
1179 /// Returns: the absolute value of `x` converted to the corresponding unsigned type.
1180 Unsigned!T absUnsign(T)(auto ref const MpZ x) // for `std.bigint.BigInt` compatibility
1181     if (isIntegral!T)
1182 {
1183     return _integralAbs(cast(T)x);
1184 }
1185 
1186 /** Returns: absolute value of `x`.
1187     Written as a free function instead of `MpZ`-member because `__traits(isRef, this)` cannot be used.
1188  */
1189 MpZ abs()(auto ref const MpZ x) @trusted @nogc
1190 {
1191     static if (__traits(isRef, x)) // l-value `x`
1192     {
1193         typeof(return) y = null; // must use temporary
1194         __gmpz_abs(y._ptr, x._ptr); version(ccc) ++y._ccc;
1195         return y;
1196     }
1197     else                        // r-value `x`
1198     {
1199         MpZ* mut_x = (cast(MpZ*)(&x)); // @trusted because `MpZ` has no aliased indirections
1200         mut_x.absolute();
1201         return move(*mut_x);    // TODO shouldn't have to call `move` here
1202     }
1203 }
1204 
1205 /// Returns: comparison of the absolute values of `x` and `y`.
1206 int cmpabs()(auto ref const MpZ x,
1207              auto ref const MpZ y) @trusted @nogc
1208 {
1209     return __gmpz_cmpabs(x._ptr, y._ptr);
1210 }
1211 /// ditto
1212 int cmpabs()(auto ref const MpZ x, double y) @trusted @nogc
1213 {
1214     return __gmpz_cmpabs_d(x._ptr, y);
1215 }
1216 /// ditto
1217 int cmpabs()(auto ref const MpZ x, ulong y) @trusted @nogc
1218 {
1219     return __gmpz_cmpabs_ui(x._ptr, y);
1220 }
1221 
1222 /** Returns: next prime greater than `x`.
1223     Written as a free function instead of `MpZ`-member because `__traits(isRef, this)` cannot be used.
1224 */
1225 MpZ nextPrime()(auto ref const MpZ x) @trusted @nogc
1226 {
1227     static if (__traits(isRef, x)) // l-value `x`
1228     {
1229         typeof(return) y = null; // must use temporary
1230         __gmpz_nextprime(y._ptr, x._ptr); version(ccc) ++y._ccc;
1231         return y;
1232     }
1233     else                        // r-value `x`
1234     {
1235         MpZ* mut_x = (cast(MpZ*)(&x)); // @trusted because `MpZ` has no aliased indirections
1236         __gmpz_nextprime(mut_x._ptr, x._ptr); version(ccc) ++mut_x._ccc;
1237         return move(*mut_x);    // TODO shouldn't have to call `move` here
1238     }
1239 }
1240 
1241 /// Returns: greatest common divisor (gcd) of `x` and `y`.
1242 MpZ gcd()(auto ref const MpZ x,
1243           auto ref const MpZ y) @trusted @nogc
1244 {
1245     static      if (!__traits(isRef, x)) // r-value `x`
1246     {
1247         MpZ* mut_x = (cast(MpZ*)(&x)); // @trusted because `MpZ` has no aliased indirections
1248         __gmpz_gcd(mut_x._ptr, x._ptr, y._ptr); version(ccc) ++mut_x._ccc;
1249         return move(*mut_x);    // TODO shouldn't have to call `move` here
1250     }
1251     else static if (!__traits(isRef, y)) // r-value `y`
1252     {
1253         MpZ* mut_y = (cast(MpZ*)(&y)); // @trusted because `MpZ` has no aliased indirections
1254         __gmpz_gcd(mut_y._ptr, x._ptr, y._ptr); version(ccc) ++mut_y._ccc;
1255         return move(*mut_y);    // TODO shouldn't have to call `move` here
1256     }
1257     else                        // l-value `x` and `y`
1258     {
1259         MpZ z = null;
1260         __gmpz_gcd(z._ptr, x._ptr, y._ptr); version(ccc) ++z._ccc;
1261         return z;
1262     }
1263 }
1264 /// ditto
1265 MpZ gcd()(auto ref const MpZ x,
1266           ulong y) @trusted @nogc
1267 {
1268     static if (__traits(isRef, x)) // l-value `x`
1269     {
1270         MpZ z = null;
1271         const z_ui = __gmpz_gcd_ui(z._ptr, x._ptr, y); version(ccc) ++z._ccc;
1272         return z;
1273     }
1274     else
1275     {
1276         MpZ* mut_x = (cast(MpZ*)(&x)); // @trusted because `MpZ` has no aliased indirections
1277         const z_ui = __gmpz_gcd_ui(mut_x._ptr, x._ptr, y); version(ccc) ++mut_x._ccc;
1278         return move(*mut_x);    // TODO shouldn't have to call `move` here
1279     }
1280 }
1281 
1282 /// Returns: least common multiple (lcm) of `x` and `y`.
1283 MpZ lcm()(auto ref const MpZ x,
1284           auto ref const MpZ y) @trusted @nogc
1285 {
1286     static      if (!__traits(isRef, x)) // r-value `x`
1287     {
1288         MpZ* mut_x = (cast(MpZ*)(&x)); // @trusted because `MpZ` has no aliased indirections
1289         __gmpz_lcm(mut_x._ptr, x._ptr, y._ptr); version(ccc) ++mut_x._ccc;
1290         return move(*mut_x);    // TODO shouldn't have to call `move` here
1291     }
1292     else static if (!__traits(isRef, y)) // r-value `y`
1293     {
1294         MpZ* mut_y = (cast(MpZ*)(&y)); // @trusted because `MpZ` has no aliased indirections
1295         __gmpz_lcm(mut_y._ptr, x._ptr, y._ptr); version(ccc) ++mut_y._ccc;
1296         return move(*mut_y);    // TODO shouldn't have to call `move` here
1297     }
1298     else                        // l-value `x` and `y`
1299     {
1300         MpZ z = null;
1301         __gmpz_lcm(z._ptr, x._ptr, y._ptr); version(ccc) ++z._ccc;
1302         return z;
1303     }
1304 }
1305 /// ditto
1306 MpZ lcm()(auto ref const MpZ x,
1307           ulong y) @trusted @nogc
1308 {
1309     static if (__traits(isRef, x)) // l-value `x`
1310     {
1311         MpZ z = null;
1312         __gmpz_lcm_ui(z._ptr, x._ptr, y);
1313         return z;
1314     }
1315     else
1316     {
1317         MpZ* mut_x = (cast(MpZ*)(&x)); // @trusted because `MpZ` has no aliased indirections
1318         __gmpz_lcm_ui(mut_x._ptr, x._ptr, y); version(ccc) ++mut_x._ccc;
1319         return move(*mut_x);    // TODO shouldn't have to call `move` here
1320     }
1321 }
1322 
1323 /** Returns: `base` ^^ `exp` (modulo `mod`).
1324     Parameter `exp` must be positive.
1325 */
1326 MpZ powm()(auto ref const MpZ base,
1327            auto ref const MpZ exp,
1328            auto ref const MpZ mod) @trusted
1329 {
1330     typeof(return) y = 0; // result, TODO reuse `exp` or `mod` if any is an r-value
1331     assert(exp >= 0, "Negative exponent");
1332     __gmpz_powm(y._ptr, base._ptr, exp._ptr, mod._ptr); version(ccc) ++y._ccc;
1333     return y;
1334 }
1335 /// ditto
1336 MpZ powm()(auto ref const MpZ base,
1337            ulong exp,
1338            auto ref const MpZ mod) @trusted
1339 {
1340     typeof(return) y = 0;       // result, TODO reuse `exp` or `mod` if any is an r-value
1341     __gmpz_powm_ui(y._ptr, base._ptr, exp, mod._ptr); version(ccc) ++y._ccc;
1342     return y;
1343 }
1344 
1345 ///
1346 @safe @nogc unittest
1347 {
1348     const x = 42.Z;
1349     assert(x.unaryMinus() == -42);   // l-value `this`
1350     assert(42.Z.unaryMinus() == -42); // r-value `this`
1351 }
1352 
1353 /// convert to string
1354 @safe unittest
1355 {
1356     assert(mpz(    42).toString ==   `42`);
1357     assert(mpz(   -42).toString ==  `-42`);
1358     assert(mpz(`-101`).toString == `-101`);
1359 
1360     assert(mpz(-42).toDecimalString == `-42`);
1361     assert(mpz( 42).toDecimalString ==  `42`);
1362 
1363     assert(mpz( 0).toHex == `0`);
1364     assert(mpz( 1).toHex == `1`);
1365     assert(mpz( 9).toHex == `9`);
1366     assert(mpz(10).toHex == `A`);
1367     assert(mpz(14).toHex == `E`);
1368     assert(mpz(15).toHex == `F`);
1369     assert(mpz(16).toHex == `10`);
1370 
1371     assert(mpz(-42).absUnsign!ulong == 42);
1372     assert(mpz( 42).absUnsign!ulong == 42);
1373 }
1374 
1375 /// opBinary with r-value right-hand-side
1376 @safe @nogc unittest
1377 {
1378     Z a = 42;
1379     {
1380         Z b = a + 1.Z;              // r-value `rhs`
1381         assert(b.mutatingCallCount == 2);
1382         assert(b == 43);
1383     }
1384 
1385     {
1386         Z b = a - 1.Z;              // r-value `rhs`
1387         assert(b.mutatingCallCount == 2);
1388         assert(b == 41);
1389     }
1390 
1391     {
1392         Z b = a * 2.Z;              // r-value `rhs`
1393         assert(b.mutatingCallCount == 2);
1394         assert(b == 84);
1395     }
1396 
1397     {
1398         Z b = a / 2.Z;              // r-value `rhs`
1399         assert(b.mutatingCallCount == 2);
1400         assert(b == 21);
1401     }
1402 
1403     {
1404         Z b = a % 10.Z;              // r-value `rhs`
1405         assert(b.mutatingCallCount == 2);
1406         assert(b == 2);
1407     }
1408 }
1409 
1410 ///
1411 @safe @nogc unittest
1412 {
1413     const _ = (cast(uint)42).Z;
1414     const a = 42.Z;
1415     const b = 43UL.Z;
1416     const c = 43.0.Z;
1417     const z = 0.Z;
1418 
1419     // `opOpAssign` with `Unsigned`
1420     auto w = 42.Z;
1421     assert(w == 42);
1422 
1423     w += 100UL;
1424     assert(w == 142);
1425 
1426     w -= 100.Z;
1427     assert(w == 42);
1428 
1429     w += 100UL;
1430     assert(w == 142);
1431 
1432     w -= 100UL;
1433     assert(w == 42);
1434 
1435     w *= 100UL;
1436     assert(w == 4200);
1437 
1438     w /= 100UL;
1439     assert(w == 42);
1440 
1441     w %= 10UL;
1442     assert(w == 2);
1443 
1444     w ^^= 6UL;
1445     assert(w == 64);
1446 
1447     w = 42;
1448     assert(w == 42);
1449 
1450     w += 100;
1451     assert(w == 142);
1452 
1453     w -= 100;
1454     assert(w == 42);
1455 
1456     w *= 100;
1457     assert(w == 4200);
1458 
1459     w /= 100;
1460     assert(w == 42);
1461 
1462     w *= 100;
1463     assert(w == 4200);
1464 
1465     w /= -100;
1466     assert(w == -42);
1467 
1468     w *= -1;
1469     assert(w == 42);
1470 
1471     w %= 10;
1472     assert(w == 2);
1473 
1474     w = 2;
1475     w ^^= 6;
1476     assert(w == 64);
1477 
1478     w = 32.0;
1479     assert(w == 32);
1480 
1481     w = 42UL;
1482     assert(w == 42);
1483 
1484     w /= 2.Z;
1485     assert(w == 21);
1486 
1487     w /= -2.Z;
1488     assert(w == -10);
1489 
1490     w *= -2.Z;
1491     assert(w == 20);
1492 
1493     w %= 3.Z;
1494     assert(w == 2);
1495 
1496     w *= -1.Z;
1497     assert(w == -2);
1498 
1499     w /= -1.Z;
1500     assert(w == 2);
1501 
1502     // equality
1503     assert(z == 0);
1504     assert(z == cast(uint)0);
1505     assert(z == 0L);
1506     assert(z == 0UL);
1507     assert(z == 0.0f);
1508     assert(z == 0.0);
1509 
1510     // eval cast
1511 
1512     assert(a);
1513     assert(cast(ulong)a == a);
1514     assert(cast(ulong)a == 42);
1515     assert(cast(long)a == a);
1516     assert(cast(long)a == 42);
1517     assert(cast(double)a == 42.0);
1518 
1519     // binary
1520 
1521     assert(`0b11`.Z == 3);
1522     assert(`0B11`.Z == 3);
1523 
1524     // octal
1525 
1526     assert(`07`.Z == 7);
1527     assert(`010`.Z == 8);
1528 
1529     // hexadecimal
1530 
1531     assert(`0x10`.Z == 16);
1532     assert(`0X10`.Z == 16);
1533 
1534     // decimal
1535 
1536     assert(`101`.Z == 101);
1537     assert(`101`.Z == 101);
1538 
1539     immutable ic = 101UL.Z;
1540 
1541     assert(a == a.dup);
1542     assert(ic == ic.dup);
1543 
1544     // equality
1545 
1546     assert(a == a);
1547     assert(a == 42.Z);
1548     assert(a == 42.0);
1549     assert(a == 42);
1550     assert(a == cast(uint)42);
1551     assert(a == 42UL);
1552     assert(_ == 42);
1553     assert(c == 43.0);
1554 
1555     // non-equality
1556 
1557     assert(a != b);
1558 
1559     // less than
1560 
1561     assert(a < b);
1562     assert(a < 43.Z);
1563     assert(a < 43);
1564     assert(a < cast(uint)43);
1565     assert(a < 43UL);
1566     assert(a < 43.0);
1567 
1568     assert(-1.Z < 0.Z);
1569     assert(-1.Z < 0L);
1570     assert(-1.Z < 0UL);
1571     assert(-1.Z < 0.0);
1572 
1573     // greater than
1574 
1575     assert(b > a);
1576     assert(b > 42.Z);
1577     assert(b > 42);
1578     assert(b > cast(uint)42);
1579     assert(b > 42UL);
1580     assert(b > 42.0);
1581 
1582     assert(+1.Z > 0.Z);
1583     assert(+1.Z > 0L);
1584     assert(+1.Z > 0UL);
1585     assert(+1.Z > 0.0);
1586 
1587     // absolute value
1588 
1589     assert(abs(a) == a);        // free function
1590     assert(a.abs == a);         // UFCS
1591     assert(abs(-42.Z) == 42);
1592     assert(abs(-a) == a);
1593 
1594     // absolute value comparison
1595 
1596     assert(cmpabs(-43.Z,  44.Z) == -1);
1597     assert(cmpabs(-43.Z, -44.Z) == -1);
1598     assert(cmpabs(-44.Z, -43.Z) == +1);
1599     assert(cmpabs(-43.Z, -43.Z) ==  0);
1600 
1601     assert(cmpabs(-43.Z,  44.0) == -1);
1602     assert(cmpabs(-43.Z, -44.0) == -1);
1603     assert(cmpabs(-44.Z, -43.0) == +1);
1604     assert(cmpabs(-43.Z, -43.0) ==  0);
1605 
1606     assert(cmpabs(-43.Z, 44) == -1);
1607     assert(cmpabs( 43.Z, 44) == -1);
1608     assert(cmpabs(-44.Z, 43) == +1);
1609     assert(cmpabs( 44.Z, 43) == +1);
1610     assert(cmpabs(-43.Z, 43) ==  0);
1611 
1612     Z _43 = 43;
1613     Z _4 = 4;
1614     Z _24 = 24;
1615 
1616     // next prime
1617     assert(nextPrime(_4) == 5);
1618     assert(nextPrime(24.Z) == 29);
1619 
1620     assert(nextPrime(_24) == 29);
1621     assert(nextPrime(24.Z) == 29);
1622     assert(24.Z.nextPrime() == 29);
1623 
1624     assert(nextPrime(_43) == 47);
1625     assert(nextPrime(43.Z) == 47);
1626     assert(43.Z.nextPrime() == 47);
1627 
1628     // greatest common divisor
1629 
1630     assert(gcd(43.Z,  44.Z) == 1);
1631     assert(gcd(4.Z, 24.Z) == 4);
1632     assert(gcd(6.Z, 24.Z) == 6);
1633     assert(gcd(10.Z, 100.Z) == 10);
1634 
1635     assert(gcd(43.Z,  44) == 1);
1636     assert(gcd(4.Z, 24) == 4);
1637     assert(gcd(6.Z, 24) == 6);
1638     assert(gcd(10.Z, 100) == 10);
1639 
1640     assert(gcd(_43,  44) == 1);
1641     assert(gcd(_4, 24) == 4);
1642     assert(gcd(_4, _24) == 4);
1643     assert(gcd(_4, 24.Z) == 4);
1644 
1645     // least common multiple
1646 
1647     assert(lcm(43.Z,  44.Z) == 1892);
1648     assert(lcm(4.Z, 24.Z) == 24);
1649     assert(lcm(6.Z, 24.Z) == 24);
1650     assert(lcm(10.Z, 100.Z) == 100);
1651 
1652     assert(lcm(43.Z,  44) == 1892);
1653     assert(lcm(4.Z, 24) == 24);
1654     assert(lcm(6.Z, 24) == 24);
1655     assert(lcm(10.Z, 100) == 100);
1656 
1657     assert(lcm(_43,  44) == 1892);
1658     assert(lcm(_4, 24) == 24);
1659     assert(lcm(_4, _24) == 24);
1660     assert(lcm(_4, 24.Z) == 24);
1661 
1662     // negated value
1663 
1664     assert(-a == -42);
1665     assert(-(-a) == a);
1666 
1667     auto n = 42.Z;
1668     n.negate();
1669     assert(n == -42);
1670     n.negate();
1671     assert(n == 42);
1672     n.negate();
1673     assert(n == -42);
1674     n.absolute();
1675     assert(n == 42);
1676     n.absolute();
1677     assert(n == 42);
1678 
1679     // addition
1680 
1681     assert(a + b == b + a);     // commutative
1682     assert(a + 43.Z == b + a);
1683     assert(a - 43.Z == -(43.Z - a));
1684     assert(a + 0 == a);
1685     assert(a + 1 != a);
1686     assert(0 + a == a);
1687     assert(1 + a != a);
1688     assert(a + 0UL == a);
1689     assert(a + 1UL != a);
1690     assert(a + b == 42 + 43);
1691     assert(1 + a == 43);
1692     assert(a + (-1) == 41);
1693     assert(1UL + a == 43);
1694     assert(a + 1 == 1 + a);       // commutative
1695     assert(a + (-1) == (-1) + a); // commutative
1696     assert(1UL + a == a + 1UL);   // commutative
1697 
1698     // subtraction
1699 
1700     assert(a - 2 == 40);
1701     assert(2 - a == -40);
1702     assert(-2 - a == -44);
1703     assert(a - 2 == -(2 - a));     // commutative
1704     assert(a - (-2) == 44);
1705     assert(44UL - 42.Z == 2);
1706 
1707     // multiplication
1708 
1709     assert(a * 1UL == a);
1710     assert(a * 1 == a);
1711     assert(1 * a == a);
1712     assert(1UL * a == a);
1713     assert((-1) * a == -a);
1714     assert(a * 2 != a);
1715     assert(a * -2 == -(2*a));
1716     assert(a * b == b * a);
1717     assert(a * b == 42UL * 43UL);
1718 
1719     // division
1720 
1721     assert(27.Z / 3.Z == 9);
1722     assert(27.Z /   3  == 9);
1723 
1724     assert(27.Z / 10.Z  == 2);
1725     assert(27.Z /   10   == 2);
1726     assert(27.Z /   10UL == 2);
1727 
1728     assert(27.Z / -3   == -9);
1729     assert(27.Z /  3UL ==  9);
1730 
1731     assert(27.Z / -10   == -2);
1732 
1733     assert(28   /  3.Z ==  9);
1734     assert(28UL /  3.Z ==  9);
1735 
1736     assert(28   / -3.Z == -9);
1737     assert(28UL / -3.Z == -9);
1738 
1739     // modulo/remainder
1740 
1741     assert(27.Z % 3.Z == 0);
1742     assert(27.Z % 10.Z == 7);
1743 
1744     assert(27.Z % 3 == 0);
1745     assert(-27.Z % 3 == 0);
1746 
1747     assert(27.Z % 10 == 7);
1748     assert(27.Z % 10 == 7);
1749 
1750     assert(28   % 3.Z == 1);
1751     assert(28UL % 3.Z == 1);
1752 
1753     assert( 28.Z  % -3 == -1); // negative divisor gives negative remainder according to https://en.wikipedia.org/wiki/Remainder
1754     assert(-28.Z  %  3 == 1);  // dividend sign doesn't affect remainder
1755 
1756     //
1757     assert( 28.Z  % -3.Z == 1);  // TODO should be -1
1758     assert(-28.Z  %  3.Z == -1);  // TODO should be 1
1759     assert( 28  % -3.Z == 1);      // TODO should be -1
1760     assert(-28  %  3.Z == -1);     // TODO should be 1
1761 
1762     // modulo/remainder
1763 
1764     immutable one = 1.Z;
1765     const two = 2.Z;
1766     immutable three = 3.Z;
1767     const four = 4.Z;
1768     immutable five = 5.Z;
1769     const six = 6.Z;
1770     assert(six % one == 0);
1771     assert(six % two == 0);
1772     assert(six % three == 0);
1773     assert(six % four == 2);
1774     assert(six % five == 1);
1775     assert(six % six == 0);
1776 
1777     // subtraction
1778 
1779     assert(six - one == 5);
1780     assert(six - 1UL == 5);
1781     assert(six - 1 == 5);
1782     assert(1 - six == -5);
1783     assert(1L - six == -5);
1784     assert(1UL - six == -5);
1785 
1786     // exponentiation
1787 
1788     assert(0.Z^^0 == 1);
1789     assert(3.Z^^3 == 27);
1790     assert(3.Z^^3L == 27);
1791     assert(2.Z^^8 == 256);
1792     assert(2.Z^^8L == 256);
1793     assert(2.Z^^8UL == 256);
1794 
1795     assert(Z.pow(2UL, 8UL) == 256);
1796     assert(Z.pow(2UL, 8) == 256);
1797     assert(Z.pow(2UL, 8) == 256);
1798     assert(Z.pow(2, 8) == 256);
1799     assert(Z.pow(-2, 8) == 256);
1800     assert(Z.pow(-2, 7) == -128);
1801 
1802     // disallow power exponent to be an `MpZ`
1803     assert(!__traits(compiles, 2^^8.Z == 256));
1804     assert(!__traits(compiles, 2L^^8.Z == 256));
1805     assert(!__traits(compiles, 2UL^^8.Z == 256));
1806 
1807     // exponentiation plus modulus
1808 
1809     assert(2.Z.powm(8.Z, 8.Z) == 0.Z);
1810     assert(2.Z.powm(3.Z, 16.Z) == 8.Z);
1811     assert(3.Z.powm(3.Z, 16.Z) == 11.Z);
1812 
1813     assert(2.Z.powm(8, 8.Z) == 0.Z);
1814     assert(2.Z.powm(3, 16.Z) == 8.Z);
1815     assert(3.Z.powm(3, 16.Z) == 11.Z);
1816 
1817     // bitwise and, or and xor
1818 
1819     {
1820         foreach (immutable i; 0 .. 10)
1821         {
1822             foreach (immutable j; 0 .. 10)
1823             {
1824                 assert((i.Z & j.Z) == (i & j));
1825                 assert((i.Z | j.Z) == (i | j));
1826                 assert((i.Z ^ j.Z) == (i ^ j));
1827 
1828                 Z x = null;
1829 
1830                 x = i.Z;
1831                 x &= j.Z;
1832                 assert(x == (i & j));
1833 
1834                 x = i.Z;
1835                 x |= j.Z;
1836                 assert(x == (i | j));
1837 
1838                 x = i.Z;
1839                 x ^= j.Z;
1840                 assert(x == (i ^ j));
1841             }
1842         }
1843     }
1844 
1845     // swap
1846 
1847     auto x = 42.Z;
1848     auto y = 43.Z;
1849 
1850     assert(x == 42);
1851     assert(y == 43);
1852 
1853     x.swap(y);
1854 
1855     assert(y == 42);
1856     assert(x == 43);
1857 
1858     swap(x, y);
1859 
1860     assert(x == 42);
1861     assert(y == 43);
1862 
1863     assert(null.Z.fromString("42") == 42.Z);
1864     assert(null.Z.fromString("42") < 43.Z);
1865     assert(null.Z.fromString("42") > 41.Z);
1866     assert(null.Z.fromString("42") == 42);
1867     assert(null.Z.fromString("11", 2) == 3);
1868     assert(null.Z.fromString("7", 8) == 7);
1869     assert(null.Z.fromString("7") == 7);
1870     assert(null.Z.fromString("e", 16) == 14);
1871     assert(null.Z.fromString("f", 16) == 15);
1872     assert(null.Z.fromString("0xe") == 14);
1873     assert(null.Z.fromString("0xf") == 15);
1874     assert(null.Z.fromString("10", 16) == 16);
1875     assert(null.Z.fromString("10", 32) == 32);
1876 
1877     // odd and even
1878 
1879     assert(0.Z.isEven);
1880     assert(1.Z.isOdd);
1881     assert(2.Z.isEven);
1882     assert(3.Z.isOdd);
1883 
1884     assert((-1).Z.isOdd);
1885     assert((-2).Z.isEven);
1886     assert((-3).Z.isOdd);
1887 
1888     assert("300000000000000000000000000000000000000".Z.isEven);
1889     assert("300000000000000000000000000000000000001".Z.isOdd);
1890     assert("300000000000000000000000000000000000002".Z.isEven);
1891     assert("300000000000000000000000000000000000003".Z.isOdd);
1892 
1893     // negative and positive
1894 
1895     assert(0.Z.isPositive);
1896     assert(1.Z.isPositive);
1897     assert(2.Z.isPositive);
1898     assert(3.Z.isPositive);
1899 
1900     assert((-1).Z.isNegative);
1901     assert((-2).Z.isNegative);
1902     assert((-3).Z.isNegative);
1903 
1904     // sign function (sgn)
1905 
1906     assert(long.min.Z.sgn == -1);
1907     assert(int.min.Z.sgn  == -1);
1908     assert(-2.Z.sgn == -1);
1909     assert(-1.Z.sgn == -1);
1910     assert( 0.Z.sgn ==  0);
1911     assert( 1.Z.sgn ==  1);
1912     assert( 2.Z.sgn ==  1);
1913     assert(int.max.Z.sgn  == 1);
1914     assert(long.max.Z.sgn == 1);
1915 
1916     assert(!long.min.Z.isZero);
1917     assert(!int.min.Z.isZero);
1918     assert(!(-2).Z.isZero);
1919     assert(!(-1).Z.isZero);
1920     assert( 0.Z.isZero);
1921     assert(! 1.Z.isZero);
1922     assert(! 2.Z.isZero);
1923     assert(!int.max.Z.isZero);
1924     assert(!long.max.Z.isZero);
1925 
1926     // fits in type
1927 
1928     foreach (Integral; AliasSeq!(short, int, long,
1929                                  ushort, uint, ulong))
1930     {
1931         assert(Integral.min.Z.fitsIn!Integral);
1932         assert(Integral.max.Z.fitsIn!Integral);
1933     }
1934 
1935     // TODO
1936     // assert(short.min.Z.fitsIn!short);
1937     // assert(short.max.Z.fitsIn!short);
1938     // assert(ushort.min.Z.fitsIn!ushort);
1939     // assert(ushort.max.Z.fitsIn!ushort);
1940 
1941     // internal limb count
1942 
1943     assert(0.Z._limbCount == 0);
1944     assert(1.Z._limbCount == 1);
1945     assert(2.Z._limbCount == 1);
1946 
1947     assert(Z.pow(2UL, 32UL)._limbCount == 1);
1948 
1949     assert(Z.pow(2UL, 63UL)._limbCount == 1);
1950     assert(Z.pow(2UL, 63UL + 1)._limbCount == 2);
1951 
1952     assert(Z.pow(2UL, 127UL)._limbCount == 2);
1953     assert(Z.pow(2UL, 127UL + 1)._limbCount == 3);
1954 
1955     assert(Z.pow(2UL, 255UL)._limbCount == 4);
1956     assert(Z.pow(2UL, 255UL + 1)._limbCount == 5);
1957 }
1958 
1959 /// generators
1960 @safe @nogc unittest
1961 {
1962     assert(Z.mersennePrime(15) == 2^^15 - 1);
1963     assert(Z.mersennePrime(15UL) == 2^^15 - 1);
1964 }
1965 
1966 /// Phobos unittests
1967 @safe @nogc unittest
1968 {
1969     alias bigInt = mpz;
1970     alias BigInt = Z;     // Phobos naming convention
1971 
1972     {
1973         const BigInt a = "9588669891916142";
1974         const BigInt b = "7452469135154800";
1975         const c = a * b;
1976         assert(c == BigInt("71459266416693160362545788781600"));
1977         auto d = b * a;
1978         assert(d == BigInt("71459266416693160362545788781600"));
1979         assert(d == c);
1980         d = c * BigInt("794628672112");
1981         assert(d == BigInt("56783581982794522489042432639320434378739200"));
1982         auto e = c + d;
1983         assert(e == BigInt("56783581982865981755459125799682980167520800"));
1984         const f = d + c;
1985         assert(f == e);
1986         auto g = f - c;
1987         assert(g == d);
1988         g = f - d;
1989         assert(g == c);
1990         e = 12_345_678;
1991         g = c + e;
1992         immutable h = g / b;
1993         const i = g % b;
1994         assert(h == a);
1995         assert(i == e);
1996         BigInt j = "-0x9A56_57f4_7B83_AB78";
1997         j ^^= 11UL;
1998         j ^^= 2L;
1999         j ^^= 2;
2000     }
2001 
2002     {
2003         auto b = BigInt("1_000_000_000");
2004 
2005         b += 12_345;
2006         assert(b == 1_000_012_345);
2007         b += -12_345;
2008         assert(b == 1_000_000_000);
2009 
2010         b -= -12_345;
2011         assert(b == 1_000_012_345);
2012         b -= +12_345;
2013         assert(b == 1_000_000_000);
2014 
2015         b += 12_345;
2016         assert(b == 1_000_012_345);
2017 
2018         b /= 5UL;
2019         assert(b == 200_002_469);
2020     }
2021 
2022     {
2023         auto x = BigInt("123");
2024         const y = BigInt("321");
2025         x += y;
2026         assert(x == 444);
2027     }
2028 
2029     {
2030         const x = BigInt("123");
2031         const y = BigInt("456");
2032         const BigInt z = x * y;
2033         assert(z == 56_088);
2034     }
2035 
2036     {
2037         auto x = BigInt("123");
2038         x *= 300;
2039         assert(x == 36_900);
2040     }
2041 
2042     {
2043         auto x = BigInt("123");
2044         x *= -1;
2045         assert(x == -123);
2046     }
2047 
2048     {
2049         const x  = BigInt("1_000_000_500");
2050 
2051         immutable ulong ul  = 2_000_000UL;
2052         immutable uint ui   = 500_000;
2053         immutable ushort us = 30_000;
2054         immutable ubyte ub  = 50;
2055 
2056         immutable long  l = 1_000_000L;
2057         immutable int   i = 500_000;
2058         immutable short s = 30_000;
2059         immutable byte b  = 50;
2060 
2061         static assert(is(typeof(x % ul)  == ulong));
2062         static assert(is(typeof(x % ui)  == uint));
2063         static assert(is(typeof(x % us)  == ushort));
2064         static assert(is(typeof(x % ub)  == ubyte));
2065 
2066         static assert(is(typeof(x % l)  == long));
2067         static assert(is(typeof(x % i)  == int));
2068         static assert(is(typeof(x % s)  == short));
2069         static assert(is(typeof(x % b)  == byte));
2070 
2071         assert(x % ul == 500);
2072         assert(x % ui == 500);
2073         assert(x % us  == 10_500);
2074         assert(x % ub == 0);
2075 
2076         assert(x % l  == 500L);
2077         assert(x % i  == 500);
2078         assert(x % s  == 10_500);
2079         assert(x % b == 0);
2080     }
2081 
2082     {
2083         const x = BigInt("100");
2084         const BigInt y = 123 + x;
2085         assert(y == BigInt("223"));
2086 
2087         const BigInt z = 123 - x;
2088         assert(z == BigInt("23"));
2089 
2090         // Dividing a built-in integer type by BigInt always results in
2091         // something that fits in a built-in type, so the built-in type is
2092         // returned, not BigInt.
2093         static assert(is(typeof(1000 / x) == int));
2094         assert(1000 / x == 10);
2095     }
2096 
2097     {
2098         auto x = BigInt("1234");
2099         assert(+x  == BigInt(" 1234"));
2100         assert(-x  == BigInt("-1234"));
2101         ++x;
2102         assert(x == BigInt("1235"));
2103         --x;
2104         assert(x == BigInt("1234"));
2105     }
2106 
2107     {
2108         const x = BigInt("12345");
2109         const y = BigInt("12340");
2110         immutable int z = 12_345;
2111         immutable int w = 54_321;
2112         assert(x == x);
2113         assert(x != y);
2114         assert(x == y + 5);
2115         assert(x == z);
2116         assert(x != w);
2117     }
2118 
2119     {
2120         // non-zero values are regarded as `true`
2121         const x = BigInt("1");
2122         const y = BigInt("10");
2123         assert(x);
2124         assert(y);
2125 
2126         // zero value is regarded as `false`
2127         const z = BigInt("0");
2128         assert(!z);
2129     }
2130 
2131     {
2132         assert(cast(int)BigInt("0") == 0);
2133         assert(cast(ubyte)BigInt("0") == 0);
2134 
2135         assert(cast(ubyte)BigInt(255) == 255);
2136         assert(cast(ushort)BigInt(65_535) == 65_535);
2137         assert(cast(uint)BigInt(uint.max) == uint.max);
2138         assert(cast(ulong)BigInt(ulong.max) == ulong.max);
2139 
2140         assert(cast(byte)BigInt(-128) == -128);
2141         assert(cast(short)BigInt(-32_768) == -32_768);
2142         assert(cast(int)BigInt(int.min) == int.min);
2143         assert(cast(long)BigInt(long.min) == long.min);
2144 
2145         assert(cast(byte)BigInt(127) == 127);
2146         assert(cast(short)BigInt(32_767) == 32_767);
2147         assert(cast(int)BigInt(int.max) == int.max);
2148         assert(cast(long)BigInt(long.max) == long.max);
2149 
2150         // TODO:
2151         // import std.conv : to, ConvOverflowException;
2152         // import std.exception : assertThrown;
2153         // assertThrown!ConvOverflowException(BigInt("256").to!ubyte);
2154         // assertThrown!ConvOverflowException(BigInt("-1").to!ubyte);
2155     }
2156 
2157     {
2158         // TODO
2159         // segfaults because with double free
2160         // const(BigInt) x = BigInt("123");
2161         // BigInt y = cast()x;    // cast away const
2162         // assert(y == x);
2163     }
2164 
2165     {
2166         const x = BigInt("100");
2167         const y = BigInt("10");
2168         const int z = 50;
2169         const int w = 200;
2170         assert(y < x);
2171         assert(x > z);
2172         assert(z > y);
2173         assert(x < w);
2174     }
2175 
2176     {
2177         assert(BigInt("12345").toLong() == 12_345);
2178         assert(BigInt("-123450000000000000000000000000").toLong() == long.min);
2179         assert(BigInt("12345000000000000000000000000000").toLong() == long.max);
2180     }
2181 
2182     {
2183         assert(BigInt("12345").toInt() == 12_345);
2184         assert(BigInt("-123450000000000000000000000000").toInt() == int.min);
2185         assert(BigInt("12345000000000000000000000000000").toInt() == int.max);
2186     }
2187 }
2188 
2189 // Fermats Little Theorem
2190 @safe @nogc unittest
2191 {
2192     if (unittestLong) // compile but not run unless flagged for because running is slow
2193     {
2194         /*
2195           Fermats little theorem: a ^ p ≡ a (mod p) ∀ prime p check Fermats
2196           little theorem for a ≤ 100000 and all mersene primes M(p) : p ≤ 127
2197         */
2198         foreach (immutable ulong i; [2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127])
2199         {
2200             foreach (immutable ulong j; 2 .. 100_000)
2201             {
2202                 const p = Z.mersennePrime(i); // power
2203                 const a = Z(j); // base
2204                 const amp = a % p;
2205                 const b = a.powm(p, p); // result
2206                 assert(b == amp);
2207             }
2208         }
2209     }
2210 }
2211 
2212 // Euler's Sum of Powers Conjecture counter example
2213 pure @nogc unittest
2214 {
2215     /*
2216       a^5 + b^5 + c^5 + d^5 = e^5 Lander & Parkin, 1966 found the first counter
2217       example: 27^5 + 84^5 + 110^5 + 133^5 = 144^5. This test searches for this
2218       counter example by brute force for all positive a, b, c, d ≤ 144
2219     */
2220 
2221     enum LIMIT = 144 + 1;
2222     enum POWER = 5;
2223 
2224     if (unittestLong) // compile but not run unless flagged for because running is slow
2225     {
2226         bool found = false;
2227         Z r1 = 0;
2228     outermost:
2229         foreach (immutable ulong a; 1 .. LIMIT)
2230         {
2231             foreach (immutable ulong b; a .. LIMIT)
2232             {
2233                 foreach (immutable ulong c; b .. LIMIT)
2234                 {
2235                     foreach (immutable ulong d; c .. LIMIT)
2236                     {
2237                         r1 = ((Z(a) ^^ POWER) +
2238                               (Z(b) ^^ POWER) +
2239                               (Z(c) ^^ POWER) +
2240                               (Z(d) ^^ POWER));
2241                         Z rem = 0;
2242                         __gmpz_rootrem(r1._ptr, rem._ptr, r1._ptr, POWER); ++r1._ccc;
2243                         if (rem == 0UL)
2244                         {
2245                             debug printf("Counter Example Found: %lu^5 + %lu^5 + %lu^5 + %lu^5 = %lu^5\n",
2246                                          a, b, c, d, cast(ulong)r1);
2247                             found = true;
2248                             break outermost;
2249                         }
2250                     }
2251                 }
2252             }
2253         }
2254         assert(found);
2255     }
2256 }
2257 
2258 /// expression template types
2259 
2260 /// `MpZ`-`MpZ` adding expression.
2261 struct MpzAddExpr(T1, T2)
2262     if (isMpZExpr!T1 &&
2263         isMpZExpr!T2)
2264 {
2265     T1 e1;                      // first term
2266     T2 e2;                      // second term
2267     pragma(inline, true)
2268     MpZ eval() const @trusted
2269     {
2270         typeof(return) y = null;
2271         __gmpz_add(y._ptr, e1.eval()._ptr, e2.eval()._ptr); ++y._ccc;
2272         return y;
2273     }
2274 }
2275 version(unittest) static assert(isMpZExpr!(MpzAddExpr!(MpZ, MpZ)));
2276 
2277 /// Instantiator for `MpzAddExpr`.
2278 MpzAddExpr!(T1, T2) mpzAddExpr(T1, T2)(T1 t1, T2 t2)
2279     if (isMpZExpr!T1 &&
2280         isMpZExpr!T2)
2281 {
2282     // TODO don't eval certain type combinations of t1 and t2
2283     return MpzAddExpr!(T1, T2)(t1.eval(), t2.eval());
2284 }
2285 
2286 @safe @nogc unittest
2287 {
2288     assert(MpzAddExpr!(Z, Z)(3.Z, 4.Z).eval() == 3 + 4);
2289 
2290     const Z x = MpzAddExpr!(Z, Z)(3.Z, 4.Z);
2291     assert(x.mutatingCallCount == 1); // lower to `mpz_add`
2292     assert(x == 7);
2293 
2294     Z y = null;
2295     y = MpzAddExpr!(Z, Z)(3.Z, 4.Z);
2296     assert(y.mutatingCallCount == 2); // lowers to `mpz_init`, `mpz_add`
2297     assert(y == 7);
2298 
2299 }
2300 
2301 /// `MpZ`-`MpZ` subtraction expression.
2302 struct MpzSubExpr(T1, T2)
2303     if (isMpZExpr!T1 &&
2304         isMpZExpr!T2)
2305 {
2306     T1 e1;                      // first term
2307     T2 e2;                      // second term
2308     pragma(inline, true)
2309     MpZ eval() const @trusted
2310     {
2311         typeof(return) y = null;
2312         __gmpz_sub(y._ptr, e1.eval()._ptr, e2.eval()._ptr); ++y._ccc;
2313         return y;
2314     }
2315 }
2316 version(unittest) static assert(isMpZExpr!(MpzSubExpr!(MpZ, MpZ)));
2317 
2318 @safe @nogc unittest
2319 {
2320     assert(MpzSubExpr!(Z, Z)(3.Z, 4.Z).eval() == 3 - 4);
2321     const Z x = MpzSubExpr!(Z, Z)(3.Z, 4.Z);
2322     assert(x.mutatingCallCount == 1); // lowers to `mpz_sub`
2323     assert(x == -1);
2324 }
2325 
2326 /// `MpZ`-`MpZ` multiplication expression.
2327 struct MpzMulExpr(F1, F2)
2328     if (isMpZExpr!F1 &&
2329         isMpZExpr!F2)
2330 {
2331     F1 e1;                      // first factor
2332     F2 e2;                      // second factor
2333     pragma(inline, true)
2334     MpZ eval() const @trusted
2335     {
2336         typeof(return) y = null;
2337         __gmpz_mul(y._ptr, e1.eval()._ptr, e2.eval()._ptr); ++y._ccc;
2338         return y;
2339     }
2340 }
2341 version(unittest) static assert(isMpZExpr!(MpzMulExpr!(MpZ, MpZ)));
2342 
2343 @safe @nogc unittest
2344 {
2345     assert(MpzMulExpr!(Z, Z)(3.Z, 4.Z).eval() == 3 * 4);
2346 
2347     const Z x = MpzMulExpr!(Z, Z)(3.Z, 4.Z);
2348     assert(x == 12);
2349     assert(x.mutatingCallCount == 1); // lowers to `mpz_mul`
2350 }
2351 
2352 /// `MpZ`-`MpZ` division expression.
2353 struct MpzDivExpr(P, Q)
2354     if (isMpZExpr!P &&
2355         isMpZExpr!Q)
2356 {
2357     P e1;                       // divisor
2358     Q e2;                       // dividend
2359     pragma(inline, true)
2360     MpZ eval() const @trusted
2361     {
2362         typeof(return) y = null;
2363         __gmpz_tdiv_q(y._ptr, e1.eval()._ptr, e2.eval()._ptr); ++y._ccc;
2364         return y;
2365     }
2366 }
2367 version(unittest) static assert(isMpZExpr!(MpzDivExpr!(MpZ, MpZ)));
2368 
2369 @safe @nogc unittest
2370 {
2371     assert(MpzDivExpr!(Z, Z)(27.Z, 3.Z).eval() == 27 / 3);
2372     assert(MpzDivExpr!(Z, Z)(28.Z, 3.Z).eval() == 28 / 3);
2373     assert(MpzDivExpr!(Z, Z)(29.Z, 3.Z).eval() == 29 / 3);
2374     assert(MpzDivExpr!(Z, Z)(30.Z, 3.Z).eval() == 30 / 3);
2375 
2376     const Z x = MpzDivExpr!(Z, Z)(28.Z, 3.Z);
2377     assert(x == 9);
2378     assert(x.mutatingCallCount == 1); // lowers to `mpz_tdiv_q`
2379 }
2380 
2381 /// `MpZ`-`MpZ` modulus expression.
2382 struct MpzModExpr(P, Q)
2383     if (isMpZExpr!P &&
2384         isMpZExpr!Q)
2385 {
2386     P e1;                       // divisor
2387     Q e2;                       // dividend
2388     pragma(inline, true)
2389     MpZ eval() const @trusted
2390     {
2391         typeof(return) y = null;
2392         __gmpz_tdiv_r(y._ptr, e1.eval()._ptr, e2.eval()._ptr); ++y._ccc;
2393         return y;
2394     }
2395 }
2396 version(unittest) static assert(isMpZExpr!(MpzModExpr!(MpZ, MpZ)));
2397 
2398 @safe @nogc unittest
2399 {
2400     assert(MpzModExpr!(Z, Z)(27.Z, 3.Z).eval() == 27 % 3);
2401     assert(MpzModExpr!(Z, Z)(28.Z, 3.Z).eval() == 28 % 3);
2402     assert(MpzModExpr!(Z, Z)(29.Z, 3.Z).eval() == 29 % 3);
2403     assert(MpzModExpr!(Z, Z)(30.Z, 3.Z).eval() == 30 % 3);
2404 
2405     const Z x = MpzModExpr!(Z, Z)(29.Z, 3.Z);
2406     assert(x == 2);
2407     assert(x.mutatingCallCount == 1); // lowers to `mpz_tdiv_r`
2408 }
2409 
2410 /// `MpZ`-`ulong` power expression.
2411 struct MpzPowUExpr(P, Q)
2412     if (isMpZExpr!P &&
2413         isUnsigned!Q)
2414 {
2415     P e1;                       // base
2416     Q e2;                       // exponent
2417     pragma(inline, true)
2418     MpZ eval() const @trusted
2419     {
2420         typeof(return) y = null;
2421         __gmpz_pow_ui(y._ptr, e1.eval()._ptr, e2); ++y._ccc;
2422         return y;
2423     }
2424 }
2425 version(unittest) static assert(isMpZExpr!(MpzPowUExpr!(MpZ, ulong)));
2426 
2427 @safe @nogc unittest
2428 {
2429     assert(MpzPowUExpr!(Z, ulong)(3.Z, 3).eval() == 3^^3);
2430 }
2431 
2432 /// `MpZ`-`ulong`-`MpZ` power-modulo expression.
2433 struct MpzPowMUExpr(P, Q, M)
2434     if (isMpZExpr!P &&
2435         isUnsigned!Q &&
2436         isMpZExpr!M)
2437 {
2438     P base;                     // base
2439     Q exp;                      // exponent
2440     M mod;                      // modulo
2441     pragma(inline, true)
2442     MpZ eval() const @trusted
2443     {
2444         typeof(return) y = null;
2445         __gmpz_powm_ui(y._ptr, base.eval()._ptr, exp, mod._ptr); ++y._ccc;
2446         return y;
2447     }
2448 }
2449 version(unittest) static assert(isMpZExpr!(MpzPowMUExpr!(MpZ, ulong, MpZ)));
2450 
2451 @safe @nogc unittest
2452 {
2453     assert(MpzPowMUExpr!(Z, ulong, Z)(3.Z, 3, 20.Z).eval() == 3^^3 % 20);
2454 }
2455 
2456 /// `MpZ` negation expression.
2457 struct MpzNegExpr(A)
2458     if (isMpZExpr!A)
2459 {
2460     A e1;
2461     pragma(inline, true)
2462     MpZ eval() const @trusted
2463     {
2464         typeof(return) y = null;
2465         __gmpz_neg(y._ptr, e1.eval()._ptr); ++y._ccc;
2466         return y;
2467     }
2468 }
2469 version(unittest) static assert(isMpZExpr!(MpzNegExpr!(MpZ)));
2470 
2471 @safe @nogc unittest
2472 {
2473     assert(MpzNegExpr!(Z)(27.Z).eval() == -27);
2474 
2475     const Z x = MpzNegExpr!(Z)(27.Z);
2476     assert(x.mutatingCallCount == 1); // lowers to `mpz_neg`
2477     assert(x == -27);
2478 }
2479 
2480 /// Copied from `std.numeric` to prevent unnecessary Phobos deps.
2481 T _integralAbs(T)(T x)
2482     if (isIntegral!T)
2483 {
2484     return x >= 0 ? x : -x;
2485 }
2486 
2487 /** Faster than `std.traits`.
2488     See https://github.com/dlang/phobos/pull/5038
2489 */
2490 enum isArithmetic(T) = __traits(isArithmetic, T);
2491 enum isFloating(T) = __traits(isFloating, T);
2492 enum isFloatingPoint(T) = __traits(isFloating, T);
2493 enum isScalar(T) = __traits(isScalar, T);
2494 enum isScalarType(T) = __traits(isScalar, T);
2495 enum isIntegral(T) = __traits(isIntegral, T);
2496 enum isUnsigned(T) = __traits(isUnsigned, T);
2497 enum isSigned(T) = __traits(isArithmetic, T) && !__traits(isUnsigned, T);
2498 enum isStaticArray(T) = __traits(isStaticArray, T);
2499 enum isAssociativeArray(T) = __traits(isAssociativeArray, T);
2500 enum isAbstractClass(T) = __traits(isAbstractClass, T);
2501 enum isFinalClass(T) = __traits(isFinalClass, T);
2502 enum isPOD(T) = __traits(isPOD, T);
2503 enum isNested(T) = __traits(isNested, T);
2504 enum isVirtualFunction(alias fn) = __traits(isVirtualFunction, fn);
2505 enum isVirtualMethod(alias m) = __traits(isVirtualMethod, m);
2506 enum isAbstractFunction(alias fn) = __traits(isAbstractFunction, fn);
2507 enum isFinalFunction(alias fn) = __traits(isFinalFunction, fn);
2508 enum isOverrideFunction(alias fn) = __traits(isOverrideFunction, fn);
2509 enum isStaticFunction(alias fn) = __traits(isStaticFunction, fn);
2510 enum isOut(alias fn) = __traits(isOut, fn);
2511 enum isLazy(alias fn) = __traits(isLazy, fn);
2512 enum isTemplate(alias sym) = __traits(isTemplate, sym);
2513 enum hasMember(T, string member) = __traits(hasMember, T, member);
2514 enum IdentifierStringOfSymbol(alias sym) = __traits(identifier, sym);
2515 
2516 // TODO WARNING disabled because this cannot be wrapped in a template
2517 enum isRef(alias fn) = __traits(isRef, fn);
2518 
2519 /// http://forum.dlang.org/post/llwrbirvlqxawifyytqq@forum.dlang.org
2520 @safe pure nothrow @nogc unittest
2521 {
2522     struct S { int x, y; }
2523 
2524     static void f()(auto ref const S s)
2525     {
2526         static assert(__traits(isRef, s));
2527     }
2528 
2529     static void g()(auto ref const S s)
2530     {
2531         static assert(!__traits(isRef, s));
2532     }
2533 
2534     S s;
2535     static assert(!__traits(isRef, s));
2536 
2537     f(s);
2538 
2539     g(S.init);
2540 }
2541 
2542 /// as hash table key
2543 @safe unittest
2544 {
2545     // TODO disabled until non-copyable types work in AA's
2546     // string[Z] aa;
2547     // aa[123.Z] = "abc";
2548     // aa[456.Z] = "def";
2549     // assert(aa[123.Z] == "abc");
2550     // assert(aa[456.Z] == "def");
2551 }
2552 
2553 version(unittest)
2554 {
2555     import dbgio;
2556     alias Z = MpZ;
2557 }
2558 
2559 // C API
2560 extern(C)
2561 {
2562     alias __mp_limb_t = ulong;    // see `mp_limb_t` gmp.h. TODO detect when it is `uint` instead
2563     struct __mpz_struct
2564     {
2565         int _mp_alloc;		/* Number of *limbs* allocated and pointed to by
2566                                    the _mp_d field.  */
2567         int _mp_size;           /* abs(_mp_size) is the number of limbs the last
2568                                    field points to.  If _mp_size is negative
2569                                    this is a negative number.  */
2570         __mp_limb_t* _mp_d;       /* Pointer to the limbs. */
2571     }
2572     static assert(__mpz_struct.sizeof == 16); // fits in two 64-bit words
2573 
2574     alias mpz_srcptr = const(__mpz_struct)*;
2575     alias mpz_ptr = __mpz_struct*;
2576     alias mp_bitcnt_t = ulong;
2577 
2578     pure nothrow @nogc:
2579 
2580     void __gmpz_init (mpz_ptr);
2581     void __gmpz_init_set (mpz_ptr, mpz_srcptr);
2582 
2583     void __gmpz_init_set_d (mpz_ptr, double);
2584     void __gmpz_init_set_si (mpz_ptr, long);
2585     void __gmpz_init_set_ui (mpz_ptr, ulong);
2586     int __gmpz_init_set_str (mpz_ptr, const char*, int);
2587 
2588     void __gmpz_set (mpz_ptr rop, mpz_srcptr op);
2589     void __gmpz_set_ui (mpz_ptr rop, ulong op);
2590     void __gmpz_set_si (mpz_ptr rop, long op);
2591     void __gmpz_set_d (mpz_ptr rop, double op);
2592     int __gmpz_set_str (mpz_ptr, const char*, int);
2593 
2594     void __gmpz_clear (mpz_ptr);
2595 
2596     void __gmpz_abs (mpz_ptr, mpz_srcptr);
2597     void __gmpz_neg (mpz_ptr, mpz_srcptr);
2598 
2599     void __gmpz_add (mpz_ptr, mpz_srcptr, mpz_srcptr);
2600     void __gmpz_add_ui (mpz_ptr, mpz_srcptr, ulong);
2601     void __gmpz_addmul (mpz_ptr, mpz_srcptr, mpz_srcptr);
2602     void __gmpz_addmul_ui (mpz_ptr, mpz_srcptr, ulong);
2603 
2604     void __gmpz_sub (mpz_ptr, mpz_srcptr, mpz_srcptr);
2605     void __gmpz_sub_ui (mpz_ptr, mpz_srcptr, ulong);
2606     void __gmpz_ui_sub (mpz_ptr, ulong, mpz_srcptr);
2607 
2608     void __gmpz_mul (mpz_ptr, mpz_srcptr, mpz_srcptr);
2609     void __gmpz_mul_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
2610     void __gmpz_mul_si (mpz_ptr, mpz_srcptr, long);
2611     void __gmpz_mul_ui (mpz_ptr, mpz_srcptr, ulong);
2612 
2613     void __gmpz_cdiv_q_ui (mpz_ptr, mpz_srcptr, ulong);
2614     ulong __gmpz_cdiv_r_ui (mpz_ptr, mpz_srcptr, ulong);
2615     void __gmpz_cdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, ulong);
2616     void __gmpz_cdiv_ui (mpz_srcptr, ulong);
2617 
2618     void __gmpz_fdiv_q_ui (mpz_ptr, mpz_srcptr, ulong);
2619     ulong __gmpz_fdiv_r_ui (mpz_ptr, mpz_srcptr, ulong);
2620     void __gmpz_fdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, ulong);
2621     void __gmpz_fdiv_ui (mpz_srcptr, ulong);
2622 
2623     void __gmpz_tdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
2624     void __gmpz_tdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
2625     void __gmpz_tdiv_q_ui (mpz_ptr, mpz_srcptr, ulong);
2626     ulong __gmpz_tdiv_r_ui (mpz_ptr, mpz_srcptr, ulong);
2627     void __gmpz_tdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, ulong);
2628     void __gmpz_tdiv_ui (mpz_srcptr, ulong);
2629 
2630     void __gmpz_mod (mpz_ptr, mpz_srcptr, mpz_srcptr);
2631 
2632     void __gmpz_pow_ui (mpz_ptr, mpz_srcptr, ulong);
2633     void __gmpz_ui_pow_ui (mpz_ptr, ulong, ulong);
2634 
2635     void __gmpz_swap (mpz_ptr, mpz_ptr);
2636 
2637     int __gmpz_cmp (mpz_srcptr, mpz_srcptr);
2638     int __gmpz_cmp_d (mpz_srcptr, double);
2639     int __gmpz_cmp_si (mpz_srcptr, long);
2640     int __gmpz_cmp_ui (mpz_srcptr, ulong);
2641 
2642     int __gmpz_cmpabs (mpz_srcptr, mpz_srcptr);
2643     int __gmpz_cmpabs_d (mpz_srcptr, double);
2644     int __gmpz_cmpabs_ui (mpz_srcptr, ulong);
2645 
2646     void __gmpz_nextprime (mpz_ptr, mpz_srcptr);
2647 
2648     void __gmpz_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
2649     ulong __gmpz_gcd_ui (mpz_ptr, mpz_srcptr, ulong);
2650 
2651     void __gmpz_lcm (mpz_ptr, mpz_srcptr, mpz_srcptr);
2652     void __gmpz_lcm_ui (mpz_ptr, mpz_srcptr, ulong);
2653 
2654     char *__gmpz_get_str (char*, int, mpz_srcptr);
2655     size_t __gmpz_sizeinbase (mpz_srcptr, int);
2656 
2657     void __gmpz_powm (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
2658     void __gmpz_powm_ui (mpz_ptr, mpz_srcptr, ulong, mpz_srcptr);
2659 
2660     ulong __gmpz_get_ui (mpz_srcptr);
2661     long __gmpz_get_si (mpz_srcptr);
2662     double __gmpz_get_d (mpz_srcptr);
2663 
2664     int __gmpz_fits_ulong_p(mpz_srcptr);
2665     int __gmpz_fits_slong_p(mpz_srcptr);
2666     int __gmpz_fits_uint_p(mpz_srcptr);
2667     int __gmpz_fits_sint_p(mpz_srcptr);
2668     int __gmpz_fits_ushort_p(mpz_srcptr);
2669     int __gmpz_fits_sshort_p(mpz_srcptr);
2670 
2671     void __gmpz_and (mpz_ptr, mpz_srcptr, mpz_srcptr);
2672     void __gmpz_ior (mpz_ptr, mpz_srcptr, mpz_srcptr);
2673     void __gmpz_xor (mpz_ptr, mpz_srcptr, mpz_srcptr);
2674     void __gmpz_com (mpz_ptr, mpz_srcptr);
2675 
2676     // TODO wrap:
2677     void __gmpz_root (mpz_ptr, mpz_srcptr, ulong);
2678     void __gmpz_rootrem (mpz_ptr, mpz_ptr, mpz_srcptr, ulong);
2679 
2680     void __gmpz_sqrt (mpz_ptr, mpz_srcptr);
2681     void __gmpz_sqrtrem (mpz_ptr, mpz_ptr, mpz_srcptr);
2682 
2683     void __gmpz_perfect_power_p (mpz_ptr, mpz_srcptr);
2684 }
2685 
2686 // link with C library GNU MP
2687 pragma(lib, "gmp");