1 #pragma once
2 //  bitblock.hpp : bitblock class
3 //
4 // Copyright (C) 2017-2018 Stillwater Supercomputing, Inc.
5 //
6 // This file is part of the universal numbers project, which is released under an MIT Open Source license.
7 
8 #include <sstream>
9 
10 // this should be removed when we have made the transition away from std::bitset to sw::unum::bitblock
11 #include <cassert>
12 #include "ubb.h"
13 
14 
15 namespace sw { namespace universal {
16 
17 		/**
18 		 @brief templated class implementing efficient multi-precision binary arithmetic and logic
19 		 */
20 		template<size_t nbits>
21 		class bitblock : public universal_bitset::bitset<nbits> {
22 		public:
bitblock()23 			bitblock() {
24 				setzero();
25 			}
26 
27 			bitblock(const bitblock&) = default;
28 			bitblock(bitblock&&) = default;
29 			bitblock& operator=(const bitblock&) = default;
30 			bitblock& operator=(bitblock&&) = default;
31 
32 			// assignment operators for native types
operator =(signed char rhs)33 			bitblock& operator=(signed char rhs) { universal_bitset::bitset<nbits>::operator=(rhs); return *this; }
operator =(short rhs)34 			bitblock& operator=(short rhs) { universal_bitset::bitset<nbits>::operator=(rhs); return *this;	}
operator =(int rhs)35 			bitblock& operator=(int rhs) { universal_bitset::bitset<nbits>::operator=(rhs); return *this; }
operator =(long rhs)36 			bitblock& operator=(long rhs) { universal_bitset::bitset<nbits>::operator=(rhs); return *this; }
operator =(long long rhs)37 			bitblock& operator=(long long rhs) { universal_bitset::bitset<nbits>::operator=(rhs); return *this;	}
operator =(char rhs)38 			bitblock& operator=(char rhs) { universal_bitset::bitset<nbits>::operator=(rhs); return *this; }
operator =(unsigned short rhs)39 			bitblock& operator=(unsigned short rhs) {universal_bitset::bitset<nbits>::operator=(rhs); return *this; }
operator =(unsigned int rhs)40 			bitblock& operator=(unsigned int rhs) { universal_bitset::bitset<nbits>::operator=(rhs); return *this; }
operator =(unsigned long rhs)41 			bitblock& operator=(unsigned long rhs) { universal_bitset::bitset<nbits>::operator=(rhs); return *this;	}
operator =(unsigned long long rhs)42 			bitblock& operator=(unsigned long long rhs) { universal_bitset::bitset<nbits>::operator=(rhs); return *this; }
43 
to_ullong() const44 			unsigned long long to_ullong() const {
45 				return this->M_do_to_ullong();
46 			}
47 
setzero()48 			void setzero() {
49 				universal_bitset::bitset<nbits>::reset();
50 			}
51 
load_bits(const std::string & string_of_bits)52 			bool load_bits(const std::string& string_of_bits) {
53 				if (string_of_bits.length() != nbits)
54 					return false;
55 
56 				setzero();
57 				int msb = nbits - 1;
58 
59 				for (std::string::const_iterator it = string_of_bits.begin(); it != string_of_bits.end(); ++it) {
60 
61 					if (*it == '0') {
62 						this->reset(msb--);
63 					}
64 					else if (*it == '1') {
65 						this->set(msb--);
66 					}
67 					else {
68 						return false;
69 					}
70 				}
71 				return true;
72 			}
73 		};
74 
75 		/**
76 		   @param val is a bitblock value.
77 
78 		   @return value of sign bit.
79 		 */
80 		template<size_t nbits>
getSignBit(const bitblock<nbits> & val)81 		unsigned int getSignBit(const bitblock<nbits>& val) {
82 			return val[nbits - 1];
83 		}
84 
85 		// logic operators:  unsigned (in)equality inherited.
86 
87 		// this comparison is for a two's complement number only
88 		template<size_t nbits>
lessThan(const bitblock<nbits> & lhs,const bitblock<nbits> & rhs)89 		bool lessThan(const bitblock<nbits>& lhs,
90 			const bitblock<nbits>& rhs) {
91 			// Short-circuits on disparate signs:
92 			if (getSignBit(lhs) == 0 && getSignBit(rhs) == 1) {
93 				return false;
94 			}
95 			if (getSignBit(lhs) == 1 && getSignBit(rhs) == 0) {
96 				return true;
97 			}
98 
99 			// Sign bits agree, can compare bit patterns directly:
100 			return lhs < rhs;
101 		}
102 
103 		/**
104 		  @brief Vestigial alias for '<' operator:  unsigned.
105 		*/
106 		template<size_t nbits>
lessThan_unsigned(const bitblock<nbits> & lhs,const bitblock<nbits> & rhs)107 		bool lessThan_unsigned(const bitblock<nbits> &lhs,
108 			const bitblock<nbits> &rhs) {
109 			return lhs < rhs;
110 		}
111 
112 		////////////////////////////// ARITHMETIC functions
113 		//////////////////////////////////////////////////////////////////////////////////////
114 		// increment and decrement
115 
116 		/**
117 		   @brief Increments value in place.
118 
119 		   @param[in, out] number is the value to decrement.
120 
121 		   @return true iff the sign has changed from nonnegative to negative.
122 		 */
123 		template<size_t nbits>
increment_bitset(bitblock<nbits> & number)124 		bool increment_bitset(bitblock<nbits>& number) {
125 			unsigned int signPre = getSignBit(number);
126 			number.increment();
127 			unsigned int signPost = getSignBit(number);
128 			return signPost > signPre;
129 		}
130 
131 		// increment the input bitset in place, and return true if there is a carry generated.
132 		// The input number is assumed to be right adjusted starting at nbits-nrBits
133 		// [1 0 0 0] nrBits = 0 is a noop as there is no word to increment
134 		// [1 0 0 0] nrBits = 1 is the word [1]
135 		// [1 0 0 0] nrBits = 2 is the word [1 0]
136 		// [1 1 0 0] nrBits = 3 is the word [1 1 0], etc.
137 
138 		template<size_t nbits>
increment_unsigned(bitblock<nbits> & number,int nrBits=nbits-1)139 		bool increment_unsigned(bitblock<nbits>& number, int nrBits = nbits - 1) {
140 			bool carry = 1;  // ripple carry
141 			int lsb = nbits - nrBits;
142 			for (size_t i = lsb; i < nbits; i++) {
143 				bool _a = number[i];
144 				number[i] = _a ^ carry;
145 				carry = (_a & false) | (carry & (_a ^ false));
146 			}
147 			return carry;
148 		}
149 
150 
151 		/**
152 		   @brief Decrements value in place.
153 
154 		   @param[in, out] number is the value to decrement.
155 
156 		   @return true iff the sign has changed from negative to nonnegative.
157 		 */
158 		template<size_t nbits>
decrement_bitset(bitblock<nbits> & number)159 		bool decrement_bitset(bitblock<nbits>& number) {
160 			unsigned int signPre = getSignBit(number);
161 			(void)number.decrement();
162 			unsigned int signPost = getSignBit(number);
163 			return signPost < signPre;
164 		}
165 
166 
167 		//////////////////////////////////////////////////////////////////////////////////////
168 
169 		/**
170 		   @brief Adds two nbit summands into nbit+1 result.
171 
172 		   @param a is an addend.
173 
174 		   @param b is an addend.
175 
176 		   @param[out] sum contains the sum, with carry bit set.
177 
178 		   @return true iff carry precipitated.
179 		*/
180 		template<size_t nbits>
add_unsigned(const bitblock<nbits> & a,const bitblock<nbits> & b,bitblock<nbits+1> & sum)181 		bool add_unsigned(const bitblock<nbits> &a,
182 			const bitblock<nbits> &b,
183 			bitblock<nbits + 1>& sum) {
184 			return sum.add(a, b);
185 		}
186 
187 		// subtract bitsets a and b and return result in bitset dif. Return true if there is a borrow generated.
188 		template<size_t nbits>
subtract_unsigned(bitblock<nbits> a,bitblock<nbits> b,bitblock<nbits+1> & dif)189 		bool subtract_unsigned(bitblock<nbits> a,
190 			bitblock<nbits> b,
191 			bitblock<nbits + 1>& dif) {
192 			return dif.sub(a, b);
193 		}
194 
195 		template<size_t nbits>
add_signed_magnitude(bitblock<nbits> a,bitblock<nbits> b,bitblock<nbits> & sum)196 		bool add_signed_magnitude(bitblock<nbits> a,
197 			bitblock<nbits> b,
198 			bitblock<nbits>& sum) {
199 			uint8_t carry = 0;
200 			bool sign_a = a.test(nbits - 1);
201 			if (sign_a) {
202 				a = a.flip();
203 				carry += 1;
204 			}
205 			bool sign_b = b.test(nbits - 1);
206 			if (sign_b) {
207 				b = b.flip();
208 				carry += 1;
209 			}
210 			for (int i = 0; i < nbits - 2; i++) {
211 				bool _a = a[i];
212 				bool _b = b[i];
213 				sum[i] = _a ^ _b ^ carry;
214 				carry = (_a & _b) | (carry & (_a ^ _b));
215 			}
216 
217 			return carry;
218 		}
219 
220 
221 		template<size_t nbits>
subtract_signed_magnitude(bitblock<nbits> a,bitblock<nbits> b,bitblock<nbits> & diff)222 		bool subtract_signed_magnitude(bitblock<nbits> a,
223 			bitblock<nbits> b,
224 			bitblock<nbits>& diff) {
225 			bool sign_a = a.test(nbits - 1);
226 			bool sign_b = b.test(nbits - 1);
227 			std::cerr << "subtract_signed_magnitude not implemented yet" << std::endl;
228 			return false;
229 		}
230 
231 
232 		// integral type to bitblock transformations
233 		// we are using a full nbits sized bitset even though nbits-3 is the maximum fraction
234 		// a posit would contain. However, we need an extra bit after the cut-off to make the
235 		// round up/down decision. The <nbits-something> size created a lot of sw complexity
236 		// that isn't worth the trouble, so we are simplifying and simply manage a full nbits
237 		// of fraction bits.
238 
239 		template<size_t nbits>
extract_23b_fraction(uint32_t _23b_fraction_without_hidden_bit)240 		bitblock<nbits> extract_23b_fraction(uint32_t _23b_fraction_without_hidden_bit) {
241 			bitblock<nbits> _fraction;
242 			uint32_t mask = uint32_t(0x00400000ul);
243 			unsigned int ub = (nbits < 23 ? nbits : 23);
244 			for (unsigned int i = 0; i < ub; i++) {
245 				_fraction[nbits - 1 - i] = _23b_fraction_without_hidden_bit & mask;
246 				mask >>= 1;
247 			}
248 			return _fraction;
249 		}
250 
251 		template<size_t nbits>
extract_52b_fraction(uint64_t _52b_fraction_without_hidden_bit)252 		bitblock<nbits> extract_52b_fraction(uint64_t _52b_fraction_without_hidden_bit) {
253 			bitblock<nbits> _fraction;
254 			uint64_t mask = uint64_t(0x0008000000000000ull);
255 			unsigned int ub = (nbits < 52 ? nbits : 52);
256 			for (unsigned int i = 0; i < ub; i++) {
257 				_fraction[nbits - 1 - i] = _52b_fraction_without_hidden_bit & mask;
258 				mask >>= 1;
259 			}
260 			return _fraction;
261 		}
262 
263 
264 		template<size_t nbits>
extract_63b_fraction(uint64_t _63b_fraction_without_hidden_bit)265 		bitblock<nbits> extract_63b_fraction(uint64_t _63b_fraction_without_hidden_bit) {
266 			bitblock<nbits> _fraction;
267 			uint64_t mask = uint64_t(0x4000000000000000ull);
268 			unsigned int ub = (nbits < 63 ? nbits : 63);
269 			for (unsigned int i = 0; i < ub; i++) {
270 				_fraction[nbits - 1 - i] = _63b_fraction_without_hidden_bit & mask;
271 				mask >>= 1;
272 			}
273 			return _fraction;
274 		}
275 
276 		// 128 bit unsigned int mapped to two uint64_t elements
277 		typedef struct __uint128 {
278 			uint64_t lower;
279 			uint64_t upper;
280 		} uint128;
281 
282 
283 		// take in a long double mapped to two uint64_t elements
284 		template<size_t nbits>
extract_long_double_fraction(uint128 * _112b_fraction_without_hidden_bit)285 		bitblock<nbits> extract_long_double_fraction(uint128* _112b_fraction_without_hidden_bit) {
286 			bitblock<nbits> _fraction;
287 			int msb = nbits - 1;
288 			uint64_t mask = uint64_t(0x0000800000000000ull);
289 			unsigned int ub = (nbits < 48 ? nbits : 48); // 48 bits in the upper half
290 			for (unsigned int i = 0; i < ub; i++) {
291 				_fraction[msb--] = _112b_fraction_without_hidden_bit->upper & mask;
292 				mask >>= 1;
293 			}
294 			mask = uint64_t(0x8000000000000000ull);
295 			ub = (nbits < 112 - 48 ? nbits : 112 - 48); // max 64 bits in the lower half
296 			for (unsigned int i = 0; i < ub; i++) {
297 				_fraction[msb--] = _112b_fraction_without_hidden_bit->lower & mask;
298 				mask >>= 1;
299 			}
300 			return _fraction;
301 		}
302 
303 		template<size_t nbits>
copy_integer_fraction(unsigned long long _fraction_without_hidden_bit)304 		bitblock<nbits> copy_integer_fraction(unsigned long long _fraction_without_hidden_bit) {
305 			bitblock<nbits> _fraction;
306 			uint64_t mask = uint64_t(0x8000000000000000ull);
307 			unsigned int ub = (nbits < 64 ? nbits : 64);
308 			for (unsigned int i = 0; i < ub; i++) {
309 				_fraction[nbits - 1 - i] = _fraction_without_hidden_bit & mask;
310 				mask >>= 1;
311 			}
312 			return _fraction;
313 		}
314 
315 
316 		////////////////////////////////////////////////////////////////////////////////////////
317 		// bitset copy and slice operators
318 
319 		// copy a bitset into a bigger bitset starting at position indicated by the shift value
320 		template<size_t src_size, size_t tgt_size>
copy_into(const bitblock<src_size> & src,size_t shift,bitblock<tgt_size> & tgt)321 		void copy_into(const bitblock<src_size>& src, size_t shift, bitblock<tgt_size>& tgt) {
322 			tgt.reset();
323 			for (size_t i = 0; i < src_size; i++)
324 				tgt.set(i + shift, src[i]);
325 		}
326 
327 
328 		// copy a slice of a bitset into a bigger bitset starting at position indicated by the shift value
329 		template<size_t src_size, size_t tgt_size>
copy_slice_into(bitblock<src_size> & src,bitblock<tgt_size> & tgt,size_t begin=0,size_t end=src_size,size_t shift=0)330 		void copy_slice_into(bitblock<src_size>& src, bitblock<tgt_size>& tgt, size_t begin = 0, size_t end = src_size, size_t shift = 0) {
331 			// do NOT reset the target!!!
332 			if (end <= src_size) throw iteration_bound_too_large{};
333 			if (end + shift < tgt_size) throw iteration_bound_too_large{};
334 			for (size_t i = begin; i < end; i++)
335 				tgt.set(i + shift, src[i]);
336 		}
337 
338 		template<size_t from, size_t to, size_t src_size>
fixed_subset(const bitblock<src_size> & src)339 		bitblock<to - from> fixed_subset(const bitblock<src_size>& src) {
340 			static_assert(from <= to, "from cannot be larger than to");
341 			static_assert(to <= src_size, "to is larger than src_size");
342 
343 			bitblock<to - from> result;
344 			for (size_t i = 0, end = to - from; i < end; ++i)
345 				result[i] = src[i + from];
346 
347 			return result;
348 		}
349 
350 		//////////////////////////////////////////////////////////////////////////////////////
351 		// multiply and divide
352 
353 
354 		// multiply bitsets a and b and return result in bitset result.
355 		template<size_t operand_size>
multiply_unsigned(const bitblock<operand_size> & a,const bitblock<operand_size> & b,bitblock<2* operand_size> & result)356 		void multiply_unsigned(const bitblock<operand_size>& a, const bitblock<operand_size>& b, bitblock<2 * operand_size>& result) {
357 			constexpr size_t result_size = 2 * operand_size;
358 			bitblock<result_size> addend;
359 			result.reset();
360 			if (a.test(0)) {
361 				copy_into<operand_size, result_size>(b, 0, result);
362 			}
363 			for (size_t i = 1; i < operand_size; i++) {
364 				if (a.test(i)) {
365 					copy_into<operand_size, result_size>(b, i, addend);
366 					(void)result.add(addend);
367 					// we should never have a carry:  assert(carry == false);
368 				}
369 			}
370 		}
371 
372 
373 		// divide bitsets a and b and return result in bitset result.
374 		template<size_t operand_size>
integer_divide_unsigned(const bitblock<operand_size> & a,const bitblock<operand_size> & b,bitblock<2* operand_size> & result)375 		void integer_divide_unsigned(const bitblock<operand_size>& a,
376 			const bitblock<operand_size>& b,
377 			bitblock<2 * operand_size>& result) {
378 			bitblock<operand_size> subtractand, accumulator;
379 			result.reset();
380 			accumulator = a;
381 			int msb = findMostSignificantBit(b);
382 			if (msb < 0) {
383 				throw integer_divide_by_zero{};
384 			}
385 
386 			const unsigned int shift = operand_size - msb - 1;
387 			// prepare the subtractand
388 			subtractand = b;
389 			subtractand <<= shift;
390 			for (int i = shift; i >= 0; --i) {
391 				if (subtractand <= accumulator) {
392 					(void)accumulator.sub(subtractand);
393 					result.set(i);
394 				}
395 				else {
396 					result.reset(i);
397 				}
398 				subtractand >>= 1;
399 			}
400 		}
401 
402 
403 		// divide bitsets a and b and return result in bitset result.
404 		// By providing more bits in the result, the algorithm will fill these with fraction bits if available.
405 		// Radix point must be maintained by calling function.
406 		template<size_t operand_size, size_t result_size>
divide_with_fraction(const bitblock<operand_size> & a,const bitblock<operand_size> & b,bitblock<result_size> & result)407 		void divide_with_fraction(const bitblock<operand_size>& a,
408 			const bitblock<operand_size>& b,
409 			bitblock<result_size>& result) {
410 			bitblock<result_size> subtractand, accumulator;
411 			result.reset();
412 			copy_into<operand_size, result_size>(a, result_size - operand_size, accumulator);
413 			int msb = findMostSignificantBit(b);
414 			if (msb < 0) {
415 				throw integer_divide_by_zero{};
416 			}
417 
418 			int shift = operand_size - msb - 1;
419 			// prepare the subtractand
420 			copy_into<operand_size, result_size>(b, result_size - operand_size, subtractand);
421 			subtractand <<= shift;
422 			for (int i = result_size - msb - 1; i >= 0; --i) {
423 				//std::cout << "accumulator " << accumulator << std::endl;
424 				//std::cout << "subtractand " << subtractand << std::endl;
425 				if (subtractand <= accumulator) {
426 					(void)accumulator.sub(subtractand);
427 					//assert(borrow == false);
428 					result.set(i);
429 				}
430 				else {
431 					result.reset(i);
432 				}
433 				//std::cout << "result      " << result << std::endl;
434 				subtractand >>= 1;
435 			}
436 		}
437 
438 		//////////////////////////////////////////////////////////////////////////////////////
439 		// truncating and rounding
440 
441 		// truncate right-side
442 		template<size_t src_size, size_t tgt_size>
truncate(bitblock<src_size> & src,bitblock<tgt_size> & tgt)443 		void truncate(bitblock<src_size>& src, bitblock<tgt_size>& tgt) {
444 			tgt.reset();
445 			for (size_t i = 0; i < tgt_size; i++)
446 				tgt.set(tgt_size - 1 - i, src[src_size - 1 - i]);
447 		}
448 
449 
450 		// round
451 		template<size_t tgt_size, size_t src_size>
452 		struct round_t
453 		{
evalsw::universal::round_t454 			static bitblock<tgt_size> eval(const bitblock<src_size>& src, size_t n)
455 			{
456 				static_assert(src_size > 0 && tgt_size > 0, "We don't bother with empty sets.");
457 				if (n >= src_size)
458 					throw round_off_all{};
459 
460 				// look for cut-off leading bits
461 				for (size_t leading = tgt_size + n; leading < src_size; ++leading)
462 					if (src[leading])
463 						throw cut_off_leading_bit{};
464 
465 				bitblock<tgt_size> result((src >> n).to_ullong()); // convert to size_t to deal with different sizes
466 				if (n > 0 && src[n - 1]) {                                // round up potentially if first cut-off bit is true
467 #         ifdef POSIT_ROUND_TIES_AWAY_FROM_ZERO             // TODO: Evil hack to be consistent with assign_fraction, for testing only
468 					result = result.to_ullong() + 1;
469 #         else
470 
471 					bool more_bits = false;
472 					for (long i = 0; i + 1 < n && !more_bits; ++i)
473 						more_bits |= src[i];
474 					if (more_bits) {
475 						result = result.to_ullong() + 1;                // increment_unsigned is ambiguous
476 					}
477 					else {                                            // tie: round up odd number
478 #             ifndef POSIT_ROUND_TIES_TO_ZERO               // TODO: evil hack to be removed later
479 						if (result[0])
480 							result = result.to_ullong() + 1;
481 #             endif
482 					}
483 #         endif
484 
485 				}
486 				return result;
487 			}
488 		};
489 
490 		template<size_t src_size>
491 		struct round_t<0, src_size>
492 		{
evalsw::universal::round_t493 			static bitblock<0> eval(const bitblock<src_size>&, size_t)
494 			{
495 				return {};
496 			}
497 		};
498 
499 
500 
501 		/** Round off \p n last bits of bitset \p src. Round to nearest resulting in potentially smaller bitset.
502 		 *  Doesn't return carry bit in case of overflow while rounding up! TODO: Check whether we need carry or we require an extra bit for this case.
503 		 */
504 		template<size_t tgt_size, size_t src_size>
round(const bitblock<src_size> & src,size_t n)505 		bitblock<tgt_size> round(const bitblock<src_size>& src, size_t n)
506 		{
507 			return round_t<tgt_size, src_size>::eval(src, n);
508 		}
509 
510 
511 		////////////////////////////// HELPER functions
512 
513 		// Attention!
514 		// Achtung!
515 		// Regardez!
516 		// Waarschuwing!
517 		// DANGER: this depends on the implicit type conversion of number
518 		// to a uint64_t for sign-extending a 2's complement number system.
519 		// If nbits > 64 then this code breaks.
520 		template<size_t nbits, class Type>
convert_to_bitblock(Type number)521 		bitblock<nbits> convert_to_bitblock(Type number) {
522 			bitblock<nbits> bBits;
523 			const uint64_t one = uint64_t(1);
524 			for (std::size_t i = 0; i < nbits; i++) {
525 				bBits[i] = (one << i) & number;
526 			}
527 
528 			return bBits;
529 		}
530 
531 		/**
532 		   @brief Constructs a string of 1's and 0's representing the
533 		   value passed.
534 
535 		   @param bit contains the value to display.
536 
537 		   @return string representing the value.
538 		 */
539 		template<size_t nbits>
to_binary(bitblock<nbits> const & bits)540 		std::string to_binary(bitblock<nbits> const &bits) {
541 			char str[nbits + 1];
542 			str[nbits] = 0;
543 			for (size_t i = 0; i < nbits; i++) {
544 				str[nbits - 1 - i] = bits[i] ? '1' : '0';
545 			}
546 			return std::string(str);
547 		}
548 
549 		template<size_t nbits>
to_hex(bitblock<nbits> bits)550 		std::string to_hex(bitblock<nbits> bits) {
551 			char str[(nbits >> 2) + 2];   // plenty of room
552 			for (size_t i = 0; i < (nbits >> 2) + 2; ++i) str[i] = 0;
553 			const char* hexits = "0123456789ABCDEF";
554 			unsigned int maxHexDigits = (nbits >> 2) + ((nbits % 4) ? 1 : 0);
555 			for (unsigned int i = 0; i < maxHexDigits; i++) {
556 				unsigned int hexit;
557 				switch (nbits) {
558 				case 1:
559 					hexit = bits[0];
560 					break;
561 				case 2:
562 					hexit = (bits[1] << 1) + bits[0];
563 					break;
564 				case 3:
565 					hexit = (bits[2] << 2) + (bits[1] << 1) + bits[0];
566 					break;
567 				default:
568 					hexit = (bits[3] << 3) + (bits[2] << 2) + (bits[1] << 1) + bits[0];
569 					break;
570 				}
571 				str[maxHexDigits - 1 - i] = hexits[hexit];
572 				bits >>= 4;
573 			}
574 			str[maxHexDigits] = 0;  // null terminated string
575 			return std::string(str);
576 		}
577 
578 		// convert a sign/magnitude number to a string
579 		template<size_t nbits>
sign_magnitude_to_string(bitblock<nbits> bits)580 		std::string sign_magnitude_to_string(bitblock<nbits> bits) {
581 			std::stringstream ss;
582 			ss << (bits[nbits - 1] ? "n-" : "p-");
583 			if (nbits < 2) return ss.str();
584 			for (int i = nbits - 2; i >= 0; --i) {
585 				ss << (bits[i] ? "1" : "0");
586 			}
587 			return ss.str();
588 		}
589 
590 
591 		// find the MSB, return position if found, return -1 if no bits are set
592 		template<size_t nbits>
findMostSignificantBit(const bitblock<nbits> & bits)593 		int findMostSignificantBit(const bitblock<nbits>& bits) {
594 			return bits.getMSB();
595 		}
596 
597 		// calculate the 1's complement of a sign-magnitude encoded number
598 
599 		template<size_t nbits>
ones_complement(const bitblock<nbits> & number)600 		bitblock<nbits> ones_complement(const bitblock<nbits> &number) {
601 			bitblock<nbits> complement = number;
602 			complement.flip();
603 			return complement;
604 		}
605 
606 
607 		// calculate the 2's complement of a 2's complement encoded number
608 		template<size_t nbits>
twos_complement(const bitblock<nbits> & number)609 		bitblock<nbits> twos_complement(const bitblock<nbits> &number) {
610 			bitblock<nbits> complement;
611 			uint8_t carry = 1;
612 			for (size_t i = 0; i < nbits; i++) {
613 				uint8_t slice = uint8_t(!number[i]) + carry;
614 				carry = slice >> 1;
615 				complement[i] = (0x1 & slice);
616 			}
617 
618 			return complement;
619 		}
620 
621 
622 		/**
623 		   @brief Flips the sign bit of value passed.
624 
625 		   @param number is a value for which the sign is to be flipped.
626 
627 		   @return new bitset with the sign flipped as compared to number
628 		*/
629 		template<size_t nbits>
flip_sign_bit(const bitblock<nbits> & number)630 		bitblock<nbits> flip_sign_bit(const bitblock<nbits> &number) {
631 			bitblock<nbits> negate = number;
632 			negate.flip(nbits - 1);
633 			return negate;
634 		}
635 
636 		/**
637 		   @return true iff any bit at or right of msb is set.
638 		 */
639 		template<size_t nbits>
anyAfter(const bitblock<nbits> & bits,unsigned msb)640 		bool anyAfter(const bitblock<nbits>& bits, unsigned msb) {
641 			bitblock<nbits> shBits = bits;
642 			shBits <<= (nbits - 1 - msb);
643 			return shBits.count() > 0;
644 		}
645 
646 }} // namespace sw::universal
647