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