Int128.cpp (6923B)
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 #include "vm/Int128.h" 8 9 #include "mozilla/Assertions.h" 10 #include "mozilla/Casting.h" 11 #include "mozilla/FloatingPoint.h" 12 #include "mozilla/MathAlgorithms.h" 13 14 #include <stdint.h> 15 16 using namespace js; 17 18 double Uint128::toDouble(const Uint128& x, bool negative) { 19 // Simplified version of |BigInt::numberValue()| for DigitBits=64. See the 20 // comments in |BigInt::numberValue()| for how this code works. 21 22 using Double = mozilla::FloatingPoint<double>; 23 constexpr uint8_t ExponentShift = Double::kExponentShift; 24 constexpr uint8_t SignificandWidth = Double::kSignificandWidth; 25 constexpr unsigned ExponentBias = Double::kExponentBias; 26 constexpr uint8_t SignShift = Double::kExponentWidth + SignificandWidth; 27 28 constexpr uint64_t MaxIntegralPrecisionDouble = uint64_t(1) 29 << (SignificandWidth + 1); 30 31 // We compute the final mantissa of the result, shifted upward to the top of 32 // the `uint64_t` space -- plus an extra bit to detect potential rounding. 33 constexpr uint8_t BitsNeededForShiftedMantissa = SignificandWidth + 1; 34 35 uint64_t shiftedMantissa = 0; 36 uint64_t exponent = 0; 37 38 // If the extra bit is set, correctly rounding the result may require 39 // examining all lower-order bits. Also compute 1) the index of the Digit 40 // storing the extra bit, and 2) whether bits beneath the extra bit in that 41 // Digit are nonzero so we can round if needed. 42 uint64_t bitsBeneathExtraBitInDigitContainingExtraBit = 0; 43 44 if (x.high == 0) { 45 uint64_t msd = x.low; 46 47 // Fast path for the likely-common case of up to a uint64_t of magnitude not 48 // exceeding integral precision in IEEE-754. 49 if (msd <= MaxIntegralPrecisionDouble) { 50 return negative ? -double(msd) : +double(msd); 51 } 52 53 const uint8_t msdLeadingZeroes = mozilla::CountLeadingZeroes64(msd); 54 MOZ_ASSERT(msdLeadingZeroes <= 10, 55 "leading zeroes is at most 10 when the fast path isn't taken"); 56 57 exponent = 64 - msdLeadingZeroes - 1; 58 59 // Omit the most significant bit: the IEEE-754 format includes this bit 60 // implicitly for all double-precision integers. 61 const uint8_t msdIgnoredBits = msdLeadingZeroes + 1; 62 MOZ_ASSERT(1 <= msdIgnoredBits && msdIgnoredBits <= 11); 63 64 const uint8_t msdIncludedBits = 64 - msdIgnoredBits; 65 MOZ_ASSERT(53 <= msdIncludedBits && msdIncludedBits <= 63); 66 MOZ_ASSERT(msdIncludedBits >= BitsNeededForShiftedMantissa); 67 68 // Munge the most significant bits of the number into proper 69 // position in an IEEE-754 double and go to town. 70 71 // Shift `msd`'s contributed bits upward to remove high-order zeroes and the 72 // highest set bit (which is implicit in IEEE-754 integral values so must be 73 // removed) and to add low-order zeroes. (Lower-order garbage bits are 74 // discarded when `shiftedMantissa` is converted to a real mantissa.) 75 shiftedMantissa = msd << (64 - msdIncludedBits); 76 77 // Add shifted bits to `shiftedMantissa` until we have a complete mantissa 78 // and an extra bit. 79 const uint8_t countOfBitsInDigitBelowExtraBit = 80 64 - BitsNeededForShiftedMantissa - msdIgnoredBits; 81 bitsBeneathExtraBitInDigitContainingExtraBit = 82 msd & ((uint64_t(1) << countOfBitsInDigitBelowExtraBit) - 1); 83 } else { 84 uint64_t msd = x.high; 85 uint64_t second = x.low; 86 87 uint8_t msdLeadingZeroes = mozilla::CountLeadingZeroes64(msd); 88 89 exponent = 2 * 64 - msdLeadingZeroes - 1; 90 91 // Munge the most significant bits of the number into proper 92 // position in an IEEE-754 double and go to town. 93 94 // Omit the most significant bit: the IEEE-754 format includes this bit 95 // implicitly for all double-precision integers. 96 const uint8_t msdIgnoredBits = msdLeadingZeroes + 1; 97 const uint8_t msdIncludedBits = 64 - msdIgnoredBits; 98 99 // Shift `msd`'s contributed bits upward to remove high-order zeroes and the 100 // highest set bit (which is implicit in IEEE-754 integral values so must be 101 // removed) and to add low-order zeroes. (Lower-order garbage bits are 102 // discarded when `shiftedMantissa` is converted to a real mantissa.) 103 shiftedMantissa = msdIncludedBits == 0 ? 0 : msd << (64 - msdIncludedBits); 104 105 // Add shifted bits to `shiftedMantissa` until we have a complete mantissa 106 // and an extra bit. 107 if (msdIncludedBits >= BitsNeededForShiftedMantissa) { 108 const uint8_t countOfBitsInDigitBelowExtraBit = 109 64 - BitsNeededForShiftedMantissa - msdIgnoredBits; 110 bitsBeneathExtraBitInDigitContainingExtraBit = 111 msd & ((uint64_t(1) << countOfBitsInDigitBelowExtraBit) - 1); 112 113 if (bitsBeneathExtraBitInDigitContainingExtraBit == 0) { 114 bitsBeneathExtraBitInDigitContainingExtraBit = second; 115 } 116 } else { 117 shiftedMantissa |= second >> msdIncludedBits; 118 119 const uint8_t countOfBitsInSecondDigitBelowExtraBit = 120 (msdIncludedBits + 64) - BitsNeededForShiftedMantissa; 121 bitsBeneathExtraBitInDigitContainingExtraBit = 122 second << (64 - countOfBitsInSecondDigitBelowExtraBit); 123 } 124 } 125 126 constexpr uint64_t LeastSignificantBit = uint64_t(1) 127 << (64 - SignificandWidth); 128 constexpr uint64_t ExtraBit = LeastSignificantBit >> 1; 129 130 // The extra bit must be set for rounding to change the mantissa. 131 if ((shiftedMantissa & ExtraBit) != 0) { 132 bool shouldRoundUp; 133 if (shiftedMantissa & LeastSignificantBit) { 134 // If the lowest mantissa bit is set, it doesn't matter what lower bits 135 // are: nearest-even rounds up regardless. 136 shouldRoundUp = true; 137 } else { 138 // If the lowest mantissa bit is unset, *all* lower bits are relevant. 139 // All-zero bits below the extra bit situates `x` halfway between two 140 // values, and the nearest *even* value lies downward. But if any bit 141 // below the extra bit is set, `x` is closer to the rounded-up value. 142 shouldRoundUp = bitsBeneathExtraBitInDigitContainingExtraBit != 0; 143 } 144 145 if (shouldRoundUp) { 146 // Add one to the significand bits. If they overflow, the exponent must 147 // also be increased. If *that* overflows, return the correct infinity. 148 uint64_t before = shiftedMantissa; 149 shiftedMantissa += ExtraBit; 150 if (shiftedMantissa < before) { 151 exponent++; 152 } 153 } 154 } 155 156 uint64_t significandBits = shiftedMantissa >> (64 - SignificandWidth); 157 uint64_t signBit = uint64_t(negative ? 1 : 0) << SignShift; 158 uint64_t exponentBits = (exponent + ExponentBias) << ExponentShift; 159 return mozilla::BitwiseCast<double>(signBit | exponentBits | significandBits); 160 }