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