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