1 module aftermath; 2 3 private 4 { 5 import std.algorithm; 6 import std.bigint; 7 import std.conv; 8 import std.math; 9 import std.stdio; 10 import std.string; 11 import std.typecons; 12 13 // template for adding setter/getter 14 template addProperty(T, string propertyName, string defaultValue = T.init.to!string) 15 { 16 const char[] addProperty = format(` 17 private %2$s %1$s = %4$s; 18 19 void set%3$s(%2$s %1$s) 20 { 21 this.%1$s = %1$s; 22 } 23 24 %2$s get%3$s() 25 { 26 return %1$s; 27 } 28 `, "_" ~ propertyName.toLower, T.stringof, propertyName, defaultValue); 29 } 30 31 auto twoComplement(T)(T n, T bits) 32 { 33 return ((cast(T) 1 << bits) - n) % (cast(T) 1 << bits); 34 } 35 36 auto oneComplement(T)(T n, T bits) 37 { 38 return (cast(T) 1 << bits) - n - cast(T) 1; 39 } 40 41 auto countBits(T)(T n) 42 { 43 T count; 44 if (n == 0) 45 { 46 count++; 47 } 48 else 49 { 50 while (n != 0) 51 { 52 n >>= 1; 53 count++; 54 } 55 } 56 return count; 57 } 58 59 auto setBit(T)(T n, T i) 60 { 61 return n | (cast(T) 1 << i); 62 } 63 64 auto getBit(T)(T n, T i) 65 { 66 return (n >> i) & cast(T) 1; 67 } 68 69 auto toggleBit(T)(T n, T i) 70 { 71 return n ^ (cast(T) 1 << i); 72 } 73 74 auto unsetBit(T)(T n, T i) 75 { 76 return (n | (cast(T) 1 << i)) ^ (cast(T) 1 << i); 77 } 78 79 auto createMask(T)(T n, T k) 80 { 81 return ((cast(T) 1 << n) - cast(T) 1) << k; 82 } 83 84 auto extractBitField(T)(T x, T n, T k) 85 { 86 return (x & createMask(n, k)) >> k; 87 } 88 89 auto lastSettedBit(T)(T n) 90 { 91 return countBits(n) - cast(T) 1; 92 } 93 94 auto lastUnsettedBit(T)(T n) 95 { 96 return lastSettedBit(oneComplement(n, countBits(n))); 97 } 98 99 auto countTrailingZeroes(T)(T n) 100 { 101 if (n == 0) 102 { 103 return 0; 104 } 105 else 106 { 107 return countBits(n & (-n)) - cast(T) 1; 108 } 109 } 110 111 auto removeTrailingZeroes(T)(T n) 112 { 113 if (n == 0) 114 { 115 return 0; 116 } 117 else 118 { 119 return n >> countTrailingZeroes(n); 120 } 121 } 122 123 auto ceilLog2(T)(T n) 124 { 125 T x = lastSettedBit(n); 126 return x + cast(T)(n != (cast(T) 1 << x)); 127 } 128 129 auto floorLog2(T)(T n) 130 { 131 return countBits(n) - cast(T) 1; 132 } 133 134 auto nextPowerOfTwo(T)(T n) 135 { 136 return cast(T) 1 << ceilLog2(n); 137 } 138 139 auto alignValues(T, S)(T a, S b) 140 { 141 auto lengthA = countBits(a); 142 auto lengthB = countBits(b); 143 144 if (lengthA > lengthB) 145 { 146 b <<= (lengthA - lengthB); 147 } 148 else 149 { 150 if (lengthA < lengthB) 151 { 152 a <<= lengthB - lengthA; 153 } 154 } 155 156 auto trailingA = countTrailingZeroes(a); 157 auto trailingB = countTrailingZeroes(b); 158 159 a >>= min(trailingA, trailingB); 160 b >>= min(trailingA, trailingB); 161 162 return tuple(a, b); 163 } 164 165 // internals of double 166 class DoubleComponents 167 { 168 mixin(addProperty!(long, "Value")); 169 mixin(addProperty!(long, "Sign")); 170 mixin(addProperty!(long, "Exponent")); 171 mixin(addProperty!(long, "Fraction")); 172 173 this() 174 { 175 176 } 177 178 // extract data from double 179 auto fromDouble(double number) 180 { 181 // bitwise conversion to ulong 182 _value = *(cast(ulong*)&number); 183 // sign extraction 184 _sign = _value >> 63; 185 // exponent extraction 186 _exponent = ((_value & ((1UL << 63) - 1)) >> 52) - 1023; 187 // fraction extraction 188 _fraction = (1UL << 52) | (_value & ((1UL << 52) - 1)); 189 } 190 } 191 192 // representation of internal posit structure 193 class PositComponents 194 { 195 // 0 or 1 in begin of regime 196 mixin(addProperty!(long, "RegimeSign")); 197 // sign bit 198 mixin(addProperty!(long, "Sign")); 199 // regime 200 mixin(addProperty!(long, "Regime")); 201 // exponent 202 mixin(addProperty!(long, "Exponent")); 203 // fraction 204 mixin(addProperty!(long, "Fraction")); 205 // regime length 206 mixin(addProperty!(long, "RegimeLength")); 207 // exponent length 208 mixin(addProperty!(long, "ExponentLength")); 209 // fraction length 210 mixin(addProperty!(long, "FractionLength")); 211 212 this() 213 { 214 215 } 216 217 // extract component from long value (value is bit pattern) 218 auto fromLong(long numberOfBits, long exponentSize)(long number) 219 { 220 long _number = number; 221 _sign = getBit(_number, numberOfBits - 1); 222 223 if (_sign == 1) 224 { 225 _number = twoComplement(_number, numberOfBits); 226 } 227 228 _regimesign = getBit(_number, numberOfBits - 2); 229 230 if (_regimesign == 0) 231 { 232 _regimelength = numberOfBits - lastSettedBit(_number) - 1; 233 } 234 else 235 { 236 _regimelength = numberOfBits - lastUnsettedBit(_number) - 1; 237 } 238 239 _exponentlength = max(0, min(exponentSize, numberOfBits - 1 - _regimelength)); 240 _fractionlength = max(0, numberOfBits - 1 - _regimelength - _exponentlength); 241 242 if (_regimesign == 0) 243 { 244 _regime = -_regimelength + 1; 245 } 246 else 247 { 248 _regime = _regimelength - 2; 249 } 250 251 _exponent = extractBitField(_number, _exponentlength, _fractionlength) << ( 252 exponentSize - _exponentlength); 253 _fraction = removeTrailingZeroes(setBit(extractBitField(_number, 254 _fractionlength, 0), _fractionlength)); 255 } 256 } 257 258 // posit container 259 template PositContainer(uint size) 260 { 261 static if (size == 8) 262 alias PositContainer = ubyte; 263 else static if (size == 16) 264 alias PositContainer = ushort; 265 else static if (size == 32) 266 alias PositContainer = uint; 267 else static if (size == 64) 268 alias PositContainer = ulong; 269 else 270 static assert(0); 271 } 272 273 class Posit(uint numberOfBits, uint exponentSize) 274 { 275 private 276 { 277 // type for internal's of posit 278 alias Unum = PositContainer!numberOfBits; 279 // internal representation of posit 280 mixin(addProperty!(Unum, "Unum")); 281 // size of posit in bit 282 enum NBITS = numberOfBits; 283 // maximal size of exponent in bit 284 enum ES = exponentSize; 285 // useed 286 enum USEED = 2 ^^ (2 ^^ ES); 287 // minimal *positive* value (bit pattern) 288 enum MINPOS = 1; 289 // maximal *positive* value (bit pattern) 290 enum MAXPOS = (2 ^^ (NBITS - 1)) - 1; 291 // NaR (not a real) pattern 292 enum NOT_A_REAL = 2 ^^ (NBITS - 1); 293 // zero pattern 294 enum ZERO = 0; 295 // number of patterns 296 enum NPAT = 2 ^^ NBITS; 297 298 PositComponents components = new PositComponents; 299 } 300 301 this() 302 { 303 304 } 305 306 // construct posit from his elements: (sign, scale, fraction) 307 auto construct(T)(T sign, T scale, T fraction) 308 { 309 Posit!(NBITS, ES) posit = new Posit!(NBITS, ES); 310 311 if (fraction == 0) 312 { 313 return posit; 314 } 315 316 long n = 0; 317 long regime = scale >> ES; 318 long exponent = scale & createMask(ES, 0); 319 320 long regimeLength; 321 322 if (regime >= 0) 323 { 324 regimeLength = regime + 2; 325 } 326 else 327 { 328 regimeLength = -regime + 1; 329 } 330 331 if (regimeLength >= (NBITS + 1)) 332 { 333 if (regime >= 0) 334 { 335 posit.fromBits(MAXPOS); 336 } 337 else 338 { 339 posit.fromBits(MINPOS); 340 } 341 342 if (sign == 1) 343 { 344 auto unum = posit.getUnum; 345 posit.fromBits(twoComplement(_unum.to!long, NBITS).to!Unum); 346 } 347 348 return posit; 349 } 350 351 if (regime >= 0) 352 { 353 n |= createMask(regimeLength - 1, NBITS - regimeLength); 354 } 355 else 356 { 357 if (NBITS - 1 >= regimeLength) 358 { 359 n |= setBit(n, NBITS - 1 - regimeLength); 360 } 361 } 362 363 long exponentBits = min(ES, NBITS - 1 - regimeLength); 364 long fractionBits = NBITS - 1 - regimeLength - exponentBits; 365 366 fraction = removeTrailingZeroes(fraction); 367 long fractionLength = countBits(fraction) - 1; 368 fraction &= 2 ^^ (countBits(fraction) - 1) - 1; 369 370 long trailingBits = NBITS - 1 - regimeLength; 371 long expFrac = removeTrailingZeroes(exponent << (fractionLength) | fraction); 372 373 long expFracBits; 374 375 if (fractionLength == 0) 376 { 377 expFracBits = ES - countTrailingZeroes(exponent); 378 } 379 else 380 { 381 expFracBits = ES + fractionLength; 382 } 383 384 if (trailingBits < expFracBits) 385 { 386 long mask = expFrac & createMask(expFracBits - trailingBits, 0); 387 long overflown = expFrac & mask; 388 n |= expFrac >> (expFracBits - trailingBits); 389 auto overflowMask = (1L << (expFracBits - trailingBits - 1L)); 390 391 if (overflown == overflowMask) 392 { 393 if (getBit(expFrac, expFracBits - trailingBits) == 1) 394 { 395 n += 1; 396 } 397 } 398 else 399 { 400 if (overflown > overflowMask) 401 { 402 n += 1; 403 } 404 else 405 { 406 // for another way actions don't needed 407 } 408 } 409 } 410 else 411 { 412 n |= expFrac << (trailingBits - expFracBits); 413 } 414 415 if (sign == 0) 416 { 417 posit.fromBits(n); 418 } 419 else 420 { 421 posit.fromBits(twoComplement(n.to!long, NBITS)); 422 } 423 424 return posit; 425 } 426 427 // decoding components of posit 428 PositComponents decode() @property 429 { 430 components.fromLong!(NBITS, ES)(_unum); 431 return components; 432 } 433 434 // set from bit pattern 435 auto fromBits(T)(T bitPattern) 436 { 437 this.setUnum(bitPattern.to!Unum); 438 decode; 439 } 440 441 // set from double 442 auto fromDouble(double x) 443 { 444 if (x == 0.0) 445 { 446 _unum = ZERO; 447 } 448 else 449 { 450 if (x.isNaN || x.isInfinity) 451 { 452 _unum = NOT_A_REAL; 453 } 454 else 455 { 456 DoubleComponents dc = new DoubleComponents; 457 dc.fromDouble(x); 458 459 _unum = construct(dc.getSign, dc.getExponent, dc.getFraction).getUnum; 460 decode; 461 } 462 } 463 } 464 465 // set from integer 466 auto fromInteger(int x) 467 { 468 if (x == 0) 469 { 470 _unum = ZERO; 471 } 472 else 473 { 474 auto sign = (x >= 0) ? 0 : 1; 475 if (sign == 1) 476 { 477 x = abs(x); 478 } 479 auto exponent = countBits(x) - 1; 480 auto fraction = x; 481 _unum = construct(sign, exponent, fraction).getUnum; 482 decode; 483 } 484 } 485 486 // is maximal value of posit ? 487 bool isMax() @property 488 { 489 return (_unum == MAXPOS); 490 } 491 492 // is minimal value of posit ? 493 bool isMin() @property 494 { 495 return (_unum == MINPOS); 496 } 497 498 // is a +/- infinity ? 499 bool isNaR() @property 500 { 501 return (_unum == NOT_A_REAL); 502 } 503 504 // is valid posit ? 505 bool isValid() @property 506 { 507 return ((0 <= _unum) && (_unum < NPAT)); 508 } 509 510 // is a posit zero ? 511 bool isZero() @property 512 { 513 return (_unum == ZERO); 514 } 515 516 // addition 517 auto opBinary(string op)(Posit!(NBITS, ES) rhs) if (op == "+") 518 { 519 if (_unum == 0) 520 { 521 return rhs; 522 } 523 524 if (rhs.isZero) 525 { 526 return this; 527 } 528 else 529 { 530 if ((rhs.isNaR) || (_unum == NOT_A_REAL)) 531 { 532 return rhs; 533 } 534 } 535 536 PositComponents components2 = new PositComponents; 537 decode; 538 components2.fromLong!(NBITS, ES)(rhs.getUnum); 539 540 auto fractions = alignValues(components.getFraction, components2.getFraction); 541 long fraction1 = fractions[0]; 542 long fraction2 = fractions[1]; 543 long scale1 = 2 ^^ ES * components.getRegime + components.getExponent; 544 long scale2 = 2 ^^ ES * components2.getRegime + components2.getExponent; 545 long scale = max(scale1, scale2); 546 547 long estimatedLength; 548 549 if (scale1 > scale2) 550 { 551 fraction1 <<= scale1 - scale2; 552 estimatedLength = countBits(fraction1); 553 } 554 else 555 { 556 fraction2 <<= scale2 - scale1; 557 estimatedLength = countBits(fraction2); 558 } 559 560 long fraction = ((-1) ^^ components.getSign * fraction1) + ( 561 (-1) ^^ components2.getSign * fraction2); 562 long sign = (fraction < 0) ? 1 : 0; 563 fraction = abs(fraction); 564 565 long resultLength = countBits(fraction); 566 scale += resultLength - estimatedLength; 567 fraction = removeTrailingZeroes(fraction); 568 569 return construct(sign, scale, fraction); 570 } 571 572 // subtraction 573 auto opBinary(string op)(Posit!(NBITS, ES) rhs) if (op == "-") 574 { 575 return (this + (-rhs)); 576 } 577 578 // conversion to int 579 int opCast(T : int)() 580 { 581 if (_unum == 0) 582 { 583 return 0; 584 } 585 else 586 { 587 if (_unum == NOT_A_REAL) 588 { 589 return T.max; 590 } 591 else 592 { 593 return (cast(double) this).to!int; 594 } 595 } 596 } 597 598 // conversion to double 599 double opCast(T : double)() 600 { 601 if (_unum == 0) 602 { 603 return 0.0; 604 } 605 else 606 { 607 if (_unum == NOT_A_REAL) 608 { 609 return double.nan; 610 } 611 else 612 { 613 decode; 614 double fraction = components.getFraction; 615 double n = countBits(components.getFraction) - 1; 616 return ((-1.0) ^^ components.getSign * 2.0 ^^ ( 617 2.0 ^^ ES * components.getRegime + components.getExponent - n) 618 * fraction); 619 } 620 } 621 } 622 623 // multiplication 624 auto opBinary(string op)(Posit!(NBITS, ES) rhs) if (op == "*") 625 { 626 if (this.isZero || this.isNaR) 627 { 628 return this; 629 } 630 else 631 { 632 if (rhs.isZero || rhs.isNaR) 633 { 634 return rhs; 635 } 636 } 637 638 PositComponents components2 = new PositComponents; 639 decode; 640 components2.fromLong!(NBITS, ES)(rhs.getUnum); 641 642 long sign = components.getSign ^ components2.getSign; 643 644 long scale = (2 ^^ ES * ( 645 components.getRegime + components2.getRegime) 646 + components.getExponent + components2.getExponent); 647 long fraction = components.getFraction * components2.getFraction; 648 649 long fa = floorLog2(components.getFraction); 650 long fb = floorLog2(components2.getFraction); 651 long fc = floorLog2(fraction); 652 653 scale += fc - fa - fb; 654 655 return construct(sign, scale, fraction); 656 } 657 658 // division 659 auto opBinary(string op)(Posit!(NBITS, ES) rhs) if (op == "/") 660 { 661 if (this.isZero || this.isNaR) 662 { 663 return this; 664 } 665 else 666 { 667 if (rhs.isZero || rhs.isNaR) 668 { 669 return rhs; 670 } 671 } 672 673 PositComponents components2 = new PositComponents; 674 decode; 675 components2.fromLong!(NBITS, ES)(rhs.getUnum); 676 677 long fraction1 = components.getFraction; 678 679 if ((fraction1 & (fraction1 - 1)) == 0) 680 { 681 return this * rhs.reciprocal; 682 } 683 else 684 { 685 long sign = components.getSign ^ components2.getSign; 686 long scale = (2 ^^ ES * ( 687 components.getRegime - components2.getRegime) 688 + components.getExponent - components2.getExponent); 689 long fraction2 = components2.getFraction; 690 auto fractions = alignValues(fraction1, fraction2); 691 import std.bigint; 692 693 auto n = BigInt(fractions[0].to!string); 694 fraction2 = fractions[1]; 695 long fa = floorLog2(n << (NBITS * 4)).to!long; 696 long fb = floorLog2(fraction2); 697 auto fraction = (n << (NBITS * 4) / fraction2).to!long; 698 long fc = floorLog2(fraction); 699 700 scale -= fa - fb - fc; 701 702 return construct(sign, scale, fraction); 703 } 704 } 705 706 override int opCmp(Object o) 707 { 708 int result; 709 if (typeid(o) == typeid(Posit!(NBITS, ES))) 710 { 711 auto a = this.toSignedInteger; 712 auto b = (cast(Posit!(NBITS, ES)) o).toSignedInteger; 713 714 if (a > b) 715 { 716 result = 1; 717 } 718 else 719 { 720 if (a < b) 721 { 722 result = -1; 723 } 724 else 725 { 726 result = 0; 727 } 728 } 729 } 730 return result; 731 } 732 733 // unary minus 734 auto opUnary(string op)() if (op == "-") 735 { 736 Posit!(NBITS, ES) posit = new Posit!(NBITS, ES); 737 posit.fromBits(twoComplement(_unum.to!ulong, NBITS)); 738 return posit; 739 } 740 741 // reciprocal 742 auto reciprocal() 743 { 744 Posit!(NBITS, ES) posit = new Posit!(NBITS, ES); 745 long bits = unsetBit(twoComplement(_unum.to!long, NBITS), NBITS - 1); 746 posit.fromBits(bits); 747 748 return posit; 749 } 750 751 version (linux) 752 { 753 // nice binary representation with color 754 string toBinaryFormatted() 755 { 756 // for sign format (sign is string) (red colored) 757 enum SIGN_FORMAT = "\u001b[41m\u001b[97m\u001b[1m%s\u001b[0m"; 758 // for regime format (regime is string) (yellow colored) 759 enum REGIME_FORMAT = "\u001b[43m\u001b[97m\u001b[1m%s\u001b[0m"; 760 // for exponent format (exponent is string) (blue colored) 761 enum EXPONENT_FORMAT = "\u001b[44m\u001b[97m\u001b[1m%s\u001b[0m"; 762 // for fraction format (fraction is string) (black colored) 763 enum FRACTION_FORMAT = "\u001b[40m\u001b[97m\u001b[1m%s\u001b[0m"; 764 765 // fill the data structure with current data from posit 766 decode; 767 string formattedData; 768 769 // binary string from number 770 auto rawData = ("%0." ~ NBITS.to!string ~ "b").format(_unum); 771 772 // rawData[0] - first digit of binary representation, i.e sign of posit 773 formattedData ~= SIGN_FORMAT.format(rawData[0].to!string); 774 // position of posits components in unsigned his representation 775 auto position = 1 + components.getRegimeLength; 776 // regime started at second position 777 formattedData ~= REGIME_FORMAT.format(rawData[1 .. position]); 778 779 // if exponent exists 780 if (components.getExponentLength != 0) 781 { 782 formattedData ~= EXPONENT_FORMAT.format( 783 rawData[position .. position + components.getExponentLength]); 784 position += components.getExponentLength; 785 } 786 787 // if fraction exists 788 if (components.getFractionLength != 0) 789 { 790 formattedData ~= FRACTION_FORMAT.format(rawData[position .. $]); 791 } 792 793 return formattedData; 794 } 795 } 796 797 // to signed integer 798 auto toSignedInteger() 799 { 800 template SignedType(T) 801 { 802 static if (is(T == ubyte)) 803 alias SignedType = byte; 804 else static if (is(T == ushort)) 805 alias SignedType = short; 806 else static if (is(T == uint)) 807 alias SignedType = int; 808 else static if (is(T == ulong)) 809 alias SignedType = long; 810 else 811 static assert(0); 812 } 813 814 alias SignedUnum = SignedType!Unum; 815 816 SignedUnum unum = cast(SignedUnum) _unum; 817 818 return unum; 819 } 820 821 // to unsigned integer 822 auto toUnsignedInteger() 823 { 824 return _unum; 825 } 826 827 // string representation 828 override string toString() 829 { 830 enum string positFormat = `Posit{%d, %d}(0x%0.` ~ to!string(NBITS >> 2) ~ `x)[%0.32f]`; 831 832 return positFormat.format(NBITS, ES, _unum, cast(double) this); 833 } 834 835 alias components this; 836 } 837 } 838 839 alias Posit8 = Posit!(8, 0); 840 alias Posit16 = Posit!(16, 1); 841 alias Posit32 = Posit!(32, 2); 842 alias SoftFloat = Posit!(8, 2);