1 // conversion_functions.cpp : api experiments for conversion algorithms
2 //
3 // Copyright (C) 2017-2021 Stillwater Supercomputing, Inc.
4 //
5 // This file is part of the universal numbers project, which is released under an MIT Open Source license.
6
7 // minimum set of include files
8 #include "universal/number/posit/posit_impl.hpp"
9 #include "universal/number/posit/manipulators.hpp"
10
11 template<size_t nbits, size_t es>
GenerateLogicPattern(double input,const sw::universal::posit<nbits,es> & presult,const sw::universal::posit<nbits+1,es> & pnext)12 void GenerateLogicPattern(double input, const sw::universal::posit<nbits, es>& presult, const sw::universal::posit<nbits + 1, es>& pnext) {
13 const int VALUE_WIDTH = 15;
14 bool fail = presult != pnext;
15 sw::universal::internal::value<52> v(input);
16 std::cout << std::setw(VALUE_WIDTH) << input << " "
17 << " result " << std::setw(VALUE_WIDTH) << presult
18 << " scale= " << std::setw(3) << presult.scale()
19 << " k= " << std::setw(3) << sw::universal::calculate_k<nbits, es>(v.scale())
20 << " exp= " << std::setw(3) << presult.get_exponent() << " "
21 << presult.get() << " "
22 << pnext.get() << " "
23 << std::setw(VALUE_WIDTH) << pnext << " "
24 << (fail ? "FAIL" : " PASS")
25 << std::endl;
26 }
27
28 template<size_t nbits, size_t es>
GenerateLogicPatternsForDebug()29 void GenerateLogicPatternsForDebug() {
30 // we are going to generate a test set that consists of all posit configs and their midpoints
31 // we do this by enumerating a posit that is 1-bit larger than the test posit configuration
32 const int NR_TEST_CASES = (1 << (nbits + 1));
33 const int HALF = (1 << nbits);
34 sw::universal::posit<nbits + 1, es> pref, pprev, pnext;
35
36 // execute the test
37 const double eps = 1.0e-10; // TODO for big posits, eps is important to resolve differences
38 double da, input;
39 sw::universal::posit<nbits, es> pa;
40 std::cout << sw::universal::dynamic_range(pa) << std::endl;
41 for (size_t i = 0; i < NR_TEST_CASES; i++) {
42 pref.setbits(i);
43 da = double(pref);
44 if (i % 2) {
45 if (i == 1) {
46 // special case of projecting to +minpos
47 // even the -delta goes to +minpos
48 input = da - eps;
49 pa = input;
50 pnext.setbits(i + 1);
51 std::cout << "p"; // indicate that this needs to 'project'
52 GenerateLogicPattern(input, pa, pnext);
53 input = da + eps;
54 pa = input;
55 std::cout << "p"; // indicate that this needs to 'project'
56 GenerateLogicPattern(input, pa, pnext);
57
58 }
59 else if (i == HALF - 1) {
60 // special case of projecting to +maxpos
61 input = da - eps;
62 pa = input;
63 pprev.setbits(HALF - 2);
64 std::cout << "p"; // indicate that this needs to 'project'
65 GenerateLogicPattern(input, pa, pprev);
66 }
67 else if (i == HALF + 1) {
68 // special case of projecting to -maxpos
69 input = da - eps;
70 pa = input;
71 pprev.setbits(HALF + 2);
72 std::cout << "p"; // indicate that this needs to 'project'
73 GenerateLogicPattern(input, pa, pprev);
74 }
75 else if (i == NR_TEST_CASES - 1) {
76 // special case of projecting to -minpos
77 // even the +delta goes to -minpos
78 input = da - eps;
79 pa = input;
80 pprev.setbits(i - 1);
81 std::cout << "p"; // indicate that this needs to 'project'
82 GenerateLogicPattern(input, pa, pprev);
83 input = da + eps;
84 pa = input;
85 std::cout << "p"; // indicate that this needs to 'project'
86 GenerateLogicPattern(input, pa, pprev);
87 }
88 else {
89 // for odd values, we are between posit values, so we create the round-up and round-down cases
90 // round-down
91 input = da - eps;
92 pa = input;
93 pprev.setbits(i - 1);
94 std::cout << "d"; // indicate that this needs to round down
95 GenerateLogicPattern(input, pa, pprev);
96 // round-up
97 input = da + eps;
98 pa = input;
99 pnext.setbits(i + 1);
100 std::cout << "u"; // indicate that this needs to round up
101 GenerateLogicPattern(input, pa, pnext);
102 }
103 }
104 else {
105 // for the even values, we generate the round-to-actual cases
106 if (i == 0) {
107 // special case of projecting to +minpos
108 input = da + eps;
109 pa = input;
110 pnext.setbits(i + 2);
111 std::cout << "p"; // indicate that this needs to 'project'
112 GenerateLogicPattern(input, pa, pnext);
113 }
114 else if (i == NR_TEST_CASES - 2) {
115 // special case of projecting to -minpos
116 input = da - eps;
117 pa = input;
118 pprev.setbits(NR_TEST_CASES - 2);
119 std::cout << "p"; // indicate that this needs to 'project'
120 GenerateLogicPattern(input, pa, pprev);
121 }
122 else {
123 // round-up
124 input = da - eps;
125 pa = input;
126 std::cout << "u"; // indicate that this needs to round up
127 GenerateLogicPattern(input, pa, pref);
128 // round-down
129 input = da + eps;
130 pa = input;
131 std::cout << "d"; // indicate that this needs to round down
132 GenerateLogicPattern(input, pa, pref);
133 }
134 }
135 }
136 }
137
138 template<size_t nbits>
LowerSegment(sw::universal::bitblock<nbits> & bits,unsigned msb)139 std::string LowerSegment(sw::universal::bitblock<nbits>& bits, unsigned msb) {
140 std::stringstream ss;
141 for (int i = msb; i >= 0; i--) {
142 if (bits.test(i)) {
143 ss << "1";
144 }
145 else {
146 ss << "0";
147 }
148 }
149 return ss.str();
150 }
151 template<size_t src_size, size_t nbits>
CopyLowerSegment(sw::universal::bitblock<src_size> & src,sw::universal::bitblock<nbits> & tgt,unsigned msb=nbits-1)152 void CopyLowerSegment(sw::universal::bitblock<src_size>& src, sw::universal::bitblock<nbits>& tgt, unsigned msb = nbits-1) {
153 for (int i = msb; i >= 0; i--) {
154 tgt[i] = src[i];
155 }
156 }
157 template<size_t nbits, size_t src_size>
CopyInto(sw::universal::bitblock<src_size> & src)158 sw::universal::bitblock<nbits> CopyInto(sw::universal::bitblock<src_size>& src) {
159 sw::universal::bitblock<nbits> tgt;
160 for (int i = nbits - 1; i >= 0; i--) {
161 tgt.set(i, src[i]);
162 }
163 return tgt;
164 }
165
166 // calculate the 2's complement of a 2's complement encoded number
167 template<size_t nbits>
_twos_complement(sw::universal::bitblock<nbits> number)168 sw::universal::bitblock<nbits> _twos_complement(sw::universal::bitblock<nbits> number) {
169 sw::universal::bitblock<nbits> complement;
170 uint8_t _slice = 0;
171 uint8_t carry = 1;
172 for (size_t i = 0; i < nbits; i++) {
173 _slice = uint8_t(!number[i]) + carry;
174 carry = _slice >> 1;
175 complement[i] = (0x1 & _slice);
176 }
177 return complement;
178 }
179
180 template<size_t nbits>
increment_unsigned(sw::universal::bitblock<nbits> & number,int nrBits=nbits-1)181 bool increment_unsigned(sw::universal::bitblock<nbits>& number, int nrBits = nbits - 1) {
182 bool carry = 1; // ripple carry
183 int lsb = nbits - nrBits;
184 for (size_t i = lsb; i < nbits; i++) {
185 bool _a = number[i];
186 number[i] = _a ^ carry;
187 carry = (_a & false) | (carry & (_a ^ false));
188 }
189 return carry;
190 }
191
192 // increment the input bitblock in place, and return true if there is a carry generated.
193 template<size_t nbits>
increment_bitblock(sw::universal::bitblock<nbits> & number)194 bool increment_bitblock(sw::universal::bitblock<nbits>& number) {
195 bool carry = true; // ripple carry
196 for (size_t i = 0; i < nbits; i++) {
197 bool _a = number[i];
198 number[i] = _a ^ carry;
199 carry = carry & (_a ^ false);
200 }
201 return carry;
202 }
203
204 // decrement the input bitblock in place, and return true if there is a borrow generated.
205 template<size_t nbits>
decrement_bitblock(sw::universal::bitblock<nbits> & number)206 bool decrement_bitblock(sw::universal::bitblock<nbits>& number) {
207 bool borrow = true;
208 for (size_t i = 0; i < nbits; i++) {
209 bool _a = number[i];
210 number[i] = _a ^ borrow;
211 borrow = (!(!_a ^ true) & borrow);
212 }
213 return borrow;
214 }
215
216 // DANGER: this depends on the implicit type conversion of number to a uint64_t to sign extent a 2's complement number system
217 // if nbits > 64 then this code breaks.
218 template<size_t nbits, class Type>
_convert_to_bitblock(Type number)219 sw::universal::bitblock<nbits> _convert_to_bitblock(Type number) {
220 sw::universal::bitblock<nbits> _Bits;
221 uint64_t mask = uint64_t(1);
222 for (size_t i = 0; i < nbits; i++) {
223 _Bits[i] = mask & number;
224 mask <<= 1;
225 }
226 return _Bits;
227 }
228
229 // sticky bit representation of all the bits from [msb, lsb], that is, msb is included
230 template<size_t nbits>
_anyAfter(const sw::universal::bitblock<nbits> & bits,unsigned msb)231 bool _anyAfter(const sw::universal::bitblock<nbits>& bits, unsigned msb) {
232 bool running = false;
233 for (int i = msb; i >= 0; i--) {
234 running |= bits.test(i);
235 }
236 return running;
237 }
238
239 /*
240 p[x_] := Module[{s, y, r, e, f, run, reg, esval, nf, len, fv, sb, pt, blast, bafter, bsticky, rb, ptt, p},
241 s = Boole[x < 0];
242 y = Max[minpos, Min[maxpos, Abs[x]]];
243 r = Boole[y ≥ 1];
244 e = Floor[Log[2, y]];
245 f = y / 2^e - 1;
246 run = Abs[Floor[e / 2^es]] + r;
247 reg = BitOr[BitShiftLeft[r * (2^run - 1), 1], BitXor[1, r]];
248 esval = Mod[e, 2^es];
249 nf = Max[0, (nbits + 1) - (2 + run + es)];
250 len = 1 + Max[nbits + 1, 2 + run + es];
251 fv = Floor[f * 2^nf];
252 sb = Boole[f * 2^nf > fv];
253 pt = BitOr[BitShiftLeft[reg, es + nf + 1], BitShiftLeft[esval, nf + 1], BitShiftLeft[fv, 1], sb];
254 blast = BitGet[pt, len - nbits];
255 bafter = BitGet[pt, len - nbits - 1];
256 bsticky = Boole[BitAnd[2len-nbits-1 - 1, pt] > 0];
257 rb = BitOr[BitAnd[blast, bafter], BitAnd[bafter, bsticky]];
258 ptt = BitShiftRight[pt, len - nbits] + rb;
259 BitXor[s * (2^nbits - 1), ptt] + s]
260 */
261 template<size_t nbits, size_t es>
convert_to_posit(float x,bool bPrintIntermediateSteps=false)262 void convert_to_posit(float x, bool bPrintIntermediateSteps = false) {
263 using namespace sw::universal;
264 using namespace sw::universal::internal;
265
266 std::cout << "convert to posit<" << nbits << "," << es << ">\n";
267 // obtain the sign/scale/fraction representation of a float
268 constexpr int nrfbits = std::numeric_limits<float>::digits - 1;
269 internal::value<nrfbits> v(x);
270 // ignore for the sake of clarity the special cases 0 and NaR (Not a Real)
271 //bool sign = v.sign();
272 int scale = v.scale();
273 bitblock<nrfbits> bits = v.fraction();
274 std::cout << v << " = " << to_triple(v) << '\n';
275
276 float minpos = (float)posit<nbits, es>(SpecificValue::minpos);
277 float maxpos = (float)posit<nbits, es>(SpecificValue::maxpos);
278
279 const size_t pt_len = nbits + 3 + es;
280 internal::bitblock<pt_len> pt_bits;
281 internal::bitblock<pt_len> regime;
282 internal::bitblock<pt_len> exponent;
283 internal::bitblock<pt_len> fraction;
284 internal::bitblock<pt_len> sticky_bit;
285
286 bool s = (x < 0);
287 if (bPrintIntermediateSteps) std::cout << "s = " << (s ? "negative" : "positive") << '\n';
288 if (bPrintIntermediateSteps) std::cout << "x = " << (float)x << '\n';
289 if (bPrintIntermediateSteps) std::cout << "Abs(x) = " << (float)std::abs(x) << '\n';
290 float y = std::max<float>(minpos, std::min<float>(maxpos, (float)std::abs(x)));
291 if (bPrintIntermediateSteps) std::cout << "y = " << y << '\n';
292 bool r = (y >= 1.0f);
293 if (bPrintIntermediateSteps) std::cout << "r = " << (r ? "1" : "0") << '\n';
294 #if (defined(__SUNPRO_C) || defined(__SUNPRO_CC)) && ((__SUNPRO_C < 0x5150) || (__SUNPRO_CC < 0x5150))
295 float e = std::floor(log2f(y));
296 #else
297 float e = std::floor(std::log2(y));
298 #endif
299 if (bPrintIntermediateSteps) std::cout << "e = " << e << '\n';
300 float f = y / float(pow(2.0, scale)) - 1.0f;
301 if (bPrintIntermediateSteps) std::cout << "f = " << f << '\n';
302 if (bPrintIntermediateSteps) std::cout << "bits = " << bits << '\n';
303 int run = (int)std::abs(std::floor(e / pow(2, es))) + r;
304 if (bPrintIntermediateSteps) std::cout << "run = " << run << '\n';
305 unsigned _run = (r ? 1 + (scale >> es) : -(scale >> es));
306 if (bPrintIntermediateSteps) std::cout << "_run = " << _run << '\n';
307 // reg = BitOr[BitShiftLeft[r * (2^run - 1), 1], BitXor[1, r]];
308 regime.set(0, 1 ^ r);
309 for (int i = 1; i <= run; i++) regime.set(i, r);
310 if (bPrintIntermediateSteps) std::cout << "reg = " << LowerSegment(regime,run) << '\n';
311 sw::universal::regime<nbits, es> _reg; _reg.assign(scale);
312 if (bPrintIntermediateSteps) std::cout << "_reg = " << _reg << '\n';
313 unsigned esval = scale % (uint32_t(1) << es);
314 if (bPrintIntermediateSteps) std::cout << "esval = " << esval << '\n';
315 exponent = _convert_to_bitblock<pt_len>(esval);
316 unsigned nf = (unsigned)std::max<int>(0, (nbits + 1) - (2 + run + es));
317 if (bPrintIntermediateSteps) std::cout << "nf = " << nf << '\n';
318 // copy the most significant nf fraction bits into fraction
319 for (int i = 0; i < (int)nf; i++) fraction[i] = bits[nrfbits - nf + i];
320 if (bPrintIntermediateSteps) std::cout << "fraction = " << fraction << '\n';
321 float fv = (float)std::floor((double)(f * (unsigned(1) << nf)));
322 if (bPrintIntermediateSteps) std::cout << "fv = " << fv << '\n';
323 bool sb = ((f * (unsigned(1) << nf)) > fv);
324 if (bPrintIntermediateSteps) std::cout << "sb = " << (sb ? "1" : "0") << '\n';
325
326 // construct the bigger posit
327 // pt = BitOr[BitShiftLeft[reg, es + nf + 1], BitShiftLeft[esval, nf + 1], BitShiftLeft[fv, 1], sb];
328 regime <<= es + nf + 1;
329 exponent <<= nf + 1;
330 fraction <<= 1;
331 sticky_bit.set(0, sb);
332
333 if (bPrintIntermediateSteps) {
334 std::cout << "regime = " << regime << '\n';
335 std::cout << "exponent = " << exponent << '\n';
336 std::cout << "fraction = " << fraction << '\n';
337 std::cout << "sticky = " << sticky_bit << '\n';
338 }
339 pt_bits |= regime;
340 pt_bits |= exponent;
341 pt_bits |= fraction;
342 pt_bits |= sticky_bit;
343
344 if (bPrintIntermediateSteps) std::cout << "pt bits = " << pt_bits << '\n';
345 if (bPrintIntermediateSteps) std::cout << "pt bits = " << LowerSegment(pt_bits, 2 + run + es) << '\n';
346 unsigned len = 1 + std::max<unsigned>((nbits + 1), (2 + run + es));
347 if (bPrintIntermediateSteps) std::cout << "pt_len = " << pt_len << '\n';
348 if (bPrintIntermediateSteps) std::cout << "len = " << len << '\n';
349 if (bPrintIntermediateSteps) std::cout << "blast at = " << len - nbits << '\n';
350 bool blast = pt_bits.test(len - nbits);
351 bool bafter = pt_bits.test(len - nbits - 1);
352 bool bsticky = _anyAfter(pt_bits, len - nbits - 1 - 1);
353 if (bPrintIntermediateSteps) std::cout << "blast = " << blast << '\n';
354 if (bPrintIntermediateSteps) std::cout << "bafter = " << bafter << '\n';
355 if (bPrintIntermediateSteps) std::cout << "bsticky = " << bsticky << '\n';
356
357 bool rb = (blast & bafter) | (bafter & bsticky);
358 std::cout << "rb = " << rb << '\n';
359 internal::bitblock<pt_len> ptt = pt_bits;
360 ptt >>= (len - nbits);
361 if (bPrintIntermediateSteps) std::cout << "ptt = " << ptt << '\n';
362 if (rb) increment_bitblock(ptt);
363 if (s) ptt = _twos_complement(ptt);
364 std::cout << "posit<" << nbits << "," << es << "> = " << LowerSegment(ptt, nbits-1) << '\n';
365
366 internal::bitblock<nbits> ptt_t;
367 CopyLowerSegment(ptt, ptt_t);
368 posit<nbits, es> p;
369 p.setbits(ptt_t.to_ullong());
370 std::cout << "p = " << components(p) << '\n';
371 }
372
373 template<size_t nbits, size_t es, size_t nrfbits>
convert_to_posit(sw::universal::value<nrfbits> v,bool bPrintIntermediateSteps=false)374 sw::universal::posit<nbits, es> convert_to_posit(sw::universal::value<nrfbits> v, bool bPrintIntermediateSteps = false) {
375 using namespace sw::universal;
376
377 std::cout << "convert to posit<" << nbits << "," << es << ">\n";
378 // ignore for the sake of clarity the special cases 0 and NaR (Not a Real)
379 bitblock<nrfbits> bits = v.fraction();
380
381 //float minpos = (float)sw::universal::minpos_value<nbits, es>();
382 //float maxpos = (float)sw::universal::maxpos_value<nbits, es>();
383
384 const size_t pt_len = nbits + 3 + es;
385 bitblock<pt_len> pt_bits;
386 bitblock<pt_len> regime;
387 bitblock<pt_len> exponent;
388 bitblock<pt_len> fraction;
389 bitblock<pt_len> sticky_bit;
390
391 bool s = v.sign();
392 int e = v.scale();
393 bool r = (e >= 0);
394
395 unsigned run = (r ? 1 + (e >> es) : -(e >> es));
396 regime.set(0, 1 ^ r);
397 for (unsigned i = 1; i <= run; i++) regime.set(i, r);
398
399 unsigned esval = e % (uint32_t(1) << es);
400 exponent = _convert_to_bitblock<pt_len>(esval);
401 unsigned nf = (unsigned)std::max<int>(0, (nbits + 1) - (2 + run + es));
402 // copy the most significant nf fraction bits into fraction
403 for (int i = 0; i < (int)nf; i++) fraction[i] = bits[nrfbits - nf + i];
404
405 //float f = y / float(pow(2.0, scale)) - 1.0f;
406 //float fv = (float)std::floor((double)(f * (unsigned(1) << nf)));
407 //bool sb = ((f * (unsigned(1) << nf)) > fv);
408 bool sb = anyAfter(bits, nrfbits - 1 - nf);
409
410 // construct the untruncated posit
411 // pt = BitOr[BitShiftLeft[reg, es + nf + 1], BitShiftLeft[esval, nf + 1], BitShiftLeft[fv, 1], sb];
412 regime <<= es + nf + 1;
413 exponent <<= nf + 1;
414 fraction <<= 1;
415 sticky_bit.set(0, sb);
416
417 pt_bits |= regime;
418 pt_bits |= exponent;
419 pt_bits |= fraction;
420 pt_bits |= sticky_bit;
421 std::cout << "pt_bits = " << pt_bits << '\n';
422
423 unsigned len = 1 + std::max<unsigned>((nbits + 1), (2 + run + es));
424 bool blast = pt_bits.test(len - nbits);
425 bool bafter = pt_bits.test(len - nbits - 1);
426 bool bsticky = anyAfter(pt_bits, len - nbits - 1 - 1);
427
428 bool rb = (blast & bafter) | (bafter & bsticky);
429
430 pt_bits <<= pt_len - len;
431 bitblock<nbits> ptt;
432 truncate(pt_bits, ptt);
433 std::cout << "ptt = " << ptt << '\n';
434 //ptt >>= (len - nbits);
435 if (rb) increment_bitblock(ptt);
436 if (s) ptt = twos_complement(ptt);
437 if (bPrintIntermediateSteps) {
438 std::cout << "s = " << (s ? "1" : "0") << '\n';
439 std::cout << "e = " << e << '\n';
440 std::cout << "r = " << (r ? "1" : "0") << '\n';
441 std::cout << "run = " << run << '\n';
442 std::cout << "reg = " << regime << '\n';
443 std::cout << "esval = " << esval << '\n';
444 std::cout << "nf = " << nf << '\n';
445 std::cout << "bits = " << bits << '\n';
446 std::cout << "fraction = " << fraction << '\n';
447 std::cout << "sb = " << sb << '\n';
448 std::cout << "pt_len = " << pt_len << '\n';
449 std::cout << "len = " << len << '\n';
450 std::cout << "blast at = " << len - nbits << '\n';
451 std::cout << "regime = " << regime << '\n';
452 std::cout << "exponent = " << exponent << '\n';
453 std::cout << "fraction = " << fraction << '\n';
454 std::cout << "sticky = " << sticky_bit << '\n';
455 std::cout << "pt_bits = " << pt_bits << '\n';
456 std::cout << "blast = " << blast << '\n';
457 std::cout << "bafter = " << bafter << '\n';
458 std::cout << "bsticky = " << bsticky << '\n';
459 std::cout << "rb = " << rb << '\n';
460
461 std::cout << "ptt = " << ptt << '\n';
462 }
463 std::cout << "posit<" << nbits << "," << es << "> = " << LowerSegment(ptt, nbits - 1) << '\n';
464
465 sw::universal::posit<nbits, es> p;
466 p.set(ptt);
467 std::cout << "p = " << p.to_float() << '\n';
468 return p;
469 }
470
471 // basic concept is that we are building a 'maximum size' posit, apply the rounding to it
472 // and then apply the nbits constraint to truncate to the final posit size.
473 template<size_t nbits, size_t es>
posit_component_conversion(float x,bool bPrintIntermediateSteps=false)474 void posit_component_conversion(float x, bool bPrintIntermediateSteps = false) {
475 sw::universal::internal::value<23> v(x);
476 int scale = v.scale();
477
478 unsigned run = (scale >= 0 ? 1 + (scale >> es) : -scale >> es);
479 int k = sw::universal::calculate_k<nbits, es>(scale);
480 if (bPrintIntermediateSteps) std::cout << "k = " << k << std::endl;
481 sw::universal::regime<nbits, es> _regime;
482 unsigned nr_of_regime_bits = _regime.assign(scale);
483 if (bPrintIntermediateSteps) std::cout << "regime = " << _regime << " rbits " << nr_of_regime_bits << std::endl;
484 sw::universal::exponent<nbits, es> _exponent;
485 _exponent.assign(scale);
486 if (bPrintIntermediateSteps) std::cout << "exponent = " << _exponent << std::endl;
487 unsigned nf = (unsigned)std::max<int>(0, (nbits + 1) - (2 + run + es));
488 if (bPrintIntermediateSteps) std::cout << "nf = " << nf << std::endl;
489 sw::universal::bitblock<23> fraction_bitblock = v.fraction();
490 sw::universal::fraction<23> _fraction;
491 bool sb = _fraction.assign<23>(nf, fraction_bitblock, nf+1); // assign and create sticky bit
492 if (bPrintIntermediateSteps) std::cout << "sb = " << sb << std::endl;
493 // assess if we need to round up the truncated posit
494 /*
495 unsigned len = 1 + std::max<unsigned>((nbits + 1), (2 + run + es));
496 if (bPrintIntermediateSteps) std::cout << "len = " << len << std::endl;
497 if (bPrintIntermediateSteps) std::cout << "blast at = " << len - nbits << std::endl;
498 bool blast = pt_bits.test(len - nbits);
499 bool bafter = pt_bits.test(len - nbits - 1);
500 bool bsticky = Any(pt_bits, len - nbits - 1 - 1);
501 if (bPrintIntermediateSteps) std::cout << "blast = " << blast << std::endl;
502 if (bPrintIntermediateSteps) std::cout << "bafter = " << bafter << std::endl;
503 if (bPrintIntermediateSteps) std::cout << "bsticky = " << bsticky << std::endl;
504 bool rb = (blast & bafter) | (bafter & bsticky);
505 if (bPrintIntermediateSteps) std::cout << "rb = " << rb << std::endl;
506 bitblock<pt_len> ptt = pt_bits;
507 ptt >>= (len - nbits);
508
509 if (roundUp) {
510 bool carry = _fraction.increment();
511 if (carry && es > 0) carry = _exponent.increment();
512 if (carry) carry = _regime.increment();
513 if (carry) std::cout << "Error" << std::endl;
514 }
515 */
516 }
517
518
519
520 // a posit has the form: useed^k * 2^exp * 1.fraction
521 // useed^k is the regime and is encoded by the run length m of:
522 // - a string of 0's for numbers [0,1), and
523 // - a string of 1's for numbers [1,inf)
524
525 // The value k ranges from [1-nbits,nbits-2]
526 // m s-regime k
527 // ...
528 // 4 0-00001 -4
529 // 3 0-0001 -3
530 // 2 0-001 -2
531 // 1 0-01 -1
532 // 1 0-10 0
533 // 2 0-110 1
534 // 3 0-1110 2
535 // 4 0-11110 3
536 // ...
537 //
538
539 // algorithm: convert int64 to posit<nbits,es>
540 // step 1: find base regime
541 // if int64 is positive
542 // base regime = useed ^ k, where k = msb_of_int64 >> es
543 // else
544 // negate int64
545 // base regime = useed ^ k, where k = msb_of_negated_int64 >> es
546 // step 2: find exponent
547 // exp = msb % 2^es
548 // step 3: extract remaining fraction
549 // remove hidden bit
550 // step 4: if int64 is negative, take 2's complement the posit of positive int64 calculated above
551 //
552
553
554
555 constexpr int SE_QUANDRANT = 0;
556 constexpr int NE_QUANDRANT = 1;
557 constexpr int NW_QUANDRANT = 2;
558 constexpr int SW_QUANDRANT = 3;
559
560 template<size_t nbits, size_t es>
GenerateTestSample(int quadrant,bool bPrintIntermediateSteps=false)561 void GenerateTestSample(int quadrant, bool bPrintIntermediateSteps = false) {
562 using namespace sw::universal;
563
564 posit<nbits, es> p;
565 std::cout << "\n\n-------------------------------------------\n";
566 std::cout << dynamic_range(p) << '\n';
567 std::cout << components_to_string(p) << '\n';
568
569 int index;
570 float sign_factor = 1.0;
571 switch (quadrant) {
572 case SE_QUANDRANT:
573 index = 1;
574 break;
575 case NE_QUANDRANT:
576 index = ( int(1) << (nbits-1) ) - 2;
577 break;
578 case NW_QUANDRANT:
579 index = (int(1) << (nbits - 1) ) + 1;
580 sign_factor = -1.0;
581 break;
582 case SW_QUANDRANT:
583 index = -2;
584 sign_factor = -1.0;
585 break;
586 }
587 p.setbits(index); std::cout << components_to_string(p) << '\n'; float f1 = p.to_float();
588 p.setbits(index+1); std::cout << components_to_string(p) << '\n'; float f2 = p.to_float();
589 p.setbits(index+2); std::cout << components_to_string(p) << '\n'; float f3 = p.to_float();
590
591 float eps = float(f1 / 100000.0);
592 float f_mineps, f, f_pluseps;
593 std::string roundingType;
594 if (es > 0) {
595 // geometric rounding in this region
596 f = sign_factor * std::sqrt(f1 * f2);
597 roundingType = "geometric";
598 } else {
599 // arithmetic rounding in this region
600 f = (float)((f1 + f2)/2.0);
601 roundingType = "arithmetic";
602 }
603 f_mineps = (float)(f - eps);
604 f_pluseps = (float)(f + eps);
605 internal::value<23> v_mineps(f_mineps);
606 internal::value<23> v(f);
607 internal::value<23> v_pluseps(f_pluseps);
608 std::cout << roundingType << " mean - eps: " << f_mineps << " " << to_triple(v_mineps) << '\n';
609 std::cout << roundingType << " mean : " << f << " " << to_triple(v) << '\n';
610 std::cout << roundingType << " mean + eps: " << f_pluseps << " " << to_triple(v_pluseps) << '\n';
611 convert_to_posit<nbits, es>(f_mineps, bPrintIntermediateSteps);
612 posit_component_conversion<nbits, es>(f_mineps, bPrintIntermediateSteps);
613 convert_to_posit<nbits, es>(f, bPrintIntermediateSteps);
614 posit_component_conversion<nbits, es>(f, bPrintIntermediateSteps);
615 convert_to_posit<nbits, es>(f_pluseps, bPrintIntermediateSteps);
616 posit_component_conversion<nbits, es>(f_pluseps, bPrintIntermediateSteps);
617
618 posit<nbits, es> p1(f1), p2(f2), p3(f3);
619 std::cout << components_to_string(p1) << '\n';
620 std::cout << components_to_string(p2) << '\n';
621 std::cout << components_to_string(p3) << '\n';
622 }
623
624 #define MANUAL_TESTING 1
625 #define STRESS_TESTING 0
626
main()627 int main()
628 try {
629 using namespace sw::universal;
630
631 //bool bReportIndividualTestCases = false;
632 int nrOfFailedTestCases = 0;
633
634 std::string tag = "Conversion failed: ";
635
636 #if MANUAL_TESTING
637 const size_t nbits = 5;
638 const size_t es = 0;
639 /*
640 bool bPrintIntermediateResults = true;
641 GenerateTestSample<nbits, es>(SE_QUANDRANT, bPrintIntermediateResults);
642 GenerateTestSample<nbits, es>(NE_QUANDRANT, bPrintIntermediateResults);
643 GenerateTestSample<nbits, es>(NW_QUANDRANT, bPrintIntermediateResults);
644 GenerateTestSample<nbits, es>(SW_QUANDRANT, bPrintIntermediateResults);
645 */
646 float f1 = 1.125f;
647 float f2 = 1.126f;
648 float f3 = 1.25f;
649 convert_to_posit<nbits, es>(f1, true);
650 convert_to_posit<nbits, es>(f2, true);
651 convert_to_posit<nbits, es>(f3, true);
652
653 #else
654 ReportPositScales();
655
656 GenerateLogicPatternsForDebug<5, 0>();
657 GenerateLogicPatternsForDebug<5, 1>();
658 GenerateLogicPatternsForDebug<5, 2>();
659
660 #if STRESS_TESTING
661
662 #endif // STRESS_TESTING
663
664 #endif // MANUAL_TESTING
665
666 return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
667 }
668 catch (char const* msg) {
669 std::cerr << msg << std::endl;
670 return EXIT_FAILURE;
671 }
672 catch (const sw::universal::posit_arithmetic_exception& err) {
673 std::cerr << "Uncaught posit arithmetic exception: " << err.what() << std::endl;
674 return EXIT_FAILURE;
675 }
676 catch (const sw::universal::posit_internal_exception& err) {
677 std::cerr << "Uncaught posit internal exception: " << err.what() << std::endl;
678 return EXIT_FAILURE;
679 }
680 catch (const std::runtime_error& err) {
681 std::cerr << "Uncaught runtime exception: " << err.what() << std::endl;
682 return EXIT_FAILURE;
683 }
684 catch (...) {
685 std::cerr << "Caught unknown exception" << std::endl;
686 return EXIT_FAILURE;
687 }
688
689
690