1 #pragma once
2 // posit_4_0.hpp: specialized 4-bit posit using lookup table arithmetic
3 //
4 // Copyright (C) 2017-2021 Supercomputing, Inc.
5 // First implementation: 2019
6 //
7 // This file is part of the universal numbers project, which is released under an MIT Open Source license.
8
9 // DO NOT USE DIRECTLY!
10 // the compile guards in this file are only valid in the context of the specialization logic
11 // configured in the main <universal/posit/posit>
12
13 #ifndef POSIT_FAST_POSIT_4_0
14 #define POSIT_FAST_POSIT_4_0 0
15 #endif
16
17 namespace sw::universal {
18
19 // set the fast specialization variable to indicate that we are running a special template specialization
20 #if POSIT_FAST_POSIT_4_0
21 #ifdef _MSC_VER
22 #pragma message("Fast specialization of posit<4,0>")
23 //#else
24 //#warning("Fast specialization of posit<4,0>")
25 #endif
26
27 constexpr uint8_t posit_4_0_addition_lookup[256] = {
28 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
29 1,2,3,4,4,6,6,7,8,9,10,12,13,14,15,0,
30 2,3,4,4,5,6,6,7,8,9,11,12,14,15,0,1,
31 3,4,4,5,6,6,6,7,8,9,12,13,15,0,1,2,
32 4,4,5,6,6,6,6,7,8,10,12,14,0,1,2,3,
33 5,6,6,6,6,6,7,7,8,10,14,0,2,3,4,4,
34 6,6,6,6,6,7,7,7,8,10,0,2,4,4,5,6,
35 7,7,7,7,7,7,7,7,8,0,6,6,6,7,7,7,
36 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
37 9,9,9,9,10,10,10,0,8,9,9,9,9,9,9,9,
38 10,10,11,12,12,14,0,6,8,9,9,9,10,10,10,10,
39 11,12,12,13,14,0,2,6,8,9,9,10,10,10,10,10,
40 12,13,14,15,0,2,4,6,8,9,10,10,10,10,11,12,
41 13,14,15,0,1,3,4,7,8,9,10,10,10,11,12,12,
42 14,15,0,1,2,4,5,7,8,9,10,10,11,12,12,13,
43 15,0,1,2,3,4,6,7,8,9,10,10,12,12,13,14,
44 };
45
46 constexpr uint8_t posit_4_0_subtraction_lookup[256] = {
47 0,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,
48 1,0,15,14,13,12,10,9,8,7,6,6,4,4,3,2,
49 2,1,0,15,14,12,11,9,8,7,6,6,5,4,4,3,
50 3,2,1,0,15,13,12,9,8,7,6,6,6,5,4,4,
51 4,3,2,1,0,14,12,10,8,7,6,6,6,6,5,4,
52 5,4,4,3,2,0,14,10,8,7,7,6,6,6,6,6,
53 6,6,5,4,4,2,0,10,8,7,7,7,6,6,6,6,
54 7,7,7,7,6,6,6,0,8,7,7,7,7,7,7,7,
55 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
56 9,9,9,9,9,9,9,9,8,0,10,10,10,9,9,9,
57 10,10,10,10,10,9,9,9,8,6,0,14,12,12,11,10,
58 11,10,10,10,10,10,9,9,8,6,2,0,14,13,12,12,
59 12,12,11,10,10,10,10,9,8,6,4,2,0,15,14,13,
60 13,12,12,11,10,10,10,9,8,7,4,3,1,0,15,14,
61 14,13,12,12,11,10,10,9,8,7,5,4,2,1,0,15,
62 15,14,13,12,12,10,10,9,8,7,6,4,3,2,1,0,
63 };
64
65 constexpr uint8_t posit_4_0_multiplication_lookup[256] = {
66 0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,
67 0,1,1,1,1,2,2,4,8,12,14,14,15,15,15,15,
68 0,1,1,2,2,3,4,6,8,10,12,13,14,14,15,15,
69 0,1,2,2,3,4,5,6,8,10,11,12,13,14,14,15,
70 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
71 0,2,3,4,5,6,6,7,8,9,10,10,11,12,13,14,
72 0,2,4,5,6,6,7,7,8,9,9,10,10,11,12,14,
73 0,4,6,6,7,7,7,7,8,9,9,9,9,10,10,12,
74 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
75 0,12,10,10,9,9,9,9,8,7,7,7,7,6,6,4,
76 0,14,12,11,10,10,9,9,8,7,7,6,6,5,4,2,
77 0,14,13,12,11,10,10,9,8,7,6,6,5,4,3,2,
78 0,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,
79 0,15,14,14,13,12,11,10,8,6,5,4,3,2,2,1,
80 0,15,15,14,14,13,12,10,8,6,4,3,2,2,1,1,
81 0,15,15,15,15,14,14,12,8,4,2,2,1,1,1,1,
82 };
83
84 constexpr uint8_t posit_4_0_division_lookup[256] = {
85 8,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,
86 8,4,2,1,1,1,1,1,8,15,15,15,15,15,14,12,
87 8,6,4,3,2,1,1,1,8,15,15,15,14,13,12,10,
88 8,6,5,4,3,2,2,1,8,15,14,14,13,12,11,10,
89 8,7,6,5,4,3,2,1,8,15,14,13,12,11,10,9,
90 8,7,6,6,5,4,3,2,8,14,13,12,11,10,10,9,
91 8,7,7,6,6,5,4,2,8,14,12,11,10,10,9,9,
92 8,7,7,7,7,6,6,4,8,12,10,10,9,9,9,9,
93 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
94 8,9,9,9,9,10,10,12,8,4,6,6,7,7,7,7,
95 8,9,9,10,10,11,12,14,8,2,4,5,6,6,7,7,
96 8,9,10,10,11,12,13,14,8,2,3,4,5,6,6,7,
97 8,9,10,11,12,13,14,15,8,1,2,3,4,5,6,7,
98 8,10,11,12,13,14,14,15,8,1,2,2,3,4,5,6,
99 8,10,12,13,14,15,15,15,8,1,1,1,2,3,4,6,
100 8,12,14,15,15,15,15,15,8,1,1,1,1,1,2,4,
101 };
102
103 constexpr uint8_t posit_4_0_reciprocal_lookup[16] = {
104 8,7,6,5,4,3,2,1,8,15,14,13,12,11,10,9,
105 };
106
107 template<>
108 class posit<NBITS_IS_4, ES_IS_0> {
109 public:
110 static constexpr size_t nbits = NBITS_IS_4;
111 static constexpr size_t es = ES_IS_0;
112 static constexpr size_t sbits = 1;
113 static constexpr size_t rbits = nbits - sbits;
114 static constexpr size_t ebits = es;
115 static constexpr size_t fbits = nbits - 3;
116 static constexpr size_t fhbits = fbits + 1;
117 static constexpr uint8_t index_shift = 4;
118 static constexpr uint8_t bit_mask = 0x0F;
119 static constexpr uint8_t nar_encoding = 0x08;
120 static constexpr uint8_t one_encoding = 0x04; // 0100
121 static constexpr uint8_t minusone_encoding = 0x0C; // 1100
122
posit()123 posit() { _bits = 0; }
124 posit(const posit&) = default;
125 posit(posit&&) = default;
126 posit& operator=(const posit&) = default;
127 posit& operator=(posit&&) = default;
128
129 // specific value constructor
posit(const SpecificValue code)130 constexpr posit(const SpecificValue code) : _bits(0) {
131 switch (code) {
132 case SpecificValue::infpos:
133 case SpecificValue::maxpos:
134 maxpos();
135 break;
136 case SpecificValue::minpos:
137 minpos();
138 break;
139 case SpecificValue::zero:
140 default:
141 zero();
142 break;
143 case SpecificValue::minneg:
144 minneg();
145 break;
146 case SpecificValue::infneg:
147 case SpecificValue::maxneg:
148 maxneg();
149 break;
150 case SpecificValue::qnan:
151 case SpecificValue::snan:
152 case SpecificValue::nar:
153 setnar();
154 break;
155 }
156 }
157
posit(signed char initial_value)158 explicit posit(signed char initial_value) { *this = (long long)initial_value; }
posit(short initial_value)159 explicit posit(short initial_value) { *this = (long long)initial_value; }
posit(int initial_value)160 explicit posit(int initial_value) { *this = (long long)initial_value; }
posit(long int initial_value)161 explicit posit(long int initial_value) { *this = (long long)initial_value; }
posit(long long initial_value)162 posit(long long initial_value) { *this = (long long)initial_value; }
posit(char initial_value)163 explicit posit(char initial_value) { *this = (long long)initial_value; }
posit(unsigned short initial_value)164 explicit posit(unsigned short initial_value) { *this = (long long)initial_value; }
posit(unsigned int initial_value)165 explicit posit(unsigned int initial_value) { *this = (long long)initial_value; }
posit(unsigned long int initial_value)166 explicit posit(unsigned long int initial_value) { *this = (long long)initial_value; }
posit(unsigned long long initial_value)167 explicit posit(unsigned long long initial_value) { *this = (long long)initial_value; }
posit(float initial_value)168 explicit posit(float initial_value) { *this = initial_value; }
posit(double initial_value)169 explicit posit(double initial_value) { *this = initial_value; }
posit(long double initial_value)170 explicit posit(long double initial_value) { *this = initial_value; }
171
172 // assignment operators for native types
operator =(int rhs)173 posit& operator=(int rhs) {
174 return operator=((long long)(rhs));
175 }
operator =(long int rhs)176 posit& operator=(long int rhs) {
177 return operator=((long long)(rhs));
178 }
operator =(long long rhs)179 posit& operator=(long long rhs) {
180 // only valid integers are -4, -2, -1, 0, 1, 2, 4
181 _bits = uint8_t(0);
182 if (rhs <= -4) {
183 _bits = 0x9; // value is -4, or -maxpos
184 }
185 else if (-4 > rhs && rhs <= -2) {
186 _bits = 0xA; // value is -2
187 }
188 else if (-2 > rhs && rhs <= -1) {
189 _bits = 0xC; // value is -1
190 }
191 else if (-1 > rhs && rhs < 1) {
192 _bits = 0x0; // value is 0
193 }
194 else if (1 <= rhs && rhs < 2) {
195 _bits = 0x4; // value is 1
196 }
197 else if (2 <= rhs && rhs < 4) {
198 _bits = 0x6; // value is 2
199 }
200 else if (4 <= rhs) {
201 _bits = 0x7; // value is 4, or maxpos
202 }
203 return *this;
204 }
operator =(const float rhs)205 posit& operator=(const float rhs) {
206 return float_assign(rhs);
207 }
operator =(const double rhs)208 posit& operator=(const double rhs) {
209 return float_assign(rhs);
210 }
operator =(const long double rhs)211 posit& operator=(const long double rhs) {
212 return float_assign(rhs);
213 }
214
operator long double() const215 explicit operator long double() const { return to_long_double(); }
operator double() const216 explicit operator double() const { return to_double(); }
operator float() const217 explicit operator float() const { return to_float(); }
operator long long() const218 explicit operator long long() const { return to_long_long(); }
operator long() const219 explicit operator long() const { return to_long(); }
operator int() const220 explicit operator int() const { return to_int(); }
operator unsigned long long() const221 explicit operator unsigned long long() const { return to_long_long(); }
operator unsigned long() const222 explicit operator unsigned long() const { return to_long(); }
operator unsigned int() const223 explicit operator unsigned int() const { return to_int(); }
224
setBitblock(sw::universal::bitblock<NBITS_IS_4> & raw)225 posit& setBitblock(sw::universal::bitblock<NBITS_IS_4>& raw) {
226 _bits = uint8_t(raw.to_ulong());
227 return *this;
228 }
setbits(uint64_t value)229 posit& setbits(uint64_t value) {
230 _bits = uint8_t(value & bit_mask);
231 return *this;
232 }
operator -() const233 posit operator-() const {
234 if (iszero()) {
235 return *this;
236 }
237 if (isnar()) {
238 return *this;
239 }
240 posit p;
241 return p.setbits((~_bits) + 1);
242 }
operator +=(const posit & b)243 posit& operator+=(const posit& b) {
244 uint16_t index = (_bits << index_shift) | b._bits;
245 _bits = posit_4_0_addition_lookup[index];
246 return *this;
247 }
operator -=(const posit & b)248 posit& operator-=(const posit& b) {
249 uint16_t index = (_bits << index_shift) | b._bits;
250 _bits = posit_4_0_subtraction_lookup[index];
251 return *this;
252 }
operator *=(const posit & b)253 posit& operator*=(const posit& b) {
254 uint16_t index = (_bits << index_shift) | b._bits;
255 _bits = posit_4_0_multiplication_lookup[index];
256 return *this;
257 }
operator /=(const posit & b)258 posit& operator/=(const posit& b) {
259 uint16_t index = (_bits << index_shift) | b._bits;
260 _bits = posit_4_0_division_lookup[index];
261 return *this;
262 }
operator ++()263 posit& operator++() {
264 _bits = (_bits + 1) & bit_mask;
265 return *this;
266 }
operator ++(int)267 posit operator++(int) {
268 posit tmp(*this);
269 operator++();
270 return tmp;
271 }
operator --()272 posit& operator--() {
273 _bits = (_bits - 1) & bit_mask;
274 return *this;
275 }
operator --(int)276 posit operator--(int) {
277 posit tmp(*this);
278 operator--();
279 return tmp;
280 }
reciprocate() const281 posit reciprocate() const {
282 posit p;
283 p.setbits(posit_4_0_reciprocal_lookup[_bits]);
284 return p;
285 }
286 // SELECTORS
sign() const287 inline bool sign() const { return bool(_bits & 0x08u); }
isnar() const288 inline bool isnar() const { return (_bits == nar_encoding); }
iszero() const289 inline bool iszero() const { return (_bits == 0); }
isone() const290 inline bool isone() const { // pattern 0100....
291 return (_bits == one_encoding);
292 }
isminusone() const293 inline bool isminusone() const { // pattern 1100...
294 return (_bits == minusone_encoding);
295 }
isneg() const296 inline bool isneg() const { return bool(_bits & 0x08u); }
ispos() const297 inline bool ispos() const { return !isneg(); }
ispowerof2() const298 inline bool ispowerof2() const { return !(_bits & 0x1u); }
299
sign_value() const300 inline int sign_value() const { return (_bits & 0x08u ? -1 : 1); }
301
get() const302 bitblock<NBITS_IS_4> get() const { bitblock<NBITS_IS_4> bb; bb = int(_bits & bit_mask); return bb; }
encoding() const303 unsigned int encoding() const { return (unsigned int)(_bits & bit_mask); }
304
clear()305 inline void clear() { _bits = 0; }
setzero()306 inline void setzero() { clear(); }
setnar()307 inline void setnar() { _bits = nar_encoding; }
minpos()308 inline posit& minpos() {
309 clear();
310 return ++(*this);
311 }
maxpos()312 inline posit& maxpos() {
313 setnar();
314 return --(*this);
315 }
zero()316 inline posit& zero() {
317 clear();
318 return *this;
319 }
minneg()320 inline posit& minneg() {
321 clear();
322 return --(*this);
323 }
maxneg()324 inline posit& maxneg() {
325 setnar();
326 return ++(*this);
327 }
328 private:
329 uint8_t _bits;
330
331 // Conversion functions
332 #if POSIT_THROW_ARITHMETIC_EXCEPTION
to_int() const333 int to_int() const {
334 if (iszero()) return 0;
335 if (isnar()) throw posit_nar{};
336 return int(to_float());
337 }
to_long() const338 long to_long() const {
339 if (iszero()) return 0;
340 if (isnar()) throw posit_nar{};
341 return long(to_double());
342 }
to_long_long() const343 long long to_long_long() const {
344 if (iszero()) return 0;
345 if (isnar()) throw posit_nar{};
346 return long(to_long_double());
347 }
348 #else
to_int() const349 int to_int() const {
350 if (iszero()) return 0;
351 if (isnar()) return int(INFINITY);
352 return int(to_float());
353 }
to_long() const354 long to_long() const {
355 if (iszero()) return 0;
356 if (isnar()) return long(INFINITY);
357 return long(to_double());
358 }
to_long_long() const359 long long to_long_long() const {
360 if (iszero()) return 0;
361 if (isnar()) return (long long)(INFINITY);
362 return long(to_long_double());
363 }
364 #endif
to_float() const365 float to_float() const {
366 return (float)to_double();
367 }
to_double() const368 double to_double() const {
369 if (iszero()) return 0.0;
370 if (isnar()) return NAN;
371 bool _sign;
372 regime<nbits, es> _regime;
373 exponent<nbits, es> _exponent;
374 fraction<fbits> _fraction;
375 bitblock<nbits> _raw_bits;
376 _raw_bits.reset();
377 uint64_t mask = 1;
378 for (size_t i = 0; i < nbits; i++) {
379 _raw_bits.set(i, (_bits & mask));
380 mask <<= 1;
381 }
382 decode(_raw_bits, _sign, _regime, _exponent, _fraction);
383 double s = (_sign ? -1.0 : 1.0);
384 double r = _regime.value();
385 double e = _exponent.value();
386 double f = (1.0 + _fraction.value());
387 return s * r * e * f;
388 }
to_long_double() const389 long double to_long_double() const {
390 if (iszero()) return 0.0;
391 if (isnar()) return NAN;
392 bool _sign;
393 regime<nbits, es> _regime;
394 exponent<nbits, es> _exponent;
395 fraction<fbits> _fraction;
396 bitblock<nbits> _raw_bits;
397 _raw_bits.reset();
398 uint64_t mask = 1;
399 for (size_t i = 0; i < nbits; i++) {
400 _raw_bits.set(i, (_bits & mask));
401 mask <<= 1;
402 }
403 decode(_raw_bits, _sign, _regime, _exponent, _fraction);
404 long double s = (_sign ? -1.0 : 1.0);
405 long double r = _regime.value();
406 long double e = _exponent.value();
407 long double f = (1.0 + _fraction.value());
408 return s * r * e * f;
409 }
410
411 template <typename T>
float_assign(const T & rhs)412 posit& float_assign(const T& rhs) {
413 constexpr int dfbits = std::numeric_limits<T>::digits - 1;
414 internal::value<dfbits> v((T)rhs);
415
416 // special case processing
417 if (v.iszero()) {
418 setzero();
419 return *this;
420 }
421 if (v.isinf() || v.isnan()) { // posit encode for FP_INFINITE and NaN as NaR (Not a Real)
422 setnar();
423 return *this;
424 }
425 bitblock<NBITS_IS_4> ptt;
426 convert_to_bb<NBITS_IS_4, ES_IS_0, dfbits>(v.sign(), v.scale(), v.fraction(), ptt); // TODO: needs to be faster
427 _bits = uint8_t(ptt.to_ulong());
428 return *this;
429 }
430
431 // I/O operators
432 friend std::ostream& operator<< (std::ostream& ostr, const posit<NBITS_IS_4, ES_IS_0>& p);
433 friend std::istream& operator>> (std::istream& istr, posit<NBITS_IS_4, ES_IS_0>& p);
434
435 // posit - posit logic functions
436 friend bool operator==(const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs);
437 friend bool operator!=(const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs);
438 friend bool operator< (const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs);
439 friend bool operator> (const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs);
440 friend bool operator<=(const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs);
441 friend bool operator>=(const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs);
442
443 };
444
445 // posit I/O operators
446 // generate a posit format ASCII format nbits.esxNN...NNp
operator <<(std::ostream & ostr,const posit<NBITS_IS_4,ES_IS_0> & p)447 inline std::ostream& operator<<(std::ostream& ostr, const posit<NBITS_IS_4, ES_IS_0>& p) {
448 // to make certain that setw and left/right operators work properly
449 // we need to transform the posit into a string
450 std::stringstream ss;
451 #if POSIT_ROUNDING_ERROR_FREE_IO_FORMAT
452 ss << NBITS_IS_4 << '.' << ES_IS_0 << 'x' << to_hex(p.get()) << 'p';
453 #else
454 std::streamsize prec = ostr.precision();
455 std::streamsize width = ostr.width();
456 std::ios_base::fmtflags ff;
457 ff = ostr.flags();
458 ss.flags(ff);
459 ss << std::showpos << std::setw(width) << std::setprecision(prec) << (long double)p;
460 #endif
461 return ostr << ss.str();
462 }
463
464 // read an ASCII float or posit format: nbits.esxNN...NNp, for example: 32.2x80000000p
operator >>(std::istream & istr,posit<NBITS_IS_4,ES_IS_0> & p)465 inline std::istream& operator>> (std::istream& istr, posit<NBITS_IS_4, ES_IS_0>& p) {
466 std::string txt;
467 istr >> txt;
468 if (!parse(txt, p)) {
469 std::cerr << "unable to parse -" << txt << "- into a posit value\n";
470 }
471 return istr;
472 }
473
474 // convert a posit value to a string using "nar" as designation of NaR
to_string(const posit<NBITS_IS_4,ES_IS_0> & p,std::streamsize precision)475 inline std::string to_string(const posit<NBITS_IS_4, ES_IS_0>& p, std::streamsize precision) {
476 if (p.isnar()) {
477 return std::string("nar");
478 }
479 std::stringstream ss;
480 ss << std::setprecision(precision) << float(p);
481 return ss.str();
482 }
483
484 // posit - posit binary logic operators
operator ==(const posit<NBITS_IS_4,ES_IS_0> & lhs,const posit<NBITS_IS_4,ES_IS_0> & rhs)485 inline bool operator==(const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs) {
486 return lhs._bits == rhs._bits;
487 }
operator !=(const posit<NBITS_IS_4,ES_IS_0> & lhs,const posit<NBITS_IS_4,ES_IS_0> & rhs)488 inline bool operator!=(const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs) {
489 return !operator==(lhs, rhs);
490 }
operator <(const posit<NBITS_IS_4,ES_IS_0> & lhs,const posit<NBITS_IS_4,ES_IS_0> & rhs)491 inline bool operator< (const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs) {
492 if (rhs.isnar()) {
493 return false;
494 }
495 posit<NBITS_IS_4, ES_IS_0> r = lhs - rhs; // else calculate the difference and check if negative
496 return r.isneg();
497 }
operator >(const posit<NBITS_IS_4,ES_IS_0> & lhs,const posit<NBITS_IS_4,ES_IS_0> & rhs)498 inline bool operator> (const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs) {
499 return operator< (rhs, lhs);
500 }
operator <=(const posit<NBITS_IS_4,ES_IS_0> & lhs,const posit<NBITS_IS_4,ES_IS_0> & rhs)501 inline bool operator<=(const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs) {
502 return operator< (lhs, rhs) || operator==(lhs, rhs);
503 }
operator >=(const posit<NBITS_IS_4,ES_IS_0> & lhs,const posit<NBITS_IS_4,ES_IS_0> & rhs)504 inline bool operator>=(const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs) {
505 return !operator< (lhs, rhs);
506 }
507
operator +(const posit<NBITS_IS_4,ES_IS_0> & lhs,const posit<NBITS_IS_4,ES_IS_0> & rhs)508 inline posit<NBITS_IS_4, ES_IS_0> operator+(const posit<NBITS_IS_4, ES_IS_0>& lhs, const posit<NBITS_IS_4, ES_IS_0>& rhs) {
509 posit<NBITS_IS_4, ES_IS_0> sum = lhs;
510 sum += rhs;
511 return sum;
512 }
513
514 #endif // POSIT_FAST_POSIT_4_0
515
516 } // namespace sw::universal
517