1 /++ 2 Low-level betterC utilities for big integer arithmetic libraries. 3 4 The module provides $(REF BigUIntView), and $(LREF BigIntView), $(REF DecimalView). 5 6 Note: 7 The module doesn't provide full arithmetic API for now. 8 +/ 9 module mir.bignum.low_level_view; 10 11 import mir.checkedint; 12 import std.traits; 13 14 private alias cop(string op : "-") = subu; 15 private alias cop(string op : "+") = addu; 16 private enum inverseSign(string op) = op == "+" ? "-" : "+"; 17 18 package immutable hexStringErrorMsg = "Incorrect hex string for BigUIntView.fromHexString"; 19 package immutable binaryStringErrorMsg = "Incorrect binary string for BigUIntView.fromBinaryString"; 20 version (D_Exceptions) 21 { 22 package immutable hexStringException = new Exception(hexStringErrorMsg); 23 package immutable binaryStringException = new Exception(binaryStringErrorMsg); 24 } 25 26 package template MaxWordPow10(T) 27 { 28 static if (is(T == ubyte)) 29 enum MaxWordPow10 = 2; 30 else 31 static if (is(T == ushort)) 32 enum MaxWordPow10 = 4; 33 else 34 static if (is(T == uint)) 35 enum MaxWordPow10 = 9; 36 else 37 static if (is(T == ulong)) 38 enum MaxWordPow10 = 19; 39 else 40 static assert(0); 41 } 42 43 /++ 44 Fast integer computation of `ceil(log10(exp2(e)))` with 64-bit mantissa precision. 45 The result is guaranted to be greater then `log10(exp2(e))`, which is irrational number. 46 +/ 47 T ceilLog10Exp2(T)(const T e) 48 @safe pure nothrow @nogc 49 if (is(T == ubyte) || is(T == ushort) || is(T == uint) || is(T == ulong)) 50 { 51 import mir.utility: extMul; 52 auto result = extMul(0x9a209a84fbcff799UL, e); 53 return cast(T) ((result.high >> 1) + ((result.low != 0) | (result.high & 1))); 54 } 55 56 /// 57 version(mir_bignum_test_llv) 58 @safe pure nothrow @nogc unittest 59 { 60 assert(ceilLog10Exp2(ubyte(10)) == 4); // ubyte 61 assert(ceilLog10Exp2(10U) == 4); // uint 62 assert(ceilLog10Exp2(10UL) == 4); // ulong 63 } 64 65 /++ 66 Arbitrary length unsigned integer view. 67 +/ 68 struct BigUIntView(W) 69 if (__traits(isUnsigned, W)) 70 { 71 import mir.bignum.fp: Fp, half; 72 import mir.bignum.fixed: UInt; 73 74 /++ 75 A group of coefficients for a radix `W.max + 1`. 76 77 The order corresponds to endianness. 78 +/ 79 W[] coefficients; 80 81 @safe: 82 83 /++ 84 Retrurns: signed integer view using the same data payload 85 +/ 86 size_t length()() @safe pure nothrow @nogc const @property 87 { 88 return coefficients.length; 89 } 90 91 /++ 92 Retrurns: signed integer view using the same data payload 93 +/ 94 BigIntView!W signed()(bool sign = false) @safe pure nothrow @nogc return scope @property 95 { 96 return typeof(return)(this, sign); 97 } 98 99 static if (W.sizeof >= size_t.sizeof) 100 /// 101 T opCast(T)() const scope 102 if (isFloatingPoint!T && isMutable!T) 103 { 104 import mir.bignum.internal.dec2float: binaryTo; 105 return normalized.coefficients.binaryTo!T; 106 } 107 108 static if (W.sizeof >= size_t.sizeof) 109 /// 110 @safe 111 T opCast(T : Fp!coefficientSize, uint coefficientSize)() const scope 112 { 113 static if (isMutable!W) 114 { 115 return lightConst.opCast!T; 116 } 117 else 118 static if (W.sizeof > size_t.sizeof) 119 { 120 return lightConst.opCast!(BigUIntView!(const size_t)).opCast!T; 121 } 122 else 123 { 124 import mir.bignum.internal.dec2float: binaryToFp; 125 auto coefficients = normalized.coefficients; 126 return coefficients.length 127 ? coefficients.binaryToFp!coefficientSize 128 : Fp!coefficientSize.init; 129 } 130 } 131 132 /// 133 T opCast(T, bool nonZero = false)() const scope 134 if (isIntegral!T && isUnsigned!T && isMutable!T) 135 { 136 auto work = lightConst; 137 static if (!nonZero) 138 { 139 if (coefficients.length == 0) 140 { 141 return 0; 142 } 143 } 144 static if (T.sizeof <= W.sizeof) 145 { 146 return cast(T) work.coefficients[0]; 147 } 148 else 149 { 150 T ret; 151 do 152 { 153 ret <<= W.sizeof * 8; 154 ret |= work.coefficients[$ - 1]; 155 work.popMostSignificant; 156 } 157 while(work.coefficients.length); 158 return ret; 159 } 160 } 161 162 /// 163 pure nothrow @nogc 164 BigUIntView!V opCast(T : BigUIntView!V, V)() return scope 165 if (V.sizeof <= W.sizeof) 166 { 167 return typeof(return)(cast(V[])this.coefficients); 168 } 169 170 pure nothrow @nogc 171 BigUIntView!V opCast(T : BigUIntView!V, V)() const return scope 172 if (V.sizeof <= W.sizeof) 173 { 174 return typeof(return)(cast(V[])this.coefficients); 175 } 176 177 /// 178 BigUIntView!(const W) lightConst()() return scope 179 const @safe pure nothrow @nogc @property 180 { 181 return typeof(return)(coefficients); 182 } 183 ///ditto 184 alias lightConst this; 185 186 /++ 187 +/ 188 sizediff_t opCmp(scope BigUIntView!(const W) rhs) 189 const @safe pure nothrow @nogc scope 190 { 191 import mir.algorithm.iteration: cmp; 192 auto l = this.lightConst.normalized; 193 auto r = rhs.lightConst.normalized; 194 if (sizediff_t d = l.coefficients.length - r.coefficients.length) 195 return d; 196 return cmp(l.mostSignificantFirst, r.mostSignificantFirst); 197 } 198 199 /// 200 bool opEquals(BigUIntView!(const W) rhs) 201 const @safe pure nothrow @nogc scope 202 { 203 return this.coefficients == rhs.coefficients; 204 } 205 206 /++ 207 +/ 208 void popMostSignificant() scope 209 { 210 coefficients = coefficients[0 .. $ - 1]; 211 } 212 213 /++ 214 +/ 215 void popLeastSignificant() scope 216 { 217 coefficients = coefficients[1 .. $]; 218 } 219 220 /++ 221 +/ 222 BigUIntView topMostSignificantPart(size_t length) 223 in (length <= coefficients.length) 224 { 225 return BigUIntView(coefficients[$ - length .. $]); 226 } 227 228 /++ 229 +/ 230 BigUIntView topLeastSignificantPart(size_t length) 231 in (length <= coefficients.length) 232 { 233 return BigUIntView(coefficients[0 .. length]); 234 } 235 236 /++ 237 Shifts left using at most `size_t.sizeof * 8 - 1` bits 238 +/ 239 void smallLeftShiftInPlace()(uint shift) scope 240 { 241 assert(shift < W.sizeof * 8); 242 if (shift == 0) 243 return; 244 auto csh = W.sizeof * 8 - shift; 245 auto d = coefficients[]; 246 assert(d.length); 247 foreach_reverse (i; 1 .. d.length) 248 d[i] = (d[i] << shift) | (d[i - 1] >>> csh); 249 d[0] <<= shift; 250 } 251 252 /++ 253 Shifts right using at most `size_t.sizeof * 8 - 1` bits 254 +/ 255 void smallRightShiftInPlace()(uint shift) 256 { 257 assert(shift < W.sizeof * 8); 258 if (shift == 0) 259 return; 260 auto csh = W.sizeof * 8 - shift; 261 auto d = coefficients[]; 262 assert(d.length); 263 foreach (i; 0 .. d.length - 1) 264 d[i] = (d[i] >>> shift) | (d[i + 1] << csh); 265 d[$ - 1] >>>= shift; 266 } 267 268 /++ 269 +/ 270 static BigUIntView fromHexString(C, bool allowUnderscores = false)(scope const(C)[] str) 271 @trusted pure 272 if (isSomeChar!C) 273 { 274 auto length = str.length / (W.sizeof * 2) + (str.length % (W.sizeof * 2) != 0); 275 auto data = new Unqual!W[length]; 276 auto view = BigUIntView!(Unqual!W)(data); 277 if (view.fromHexStringImpl!(C, allowUnderscores)(str)) 278 return BigUIntView(cast(W[])view.coefficients); 279 version(D_Exceptions) 280 { import mir.exception : toMutable; throw hexStringException.toMutable; } 281 else 282 assert(0, hexStringErrorMsg); 283 } 284 285 static if (isMutable!W) 286 /++ 287 +/ 288 bool fromHexStringImpl(C, bool allowUnderscores = false)(scope const(C)[] str) 289 @safe pure @nogc nothrow scope 290 if (isSomeChar!C) 291 { 292 pragma(inline, false); 293 import mir.utility: _expect; 294 static if (allowUnderscores) { 295 if (_expect(str.length == 0, false)) // can't tell how big the coeff array needs to be, rely on a runtime check 296 return false; 297 } else { 298 if (_expect(str.length == 0 || str.length > coefficients.length * W.sizeof * 2, false)) 299 return false; 300 } 301 302 coefficients[0] = 0; 303 auto work = topLeastSignificantPart(1); 304 W current; 305 size_t i, j; 306 static if (allowUnderscores) bool recentUnderscore; 307 308 do 309 { 310 ubyte c; 311 switch(str[$ - ++i]) 312 { 313 case '0': c = 0x0; break; 314 case '1': c = 0x1; break; 315 case '2': c = 0x2; break; 316 case '3': c = 0x3; break; 317 case '4': c = 0x4; break; 318 case '5': c = 0x5; break; 319 case '6': c = 0x6; break; 320 case '7': c = 0x7; break; 321 case '8': c = 0x8; break; 322 case '9': c = 0x9; break; 323 case 'A': 324 case 'a': c = 0xA; break; 325 case 'B': 326 case 'b': c = 0xB; break; 327 case 'C': 328 case 'c': c = 0xC; break; 329 case 'D': 330 case 'd': c = 0xD; break; 331 case 'E': 332 case 'e': c = 0xE; break; 333 case 'F': 334 case 'f': c = 0xF; break; 335 static if (allowUnderscores) 336 { 337 case '_': 338 if (recentUnderscore) return false; 339 recentUnderscore = true; 340 continue; 341 } 342 default: return false; 343 } 344 ++j; 345 static if (allowUnderscores) recentUnderscore = false; 346 // how far do we need to shift to get to the top 4 bits 347 enum s = W.sizeof * 8 - 4; 348 // shift number to the top most 4 bits 349 W cc = cast(W)(W(c) << s); 350 // shift unsigned right 4 bits 351 current >>>= 4; 352 // add number to top most 4 bits of current var 353 current |= cc; 354 if (j % (W.sizeof * 2) == 0) // is this packed var full? 355 { 356 work.coefficients[$ - 1] = current; 357 current = 0; 358 if (_expect(work.coefficients.length < coefficients.length, true)) 359 { 360 work = topLeastSignificantPart(work.coefficients.length + 1); 361 } 362 else if (i < str.length) // if we've run out of coefficients before reaching the end of the string, error 363 { 364 return false; 365 } 366 } 367 } 368 while(i < str.length); 369 370 static if (allowUnderscores) 371 { 372 // check for a underscore at the beginning or the end 373 if (recentUnderscore || str[$ - 1] == '_') return false; 374 } 375 376 if (current) 377 { 378 current >>>= 4 * (W.sizeof * 2 - j % (W.sizeof * 2)); 379 work.coefficients[$ - 1] = current; 380 } 381 else 382 { 383 work.coefficients = work.coefficients[0 .. (j / (W.sizeof * 2) + (j % (W.sizeof * 2) != 0))]; 384 work = work.normalized; 385 } 386 387 ()@trusted {this = work;}(); 388 return true; 389 } 390 391 /++ 392 +/ 393 static BigUIntView fromBinaryString(C, bool allowUnderscores = false)(scope const(C)[] str) 394 @trusted pure 395 if (isSomeChar!C) 396 { 397 auto length = str.length / (W.sizeof * 8) + (str.length % (W.sizeof * 8) != 0); 398 auto data = new Unqual!W[length]; 399 auto view = BigUIntView!(Unqual!W)(data); 400 if (view.fromBinaryStringImpl!(C, allowUnderscores)(str)) 401 return BigUIntView(cast(W[])view.coefficients); 402 version(D_Exceptions) 403 { import mir.exception : toMutable; throw binaryStringException.toMutable; } 404 else 405 assert(0, binaryStringErrorMsg); 406 } 407 408 static if (isMutable!W) 409 /++ 410 +/ 411 bool fromBinaryStringImpl(C, bool allowUnderscores = false)(scope const(C)[] str) 412 @safe pure @nogc nothrow scope 413 if (isSomeChar!C) 414 { 415 pragma(inline, false); 416 import mir.utility: _expect; 417 static if (allowUnderscores) { 418 if (_expect(str.length == 0, false)) // can't tell how big the coeff array needs to be, rely on a runtime check 419 return false; 420 } else { 421 if (_expect(str.length == 0 || str.length > coefficients.length * W.sizeof * 8, false)) 422 return false; 423 } 424 425 coefficients[0] = 0; 426 auto work = topLeastSignificantPart(1); 427 W current; 428 size_t i, j; 429 static if (allowUnderscores) bool recentUnderscore; 430 431 do 432 { 433 ubyte c; 434 switch(str[$ - ++i]) 435 { 436 case '0': c = 0x0; break; 437 case '1': c = 0x1; break; 438 static if (allowUnderscores) 439 { 440 case '_': 441 if (recentUnderscore) return false; 442 recentUnderscore = true; 443 continue; 444 } 445 default: return false; 446 } 447 ++j; 448 static if (allowUnderscores) recentUnderscore = false; 449 // how far do we need to shift to get to the top bit? 450 enum s = W.sizeof * 8 - 1; 451 // shift number to the top most bit 452 W cc = cast(W)(W(c) << s); 453 // shift unsigned right 1 bit 454 current >>>= 1; 455 // add number to top most bit of current var 456 current |= cc; 457 if (j % (W.sizeof * 8) == 0) // is this packed var full? 458 { 459 work.coefficients[$ - 1] = current; 460 current = 0; 461 if (_expect(work.coefficients.length < coefficients.length, true)) 462 { 463 work = topLeastSignificantPart(work.coefficients.length + 1); 464 } 465 else if (i < str.length) // if we've run out of coefficients before reaching the end of the string, error 466 { 467 return false; 468 } 469 } 470 } 471 while(i < str.length); 472 473 static if (allowUnderscores) 474 { 475 // check for a underscore at the beginning or the end 476 if (recentUnderscore || str[$ - 1] == '_') return false; 477 } 478 479 if (current) 480 { 481 current >>>= (W.sizeof * 8 - j % (W.sizeof * 8)); 482 work.coefficients[$ - 1] = current; 483 } 484 else 485 { 486 work.coefficients = work.coefficients[0 .. (j / (W.sizeof * 8) + (j % (W.sizeof * 8) != 0))]; 487 work = work.normalized; 488 } 489 490 ()@trusted {this = work;}(); 491 return true; 492 } 493 494 static if (isMutable!W && W.sizeof >= 4) 495 /++ 496 Returns: false in case of overflow or incorrect string. 497 Precondition: non-empty coefficients 498 Note: doesn't support signs. 499 +/ 500 bool fromStringImpl(C)(scope const(C)[] str) 501 scope @trusted pure @nogc nothrow 502 if (isSomeChar!C) 503 { 504 import mir.utility: _expect; 505 506 assert(coefficients.length); 507 508 if (_expect(str.length == 0, false)) 509 return false; 510 511 coefficients[0] = 0; 512 uint d = str[0] - '0'; 513 str = str[1 .. $]; 514 515 W v; 516 W t = 1; 517 518 if (d == 0) 519 { 520 if (str.length == 0) 521 { 522 coefficients = null; 523 return true; 524 } 525 return false; 526 } 527 else 528 if (d >= 10) 529 return false; 530 531 size_t len = 1; 532 goto S; 533 534 for(;;) 535 { 536 enum mp10 = W(10) ^^ MaxWordPow10!W; 537 d = str[0] - '0'; 538 str = str[1 .. $]; 539 if (_expect(d > 10, false)) 540 break; 541 v *= 10; 542 S: 543 t *= 10; 544 v += d; 545 546 if (_expect(t == mp10 || str.length == 0, false)) 547 { 548 L: 549 if (auto overflow = topLeastSignificantPart(len).opOpAssign!"*"(t, v)) 550 { 551 if (_expect(len < coefficients.length, true)) 552 { 553 coefficients[len++] = overflow; 554 } 555 else 556 { 557 return false; 558 } 559 } 560 v = 0; 561 t = 1; 562 if (str.length == 0) 563 { 564 this = topLeastSignificantPart(len); 565 return true; 566 } 567 } 568 } 569 return false; 570 } 571 572 static if (isMutable!W && W.sizeof >= 4) 573 /++ 574 Performs `bool overflow = big +(-)= big` operatrion. 575 Params: 576 rhs = value to add with non-empty coefficients 577 overflow = (overflow) initial iteration overflow 578 Precondition: non-empty coefficients length of greater or equal to the `rhs` coefficients length. 579 Returns: 580 true in case of unsigned overflow 581 +/ 582 bool opOpAssign(string op)(scope BigUIntView!(const W) rhs, bool overflow = false) 583 @safe pure nothrow @nogc scope 584 if (op == "+" || op == "-") 585 { 586 assert(this.coefficients.length > 0); 587 assert(rhs.coefficients.length <= this.coefficients.length); 588 auto ls = this.coefficients; 589 auto rs = rhs.coefficients; 590 do 591 { 592 bool overflowM, overflowG; 593 ls[0] = ls[0].cop!op(rs[0], overflowM).cop!op(overflow, overflowG); 594 overflow = overflowG | overflowM; 595 ls = ls[1 .. $]; 596 rs = rs[1 .. $]; 597 } 598 while(rs.length); 599 if (overflow && ls.length) 600 return topMostSignificantPart(ls.length).opOpAssign!op(W(overflow)); 601 return overflow; 602 } 603 604 static if (isMutable!W && W.sizeof >= 4) 605 /// ditto 606 bool opOpAssign(string op)(scope BigIntView!(const W) rhs, bool overflow = false) 607 @safe pure nothrow @nogc scope 608 if (op == "+" || op == "-") 609 { 610 return rhs.sign == false ? 611 opOpAssign!op(rhs.unsigned, overflow): 612 opOpAssign!(inverseSign!op)(rhs.unsigned, overflow); 613 } 614 615 static if (isMutable!W && W.sizeof >= 4) 616 /++ 617 Performs `bool Overflow = big +(-)= scalar` operatrion. 618 Precondition: non-empty coefficients 619 Params: 620 rhs = value to add 621 Returns: 622 true in case of unsigned overflow 623 +/ 624 bool opOpAssign(string op, T)(const T rhs) 625 @safe pure nothrow @nogc scope 626 if ((op == "+" || op == "-") && is(T == W)) 627 { 628 assert(this.coefficients.length > 0); 629 auto ns = this.coefficients; 630 W additive = rhs; 631 do 632 { 633 bool overflow; 634 ns[0] = ns[0].cop!op(additive, overflow); 635 if (!overflow) 636 return overflow; 637 additive = overflow; 638 ns = ns[1 .. $]; 639 } 640 while (ns.length); 641 return true; 642 } 643 644 static if (isMutable!W && W.sizeof >= 4) 645 /// ditto 646 bool opOpAssign(string op, T)(const T rhs) 647 @safe pure nothrow @nogc scope 648 if ((op == "+" || op == "-") && is(T == Signed!W)) 649 { 650 return rhs >= 0 ? 651 opOpAssign!op(cast(W)rhs): 652 opOpAssign!(inverseSign!op)(cast(W)(-rhs)); 653 } 654 655 static if (isMutable!W && W.sizeof >= 4) 656 /++ 657 Performs `W overflow = (big += overflow) *= scalar` operatrion. 658 Precondition: non-empty coefficients 659 Params: 660 rhs = unsigned value to multiply by 661 overflow = initial overflow 662 Returns: 663 unsigned overflow value 664 +/ 665 W opOpAssign(string op : "*")(W rhs, W overflow = 0u) 666 @safe pure nothrow @nogc scope 667 { 668 auto ns = this.coefficients; 669 while (ns.length) 670 { 671 import mir.utility: extMul; 672 auto ext = ns[0].extMul(rhs); 673 bool overflowM; 674 ns[0] = ext.low.cop!"+"(overflow, overflowM); 675 overflow = ext.high + overflowM; 676 ns = ns[1 .. $]; 677 } 678 return overflow; 679 } 680 681 static if (isMutable!W && W.sizeof == 4 || W.sizeof == 8) 682 /++ 683 Performs `uint remainder = (overflow$big) /= scalar` operatrion, where `$` denotes big-endian concatenation. 684 Precondition: non-empty coefficients, `overflow < rhs` 685 Params: 686 rhs = unsigned value to devide by 687 overflow = initial unsigned overflow 688 Returns: 689 unsigned remainder value (evaluated overflow) 690 +/ 691 uint opOpAssign(string op : "/")(uint rhs, uint overflow = 0) 692 @safe pure nothrow @nogc scope 693 { 694 assert(overflow < rhs); 695 assert(coefficients.length); 696 static if (W.sizeof == 4) 697 { 698 auto ns = this.mostSignificantFirst; 699 size_t i; 700 do 701 { 702 auto ext = (ulong(overflow) << 32) ^ ns[i]; 703 ns[i] = cast(uint)(ext / rhs); 704 overflow = ext % rhs; 705 } 706 while (++i < ns.length); 707 if (coefficients[$ - 1] == 0) 708 popMostSignificant; 709 return overflow; 710 } 711 else 712 { 713 auto work = opCast!(BigUIntView!uint); 714 if (work.coefficients[$ - 1] == 0) 715 work.popMostSignificant; 716 auto remainder = work.opOpAssign!op(rhs, overflow); 717 coefficients = coefficients[0 .. work.coefficients.length / 2 + work.coefficients.length % 2]; 718 return remainder; 719 } 720 } 721 722 static if (isMutable!W && W.sizeof == size_t.sizeof) 723 /++ 724 Performs `W overflow = (big += overflow) *= scalar` operatrion. 725 Precondition: non-empty coefficients 726 Params: 727 rhs = unsigned fixed-length integer to multiply by 728 overflow = initial overflow 729 Returns: 730 unsigned fixed-length integer overflow value 731 +/ 732 UInt!size 733 opOpAssign(string op : "*", size_t size)(UInt!size rhs, UInt!size overflow = 0) 734 @safe pure nothrow @nogc scope 735 { 736 assert(coefficients.length); 737 auto ns = this.coefficients; 738 do 739 { 740 auto t = rhs; 741 auto overflowW = t.view *= ns[0]; 742 auto overflowM = t += overflow; 743 overflowW += overflowM; 744 ns[0] = cast(size_t) t; 745 static if (size > size_t.sizeof * 8) 746 overflow = t.toSize!(size - size_t.sizeof * 8, false).toSize!size; 747 BigUIntView!size_t(overflow.data).coefficients[$ - 1] = overflowW; 748 ns = ns[1 .. $]; 749 } 750 while (ns.length); 751 return overflow; 752 } 753 754 /++ 755 Returns: the same intger view with inversed sign 756 +/ 757 BigIntView!W opUnary(string op : "-")() 758 { 759 return typeof(return)(this, true); 760 } 761 762 static if (isMutable!W && W.sizeof >= 4) 763 /++ 764 +/ 765 void bitwiseNotInPlace() scope 766 { 767 foreach (ref coefficient; this.coefficients) 768 coefficient = cast(W)~(0 + coefficient); 769 } 770 771 static if (isMutable!W && W.sizeof >= 4) 772 /++ 773 Performs `number=-number` operatrion. 774 Precondition: non-empty coefficients 775 Returns: 776 true if 'number=-number=0' and false otherwise 777 +/ 778 bool twoComplementInPlace() scope 779 { 780 assert(coefficients.length); 781 bitwiseNotInPlace(); 782 return this.opOpAssign!"+"(W(1)); 783 } 784 785 /++ 786 Returns: a slice of coefficients starting from the most significant. 787 +/ 788 auto mostSignificantFirst() 789 @safe pure nothrow @nogc @property 790 { 791 import mir.ndslice.slice: sliced; 792 import mir.ndslice.topology: retro; 793 return coefficients.sliced.retro; 794 } 795 796 /// 797 auto mostSignificantFirst() 798 const @safe pure nothrow @nogc @property 799 { 800 import mir.ndslice.slice: sliced; 801 import mir.ndslice.topology: retro; 802 return coefficients.sliced.retro; 803 } 804 805 /++ 806 Strips most significant zero coefficients. 807 +/ 808 BigUIntView normalized() return scope 809 { 810 auto number = this; 811 if (number.coefficients.length) do 812 { 813 if (number.coefficients[$ - 1]) 814 break; 815 number.coefficients = number.coefficients[0 .. $ - 1]; 816 } 817 while (number.coefficients.length); 818 return number; 819 } 820 821 ///ditto 822 BigUIntView!(const W) normalized() const return scope 823 { 824 return lightConst.normalized; 825 } 826 827 /++ 828 +/ 829 bool bt()(size_t position) scope 830 { 831 import mir.ndslice.topology: bitwise; 832 assert(position < coefficients.length * W.sizeof * 8); 833 return coefficients.bitwise[position]; 834 } 835 836 /++ 837 +/ 838 size_t ctlz()() scope const @property 839 @safe pure nothrow @nogc 840 { 841 import mir.bitop: ctlz; 842 assert(coefficients.length); 843 auto d = mostSignificantFirst; 844 size_t ret; 845 do 846 { 847 if (auto c = d[0]) 848 { 849 ret += ctlz(c); 850 break; 851 } 852 ret += W.sizeof * 8; 853 d = d[1 .. $]; 854 } 855 while(d.length); 856 return ret; 857 } 858 859 /++ 860 +/ 861 size_t cttz()() scope const @property 862 @safe pure nothrow @nogc 863 in (coefficients.length) 864 { 865 import mir.bitop: cttz; 866 auto d = coefficients[]; 867 size_t ret; 868 do 869 { 870 if (auto c = d[0]) 871 { 872 ret += cttz(c); 873 break; 874 } 875 ret += W.sizeof * 8; 876 d = d[1 .. $]; 877 } 878 while(d.length); 879 return ret; 880 } 881 882 /// 883 BigIntView!W withSign()(bool sign) return scope 884 { 885 return typeof(return)(this, sign); 886 } 887 888 /++ 889 Params: 890 value = (out) unsigned integer 891 Returns: true on success 892 +/ 893 bool get(U)(scope out U value) 894 @safe pure nothrow @nogc const 895 if (isUnsigned!U) 896 { 897 auto d = lightConst.mostSignificantFirst; 898 if (d.length == 0) 899 return false; 900 static if (U.sizeof > W.sizeof) 901 { 902 size_t i; 903 for(;;) 904 { 905 value |= d[0]; 906 d = d[1 .. $]; 907 if (d.length == 0) 908 return false; 909 i += cast(bool)value; 910 value <<= W.sizeof * 8; 911 import mir.utility: _expect; 912 if (_expect(i >= U.sizeof / W.sizeof, false)) 913 return true; 914 } 915 } 916 else 917 { 918 for(;;) 919 { 920 W f = d[0]; 921 d = d[1 .. $]; 922 if (d.length == 0) 923 { 924 value = cast(U)f; 925 static if (U.sizeof < W.sizeof) 926 { 927 if (value != f) 928 return true; 929 } 930 return false; 931 } 932 if (f) 933 return true; 934 } 935 } 936 } 937 938 /++ 939 Returns: true if the integer and equals to `rhs`. 940 +/ 941 bool opEquals(ulong rhs) 942 @safe pure nothrow @nogc const scope 943 { 944 foreach (d; lightConst.coefficients) 945 { 946 static if (W.sizeof >= ulong.sizeof) 947 { 948 if (d != rhs) 949 return false; 950 rhs = 0; 951 } 952 else 953 { 954 if (d != (rhs & W.max)) 955 return false; 956 rhs >>>= W.sizeof * 8; 957 } 958 } 959 return rhs == 0; 960 } 961 962 963 static if (isMutable!W && W.sizeof >= 4) 964 /++ 965 Params: 966 str = string buffer, the tail paer 967 Precondition: mutable number with word size at least 4 bytes 968 Postconditoin: the number is destroyed 969 Returns: last N bytes used in the buffer 970 +/ 971 size_t toStringImpl(C)(scope C[] str) 972 @safe pure nothrow @nogc 973 if (isSomeChar!C && isMutable!C) 974 { 975 assert(str.length); 976 assert(str.length >= ceilLog10Exp2(coefficients.length * (W.sizeof * 8))); 977 978 size_t i = str.length; 979 while(coefficients.length > 1) 980 { 981 uint rem = this /= 1_000_000_000; 982 foreach (_; 0 .. 9) 983 { 984 str[--i] = cast(char)(rem % 10 + '0'); 985 rem /= 10; 986 } 987 } 988 989 W rem = coefficients.length == 1 ? coefficients[0] : W(0); 990 do 991 { 992 str[--i] = cast(char)(rem % 10 + '0'); 993 rem /= 10; 994 } 995 while(rem); 996 997 return str.length - i; 998 } 999 1000 } 1001 1002 /// 1003 version(mir_bignum_test_llv) 1004 @safe pure @nogc 1005 unittest 1006 { 1007 import mir.bignum.integer; 1008 1009 auto a = BigInt!2("123456789098765432123456789098765432100"); 1010 char[ceilLog10Exp2(a.data.length * (size_t.sizeof * 8))] buffer; 1011 auto len = a.view.unsigned.toStringImpl(buffer); 1012 assert(buffer[$ - len .. $] == "123456789098765432123456789098765432100"); 1013 } 1014 1015 /// 1016 version(mir_bignum_test_llv) 1017 @safe pure 1018 unittest 1019 { 1020 import mir.test; 1021 auto view = BigUIntView!size_t.fromHexString!(char, true)("abcd_efab_cdef"); 1022 (cast(ulong)view).should == 0xabcd_efab_cdef; 1023 } 1024 1025 /// 1026 version(mir_bignum_test_llv) 1027 @safe pure 1028 unittest 1029 { 1030 auto a = BigUIntView!size_t.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"); 1031 a.smallLeftShiftInPlace(4); 1032 assert(a == BigUIntView!size_t.fromHexString("fbbfae3cd0aff2714a1de7022b0029d0")); 1033 a.smallLeftShiftInPlace(0); 1034 assert(a == BigUIntView!size_t.fromHexString("fbbfae3cd0aff2714a1de7022b0029d0")); 1035 } 1036 1037 /// 1038 version(mir_bignum_test_llv) 1039 @safe pure 1040 unittest 1041 { 1042 auto a = BigUIntView!size_t.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"); 1043 a.smallRightShiftInPlace(4); 1044 assert(a == BigUIntView!size_t.fromHexString("afbbfae3cd0aff2714a1de7022b0029")); 1045 } 1046 1047 1048 /// 1049 version(mir_bignum_test_llv) 1050 @safe pure 1051 unittest 1052 { 1053 // Check that invalid underscores in hex literals throw an error. 1054 void expectThrow(const(char)[] input) { 1055 bool caught = false; 1056 try { 1057 auto view = BigUIntView!size_t.fromHexString!(char, true)(input); 1058 } catch (Exception e) { 1059 caught = true; 1060 } 1061 1062 assert(caught); 1063 } 1064 1065 expectThrow("abcd_efab_cef_"); 1066 expectThrow("abcd__efab__cef"); 1067 expectThrow("_abcd_efab_cdef"); 1068 expectThrow("_abcd_efab_cdef_"); 1069 expectThrow("_abcd_efab_cdef__"); 1070 expectThrow("__abcd_efab_cdef"); 1071 expectThrow("__abcd_efab_cdef_"); 1072 expectThrow("__abcd_efab_cdef__"); 1073 expectThrow("__abcd__efab_cdef__"); 1074 expectThrow("__abcd__efab__cdef__"); 1075 } 1076 1077 /// 1078 version(mir_bignum_test_llv) 1079 @safe pure 1080 unittest 1081 { 1082 auto view = BigUIntView!size_t.fromBinaryString!(char, true)("1111_0000_0101"); 1083 assert(cast(ulong)view == 0b1111_0000_0101); 1084 } 1085 1086 /// 1087 version(mir_bignum_test_llv) 1088 @safe pure 1089 unittest 1090 { 1091 // Check that invalid underscores in hex literals throw an error. 1092 void expectThrow(const(char)[] input) { 1093 bool caught = false; 1094 try { 1095 auto view = BigUIntView!size_t.fromBinaryString!(char, true)(input); 1096 } catch (Exception e) { 1097 caught = true; 1098 } 1099 1100 assert(caught); 1101 } 1102 1103 expectThrow("abcd"); 1104 expectThrow("0101__1011__0111"); 1105 expectThrow("_0101_1011_0111"); 1106 expectThrow("_0101_1011_0111_"); 1107 expectThrow("_0101_1011_0111__"); 1108 expectThrow("__0101_1011_0111_"); 1109 expectThrow("__0101_1011_0111__"); 1110 expectThrow("__0101__1011_0111__"); 1111 expectThrow("__1011__0111__1011__"); 1112 } 1113 1114 /// 1115 version(mir_bignum_test_llv) 1116 unittest 1117 { 1118 auto a = cast(double) BigUIntView!size_t.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"); 1119 assert(a == 0xa.fbbfae3cd0bp+124); 1120 assert(cast(double) BigUIntView!size_t.init == 0); 1121 assert(cast(double) BigUIntView!size_t([0]) == 0); 1122 } 1123 1124 /// 1125 version(mir_bignum_test_llv) 1126 @safe pure 1127 unittest 1128 { 1129 import mir.bignum.fp: Fp; 1130 import mir.bignum.fixed: UInt; 1131 1132 auto fp = cast(Fp!128) BigUIntView!ulong.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"); 1133 assert(fp.exponent == 0); 1134 assert(fp.coefficient == UInt!128.fromHexString("afbbfae3cd0aff2714a1de7022b0029d")); 1135 1136 fp = cast(Fp!128) BigUIntView!size_t.fromHexString("ae3cd0aff2714a1de7022b0029d"); 1137 assert(fp.exponent == -20); 1138 assert(fp.coefficient == UInt!128.fromHexString("ae3cd0aff2714a1de7022b0029d00000")); 1139 1140 fp = cast(Fp!128) BigUIntView!size_t.fromHexString("e7022b0029d"); 1141 assert(fp.exponent == -84); 1142 assert(fp.coefficient == UInt!128.fromHexString("e7022b0029d000000000000000000000")); 1143 1144 fp = cast(Fp!128) BigUIntView!size_t.fromHexString("e7022b0029d"); 1145 assert(fp.exponent == -84); 1146 assert(fp.coefficient == UInt!128.fromHexString("e7022b0029d000000000000000000000")); 1147 1148 fp = cast(Fp!128) BigUIntView!size_t.fromHexString("e7022b0029d"); 1149 assert(fp.exponent == -84); 1150 assert(fp.coefficient == UInt!128.fromHexString("e7022b0029d000000000000000000000")); 1151 1152 fp = cast(Fp!128) BigUIntView!size_t.fromHexString("ffffffffffffffffffffffffffffffff1000000000000000"); 1153 assert(fp.exponent == 64); 1154 assert(fp.coefficient == UInt!128.fromHexString("ffffffffffffffffffffffffffffffff")); 1155 1156 fp = cast(Fp!128) BigUIntView!size_t.fromHexString("ffffffffffffffffffffffffffffffff8000000000000000"); 1157 assert(fp.exponent == 65); 1158 assert(fp.coefficient == UInt!128.fromHexString("80000000000000000000000000000000")); 1159 1160 fp = cast(Fp!128) BigUIntView!size_t.fromHexString("fffffffffffffffffffffffffffffffe8000000000000000"); 1161 assert(fp.exponent == 64); 1162 assert(fp.coefficient == UInt!128.fromHexString("fffffffffffffffffffffffffffffffe")); 1163 1164 fp = cast(Fp!128) BigUIntView!size_t.fromHexString("fffffffffffffffffffffffffffffffe8000000000000001"); 1165 assert(fp.exponent == 64); 1166 assert(fp.coefficient == UInt!128.fromHexString("ffffffffffffffffffffffffffffffff")); 1167 } 1168 1169 /// 1170 version(mir_bignum_test_llv) 1171 @safe pure 1172 unittest 1173 { 1174 auto view = BigUIntView!ulong.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"); 1175 assert(cast(ulong) view == 0x14a1de7022b0029d); 1176 assert(cast(uint) view == 0x22b0029d); 1177 assert(cast(ubyte) view == 0x9d); 1178 } 1179 version(mir_bignum_test_llv) 1180 @safe pure 1181 unittest 1182 { 1183 auto view = BigUIntView!ushort.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"); 1184 assert(cast(ulong) view == 0x14a1de7022b0029d); 1185 assert(cast(uint) view == 0x22b0029d); 1186 assert(cast(ubyte) view == 0x9d); 1187 } 1188 1189 version(mir_bignum_test_llv) 1190 @safe pure 1191 unittest 1192 { 1193 auto view = BigUIntView!uint.fromHexString("afbbfae3cd0aff2714a1de7022b0029d"); 1194 assert(cast(ulong) view == 0x14a1de7022b0029d); 1195 assert(cast(uint) view == 0x22b0029d); 1196 assert(cast(ubyte) view == 0x9d); 1197 } 1198 1199 1200 /// 1201 version(mir_bignum_test_llv) 1202 @safe pure nothrow 1203 unittest 1204 { 1205 import std.traits; 1206 alias AliasSeq(T...) = T; 1207 1208 foreach (T; AliasSeq!(ubyte, ushort, uint, ulong)) 1209 { 1210 T[3] lhsData = [1, T.max-1, 0]; 1211 T[3] rhsData = [T.max, T.max, 0]; 1212 1213 auto lhs = BigUIntView!T(lhsData).normalized; 1214 1215 /// bool overflow = bigUInt op= scalar 1216 assert(lhs.coefficients == [1, T.max-1]); 1217 assert(lhs.mostSignificantFirst == [T.max-1, 1]); 1218 static if (T.sizeof >= 4) 1219 { 1220 assert((lhs += T.max) == false); 1221 assert(lhs.coefficients == [0, T.max]); 1222 assert((lhs += T.max) == false); 1223 assert((lhs += T.max) == true); // overflow bit 1224 assert(lhs.coefficients == [T.max-1, 0]); 1225 assert((lhs -= T(1)) == false); 1226 assert(lhs.coefficients == [T.max-2, 0]); 1227 assert((lhs -= T.max) == true); // underflow bit 1228 assert(lhs.coefficients == [T.max-1, T.max]); 1229 assert((lhs -= Signed!T(-4)) == true); // overflow bit 1230 assert(lhs.coefficients == [2, 0]); 1231 assert((lhs += Signed!T.max) == false); // overflow bit 1232 assert(lhs.coefficients == [Signed!T.max + 2, 0]); 1233 1234 /// bool overflow = bigUInt op= bigUInt/bigInt 1235 lhs = BigUIntView!T(lhsData); 1236 auto rhs = BigUIntView!T(rhsData).normalized; 1237 assert(lhs.coefficients == [Signed!T.max + 2, 0, 0]); 1238 assert(rhs.coefficients == [T.max, T.max]); 1239 assert((lhs += rhs) == false); 1240 assert(lhs.coefficients == [Signed!T.max + 1, 0, 1]); 1241 assert((lhs -= rhs) == false); 1242 assert(lhs.coefficients == [Signed!T.max + 2, 0, 0]); 1243 assert((lhs += -rhs) == true); 1244 assert(lhs.coefficients == [Signed!T.max + 3, 0, T.max]); 1245 assert((lhs += -(-rhs)) == true); 1246 assert(lhs.coefficients == [Signed!T.max + 2, 0, 0]); 1247 1248 /// W overflow = bigUInt *= scalar 1249 assert((lhs *= T.max) == 0); 1250 assert((lhs += T(Signed!T.max + 2)) == false); 1251 assert(lhs.coefficients == [0, Signed!T.max + 2, 0]); 1252 lhs = lhs.normalized; 1253 lhs.coefficients[1] = T.max / 2 + 3; 1254 assert(lhs.coefficients == [0, T.max / 2 + 3]); 1255 assert((lhs *= 8u) == 4); 1256 assert(lhs.coefficients == [0, 16]); 1257 } 1258 } 1259 } 1260 1261 /++ 1262 Arbitrary length signed integer view. 1263 +/ 1264 struct BigIntView(W) 1265 if (is(Unqual!W == ubyte) || is(Unqual!W == ushort) || is(Unqual!W == uint) || is(Unqual!W == ulong)) 1266 { 1267 import mir.bignum.fp: Fp; 1268 1269 /++ 1270 Self-assigned to unsigned integer view $(MREF BigUIntView). 1271 1272 Sign is stored in the most significant bit. 1273 1274 The number is encoded as pair of `unsigned` and `sign`. 1275 +/ 1276 BigUIntView!W unsigned; 1277 1278 /++ 1279 Sign bit 1280 +/ 1281 bool sign; 1282 1283 @safe: 1284 1285 /// 1286 inout(W)[] coefficients() inout @property 1287 { 1288 return unsigned.coefficients; 1289 } 1290 1291 /// 1292 this(W[] coefficients, bool sign = false) 1293 { 1294 this(BigUIntView!W(coefficients), sign); 1295 } 1296 1297 /// 1298 this(BigUIntView!W unsigned, bool sign = false) 1299 { 1300 this.unsigned = unsigned; 1301 this.sign = sign; 1302 } 1303 1304 static if (isMutable!W && W.sizeof >= 4) 1305 /++ 1306 Returns: false in case of overflow or incorrect string. 1307 Precondition: non-empty coefficients. 1308 +/ 1309 bool fromStringImpl(C)(scope const(C)[] str) 1310 scope @trusted pure @nogc nothrow 1311 if (isSomeChar!C) 1312 { 1313 import mir.utility: _expect; 1314 1315 if (_expect(str.length == 0, false)) 1316 return false; 1317 1318 if (str[0] == '-') 1319 { 1320 sign = true; 1321 str = str[1 .. $]; 1322 } 1323 else 1324 if (_expect(str[0] == '+', false)) 1325 { 1326 str = str[1 .. $]; 1327 } 1328 1329 if (!unsigned.fromStringImpl(str)) 1330 return false; 1331 sign &= unsigned.coefficients.length != 0; 1332 return true; 1333 } 1334 1335 /++ 1336 +/ 1337 static BigIntView fromHexString(C, bool allowUnderscores = false)(scope const(C)[] str) 1338 @trusted pure 1339 if (isSomeChar!C) 1340 { 1341 auto length = str.length / (W.sizeof * 2) + (str.length % (W.sizeof * 2) != 0); 1342 auto ret = BigIntView!(Unqual!W)(new Unqual!W[length]); 1343 if (ret.fromHexStringImpl!(C, allowUnderscores)(str)) 1344 return cast(BigIntView) ret; 1345 version(D_Exceptions) 1346 { import mir.exception : toMutable; throw hexStringException.toMutable; } 1347 else 1348 assert(0, hexStringErrorMsg); 1349 } 1350 1351 static if (isMutable!W) 1352 /++ 1353 +/ 1354 bool fromHexStringImpl(C, bool allowUnderscores = false)(scope const(C)[] str) 1355 @safe pure @nogc nothrow 1356 if (isSomeChar!C) 1357 { 1358 pragma(inline, false); 1359 import mir.utility: _expect; 1360 1361 assert(unsigned.coefficients.length); 1362 1363 if (_expect(str.length == 0, false)) 1364 return false; 1365 1366 sign = false; 1367 1368 if (str[0] == '-') 1369 { 1370 sign = true; 1371 str = str[1 .. $]; 1372 } 1373 else 1374 if (_expect(str[0] == '+', false)) 1375 { 1376 str = str[1 .. $]; 1377 } 1378 1379 auto ret = unsigned.fromHexStringImpl!(C, allowUnderscores)(str); 1380 sign = sign && unsigned.coefficients.length; 1381 return ret; 1382 } 1383 1384 /++ 1385 +/ 1386 static BigIntView fromBinaryString(C, bool allowUnderscores = false)(scope const(C)[] str) 1387 @trusted pure 1388 if (isSomeChar!C) 1389 { 1390 auto length = str.length / (W.sizeof * 8) + (str.length % (W.sizeof * 8) != 0); 1391 auto ret = BigIntView!(Unqual!W)(new Unqual!W[length]); 1392 if (ret.fromBinaryStringImpl!(C, allowUnderscores)(str)) 1393 return cast(BigIntView) ret; 1394 version(D_Exceptions) 1395 { import mir.exception : toMutable; throw binaryStringException.toMutable; } 1396 else 1397 assert(0, binaryStringErrorMsg); 1398 } 1399 1400 static if (isMutable!W) 1401 /++ 1402 +/ 1403 bool fromBinaryStringImpl(C, bool allowUnderscores = false)(scope const(C)[] str) 1404 @safe pure @nogc nothrow 1405 if (isSomeChar!C) 1406 { 1407 pragma(inline, false); 1408 import mir.utility: _expect; 1409 1410 assert(unsigned.coefficients.length); 1411 1412 if (_expect(str.length == 0, false)) 1413 return false; 1414 1415 sign = false; 1416 1417 if (str[0] == '-') 1418 { 1419 sign = true; 1420 str = str[1 .. $]; 1421 } 1422 else 1423 if (_expect(str[0] == '+', false)) 1424 { 1425 str = str[1 .. $]; 1426 } 1427 1428 auto ret = unsigned.fromBinaryStringImpl!(C, allowUnderscores)(str); 1429 sign = sign && unsigned.coefficients.length; 1430 return ret; 1431 } 1432 1433 /// 1434 T opCast(T)() const scope 1435 if (isFloatingPoint!T && isMutable!T) 1436 { 1437 auto ret = this.unsigned.opCast!T; 1438 if (sign) 1439 ret = -ret; 1440 return ret; 1441 } 1442 1443 /// 1444 T opCast(T, bool nonZero = false)() const scope 1445 if (is(T == long) || is(T == int)) 1446 { 1447 auto ret = this.unsigned.opCast!(Unsigned!T, nonZero); 1448 if (sign) 1449 ret = -ret; 1450 return ret; 1451 } 1452 1453 static if (W.sizeof == size_t.sizeof) 1454 /// 1455 version(mir_bignum_test) 1456 @safe pure 1457 unittest 1458 { 1459 auto view = BigIntView!size_t.fromHexString("-afbbfae3cd0aff2714a1de7022b0021d"); 1460 assert(cast(long) view == -0x14a1de7022b0021d); 1461 assert(cast(int) view == -0x22b0021d); 1462 } 1463 1464 static if (W.sizeof == size_t.sizeof) 1465 /// 1466 version(mir_bignum_test) 1467 @safe pure 1468 unittest 1469 { 1470 auto view = BigIntView!size_t.fromHexString!(char, true)("-afbb_fae3_cd0a_ff27_14a1_de70_22b0_021d"); 1471 assert(cast(long) view == -0x14a1de7022b0021d); 1472 assert(cast(int) view == -0x22b0021d); 1473 } 1474 1475 static if (W.sizeof == size_t.sizeof) 1476 version(mir_bignum_test) 1477 @safe pure 1478 unittest 1479 { 1480 auto view = BigIntView!ushort.fromHexString("-afbbfae3cd0aff2714a1de7022b0021d"); 1481 assert(cast(long) view == -0x14a1de7022b0021d); 1482 assert(cast(int) view == -0x22b0021d); 1483 } 1484 1485 static if (W.sizeof == size_t.sizeof) 1486 version(mir_bignum_test_llv) 1487 @safe pure 1488 unittest 1489 { 1490 auto view = BigIntView!ushort.fromHexString!(char, true)("-afbb_fae3_cd0a_ff27_14a1_de70_22b0_021d"); 1491 assert(cast(long) view == -0x14a1de7022b0021d); 1492 assert(cast(int) view == -0x22b0021d); 1493 } 1494 1495 static if (W.sizeof == size_t.sizeof) 1496 version(mir_bignum_test) 1497 @safe pure 1498 unittest 1499 { 1500 auto view = BigIntView!ubyte.fromHexString("-afbbfae3cd0aff2714a1de7022b0021d"); 1501 assert(cast(long) view == -0x14a1de7022b0021d); 1502 assert(cast(int) view == -0x22b0021d); 1503 } 1504 1505 static if (W.sizeof == size_t.sizeof) 1506 version(mir_bignum_test) 1507 @safe pure 1508 unittest 1509 { 1510 auto view = BigIntView!ubyte.fromHexString!(char, true)("-afbb_fae3_cd0a_ff27_14a1_de70_22b0_021d"); 1511 assert(cast(long) view == -0x14a1de7022b0021d); 1512 assert(cast(int) view == -0x22b0021d); 1513 } 1514 1515 static if (W.sizeof == size_t.sizeof) 1516 version(mir_bignum_test) 1517 @safe pure 1518 unittest 1519 { 1520 auto view = BigIntView!size_t.fromBinaryString!(char, true)("-10101111101110111111101011100011110011010000101011111111001001110001010010100001110111100111000000100010101100000000001000011101"); 1521 assert(cast(long) view == -0x14a1de7022b0021d); 1522 assert(cast(int) view == -0x22b0021d); 1523 } 1524 1525 static if (W.sizeof == size_t.sizeof) 1526 version(mir_bignum_test) 1527 @safe pure 1528 unittest 1529 { 1530 auto view = BigIntView!size_t.fromBinaryString!(char, true)("-1010_1111_1011_1011_1111_1010_1110_0011_1100_1101_0000_1010_1111_1111_0010_0111_0001_0100_1010_0001_1101_1110_0111_0000_0010_0010_1011_0000_0000_0010_0001_1101"); 1531 assert(cast(long) view == -0x14a1de7022b0021d); 1532 assert(cast(int) view == -0x22b0021d); 1533 } 1534 1535 static if (W.sizeof == size_t.sizeof) 1536 version(mir_bignum_test) 1537 @safe pure 1538 unittest 1539 { 1540 auto view = BigIntView!ushort.fromBinaryString!(char, true)("-10101111101110111111101011100011110011010000101011111111001001110001010010100001110111100111000000100010101100000000001000011101"); 1541 assert(cast(long) view == -0x14a1de7022b0021d); 1542 assert(cast(int) view == -0x22b0021d); 1543 } 1544 1545 static if (W.sizeof == size_t.sizeof) 1546 version(mir_bignum_test) 1547 @safe pure 1548 unittest 1549 { 1550 auto view = BigIntView!ushort.fromBinaryString!(char, true)("-1010_1111_1011_1011_1111_1010_1110_0011_1100_1101_0000_1010_1111_1111_0010_0111_0001_0100_1010_0001_1101_1110_0111_0000_0010_0010_1011_0000_0000_0010_0001_1101"); 1551 assert(cast(long) view == -0x14a1de7022b0021d); 1552 assert(cast(int) view == -0x22b0021d); 1553 } 1554 1555 static if (W.sizeof == size_t.sizeof) 1556 version(mir_bignum_test) 1557 @safe pure 1558 unittest 1559 { 1560 auto view = BigIntView!ubyte.fromBinaryString!(char, true)("-10101111101110111111101011100011110011010000101011111111001001110001010010100001110111100111000000100010101100000000001000011101"); 1561 assert(cast(long) view == -0x14a1de7022b0021d); 1562 assert(cast(int) view == -0x22b0021d); 1563 } 1564 1565 static if (W.sizeof == size_t.sizeof) 1566 version(mir_bignum_test_llv) 1567 @safe pure 1568 unittest 1569 { 1570 auto view = BigIntView!ubyte.fromBinaryString!(char, true)("-1010_1111_1011_1011_1111_1010_1110_0011_1100_1101_0000_1010_1111_1111_0010_0111_0001_0100_1010_0001_1101_1110_0111_0000_0010_0010_1011_0000_0000_0010_0001_1101"); 1571 assert(cast(long) view == -0x14a1de7022b0021d); 1572 assert(cast(int) view == -0x22b0021d); 1573 } 1574 1575 /++ 1576 +/ 1577 T opCast(T : Fp!coefficientSize, uint coefficientSize)() const scope 1578 { 1579 auto ret = unsigned.opCast!(Fp!coefficientSize); 1580 ret.sign = sign; 1581 return ret; 1582 } 1583 1584 /// 1585 BigIntView!V opCast(T : BigIntView!V, V)() return scope 1586 if (V.sizeof <= W.sizeof) 1587 { 1588 return typeof(return)(this.unsigned.opCast!(BigUIntView!V), sign); 1589 } 1590 1591 /// 1592 BigIntView!V opCast(T : BigIntView!V, V)() const return scope 1593 if (V.sizeof <= W.sizeof) 1594 { 1595 return typeof(return)(this.unsigned.opCast!(BigUIntView!V), sign); 1596 } 1597 1598 /// 1599 BigIntView!(const W) lightConst()() return scope 1600 const @safe pure nothrow @nogc @property 1601 { 1602 return typeof(return)(unsigned.lightConst, sign); 1603 } 1604 1605 ///ditto 1606 alias lightConst this; 1607 1608 /++ 1609 +/ 1610 sizediff_t opCmp(BigIntView!(const W) rhs) 1611 const @safe pure nothrow @nogc scope 1612 { 1613 import mir.algorithm.iteration: cmp; 1614 if (auto s = rhs.sign - this.sign) 1615 { 1616 if (this.unsigned.coefficients.length && rhs.unsigned.coefficients.length) 1617 return s; 1618 } 1619 auto d = this.unsigned.opCmp(rhs.unsigned); 1620 return sign ? -d : d; 1621 } 1622 1623 /// 1624 bool opEquals(BigIntView!(const W) rhs) 1625 const @safe pure nothrow @nogc scope 1626 { 1627 return (this.sign == rhs.sign || unsigned.coefficients.length == 0) && this.unsigned == rhs.unsigned; 1628 } 1629 1630 /++ 1631 Returns: true if the integer and equals to `rhs`. 1632 +/ 1633 bool opEquals(long rhs) 1634 @safe pure nothrow @nogc const scope 1635 { 1636 if (rhs == 0 && unsigned.coefficients.length == 0) 1637 return true; 1638 bool sign = rhs < 0; 1639 ulong urhs = sign ? -rhs : rhs; 1640 return sign == this.sign && unsigned == urhs; 1641 } 1642 1643 /++ 1644 +/ 1645 BigIntView topMostSignificantPart(size_t length) 1646 { 1647 return BigIntView(unsigned.topMostSignificantPart(length), sign); 1648 } 1649 1650 /++ 1651 +/ 1652 BigIntView topLeastSignificantPart(size_t length) 1653 { 1654 return BigIntView(unsigned.topLeastSignificantPart(length), sign); 1655 } 1656 1657 static if (isMutable!W && W.sizeof >= 4) 1658 /++ 1659 Performs `bool overflow = big +(-)= big` operatrion. 1660 Params: 1661 rhs = value to add with non-empty coefficients 1662 overflow = (overflow) initial iteration overflow 1663 Precondition: non-empty coefficients length of greater or equal to the `rhs` coefficients length. 1664 Returns: 1665 true in case of unsigned overflow 1666 +/ 1667 bool opOpAssign(string op)(scope BigIntView!(const W) rhs, bool overflow = false) 1668 @safe pure nothrow @nogc 1669 if (op == "+" || op == "-") 1670 { 1671 assert(rhs.coefficients.length > 0); 1672 import mir.conv; 1673 debug assert(this.coefficients.length >= rhs.coefficients.length, this.coefficients.length.to!string ~ " " ~ rhs.coefficients.length.to!string); 1674 enum sum = op == "+"; 1675 // pos += pos 1676 // neg += neg 1677 // neg -= pos 1678 // pos -= neg 1679 if ((sign == rhs.sign) == sum) 1680 return unsigned.opOpAssign!"+"(rhs.unsigned, overflow); 1681 // pos -= pos 1682 // pos += neg 1683 // neg += pos 1684 // neg -= neg 1685 if (unsigned.opOpAssign!"-"(rhs.unsigned, overflow)) 1686 { 1687 sign = !sign; 1688 unsigned.twoComplementInPlace; 1689 } 1690 return false; 1691 } 1692 1693 static if (isMutable!W && W.sizeof >= 4) 1694 /// ditto 1695 bool opOpAssign(string op)(scope BigUIntView!(const W) rhs, bool overflow = false) 1696 @safe pure nothrow @nogc 1697 if (op == "+" || op == "-") 1698 { 1699 return opOpAssign!op(rhs.signed, overflow); 1700 } 1701 1702 static if (isMutable!W && W.sizeof >= 4) 1703 /++ 1704 Performs `bool overflow = big +(-)= scalar` operatrion. 1705 Precondition: non-empty coefficients 1706 Params: 1707 rhs = value to add 1708 Returns: 1709 true in case of unsigned overflow 1710 +/ 1711 bool opOpAssign(string op, T)(const T rhs) 1712 @safe pure nothrow @nogc 1713 if ((op == "+" || op == "-") && is(T == Signed!W)) 1714 { 1715 assert(this.coefficients.length > 0); 1716 enum sum = op == "+"; 1717 // pos += pos 1718 // neg += neg 1719 // neg -= pos 1720 // pos -= neg 1721 auto urhs = cast(W) (rhs < 0 ? -rhs : rhs); 1722 if ((sign == (rhs < 0)) == sum) 1723 return unsigned.opOpAssign!"+"(urhs); 1724 // pos -= pos 1725 // pos += neg 1726 // neg += pos 1727 // neg -= neg 1728 if (unsigned.opOpAssign!"-"(urhs)) 1729 { 1730 sign = !sign; 1731 unsigned.twoComplementInPlace; 1732 } 1733 return false; 1734 } 1735 1736 static if (isMutable!W && W.sizeof >= 4) 1737 /// ditto 1738 bool opOpAssign(string op, T)(const T rhs) 1739 @safe pure nothrow @nogc 1740 if ((op == "+" || op == "-") && is(T == W)) 1741 { 1742 assert(this.coefficients.length > 0); 1743 enum sum = op == "+"; 1744 // pos += pos 1745 // neg -= pos 1746 if ((sign == false) == sum) 1747 return unsigned.opOpAssign!"+"(rhs); 1748 // pos -= pos 1749 // neg += pos 1750 if (unsigned.opOpAssign!"-"(rhs)) 1751 { 1752 sign = !sign; 1753 unsigned.twoComplementInPlace; 1754 } 1755 return false; 1756 } 1757 1758 static if (isMutable!W && W.sizeof >= 4) 1759 /++ 1760 Performs `W overflow = (big += overflow) *= scalar` operatrion. 1761 Precondition: non-empty coefficients 1762 Params: 1763 rhs = unsigned value to multiply by 1764 overflow = initial overflow 1765 Returns: 1766 unsigned overflow value 1767 +/ 1768 W opOpAssign(string op : "*")(W rhs, W overflow = 0u) 1769 @safe pure nothrow @nogc 1770 { 1771 return unsigned.opOpAssign!op(rhs, overflow); 1772 } 1773 1774 /++ 1775 Returns: the same intger view with inversed sign 1776 +/ 1777 BigIntView opUnary(string op : "-")() 1778 { 1779 return BigIntView(unsigned, !sign); 1780 } 1781 1782 /++ 1783 Returns: a slice of coefficients starting from the least significant. 1784 +/ 1785 auto coefficients() 1786 @safe pure nothrow @nogc @property 1787 { 1788 return unsigned.coefficients; 1789 } 1790 1791 /++ 1792 Returns: a slice of coefficients starting from the most significant. 1793 +/ 1794 auto mostSignificantFirst() 1795 @safe pure nothrow @nogc @property 1796 { 1797 return unsigned.mostSignificantFirst; 1798 } 1799 1800 /++ 1801 Strips zero most significant coefficients. 1802 Strips most significant zero coefficients. 1803 Sets sign to zero if no coefficients were left. 1804 +/ 1805 BigIntView normalized() return scope 1806 { 1807 auto number = this; 1808 number.unsigned = number.unsigned.normalized; 1809 number.sign = number.coefficients.length == 0 ? false : number.sign; 1810 return number; 1811 } 1812 1813 ///ditto 1814 BigIntView!(const W) normalized() const return scope 1815 { 1816 return lightConst.normalized; 1817 } 1818 } 1819 1820 /// 1821 version(mir_bignum_test) 1822 @safe pure 1823 unittest 1824 { 1825 import mir.bignum.fixed: UInt; 1826 import mir.bignum.fp: Fp; 1827 1828 auto fp = cast(Fp!128) BigIntView!size_t.fromHexString("-afbbfae3cd0aff2714a1de7022b0029d"); 1829 assert(fp.sign); 1830 assert(fp.exponent == 0); 1831 assert(fp.coefficient == UInt!128.fromHexString("afbbfae3cd0aff2714a1de7022b0029d")); 1832 } 1833 1834 /// 1835 version(mir_bignum_test) 1836 @safe pure 1837 unittest 1838 { 1839 auto a = cast(double) BigIntView!size_t.fromHexString("-afbbfae3cd0aff2714a1de7022b0029d"); 1840 assert(a == -0xa.fbbfae3cd0bp+124); 1841 } 1842 1843 /// 1844 version(mir_bignum_test) 1845 @safe pure 1846 unittest 1847 { 1848 auto a = cast(double) BigIntView!size_t.fromBinaryString("-10101111101110111111101011100011110011010000101011111111001001110001010010100001110111100111000000100010101100000000001010011101"); 1849 assert(a == -0xa.fbbfae3cd0bp+124); 1850 } 1851 1852 /// 1853 version(mir_bignum_test) 1854 @safe pure 1855 unittest 1856 { 1857 auto a = cast(double) BigIntView!size_t.fromHexString!(char, true)("-afbb_fae3_cd0a_ff27_14a1_de70_22b0_029d"); 1858 assert(a == -0xa.fbbfae3cd0bp+124); 1859 } 1860 1861 /// 1862 version(mir_bignum_test) 1863 @safe pure 1864 unittest 1865 { 1866 auto a = cast(double) BigIntView!size_t.fromBinaryString!(char, true)("-1010_1111_1011_1011_1111_1010_1110_0011_1100_1101_0000_1010_1111_1111_0010_0111_0001_0100_1010_0001_1101_1110_0111_0000_0010_0010_1011_0000_0000_0010_1001_1101"); 1867 assert(a == -0xa.fbbfae3cd0bp+124); 1868 } 1869 1870 version(mir_bignum_test_llv) 1871 @safe pure 1872 unittest 1873 { 1874 import mir.bignum.fixed: UInt; 1875 import mir.bignum.fp: Fp; 1876 1877 auto fp = cast(Fp!128) BigIntView!size_t.fromHexString!(char, true)("-afbb_fae3_cd0a_ff27_14a1_de70_22b0_029d"); 1878 assert(fp.sign); 1879 assert(fp.exponent == 0); 1880 assert(fp.coefficient == UInt!128.fromHexString("afbbfae3cd0aff2714a1de7022b0029d")); 1881 } 1882 1883 /// 1884 version(mir_bignum_test_llv) 1885 @safe pure nothrow 1886 unittest 1887 { 1888 import std.traits; 1889 alias AliasSeq(T...) = T; 1890 1891 foreach (T; AliasSeq!(ubyte, ushort, uint, ulong)) 1892 { 1893 T[3] lhsData = [1, T.max-1, 0]; 1894 T[3] rhsData = [T.max, T.max, 0]; 1895 1896 auto lhs = BigIntView!T(lhsData).normalized; 1897 1898 /// bool overflow = bigUInt op= scalar 1899 assert(lhs.coefficients == [1, T.max-1]); 1900 assert(lhs.mostSignificantFirst == [T.max-1, 1]); 1901 1902 static if (T.sizeof >= 4) 1903 { 1904 1905 assert((lhs += T.max) == false); 1906 assert(lhs.coefficients == [0, T.max]); 1907 assert((lhs += T.max) == false); 1908 assert((lhs += T.max) == true); // overflow bit 1909 assert(lhs.coefficients == [T.max-1, 0]); 1910 assert((lhs -= T(1)) == false); 1911 assert(lhs.coefficients == [T.max-2, 0]); 1912 assert((lhs -= T.max) == false); 1913 assert(lhs.coefficients == [2, 0]); 1914 assert(lhs.sign); 1915 assert((lhs -= Signed!T(-4)) == false); 1916 assert(lhs.coefficients == [2, 0]); 1917 assert(lhs.sign == false); 1918 assert((lhs += Signed!T.max) == false); 1919 assert(lhs.coefficients == [Signed!T.max + 2, 0]); 1920 1921 /// bool overflow = bigUInt op= bigUInt/bigInt 1922 lhs = BigIntView!T(lhsData); 1923 auto rhs = BigUIntView!T(rhsData).normalized; 1924 assert(lhs.coefficients == [Signed!T.max + 2, 0, 0]); 1925 assert(rhs.coefficients == [T.max, T.max]); 1926 assert((lhs += rhs) == false); 1927 assert(lhs.coefficients == [Signed!T.max + 1, 0, 1]); 1928 assert((lhs -= rhs) == false); 1929 assert(lhs.coefficients == [Signed!T.max + 2, 0, 0]); 1930 assert((lhs += -rhs) == false); 1931 assert(lhs.sign); 1932 assert(lhs.coefficients == [T.max - (Signed!T.max + 2), T.max, 0]); 1933 assert(lhs.sign); 1934 assert((lhs -= -rhs) == false); 1935 assert(lhs.coefficients == [Signed!T.max + 2, 0, 0]); 1936 assert(lhs.sign == false); 1937 } 1938 } 1939 } 1940 1941 /// 1942 version(mir_bignum_test_llv) 1943 unittest 1944 { 1945 import mir.bignum.fixed: UInt; 1946 import mir.bignum.low_level_view: BigUIntView; 1947 auto bigView = BigUIntView!size_t.fromHexString("55a325ad18b2a77120d870d987d5237473790532acab45da44bc07c92c92babf0b5e2e2c7771cd472ae5d7acdb159a56fbf74f851a058ae341f69d1eb750d7e3"); 1948 auto fixed = UInt!256.fromHexString("55e5669576d31726f4a9b58a90159de5923adc6c762ebd3c4ba518d495229072"); 1949 auto overflow = bigView *= fixed; 1950 assert(overflow == UInt!256.fromHexString("1cbbe8c42dc21f936e4ce5b2f52ac404439857f174084012fcd1b71fdec2a398")); 1951 assert(bigView == BigUIntView!size_t.fromHexString("c73fd2b26f2514c103c324943b6c90a05d2732118d5f0099c36a69a8051bb0573adc825b5c9295896c70280faa4c4d369df8e92f82bfffafe078b52ae695d316")); 1952 1953 } 1954 1955 /// 1956 version(mir_bignum_test_llv) 1957 unittest 1958 { 1959 import mir.bignum.fixed: UInt; 1960 import mir.bignum.low_level_view: BigUIntView; 1961 auto bigView2 = BigUIntView!size_t.fromHexString("55a325ad18b2a77120d870d987d5237473790532acab45da44bc07c92c92babf0b5e2e2c7771cd472ae5d7acdb159a56fbf74f851a058ae341f69d1eb750d7e3"); 1962 auto bigView = BigUIntView!size_t.fromHexString!(char, true)("55a3_25ad_18b2_a771_20d8_70d9_87d5_2374_7379_0532_acab_45da_44bc_07c9_2c92_babf_0b5e_2e2c_7771_cd47_2ae5_d7ac_db15_9a56_fbf7_4f85_1a05_8ae3_41f6_9d1e_b750_d7e3"); 1963 auto fixed = UInt!256.fromHexString!(true)("55e5_6695_76d3_1726_f4a9_b58a_9015_9de5_923a_dc6c_762e_bd3c_4ba5_18d4_9522_9072"); 1964 auto overflow = bigView *= fixed; 1965 assert(overflow == UInt!256.fromHexString("1cbbe8c42dc21f936e4ce5b2f52ac404439857f174084012fcd1b71fdec2a398")); 1966 assert(bigView == BigUIntView!size_t.fromHexString("c73fd2b26f2514c103c324943b6c90a05d2732118d5f0099c36a69a8051bb0573adc825b5c9295896c70280faa4c4d369df8e92f82bfffafe078b52ae695d316")); 1967 } 1968 1969 /++ 1970 +/ 1971 struct DecimalView(W) 1972 if (is(Unqual!W == size_t)) 1973 { 1974 import mir.parse: DecimalExponentKey; 1975 1976 /// 1977 bool sign; 1978 /// 1979 long exponent; 1980 /// 1981 BigUIntView!W coefficient; 1982 1983 @safe: 1984 1985 static if (is(W == size_t)) 1986 /++ 1987 Returns: false in case of overflow or incorrect string. 1988 Precondition: non-empty coefficients 1989 +/ 1990 bool fromStringImpl(C, 1991 bool allowSpecialValues = true, 1992 bool allowDotOnBounds = true, 1993 bool allowDExponent = true, 1994 bool allowStartingPlus = true, 1995 bool allowUnderscores = true, 1996 bool allowLeadingZeros = true, 1997 bool allowExponent = true, 1998 bool checkEmpty = true, 1999 ) 2000 (scope const(C)[] str, out DecimalExponentKey key, int exponentShift = 0) 2001 scope @trusted pure @nogc nothrow 2002 if (isSomeChar!C) 2003 in (coefficient.length) 2004 { 2005 pragma(inline, false); 2006 2007 import mir.utility: _expect; 2008 2009 BigUIntView!W work; 2010 2011 bool mullAdd(W rhs, W overflow) 2012 { 2013 import mir.stdio; 2014 // debug dump(rhs, overflow, work); 2015 if ((overflow = work.opOpAssign!"*"(rhs, overflow)) != 0) 2016 { 2017 if (_expect(work.coefficients.length < coefficient.coefficients.length, true)) 2018 { 2019 work = coefficient.topLeastSignificantPart(work.coefficients.length + 1); 2020 work.coefficients[$ - 1] = overflow; 2021 // debug dump(overflow, work); 2022 return false; 2023 } 2024 return true; 2025 } 2026 // debug dump(overflow, work); 2027 return false; 2028 } 2029 2030 import mir.bignum.internal.parse: decimalFromStringImpl; 2031 alias impl = decimalFromStringImpl!(mullAdd, W); 2032 alias specification = impl!(C, 2033 allowSpecialValues, 2034 allowDotOnBounds, 2035 allowDExponent, 2036 allowStartingPlus, 2037 allowUnderscores, 2038 allowLeadingZeros, 2039 allowExponent, 2040 checkEmpty, 2041 ); 2042 exponent += exponentShift; 2043 auto ret = specification(str, key, exponent, sign); 2044 switch (key) 2045 { 2046 case DecimalExponentKey.infinity: 2047 exponent = exponent.max; 2048 coefficient = coefficient.topLeastSignificantPart(0); 2049 return ret; 2050 case DecimalExponentKey.nan: 2051 exponent = exponent.max; 2052 coefficient = coefficient.topLeastSignificantPart(1); 2053 coefficient.coefficients[0] = 1; 2054 return ret; 2055 default: 2056 coefficient = work; 2057 return ret; 2058 } 2059 } 2060 2061 /// 2062 DecimalView!(const W) lightConst()() return scope 2063 const @safe pure nothrow @nogc @property 2064 { 2065 return typeof(return)(sign, exponent, coefficient.lightConst); 2066 } 2067 ///ditto 2068 alias lightConst this; 2069 2070 /++ 2071 +/ 2072 BigIntView!W signedCoefficient() 2073 { 2074 return typeof(return)(coefficient, sign); 2075 } 2076 2077 static if (W.sizeof >= size_t.sizeof) 2078 /++ 2079 Mir parsing supports up-to quadruple precision. The conversion error is 0 ULP for normal numbers. 2080 Subnormal numbers with an exponent greater than or equal to -512 have upper error bound equal to 1 ULP. 2081 +/ 2082 T opCast(T, bool wordNormalized = false)() const scope 2083 if (isFloatingPoint!T && isMutable!T) 2084 { 2085 import mir.bignum.internal.dec2float; 2086 2087 auto coeff = coefficient.lightConst; 2088 2089 static if (!wordNormalized) 2090 coeff = coeff.normalized; 2091 auto ret = exponent != exponent.max ? 2092 coeff.coefficients.decimalTo!T(exponent) : 2093 coeff.length ? T.nan : T.infinity; 2094 if (sign) 2095 ret = -ret; 2096 return ret; 2097 } 2098 } 2099 2100 version(none) 2101 /// 2102 unittest 2103 { 2104 { 2105 auto view = DecimalView!ulong(false, -8, BigUIntView!ulong.fromHexString("BEBC2000000011E1A3")); 2106 auto coeff = (cast(BigUIntView!uint)view.coefficient).lightConst; 2107 assert (algoM!double(0.0, coeff, cast(int)view.exponent) == 3.518437208883201171875E+013); 2108 } 2109 2110 // TBD: triggers underflow 2111 // { 2112 // auto view = DecimalView!ulong(false, 0, BigUIntView!ulong.fromHexString("88BF4748507FB9900ADB624CCFF8D78897DC900FB0460327D4D86D327219")); 2113 // auto coeff = (cast(BigUIntView!uint)view.coefficient).lightConst; 2114 // debug { 2115 // import std.stdio; 2116 // writefln("%s", algoM!float(0.0, coeff, cast(int)view.exponent)); 2117 // writefln("%s", algoM!double(0.0, coeff, cast(int)view.exponent)); 2118 // } 2119 // assert (algoM!float(0.0, coeff, cast(int)view.exponent) == float.infinity); 2120 // assert (algoM!double(0.0, coeff, cast(int)view.exponent) == 0x1.117e8e90a0ff7p+239); 2121 // } 2122 2123 { 2124 auto view = DecimalView!ulong(false, -324, BigUIntView!ulong.fromHexString("4F0CEDC95A718E")); 2125 auto coeff = (cast(BigUIntView!uint)view.coefficient).lightConst; 2126 assert (algoM!float(0.0, coeff, cast(int)view.exponent) == 0); 2127 assert (algoM!double(0.0, coeff, cast(int)view.exponent) == 2.2250738585072014e-308); 2128 } 2129 } 2130 2131 /// 2132 version(mir_bignum_test_llv) 2133 unittest 2134 { 2135 import mir.test; 2136 2137 auto view = DecimalView!size_t(false, -8, BigUIntView!size_t.fromHexString("BEBC2000000011E1A3")); 2138 2139 should(cast(float)view) == 3.518437208883201171875E+013f; 2140 should(cast(double)view) == 3.518437208883201171875E+013; 2141 static if (real.mant_dig >= 64) 2142 should(cast(real)view) == 3.518437208883201171875E+013L; 2143 2144 view = DecimalView!size_t(true, -169, BigUIntView!size_t.fromHexString("5A174AEDA65CC")); 2145 should(cast(float)view) == -0; 2146 should(cast(double)view) == -0x1.1p-511; 2147 static if (real.mant_dig >= 64) 2148 should(cast(real)view) == -0x8.80000000000019fp-514L; 2149 2150 view = DecimalView!size_t(true, 293, BigUIntView!size_t.fromHexString("36496F6C4ED38")); 2151 should(cast(float)view) == -float.infinity; 2152 should(cast(double)view) == -9.55024478104888e+307; 2153 static if (real.mant_dig >= 64) 2154 should(cast(real)view) == -9.55024478104888e+307L; 2155 2156 view = DecimalView!size_t(false, 0, BigUIntView!size_t.fromHexString("1")); 2157 should(cast(float)view) == 1; 2158 should(cast(double)view) == 1; 2159 static if (real.mant_dig >= 64) 2160 should(cast(real)view) == 1L; 2161 2162 view = DecimalView!size_t(false, -5, BigUIntView!size_t.fromHexString("3")); 2163 should(cast(float)view) == 3e-5f; 2164 should(cast(double)view) == 3e-5; 2165 static if (real.mant_dig >= 64) 2166 should(cast(real)view) == 3e-5L; 2167 2168 view = DecimalView!size_t(false, -1, BigUIntView!size_t.fromHexString("1")); 2169 should(cast(float)view) == 0.1f; 2170 should(cast(double)view) == 0.1; 2171 static if (real.mant_dig >= 64) 2172 should(cast(real)view) == 0.1L; 2173 2174 view = DecimalView!size_t(false, 0, BigUIntView!size_t.fromHexString("3039")); 2175 should(cast(float)view) == 12345.0f; 2176 should(cast(double)view) == 12345.0; 2177 static if (real.mant_dig >= 64) 2178 should(cast(real)view) == 12345.0L; 2179 2180 view = DecimalView!size_t(false, -7, BigUIntView!size_t.fromHexString("98967F")); 2181 should(cast(float)view) == 0.9999999f; 2182 should(cast(double)view) == 0.9999999; 2183 static if (real.mant_dig >= 64) 2184 should(cast(real)view) == 0.9999999L; 2185 2186 view = DecimalView!size_t(false, -324, BigUIntView!size_t.fromHexString("4F0CEDC95A718E")); 2187 should(cast(float)view) == 0; 2188 should(cast(double)view) == 2.2250738585072014e-308; 2189 static if (real.mant_dig >= 64) 2190 should(cast(real)view) == 2.2250738585072014e-308L; 2191 2192 view = DecimalView!size_t(false, 0, BigUIntView!size_t.fromHexString("1FFFFFFFFFFFFFFFD")); 2193 should(cast(float)view) == 36893488147419103229f; 2194 should(cast(double)view) == 36893488147419103229.0; 2195 static if (real.mant_dig >= 64) 2196 should(cast(real)view) == 0x1FFFFFFFFFFFFFFFDp0L; 2197 2198 view = DecimalView!size_t(false, -33, BigUIntView!size_t.fromHexString("65")); 2199 should(cast(float)view) == 101e-33f; 2200 should(cast(double)view) == 101e-33; 2201 static if (real.mant_dig >= 64) 2202 should(cast(real)view) == 101e-33L; 2203 2204 view = DecimalView!size_t(false, 23, BigUIntView!size_t.fromHexString("1")); 2205 should(cast(float)view) == 1e23f; 2206 should(cast(double)view) == 1e23; 2207 static if (real.mant_dig >= 64) 2208 should(cast(real)view) == 1e23L; 2209 2210 view = DecimalView!size_t(false, 23, BigUIntView!size_t.fromHexString("81B")); 2211 should(cast(float)view) == 2075e23f; 2212 should(cast(double)view) == 0xaba3d58a1f1a98p+32; 2213 static if (real.mant_dig >= 64) 2214 should(cast(real)view) == 0xaba3d58a1f1a9cp+32L; 2215 2216 view = DecimalView!size_t(false, -23, BigUIntView!size_t.fromHexString("2209")); 2217 should(cast(float)view) == 8713e-23f; 2218 should(cast(double)view) == 0x1.9b75b4e7de2b9p-64; 2219 static if (real.mant_dig >= 64) 2220 should(cast(real)view) == 0xc.dbada73ef15c401p-67L; 2221 2222 view = DecimalView!size_t(false, 300, BigUIntView!size_t.fromHexString("1")); 2223 should(cast(float)view) == float.infinity; 2224 should(cast(double)view) == 0x1.7e43c8800759cp+996; 2225 static if (real.mant_dig >= 64) 2226 should(cast(real)view) == 0xb.f21e44003acdd2dp+993L; 2227 2228 view = DecimalView!size_t(false, 245, BigUIntView!size_t.fromHexString("B3A73CEB227")); 2229 should(cast(float)view) == float.infinity; 2230 should(cast(double)view) == 0x1.48e3735333cb6p+857; 2231 static if (real.mant_dig >= 64) 2232 should(cast(real)view) == 0xa.471b9a999e5b01ep+854L; 2233 2234 view = DecimalView!size_t(false, 0, BigUIntView!size_t.fromHexString("88BF4748507FB9900ADB624CCFF8D78897DC900FB0460327D4D86D327219")); 2235 should(cast(float)view) == float.infinity; 2236 should(cast(double)view) == 0x1.117e8e90a0ff7p+239; 2237 static if (real.mant_dig >= 64) 2238 should(cast(real)view) == 0x8.8bf4748507fb99p+236L; 2239 2240 view = DecimalView!size_t(false, -324, BigUIntView!size_t.fromHexString("5")); 2241 should(cast(float)view) == 0; 2242 should(cast(double)view) == 0x0.0000000000001p-1022; 2243 static if (real.mant_dig >= 64) 2244 should(cast(real)view) == 0x8.18995ce7aa0e1b2p-1077L; 2245 2246 view = DecimalView!size_t(false, -324, BigUIntView!size_t.fromHexString("5B")); 2247 should(cast(float)view) == 0; 2248 should(cast(double)view) == 0x0.0000000000012p-1022; 2249 static if (real.mant_dig >= 64) 2250 should(cast(real)view) == 0x9.3594d9adeb09a55p-1073L; 2251 2252 view = DecimalView!size_t(false, -322, BigUIntView!size_t.fromHexString("1")); 2253 should(cast(float)view) == 0; 2254 should(cast(double)view) == 0x0.0000000000014p-1022; 2255 static if (real.mant_dig >= 64) 2256 should(cast(real)view) == 0xa.1ebfb4219491a1fp-1073L; 2257 2258 view = DecimalView!size_t(false, -320, BigUIntView!size_t.fromHexString("CA1CCB")); 2259 should(cast(float)view) == 0; 2260 should(cast(double)view) == 0x0.000063df832d9p-1022; 2261 static if (real.mant_dig >= 64) 2262 should(cast(real)view) == 0xc.7bf065b215888c7p-1043L; 2263 2264 view = DecimalView!size_t(false, -319, BigUIntView!size_t.fromHexString("33CE7943FB")); 2265 should(cast(float)view) == 0; 2266 should(cast(double)view) == 0x1.000000000162p-1022; 2267 static if (real.mant_dig >= 64) 2268 should(cast(real)view) == 0x8.000000000b103b6p-1025L; 2269 2270 view = DecimalView!size_t(false, -309, BigUIntView!size_t.fromHexString("15")); 2271 should(cast(float)view) == 0; 2272 should(cast(double)view) == 0x0.f19c2629ccf53p-1022; 2273 static if (real.mant_dig >= 64) 2274 should(cast(real)view) == 0xf.19c2629ccf52fc4p-1026L; 2275 2276 view = DecimalView!size_t(false, -340, BigUIntView!size_t.fromHexString("AF87023B9BF0EE")); 2277 should(cast(float)view) == 0; 2278 should(cast(double)view) == 0x0.0000000000001p-1022; 2279 static if (real.mant_dig >= 64) 2280 should(cast(real)view) == 0xf.fffffffffffff64p-1078L; 2281 2282 view = DecimalView!size_t(false, 400, BigUIntView!size_t.fromHexString("1")); 2283 should(cast(float)view) == float.infinity; 2284 should(cast(double)view) == double.infinity; 2285 static if (real.mant_dig >= 64) 2286 should(cast(real)view) == 0xd.a763fc8cb9ff9e6p+1325L; 2287 2288 view = DecimalView!size_t(false, 309, BigUIntView!size_t.fromHexString("1")); 2289 should(cast(float)view) == float.infinity; 2290 should(cast(double)view) == double.infinity; 2291 static if (real.mant_dig >= 64) 2292 should(cast(real)view) == 0xb.201833b35d63f73p+1023L; 2293 2294 view = DecimalView!size_t(false, 308, BigUIntView!size_t.fromHexString("2")); 2295 should(cast(float)view) == float.infinity; 2296 should(cast(double)view) == double.infinity; 2297 static if (real.mant_dig >= 64) 2298 should(cast(real)view) == 0x8.e679c2f5e44ff8fp+1021L; 2299 2300 view = DecimalView!size_t(false, 308, BigUIntView!size_t.fromHexString("2")); 2301 should(cast(float)view) == float.infinity; 2302 should(cast(double)view) == double.infinity; 2303 static if (real.mant_dig >= 64) 2304 should(cast(real)view) == 0x8.e679c2f5e44ff8fp+1021L; 2305 2306 view = DecimalView!size_t(false, 295, BigUIntView!size_t.fromHexString("1059949B7090")); 2307 should(cast(float)view) == float.infinity; 2308 should(cast(double)view) == double.infinity; 2309 static if (real.mant_dig >= 64) 2310 should(cast(real)view) == 0x8.00000000006955ap+1021L; 2311 2312 view = DecimalView!size_t(false, 0, BigUIntView!size_t.fromHexString("0")); 2313 should(cast(float)view) == 0; 2314 should(cast(double)view) == 0; 2315 static if (real.mant_dig >= 64) 2316 should(cast(real)view) == 0L; 2317 2318 view = view; 2319 should(cast(float)view) == 0; 2320 should(cast(double)view) == 0; 2321 static if (real.mant_dig >= 64) 2322 should(cast(real)view) == 0L; 2323 2324 view = DecimalView!size_t(false, -325, BigUIntView!size_t.fromHexString("1")); 2325 should(cast(float)view) == 0; 2326 should(cast(double)view) == 0; 2327 static if (real.mant_dig >= 64) 2328 should(cast(real)view) == 0xa.5ced43b7e3e9188p-1083L; 2329 2330 view = DecimalView!size_t(false, -326, BigUIntView!size_t.fromHexString("1")); 2331 should(cast(float)view) == 0; 2332 should(cast(double)view) == 0; 2333 static if (real.mant_dig >= 64) 2334 should(cast(real)view) == 0x8.4a57695fe98746dp-1086L; 2335 2336 view = DecimalView!size_t(false, -500, BigUIntView!size_t.fromHexString("1")); 2337 should(cast(float)view) == 0; 2338 should(cast(double)view) == 0; 2339 static if (real.mant_dig >= 64) 2340 should(cast(real)view) == 0x8.33ada2003db9a8p-1664L; 2341 2342 view = DecimalView!size_t(false, -1000, BigUIntView!size_t.fromHexString("1")); 2343 should(cast(float)view) == 0; 2344 should(cast(double)view) == 0; 2345 static if (real.mant_dig >= 64) 2346 should(cast(real)view) == 0x8.68a9188a89e1467p-3325L; 2347 2348 view = DecimalView!size_t(false, -4999, BigUIntView!size_t.fromHexString("1")); 2349 should(cast(float)view) == 0; 2350 should(cast(double)view) == 0; 2351 static if (real.mant_dig >= 64) 2352 should(cast(real)view) == 0L; 2353 2354 view = DecimalView!size_t(false, -10000, BigUIntView!size_t.fromHexString("1")); 2355 should(cast(float)view) == 0; 2356 should(cast(double)view) == 0; 2357 static if (real.mant_dig >= 64) 2358 should(cast(real)view) == 0L; 2359 2360 view = DecimalView!size_t(false, -4969, BigUIntView!size_t.fromHexString("329659A941466C6B")); 2361 should(cast(float)view) == 0; 2362 should(cast(double)view) == 0; 2363 static if (real.mant_dig >= 64) 2364 should(cast(real)view) == real.min_normal * real.epsilon; 2365 2366 view = DecimalView!size_t(false, -15, BigUIntView!size_t.fromHexString("525DB0200FFAB")); 2367 should(cast(float)view) == 1.448997445238699f; 2368 should(cast(double)view) == 0x1.72f17f1f49aadp+0; 2369 static if (real.mant_dig >= 64) 2370 should(cast(real)view) == 0xb.978bf8fa4d56cp-3L; 2371 2372 view = DecimalView!size_t(false, -15, BigUIntView!size_t.fromHexString("525DB0200FFAB")); 2373 should(cast(float)view) == 1.448997445238699f; 2374 should(cast(double)view) == 0x1.72f17f1f49aadp+0; 2375 static if (real.mant_dig >= 64) 2376 should(cast(real)view) == 0xb.978bf8fa4d56cp-3L; 2377 2378 view = DecimalView!size_t(false, -325, BigUIntView!size_t.fromHexString("1")); 2379 should(cast(float)view) == 0; 2380 should(cast(double)view) == 0; 2381 static if (real.mant_dig >= 64) 2382 should(cast(real)view) == 0xa.5ced43b7e3e9188p-1083L; 2383 2384 view = DecimalView!size_t(false, -326, BigUIntView!size_t.fromHexString("1")); 2385 should(cast(float)view) == 0; 2386 should(cast(double)view) == 0; 2387 static if (real.mant_dig >= 64) 2388 should(cast(real)view) == 0x8.4a57695fe98746dp-1086L; 2389 2390 view = DecimalView!size_t(false, 0, BigUIntView!size_t.fromHexString("1")); 2391 should(cast(float)view) == 1; 2392 should(cast(double)view) == 0x1p+0; 2393 static if (real.mant_dig >= 64) 2394 should(cast(real)view) == 0x8p-3L; 2395 2396 view = DecimalView!size_t(false, -5, BigUIntView!size_t.fromHexString("3")); 2397 should(cast(float)view) == 3e-5f; 2398 should(cast(double)view) == 0x1.f75104d551d69p-16; 2399 static if (real.mant_dig >= 64) 2400 should(cast(real)view) == 0xf.ba8826aa8eb4635p-19L; 2401 2402 view = DecimalView!size_t(false, -1, BigUIntView!size_t.fromHexString("1")); 2403 should(cast(float)view) == 0.1f; 2404 should(cast(double)view) == 0x1.999999999999ap-4; 2405 static if (real.mant_dig >= 64) 2406 should(cast(real)view) == 0xc.ccccccccccccccdp-7L; 2407 2408 view = DecimalView!size_t(false, -7, BigUIntView!size_t.fromHexString("98967F")); 2409 should(cast(float)view) == 0.9999999f; 2410 should(cast(double)view) == 0x1.fffffca501acbp-1; 2411 static if (real.mant_dig >= 64) 2412 should(cast(real)view) == 0xf.ffffe5280d65435p-4L; 2413 } 2414 2415 /++ 2416 +/ 2417 struct BinaryView(W) 2418 { 2419 /// 2420 bool sign; 2421 /// 2422 long exponent; 2423 /// 2424 BigUIntView!W coefficient; 2425 2426 @safe: 2427 2428 /// 2429 DecimalView!(const W) lightConst()() return scope 2430 const @safe pure nothrow @nogc @property 2431 { 2432 return typeof(return)(sign, exponent, coefficient.lightConst); 2433 } 2434 ///ditto 2435 alias lightConst this; 2436 2437 /++ 2438 +/ 2439 BigIntView!W signedCoefficient() 2440 { 2441 return typeof(return)(sign, coefficients); 2442 } 2443 }