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);