Int128.h (22517B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef vm_Int128_h 8 #define vm_Int128_h 9 10 #include "mozilla/Assertions.h" 11 #include "mozilla/EndianUtils.h" 12 #include "mozilla/MathAlgorithms.h" 13 14 #include <climits> 15 #include <limits> 16 #include <stdint.h> 17 #include <utility> 18 19 namespace js { 20 21 class Int128; 22 class Uint128; 23 24 /** 25 * Unsigned 128-bit integer, implemented as a pair of unsigned 64-bit integers. 26 * 27 * Supports all basic arithmetic operators. 28 */ 29 class alignas(16) Uint128 final { 30 #if MOZ_LITTLE_ENDIAN() 31 uint64_t low = 0; 32 uint64_t high = 0; 33 #else 34 uint64_t high = 0; 35 uint64_t low = 0; 36 #endif 37 38 friend class Int128; 39 40 constexpr Uint128(uint64_t low, uint64_t high) : low(low), high(high) {} 41 42 /** 43 * Return the high double-word of the multiplication of `u * v`. 44 * 45 * Based on "Multiply high unsigned" from Hacker's Delight, 2nd edition, 46 * figure 8-2. 47 */ 48 static constexpr uint64_t mulhu(uint64_t u, uint64_t v) { 49 uint64_t u0 = u & 0xffff'ffff; 50 uint64_t u1 = u >> 32; 51 52 uint64_t v0 = v & 0xffff'ffff; 53 uint64_t v1 = v >> 32; 54 55 uint64_t w0 = u0 * v0; 56 uint64_t t = u1 * v0 + (w0 >> 32); 57 uint64_t w1 = t & 0xffff'ffff; 58 uint64_t w2 = t >> 32; 59 w1 = u0 * v1 + w1; 60 return u1 * v1 + w2 + (w1 >> 32); 61 } 62 63 /** 64 * Based on "Unsigned doubleword division from long division" from 65 * Hacker's Delight, 2nd edition, figure 9-5. 66 */ 67 static constexpr std::pair<Uint128, Uint128> udivdi(const Uint128& u, 68 const Uint128& v) { 69 MOZ_ASSERT(v != Uint128{}); 70 71 // If v < 2**64 72 if (v.high == 0) { 73 // If u < 2**64 74 if (u.high == 0) { 75 // Prefer built-in division if possible. 76 return {Uint128{u.low / v.low, 0}, Uint128{u.low % v.low, 0}}; 77 } 78 79 // If u/v cannot overflow, just do one division. 80 if (Uint128{u.high, 0} < v) { 81 auto [q, r] = divlu(u.high, u.low, v.low); 82 return {Uint128{q, 0}, Uint128{r, 0}}; 83 } 84 85 // If u/v would overflow: Break u up into two halves. 86 87 // First quotient digit and first remainder, < v. 88 auto [q1, r1] = divlu(0, u.high, v.low); 89 90 // Second quotient digit. 91 auto [q0, r0] = divlu(r1, u.low, v.low); 92 93 // Return quotient and remainder. 94 return {Uint128{q0, q1}, Uint128{r0, 0}}; 95 } 96 97 // Here v >= 2**64. 98 99 // 0 <= n <= 63 100 auto n = mozilla::CountLeadingZeroes64(v.high); 101 102 // Normalize the divisor so its MSB is 1. 103 auto v1 = (v << n).high; 104 105 // To ensure no overflow. 106 auto u1 = u >> 1; 107 108 // Get quotient from divide unsigned instruction. 109 auto [q1, r1] = divlu(u1.high, u1.low, v1); 110 111 // Undo normalization and division of u by 2. 112 auto q0 = (Uint128{q1, 0} << n) >> 63; 113 114 // Make q0 correct or too small by 1. 115 if (q0 != Uint128{0}) { 116 q0 -= Uint128{1}; 117 } 118 119 // Now q0 is correct. 120 auto r0 = u - q0 * v; 121 if (r0 >= v) { 122 q0 += Uint128{1}; 123 r0 -= v; 124 } 125 126 // Return quotient and remainder. 127 return {q0, r0}; 128 } 129 130 /** 131 * Based on "Divide long unsigned, using fullword division instructions" from 132 * Hacker's Delight, 2nd edition, figure 9-3. 133 */ 134 static constexpr std::pair<uint64_t, uint64_t> divlu(uint64_t u1, uint64_t u0, 135 uint64_t v) { 136 // Number base (32 bits). 137 constexpr uint64_t base = 4294967296; 138 139 // If overflow, set the remainder to an impossible value and return the 140 // largest possible quotient. 141 if (u1 >= v) { 142 return {UINT64_MAX, UINT64_MAX}; 143 } 144 145 // Shift amount for normalization. (0 <= s <= 63) 146 int64_t s = mozilla::CountLeadingZeroes64(v); 147 148 // Normalize the divisor. 149 v = v << s; 150 151 // Normalized divisor digits. 152 // 153 // Break divisor up into two 32-bit digits. 154 uint64_t vn1 = v >> 32; 155 uint64_t vn0 = uint32_t(v); 156 157 // Dividend digit pairs. 158 // 159 // Shift dividend left. 160 uint64_t un32 = (u1 << s) | ((u0 >> ((64 - s) & 63)) & (-s >> 63)); 161 uint64_t un10 = u0 << s; 162 163 // Normalized dividend least significant digits. 164 // 165 // Break right half of dividend into two digits. 166 uint64_t un1 = un10 >> 32; 167 uint64_t un0 = uint32_t(un10); 168 169 // Compute the first quotient digit and its remainder. 170 uint64_t q1 = un32 / vn1; 171 uint64_t rhat = un32 - q1 * vn1; 172 while (q1 >= base || q1 * vn0 > base * rhat + un1) { 173 q1 -= 1; 174 rhat += vn1; 175 if (rhat >= base) { 176 break; 177 } 178 } 179 180 // Multiply and subtract. 181 uint64_t un21 = un32 * base + un1 - q1 * v; 182 183 // Compute the second quotient digit and its remainder. 184 uint64_t q0 = un21 / vn1; 185 rhat = un21 - q0 * vn1; 186 while (q0 >= base || q0 * vn0 > base * rhat + un0) { 187 q0 -= 1; 188 rhat += vn1; 189 if (rhat >= base) { 190 break; 191 } 192 } 193 194 // Return the quotient and remainder. 195 uint64_t q = q1 * base + q0; 196 uint64_t r = (un21 * base + un0 - q0 * v) >> s; 197 return {q, r}; 198 } 199 200 static double toDouble(const Uint128& x, bool negative); 201 202 public: 203 constexpr Uint128() = default; 204 constexpr Uint128(const Uint128&) = default; 205 206 explicit constexpr Uint128(int value) 207 : Uint128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {} 208 explicit constexpr Uint128(long value) 209 : Uint128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {} 210 explicit constexpr Uint128(long long value) 211 : Uint128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {} 212 213 explicit constexpr Uint128(unsigned int value) 214 : Uint128(uint64_t(value), uint64_t(0)) {} 215 explicit constexpr Uint128(unsigned long value) 216 : Uint128(uint64_t(value), uint64_t(0)) {} 217 explicit constexpr Uint128(unsigned long long value) 218 : Uint128(uint64_t(value), uint64_t(0)) {} 219 220 constexpr bool operator==(const Uint128& other) const { 221 return low == other.low && high == other.high; 222 } 223 224 constexpr bool operator<(const Uint128& other) const { 225 if (high == other.high) { 226 return low < other.low; 227 } 228 return high < other.high; 229 } 230 231 // Other operators are implemented in terms of operator== and operator<. 232 constexpr bool operator!=(const Uint128& other) const { 233 return !(*this == other); 234 } 235 constexpr bool operator>(const Uint128& other) const { return other < *this; } 236 constexpr bool operator<=(const Uint128& other) const { 237 return !(other < *this); 238 } 239 constexpr bool operator>=(const Uint128& other) const { 240 return !(*this < other); 241 } 242 243 explicit constexpr operator bool() const { return !(*this == Uint128{}); } 244 245 explicit constexpr operator int8_t() const { return int8_t(low); } 246 explicit constexpr operator int16_t() const { return int16_t(low); } 247 explicit constexpr operator int32_t() const { return int32_t(low); } 248 explicit constexpr operator int64_t() const { return int64_t(low); } 249 250 explicit constexpr operator uint8_t() const { return uint8_t(low); } 251 explicit constexpr operator uint16_t() const { return uint16_t(low); } 252 explicit constexpr operator uint32_t() const { return uint32_t(low); } 253 explicit constexpr operator uint64_t() const { return uint64_t(low); } 254 255 explicit constexpr operator Int128() const; 256 257 explicit operator double() const { return toDouble(*this, false); } 258 259 constexpr Uint128 operator+(const Uint128& other) const { 260 // "ยง2-16 Double-Length Add/Subtract" from Hacker's Delight, 2nd edition. 261 Uint128 result; 262 result.low = low + other.low; 263 result.high = high + other.high + static_cast<uint64_t>(result.low < low); 264 return result; 265 } 266 267 constexpr Uint128 operator-(const Uint128& other) const { 268 // "ยง2-16 Double-Length Add/Subtract" from Hacker's Delight, 2nd edition. 269 Uint128 result; 270 result.low = low - other.low; 271 result.high = high - other.high - static_cast<uint64_t>(low < other.low); 272 return result; 273 } 274 275 constexpr Uint128 operator*(const Uint128& other) const { 276 uint64_t w01 = low * other.high; 277 uint64_t w10 = high * other.low; 278 uint64_t w00 = mulhu(low, other.low); 279 280 uint64_t w1 = w00 + w10 + w01; 281 uint64_t w0 = low * other.low; 282 283 return Uint128{w0, w1}; 284 } 285 286 /** 287 * Return the quotient and remainder of the division. 288 */ 289 constexpr std::pair<Uint128, Uint128> divrem(const Uint128& divisor) const { 290 return udivdi(*this, divisor); 291 } 292 293 constexpr Uint128 operator/(const Uint128& other) const { 294 auto [quot, rem] = divrem(other); 295 return quot; 296 } 297 298 constexpr Uint128 operator%(const Uint128& other) const { 299 auto [quot, rem] = divrem(other); 300 return rem; 301 } 302 303 constexpr Uint128 operator<<(int shift) const { 304 MOZ_ASSERT(0 <= shift && shift <= 127, "undefined shift amount"); 305 306 // Ensure the shift amount is in range. 307 shift &= 127; 308 309 // "ยง2-17 Double-Length Shifts" from Hacker's Delight, 2nd edition. 310 if (shift >= 64) { 311 uint64_t y0 = 0; 312 uint64_t y1 = low << (shift - 64); 313 return Uint128{y0, y1}; 314 } 315 if (shift > 0) { 316 uint64_t y0 = low << shift; 317 uint64_t y1 = high << shift | low >> (64 - shift); 318 return Uint128{y0, y1}; 319 } 320 return *this; 321 } 322 323 constexpr Uint128 operator>>(int shift) const { 324 MOZ_ASSERT(0 <= shift && shift <= 127, "undefined shift amount"); 325 326 // Ensure the shift amount is in range. 327 shift &= 127; 328 329 // "ยง2-17 Double-Length Shifts" from Hacker's Delight, 2nd edition. 330 if (shift >= 64) { 331 uint64_t y0 = high >> (shift - 64); 332 uint64_t y1 = 0; 333 return Uint128{y0, y1}; 334 } 335 if (shift > 0) { 336 uint64_t y0 = low >> shift | high << (64 - shift); 337 uint64_t y1 = high >> shift; 338 return Uint128{y0, y1}; 339 } 340 return *this; 341 } 342 343 constexpr Uint128 operator&(const Uint128& other) const { 344 return Uint128{low & other.low, high & other.high}; 345 } 346 347 constexpr Uint128 operator|(const Uint128& other) const { 348 return Uint128{low | other.low, high | other.high}; 349 } 350 351 constexpr Uint128 operator^(const Uint128& other) const { 352 return Uint128{low ^ other.low, high ^ other.high}; 353 } 354 355 constexpr Uint128 operator~() const { return Uint128{~low, ~high}; } 356 357 constexpr Uint128 operator-() const { return Uint128{} - *this; } 358 359 constexpr Uint128 operator+() const { return *this; } 360 361 constexpr Uint128& operator++() { 362 *this = *this + Uint128{1, 0}; 363 return *this; 364 } 365 366 constexpr Uint128 operator++(int) { 367 auto result = *this; 368 ++*this; 369 return result; 370 } 371 372 constexpr Uint128& operator--() { 373 *this = *this - Uint128{1, 0}; 374 return *this; 375 } 376 377 constexpr Uint128 operator--(int) { 378 auto result = *this; 379 --*this; 380 return result; 381 } 382 383 constexpr Uint128 operator+=(const Uint128& other) { 384 *this = *this + other; 385 return *this; 386 } 387 388 constexpr Uint128 operator-=(const Uint128& other) { 389 *this = *this - other; 390 return *this; 391 } 392 393 constexpr Uint128 operator*=(const Uint128& other) { 394 *this = *this * other; 395 return *this; 396 } 397 398 constexpr Uint128 operator/=(const Uint128& other) { 399 *this = *this / other; 400 return *this; 401 } 402 403 constexpr Uint128 operator%=(const Uint128& other) { 404 *this = *this % other; 405 return *this; 406 } 407 408 constexpr Uint128 operator&=(const Uint128& other) { 409 *this = *this & other; 410 return *this; 411 } 412 413 constexpr Uint128 operator|=(const Uint128& other) { 414 *this = *this | other; 415 return *this; 416 } 417 418 constexpr Uint128 operator^=(const Uint128& other) { 419 *this = *this ^ other; 420 return *this; 421 } 422 423 constexpr Uint128 operator<<=(int shift) { 424 *this = *this << shift; 425 return *this; 426 } 427 428 constexpr Uint128 operator>>=(int shift) { 429 *this = *this >> shift; 430 return *this; 431 } 432 }; 433 434 /** 435 * Signed 128-bit integer, implemented as a pair of unsigned 64-bit integers. 436 * 437 * Supports all basic arithmetic operators. 438 */ 439 class alignas(16) Int128 final { 440 #if MOZ_LITTLE_ENDIAN() 441 uint64_t low = 0; 442 uint64_t high = 0; 443 #else 444 uint64_t high = 0; 445 uint64_t low = 0; 446 #endif 447 448 friend class Uint128; 449 450 constexpr Int128(uint64_t low, uint64_t high) : low(low), high(high) {} 451 452 /** 453 * Based on "Signed doubleword division from unsigned doubleword division" 454 * from Hacker's Delight, 2nd edition, figure 9-6. 455 */ 456 static constexpr std::pair<Int128, Int128> divdi(const Int128& u, 457 const Int128& v) { 458 auto [q, r] = Uint128::udivdi(u.abs(), v.abs()); 459 460 // If u and v have different signs, negate q. 461 // If is negative, negate r. 462 auto t = static_cast<Uint128>((u ^ v) >> 127); 463 auto s = static_cast<Uint128>(u >> 127); 464 return {static_cast<Int128>((q ^ t) - t), static_cast<Int128>((r ^ s) - s)}; 465 } 466 467 public: 468 constexpr Int128() = default; 469 constexpr Int128(const Int128&) = default; 470 471 explicit constexpr Int128(int value) 472 : Int128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {} 473 explicit constexpr Int128(long value) 474 : Int128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {} 475 explicit constexpr Int128(long long value) 476 : Int128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {} 477 478 explicit constexpr Int128(unsigned int value) 479 : Int128(uint64_t(value), uint64_t(0)) {} 480 explicit constexpr Int128(unsigned long value) 481 : Int128(uint64_t(value), uint64_t(0)) {} 482 explicit constexpr Int128(unsigned long long value) 483 : Int128(uint64_t(value), uint64_t(0)) {} 484 485 /** 486 * Return the quotient and remainder of the division. 487 */ 488 constexpr std::pair<Int128, Int128> divrem(const Int128& divisor) const { 489 return divdi(*this, divisor); 490 } 491 492 /** 493 * Return the absolute value of this integer. 494 */ 495 constexpr Uint128 abs() const { 496 if (*this >= Int128{}) { 497 return Uint128{low, high}; 498 } 499 auto neg = -*this; 500 return Uint128{neg.low, neg.high}; 501 } 502 503 constexpr bool operator==(const Int128& other) const { 504 return low == other.low && high == other.high; 505 } 506 507 constexpr bool operator<(const Int128& other) const { 508 if (high == other.high) { 509 return low < other.low; 510 } 511 return int64_t(high) < int64_t(other.high); 512 } 513 514 // Other operators are implemented in terms of operator== and operator<. 515 constexpr bool operator!=(const Int128& other) const { 516 return !(*this == other); 517 } 518 constexpr bool operator>(const Int128& other) const { return other < *this; } 519 constexpr bool operator<=(const Int128& other) const { 520 return !(other < *this); 521 } 522 constexpr bool operator>=(const Int128& other) const { 523 return !(*this < other); 524 } 525 526 explicit constexpr operator bool() const { return !(*this == Int128{}); } 527 528 explicit constexpr operator int8_t() const { return int8_t(low); } 529 explicit constexpr operator int16_t() const { return int16_t(low); } 530 explicit constexpr operator int32_t() const { return int32_t(low); } 531 explicit constexpr operator int64_t() const { return int64_t(low); } 532 533 explicit constexpr operator uint8_t() const { return uint8_t(low); } 534 explicit constexpr operator uint16_t() const { return uint16_t(low); } 535 explicit constexpr operator uint32_t() const { return uint32_t(low); } 536 explicit constexpr operator uint64_t() const { return uint64_t(low); } 537 538 explicit constexpr operator Uint128() const { return Uint128{low, high}; } 539 540 explicit operator double() const { 541 return Uint128::toDouble(abs(), *this < Int128{0}); 542 } 543 544 constexpr Int128 operator+(const Int128& other) const { 545 return Int128{Uint128{*this} + Uint128{other}}; 546 } 547 548 constexpr Int128 operator-(const Int128& other) const { 549 return Int128{Uint128{*this} - Uint128{other}}; 550 } 551 552 constexpr Int128 operator*(const Int128& other) const { 553 return Int128{Uint128{*this} * Uint128{other}}; 554 } 555 556 constexpr Int128 operator/(const Int128& other) const { 557 auto [quot, rem] = divrem(other); 558 return quot; 559 } 560 561 constexpr Int128 operator%(const Int128& other) const { 562 auto [quot, rem] = divrem(other); 563 return rem; 564 } 565 566 constexpr Int128 operator<<(int shift) const { 567 return Int128{Uint128{*this} << shift}; 568 } 569 570 constexpr Int128 operator>>(int shift) const { 571 MOZ_ASSERT(0 <= shift && shift <= 127, "undefined shift amount"); 572 573 // Ensure the shift amount is in range. 574 shift &= 127; 575 576 // "ยง2-17 Double-Length Shifts" from Hacker's Delight, 2nd edition. 577 if (shift >= 64) { 578 uint64_t y0 = uint64_t(int64_t(high) >> (shift - 64)); 579 uint64_t y1 = uint64_t(int64_t(high) >> 63); 580 return Int128{y0, y1}; 581 } 582 if (shift > 0) { 583 uint64_t y0 = low >> shift | high << (64 - shift); 584 uint64_t y1 = uint64_t(int64_t(high) >> shift); 585 return Int128{y0, y1}; 586 } 587 return *this; 588 } 589 590 constexpr Int128 operator&(const Int128& other) const { 591 return Int128{low & other.low, high & other.high}; 592 } 593 594 constexpr Int128 operator|(const Int128& other) const { 595 return Int128{low | other.low, high | other.high}; 596 } 597 598 constexpr Int128 operator^(const Int128& other) const { 599 return Int128{low ^ other.low, high ^ other.high}; 600 } 601 602 constexpr Int128 operator~() const { return Int128{~low, ~high}; } 603 604 constexpr Int128 operator-() const { return Int128{} - *this; } 605 606 constexpr Int128 operator+() const { return *this; } 607 608 constexpr Int128& operator++() { 609 *this = *this + Int128{1, 0}; 610 return *this; 611 } 612 613 constexpr Int128 operator++(int) { 614 auto result = *this; 615 ++*this; 616 return result; 617 } 618 619 constexpr Int128& operator--() { 620 *this = *this - Int128{1, 0}; 621 return *this; 622 } 623 624 constexpr Int128 operator--(int) { 625 auto result = *this; 626 --*this; 627 return result; 628 } 629 630 constexpr Int128 operator+=(const Int128& other) { 631 *this = *this + other; 632 return *this; 633 } 634 635 constexpr Int128 operator-=(const Int128& other) { 636 *this = *this - other; 637 return *this; 638 } 639 640 constexpr Int128 operator*=(const Int128& other) { 641 *this = *this * other; 642 return *this; 643 } 644 645 constexpr Int128 operator/=(const Int128& other) { 646 *this = *this / other; 647 return *this; 648 } 649 650 constexpr Int128 operator%=(const Int128& other) { 651 *this = *this % other; 652 return *this; 653 } 654 655 constexpr Int128 operator&=(const Int128& other) { 656 *this = *this & other; 657 return *this; 658 } 659 660 constexpr Int128 operator|=(const Int128& other) { 661 *this = *this | other; 662 return *this; 663 } 664 665 constexpr Int128 operator^=(const Int128& other) { 666 *this = *this ^ other; 667 return *this; 668 } 669 670 constexpr Int128 operator<<=(int shift) { 671 *this = *this << shift; 672 return *this; 673 } 674 675 constexpr Int128 operator>>=(int shift) { 676 *this = *this >> shift; 677 return *this; 678 } 679 }; 680 681 constexpr Uint128::operator Int128() const { return Int128{low, high}; } 682 683 } /* namespace js */ 684 685 template <> 686 class std::numeric_limits<js::Int128> { 687 public: 688 static constexpr bool is_specialized = true; 689 static constexpr bool is_signed = true; 690 static constexpr bool is_integer = true; 691 static constexpr bool is_exact = true; 692 static constexpr bool has_infinity = false; 693 static constexpr bool has_quiet_NaN = false; 694 static constexpr bool has_signaling_NaN = false; 695 static constexpr std::float_denorm_style has_denorm = std::denorm_absent; 696 static constexpr bool has_denorm_loss = false; 697 static constexpr std::float_round_style round_style = std::round_toward_zero; 698 static constexpr bool is_iec559 = false; 699 static constexpr bool is_bounded = true; 700 static constexpr bool is_modulo = true; 701 static constexpr int digits = CHAR_BIT * sizeof(js::Int128) - 1; 702 static constexpr int digits10 = int(digits * /* std::log10(2) */ 0.30102999); 703 static constexpr int max_digits10 = 0; 704 static constexpr int radix = 2; 705 static constexpr int min_exponent = 0; 706 static constexpr int min_exponent10 = 0; 707 static constexpr int max_exponent = 0; 708 static constexpr int max_exponent10 = 0; 709 static constexpr bool traps = true; 710 static constexpr bool tinyness_before = false; 711 712 static constexpr auto min() noexcept { return js::Int128{1} << 127; } 713 static constexpr auto lowest() noexcept { return min(); } 714 static constexpr auto max() noexcept { return ~min(); } 715 static constexpr auto epsilon() noexcept { return js::Int128{}; } 716 static constexpr auto round_error() noexcept { return js::Int128{}; } 717 static constexpr auto infinity() noexcept { return js::Int128{}; } 718 static constexpr auto quiet_NaN() noexcept { return js::Int128{}; } 719 static constexpr auto signaling_NaN() noexcept { return js::Int128{}; } 720 static constexpr auto denorm_min() noexcept { return js::Int128{}; } 721 }; 722 723 template <> 724 class std::numeric_limits<js::Uint128> { 725 public: 726 static constexpr bool is_specialized = true; 727 static constexpr bool is_signed = false; 728 static constexpr bool is_integer = true; 729 static constexpr bool is_exact = true; 730 static constexpr bool has_infinity = false; 731 static constexpr bool has_quiet_NaN = false; 732 static constexpr bool has_signaling_NaN = false; 733 static constexpr std::float_denorm_style has_denorm = std::denorm_absent; 734 static constexpr bool has_denorm_loss = false; 735 static constexpr std::float_round_style round_style = std::round_toward_zero; 736 static constexpr bool is_iec559 = false; 737 static constexpr bool is_bounded = true; 738 static constexpr bool is_modulo = true; 739 static constexpr int digits = CHAR_BIT * sizeof(js::Uint128); 740 static constexpr int digits10 = int(digits * /* std::log10(2) */ 0.30102999); 741 static constexpr int max_digits10 = 0; 742 static constexpr int radix = 2; 743 static constexpr int min_exponent = 0; 744 static constexpr int min_exponent10 = 0; 745 static constexpr int max_exponent = 0; 746 static constexpr int max_exponent10 = 0; 747 static constexpr bool traps = true; 748 static constexpr bool tinyness_before = false; 749 750 static constexpr auto min() noexcept { return js::Uint128{}; } 751 static constexpr auto lowest() noexcept { return min(); } 752 static constexpr auto max() noexcept { return ~js::Uint128{}; } 753 static constexpr auto epsilon() noexcept { return js::Uint128{}; } 754 static constexpr auto round_error() noexcept { return js::Uint128{}; } 755 static constexpr auto infinity() noexcept { return js::Uint128{}; } 756 static constexpr auto quiet_NaN() noexcept { return js::Uint128{}; } 757 static constexpr auto signaling_NaN() noexcept { return js::Uint128{}; } 758 static constexpr auto denorm_min() noexcept { return js::Uint128{}; } 759 }; 760 761 #endif /* vm_Int128_h */