1 // posit_3_0.hpp: specialized 3-bit posit using lookup table arithmetic
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 // DO NOT USE DIRECTLY!
8 // the compile guards in this file are only valid in the context of the specialization logic
9 // configured in the main <universal/posit/posit>
10 
11 #ifndef POSIT_FAST_POSIT_3_0
12 #define POSIT_FAST_POSIT_3_0 0
13 #endif
14 
15 namespace sw::universal {
16 
17 // set the fast specialization variable to indicate that we are running a special template specialization
18 #if POSIT_FAST_POSIT_3_0
19 #ifdef _MSC_VER
20 #pragma message("Fast specialization of posit<3,0>")
21 //#else
22 //#warning("Fast specialization of posit<3,0>")
23 #endif
24 
25 /*  values of a posit<3,0>
26 000 +0
27 001 +0.5
28 010 +1
29 011 +2
30 100 nar
31 101 -2
32 110 -1
33 111 -0.5
34 */
35 constexpr float posit_3_0_values_lookup[8] = {
36 	0.0f, 0.5f, 1.0f, 2.0f, -INFINITY, -2.0f, -1.0f, -0.5f,
37 };
38 
39 constexpr uint8_t posit_3_0_addition_lookup[64] = {
40 	0,1,2,3,4,5,6,7,
41 	1,2,2,3,4,6,7,0,
42 	2,2,3,3,4,6,0,1,
43 	3,3,3,3,4,0,2,2,
44 	4,4,4,4,4,4,4,4,
45 	5,6,6,0,4,5,5,5,
46 	6,7,0,2,4,5,5,6,
47 	7,0,1,2,4,5,6,6,
48 };
49 constexpr uint8_t posit_3_0_subtraction_lookup[64] = {
50 	0,7,6,5,4,3,2,1,
51 	1,0,7,6,4,3,2,2,
52 	2,1,0,6,4,3,3,2,
53 	3,2,2,0,4,3,3,3,
54 	4,4,4,4,4,4,4,4,
55 	5,5,5,5,4,0,6,6,
56 	6,6,5,5,4,2,0,7,
57 	7,6,6,5,4,2,1,0,
58 };
59 constexpr uint8_t posit_3_0_multiplication_lookup[64] = {
60 	0,0,0,0,4,0,0,0,
61 	0,1,1,2,4,6,7,7,
62 	0,1,2,3,4,5,6,7,
63 	0,2,3,3,4,5,5,6,
64 	4,4,4,4,4,4,4,4,
65 	0,6,5,5,4,3,3,2,
66 	0,7,6,5,4,3,2,1,
67 	0,7,7,6,4,2,1,1,
68 };
69 constexpr uint8_t posit_3_0_division_lookup[64] = {
70 	4,0,0,0,4,0,0,0,
71 	4,2,1,1,4,7,7,6,
72 	4,3,2,1,4,7,6,5,
73 	4,3,3,2,4,6,5,5,
74 	4,4,4,4,4,4,4,4,
75 	4,5,5,6,4,2,3,3,
76 	4,5,6,7,4,1,2,3,
77 	4,6,7,7,4,1,1,2,
78 };
79 
80 constexpr uint8_t posit_3_0_reciprocal_lookup[8] = {
81 	4,3,2,1,4,7,6,5,
82 };
83 
84 constexpr bool posit_3_0_less_than_lookup[64] = {
85 	0,1,1,1,0,0,0,0,
86 	0,0,1,1,0,0,0,0,
87 	0,0,0,1,0,0,0,0,
88 	0,0,0,0,0,0,0,0,
89 	1,1,1,1,0,1,1,1,
90 	1,1,1,1,0,0,1,1,
91 	1,1,1,1,0,0,0,1,
92 	1,1,1,1,0,0,0,0,
93 };
94 
95 // specialized posit<3,0>
96 template<>
97 class posit<NBITS_IS_3, ES_IS_0> {
98 public:
99 	static constexpr size_t nbits = NBITS_IS_3;
100 	static constexpr size_t es = ES_IS_0;
101 	static constexpr size_t sbits = 1;
102 	static constexpr size_t rbits = nbits - sbits;
103 	static constexpr size_t ebits = es;
104 	static constexpr size_t fbits = 0;
105 	static constexpr size_t fhbits = fbits + 1;
106 	static constexpr uint8_t index_shift = NBITS_IS_3;
107 	static constexpr uint8_t bit_mask = 0x07;  // last three bits
108 	static constexpr uint8_t nar_encoding = 0x04;
109 	static constexpr uint8_t one_encoding = 0x02;
110 	static constexpr uint8_t minus_one_encoding = 0x06;
111 
posit()112 	posit() { _bits = 0; }
113 	posit(const posit&) = default;
114 	posit(posit&&) = default;
115 	posit& operator=(const posit&) = default;
116 	posit& operator=(posit&&) = default;
117 
118 	// specific value constructor
posit(const SpecificValue code)119 	constexpr posit(const SpecificValue code) : _bits(0) {
120 		switch (code) {
121 		case SpecificValue::infpos:
122 		case SpecificValue::maxpos:
123 			maxpos();
124 			break;
125 		case SpecificValue::minpos:
126 			minpos();
127 			break;
128 		case SpecificValue::zero:
129 		default:
130 			zero();
131 			break;
132 		case SpecificValue::minneg:
133 			minneg();
134 			break;
135 		case SpecificValue::infneg:
136 		case SpecificValue::maxneg:
137 			maxneg();
138 			break;
139 		case SpecificValue::qnan:
140 		case SpecificValue::snan:
141 		case SpecificValue::nar:
142 			setnar();
143 			break;
144 		}
145 	}
146 
posit(int initial_value)147 	posit(int initial_value) { *this = (long long)initial_value; }
posit(long int initial_value)148 	posit(long int initial_value) { *this = (long long)initial_value; }
posit(long long initial_value)149 	posit(long long initial_value) { *this = initial_value; }
posit(float initial_value)150 	posit(float initial_value) {
151 		*this = float_assign(initial_value);
152 	}
posit(double initial_value)153 	posit(double initial_value) {
154 		*this = float_assign(initial_value);
155 	}
posit(long double initial_value)156 	posit(long double initial_value) {
157 		*this = float_assign(initial_value);
158 	}
159 	// assignment operators for native types
operator =(int rhs)160 	posit& operator=(int rhs) {
161 		return operator=((long long)(rhs));
162 	}
operator =(long int rhs)163 	posit& operator=(long int rhs) {
164 		return operator=((long long)(rhs));
165 	}
operator =(long long rhs)166 	posit& operator=(long long rhs) {
167 		// only valid integers are -2, -1, 0, 1, 2
168 		_bits = 0x00;
169 		if (rhs <= -2) {
170 			_bits = 0x05;   // value is -2, or -maxpos
171 		}
172 		else if (rhs == -1) {
173 			_bits = 0x06;  // value is -1
174 		}
175 		else if (rhs == 0) {
176 			_bits = 0x0;   // value is 0
177 		}
178 		else if (1 == rhs) {
179 			_bits = 0x02;   // value is 1
180 		}
181 		else if (2 <= rhs) {
182 			_bits = 0x03;  // value is 2, or maxpos
183 		}
184 		return *this;
185 	}
operator =(const float rhs)186 	posit& operator=(const float rhs) {
187 		return float_assign(rhs);
188 	}
operator =(const double rhs)189 	posit& operator=(const double rhs) {
190 		return float_assign(rhs);
191 	}
operator =(const long double rhs)192 	posit& operator=(const long double rhs) {
193 		return float_assign(rhs);
194 	}
195 
operator long double() const196 	explicit operator long double() const { return to_long_double(); }
operator double() const197 	explicit operator double() const { return to_double(); }
operator float() const198 	explicit operator float() const { return to_float(); }
operator long long() const199 	explicit operator long long() const { return to_long_long(); }
operator long() const200 	explicit operator long() const { return to_long(); }
operator int() const201 	explicit operator int() const { return to_int(); }
operator unsigned long long() const202 	explicit operator unsigned long long() const { return to_long_long(); }
operator unsigned long() const203 	explicit operator unsigned long() const { return to_long(); }
operator unsigned int() const204 	explicit operator unsigned int() const { return to_int(); }
205 
setBitblock(sw::universal::bitblock<NBITS_IS_3> & raw)206 	posit& setBitblock(sw::universal::bitblock<NBITS_IS_3>& raw) {
207 		_bits = uint8_t(raw.to_ulong() & bit_mask);
208 		return *this;
209 	}
setbits(uint64_t value)210 	posit& setbits(uint64_t value) {
211 		_bits = uint8_t(value & bit_mask);
212 		return *this;
213 	}
operator -() const214 	posit operator-() const {
215 		posit p;
216 		switch (_bits) {
217 		case 0x00:
218 			p.setbits(0x00);
219 			break;
220 		case 0x01:
221 			p.setbits(0x07);
222 			break;
223 		case 0x02:
224 			p.setbits(0x06);
225 			break;
226 		case 0x03:
227 			p.setbits(0x05);
228 			break;
229 		case 0x04:
230 			p.setbits(0x04);
231 			break;
232 		case 0x05:
233 			p.setbits(0x03);
234 			break;
235 		case 0x06:
236 			p.setbits(0x02);
237 			break;
238 		case 0x07:
239 			p.setbits(0x01);
240 			break;
241 		default:
242 			p.setbits(0x04);
243 		}
244 		return p;
245 	}
operator +=(const posit & b)246 	posit& operator+=(const posit& b) {
247 		uint16_t index = (_bits << index_shift) | b._bits;
248 		_bits = posit_3_0_addition_lookup[index];
249 		return *this;
250 	}
operator -=(const posit & b)251 	posit& operator-=(const posit& b) {
252 		uint16_t index = (_bits << index_shift) | b._bits;
253 		_bits = posit_3_0_subtraction_lookup[index];
254 		return *this;
255 	}
operator *=(const posit & b)256 	posit& operator*=(const posit& b) {
257 		uint16_t index = (_bits << index_shift) | b._bits;
258 		_bits = posit_3_0_multiplication_lookup[index];
259 		return *this;
260 	}
operator /=(const posit & b)261 	posit& operator/=(const posit& b) {
262 		uint16_t index = (_bits << index_shift) | b._bits;
263 		_bits = posit_3_0_division_lookup[index];
264 		return *this;
265 	}
operator ++()266 	posit& operator++() {
267 		_bits = (_bits + 1) & 0x07;
268 		return *this;
269 	}
operator ++(int)270 	posit operator++(int) {
271 		posit tmp(*this);
272 		operator++();
273 		return tmp;
274 	}
operator --()275 	posit& operator--() {
276 		_bits = (_bits - 1) & 0x07;
277 		return *this;
278 	}
operator --(int)279 	posit operator--(int) {
280 		posit tmp(*this);
281 		operator--();
282 		return tmp;
283 	}
reciprocate() const284 	posit reciprocate() const {
285 		posit p;
286 		p.setbits(posit_3_0_reciprocal_lookup[_bits]);
287 		return p;
288 	}
289 	// SELECTORS
sign() const290 	inline bool sign()   const { return (_bits & 0x4u); }
isnar() const291 	inline bool isnar()  const { return (_bits == nar_encoding); }
iszero() const292 	inline bool iszero() const { return (_bits == 0x0u); }
isone() const293 	inline bool isone() const { // pattern 010....
294 		return (_bits == one_encoding);
295 	}
isminusone() const296 	inline bool isminusone() const { // pattern 110...
297 		return (_bits == minus_one_encoding);
298 	}
isneg() const299 	inline bool isneg()      const { return (_bits & 0x4u); }
ispos() const300 	inline bool ispos()      const { return !isneg(); }
ispowerof2() const301 	inline bool ispowerof2() const { return !(_bits & 0x1u); }
302 
sign_value() const303 	inline int sign_value() const { return (_bits & 0x4 ? -1 : 1); }
304 
get() const305 	bitblock<NBITS_IS_3> get() const { bitblock<NBITS_IS_3> bb; bb = int(_bits); return bb; }
encoding() const306 	unsigned int encoding() const { return (unsigned int)(_bits & bit_mask); }
307 
clear()308 	inline void clear()   { _bits = 0x00; }
setzero()309 	inline void setzero() { _bits = 0x00; }
setnar()310 	inline void setnar()  { _bits = nar_encoding; }
minpos()311 	inline posit& minpos() {
312 		clear();
313 		return ++(*this);
314 	}
maxpos()315 	inline posit& maxpos() {
316 		setnar();
317 		return --(*this);
318 	}
zero()319 	inline posit& zero() {
320 		clear();
321 		return *this;
322 	}
minneg()323 	inline posit& minneg() {
324 		clear();
325 		return --(*this);
326 	}
maxneg()327 	inline posit& maxneg() {
328 		setnar();
329 		return ++(*this);
330 	}
331 
332 private:
333 	uint8_t _bits;
334 
335 	// Conversion functions
336 #if POSIT_THROW_ARITHMETIC_EXCEPTION
to_int() const337 	int         to_int() const {
338 		if (iszero()) return 0;
339 		if (isnar()) throw posit_nar{};
340 		return int(to_float());
341 	}
to_long() const342 	long        to_long() const {
343 		if (iszero()) return 0;
344 		if (isnar()) throw posit_nar{};
345 		return long(to_double());
346 	}
to_long_long() const347 	long long   to_long_long() const {
348 		if (iszero()) return 0;
349 		if (isnar()) throw posit_nar{};
350 		return long(to_long_double());
351 	}
352 #else
to_int() const353 	int         to_int() const {
354 		if (iszero()) return 0;
355 		if (isnar())  return int(INFINITY);
356 		return int(to_float());
357 	}
to_long() const358 	long        to_long() const {
359 		if (iszero()) return 0;
360 		if (isnar())  return long(INFINITY);
361 		return long(to_double());
362 	}
to_long_long() const363 	long long   to_long_long() const {
364 		if (iszero()) return 0;
365 		if (isnar())  return (long long)(INFINITY);
366 		return long(to_long_double());
367 	}
368 #endif
to_float() const369 	float       to_float() const {
370 		return posit_3_0_values_lookup[encoding()];
371 	}
to_double() const372 	double      to_double() const {
373 		return (double)posit_3_0_values_lookup[encoding()];
374 	}
to_long_double() const375 	long double to_long_double() const {
376 		return (long double)posit_3_0_values_lookup[encoding()];
377 	}
378 
379 	template <typename T>
float_assign(const T & rhs)380 	posit& float_assign(const T& rhs) {
381 		constexpr int dfbits = std::numeric_limits<T>::digits - 1;
382 		internal::value<dfbits> v((T)rhs);
383 
384 		// special case processing
385 		if (v.isinf() || v.isnan()) {  // posit encode for FP_INFINITE and NaN as NaR (Not a Real)
386 			setnar();
387 			return *this;
388 		}
389 		if (v.iszero()) {
390 			setzero();
391 			return *this;
392 		}
393 		bool _sign = v.sign();
394 		int  _scale = v.scale();
395 		bitblock<dfbits> fraction_in = v.fraction();
396 		if (check_inward_projection_range<nbits, es>(_scale)) {    // regime dominated
397 			if (_trace_conversion) std::cout << "inward projection" << std::endl;
398 			// we are projecting to minpos/maxpos
399 			int k = calculate_unconstrained_k<nbits, es>(_scale);
400 			bitblock<NBITS_IS_3> bb = k < 0 ? minpos_pattern<nbits, es>(_sign) : maxpos_pattern<nbits, es>(_sign);
401 			_bits = uint8_t(bb.to_ulong());
402 			// we are done
403 			if (_trace_rounding) std::cout << "projection  rounding ";
404 		}
405 		else {
406 			const size_t pt_len = nbits + 3 + es;
407 			bitblock<pt_len> pt_bits;
408 			bitblock<pt_len> regime;
409 			bitblock<pt_len> exponent;
410 			bitblock<pt_len> fraction;
411 			bitblock<pt_len> sticky_bit;
412 
413 			bool s = _sign;
414 			int e = _scale;
415 			bool r = (e >= 0);
416 
417 			unsigned run = (r ? 1 + (e >> es) : -(e >> es));
418 			regime.set(0, 1 ^ r);
419 			for (unsigned i = 1; i <= run; i++) regime.set(i, r);
420 
421 			unsigned esval = e % (uint32_t(1) << es);
422 			exponent = convert_to_bitblock<pt_len>(esval);
423 			unsigned nf = (unsigned)std::max<int>(0, (nbits + 1) - (2 + run + es));
424 			// TODO: what needs to be done if nf > fbits?
425 			//assert(nf <= input_fbits);
426 			// copy the most significant nf fraction bits into fraction
427 			unsigned lsb = nf <= dfbits ? 0 : nf - dfbits;
428 			for (unsigned i = lsb; i < nf; i++) fraction[i] = fraction_in[dfbits - nf + i];
429 
430 			bool sb = anyAfter(fraction_in, dfbits - 1 - nf);
431 
432 			// construct the untruncated posit
433 			// pt    = BitOr[BitShiftLeft[reg, es + nf + 1], BitShiftLeft[esval, nf + 1], BitShiftLeft[fv, 1], sb];
434 			regime <<= es + nf + 1;
435 			exponent <<= nf + 1;
436 			fraction <<= 1;
437 			sticky_bit.set(0, sb);
438 
439 			pt_bits |= regime;
440 			pt_bits |= exponent;
441 			pt_bits |= fraction;
442 			pt_bits |= sticky_bit;
443 
444 			unsigned len = 1 + std::max<unsigned>((nbits + 1), (2 + run + es));
445 			bool blast = pt_bits.test(len - nbits);
446 			bool bafter = pt_bits.test(len - nbits - 1);
447 			bool bsticky = anyAfter(pt_bits, len - nbits - 1 - 1);
448 
449 			bool rb = (blast & bafter) | (bafter & bsticky);
450 
451 			bitblock<nbits> ptt;
452 			pt_bits <<= pt_len - len;
453 			truncate(pt_bits, ptt);
454 			if (rb) increment_bitset(ptt);
455 			if (s) ptt = twos_complement(ptt);
456 			_bits = uint8_t(ptt.to_ulong());
457 		}
458 		return *this;
459 	}
460 
461 	// I/O operators
462 	friend std::ostream& operator<< (std::ostream& ostr, const posit<NBITS_IS_3, 0>& p);
463 	friend std::istream& operator>> (std::istream& istr, posit<NBITS_IS_3, 0>& p);
464 
465 	// posit - posit logic functions
466 	friend bool operator==(const posit<NBITS_IS_3, 0>& lhs, const posit<NBITS_IS_3, 0>& rhs);
467 	friend bool operator!=(const posit<NBITS_IS_3, 0>& lhs, const posit<NBITS_IS_3, 0>& rhs);
468 	friend bool operator< (const posit<NBITS_IS_3, 0>& lhs, const posit<NBITS_IS_3, 0>& rhs);
469 	friend bool operator> (const posit<NBITS_IS_3, 0>& lhs, const posit<NBITS_IS_3, 0>& rhs);
470 	friend bool operator<=(const posit<NBITS_IS_3, 0>& lhs, const posit<NBITS_IS_3, 0>& rhs);
471 	friend bool operator>=(const posit<NBITS_IS_3, 0>& lhs, const posit<NBITS_IS_3, 0>& rhs);
472 
473 };
474 
475 		// posit I/O operators
operator <<(std::ostream & ostr,const posit<NBITS_IS_3,ES_IS_0> & p)476 		inline std::ostream& operator<<(std::ostream& ostr, const posit<NBITS_IS_3, ES_IS_0>& p) {
477 			// to make certain that setw and left/right operators work properly
478 			// we need to transform the posit into a string
479 			std::stringstream ss;
480 #if POSIT_ROUNDING_ERROR_FREE_IO_FORMAT
481 			ss << nbits << '.' << es << 'x' << to_hex(p.get()) << 'p';
482 #else
483 			std::streamsize prec = ostr.precision();
484 			std::streamsize width = ostr.width();
485 			std::ios_base::fmtflags ff;
486 			ff = ostr.flags();
487 			ss.flags(ff);
488 			ss << std::showpos << std::setw(width) << std::setprecision(prec) << (long double)p;
489 #endif
490 			return ostr << ss.str();
491 		}
492 
493 		// convert a posit value to a string using "nar" as designation of NaR
to_string(const posit<NBITS_IS_3,ES_IS_0> & p,std::streamsize precision)494 		inline std::string to_string(const posit<NBITS_IS_3, ES_IS_0>& p, std::streamsize precision) {
495 			if (p.isnar()) {
496 				return std::string("nar");
497 			}
498 			std::stringstream ss;
499 			ss << std::setprecision(precision) << float(p);
500 			return ss.str();
501 		}
502 
503 		// posit - posit binary logic operators
operator ==(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)504 		inline bool operator==(const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
505 			return lhs._bits == rhs._bits;
506 		}
operator !=(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)507 		inline bool operator!=(const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
508 			return !operator==(lhs, rhs);
509 		}
operator <(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)510 		inline bool operator< (const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
511 			uint16_t index = (uint16_t(lhs.encoding()) << NBITS_IS_3) | uint16_t(rhs.encoding());
512 			return posit_3_0_less_than_lookup[index];
513 		}
operator <(int lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)514 		inline bool operator< (int lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
515 			return posit<NBITS_IS_3, ES_IS_0>(lhs) < rhs;
516 		}
operator <(const posit<NBITS_IS_3,ES_IS_0> & lhs,int rhs)517 		inline bool operator< (const posit<NBITS_IS_3, ES_IS_0>& lhs, int rhs) {
518 			return lhs < posit<NBITS_IS_3, ES_IS_0>(rhs);
519 		}
operator <(float lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)520 		inline bool operator< (float lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
521 			return posit<NBITS_IS_3, ES_IS_0>(lhs) < rhs;
522 		}
operator <(const posit<NBITS_IS_3,ES_IS_0> & lhs,float rhs)523 		inline bool operator< (const posit<NBITS_IS_3, ES_IS_0>& lhs, float rhs) {
524 			return lhs < posit<NBITS_IS_3, ES_IS_0>(rhs);
525 		}
operator <(double lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)526 		inline bool operator< (double lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
527 			return posit<NBITS_IS_3, ES_IS_0>(lhs) < rhs;
528 		}
operator <(const posit<NBITS_IS_3,ES_IS_0> & lhs,double rhs)529 		inline bool operator< (const posit<NBITS_IS_3, ES_IS_0>& lhs, double rhs) {
530 			return lhs < posit<NBITS_IS_3, ES_IS_0>(rhs);
531 		}
operator >(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)532 		inline bool operator> (const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
533 			return operator< (rhs, lhs);
534 		}
operator <=(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)535 		inline bool operator<=(const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
536 			return operator< (lhs, rhs) || operator==(lhs, rhs);
537 		}
operator >=(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)538 		inline bool operator>=(const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
539 			return !operator< (lhs, rhs);
540 		}
541 
operator +(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)542 		inline posit<NBITS_IS_3, ES_IS_0> operator+(const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
543 			posit<NBITS_IS_3, ES_IS_0> sum = lhs;
544 			sum += rhs;
545 			return sum;
546 		}
operator -(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)547 		inline posit<NBITS_IS_3, ES_IS_0> operator-(const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
548 			posit<NBITS_IS_3, ES_IS_0> sub = lhs;
549 			sub -= rhs;
550 			return sub;
551 		}
operator *(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)552 		inline posit<NBITS_IS_3, ES_IS_0> operator*(const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
553 			posit<NBITS_IS_3, ES_IS_0> mul = lhs;
554 			mul *= rhs;
555 			return mul;
556 		}
operator /(const posit<NBITS_IS_3,ES_IS_0> & lhs,const posit<NBITS_IS_3,ES_IS_0> & rhs)557 		inline posit<NBITS_IS_3, ES_IS_0> operator/(const posit<NBITS_IS_3, ES_IS_0>& lhs, const posit<NBITS_IS_3, ES_IS_0>& rhs) {
558 			posit<NBITS_IS_3, ES_IS_0> div = lhs;
559 			div /= rhs;
560 			return div;
561 		}
562 
563 #endif // POSIT_FAST_POSIT_3_0
564 
565 } // namespace sw::universal
566