зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1558538 - BigInt-to-Number conversion is rather borken. r=wingo
Differential Revision: https://phabricator.services.mozilla.com/D34678 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
d7a28a9a95
Коммит
c69f589086
|
@ -0,0 +1,187 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("BigInt"))
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// https://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
/**
|
||||
* Simple single-Digit on x64, double-Digit on x86 tests.
|
||||
*/
|
||||
|
||||
assertEq(BigInt(Number(2n**53n - 2n)), 2n**53n - 2n);
|
||||
assertEq(BigInt(Number(2n**53n - 1n)), 2n**53n - 1n);
|
||||
assertEq(BigInt(Number(2n**53n)), 2n**53n);
|
||||
assertEq(BigInt(Number(2n**53n + 1n)), 2n**53n);
|
||||
assertEq(BigInt(Number(2n**53n + 2n)), 2n**53n + 2n);
|
||||
assertEq(BigInt(Number(2n**53n + 3n)), 2n**53n + 4n);
|
||||
assertEq(BigInt(Number(2n**53n + 4n)), 2n**53n + 4n);
|
||||
assertEq(BigInt(Number(2n**53n + 5n)), 2n**53n + 4n);
|
||||
assertEq(BigInt(Number(2n**53n + 6n)), 2n**53n + 6n);
|
||||
assertEq(BigInt(Number(2n**53n + 7n)), 2n**53n + 8n);
|
||||
assertEq(BigInt(Number(2n**53n + 8n)), 2n**53n + 8n);
|
||||
|
||||
assertEq(BigInt(Number(2n**54n - 4n)), 2n**54n - 4n);
|
||||
assertEq(BigInt(Number(2n**54n - 3n)), 2n**54n - 4n);
|
||||
assertEq(BigInt(Number(2n**54n - 2n)), 2n**54n - 2n);
|
||||
assertEq(BigInt(Number(2n**54n - 1n)), 2n**54n);
|
||||
assertEq(BigInt(Number(2n**54n)), 2n**54n);
|
||||
assertEq(BigInt(Number(2n**54n + 1n)), 2n**54n);
|
||||
assertEq(BigInt(Number(2n**54n + 2n)), 2n**54n);
|
||||
assertEq(BigInt(Number(2n**54n + 3n)), 2n**54n + 4n);
|
||||
assertEq(BigInt(Number(2n**54n + 4n)), 2n**54n + 4n);
|
||||
assertEq(BigInt(Number(2n**54n + 5n)), 2n**54n + 4n);
|
||||
assertEq(BigInt(Number(2n**54n + 6n)), 2n**54n + 8n);
|
||||
assertEq(BigInt(Number(2n**54n + 7n)), 2n**54n + 8n);
|
||||
assertEq(BigInt(Number(2n**54n + 8n)), 2n**54n + 8n);
|
||||
|
||||
assertEq(BigInt(Number(2n**55n - 8n)), 2n**55n - 8n);
|
||||
assertEq(BigInt(Number(2n**55n - 7n)), 2n**55n - 8n);
|
||||
assertEq(BigInt(Number(2n**55n - 6n)), 2n**55n - 8n);
|
||||
assertEq(BigInt(Number(2n**55n - 5n)), 2n**55n - 4n);
|
||||
assertEq(BigInt(Number(2n**55n - 4n)), 2n**55n - 4n);
|
||||
assertEq(BigInt(Number(2n**55n - 3n)), 2n**55n - 4n);
|
||||
assertEq(BigInt(Number(2n**55n - 2n)), 2n**55n);
|
||||
assertEq(BigInt(Number(2n**55n - 1n)), 2n**55n);
|
||||
assertEq(BigInt(Number(2n**55n)), 2n**55n);
|
||||
assertEq(BigInt(Number(2n**55n + 1n)), 2n**55n);
|
||||
assertEq(BigInt(Number(2n**55n + 2n)), 2n**55n);
|
||||
assertEq(BigInt(Number(2n**55n + 3n)), 2n**55n);
|
||||
assertEq(BigInt(Number(2n**55n + 4n)), 2n**55n);
|
||||
assertEq(BigInt(Number(2n**55n + 5n)), 2n**55n + 8n);
|
||||
assertEq(BigInt(Number(2n**55n + 6n)), 2n**55n + 8n);
|
||||
assertEq(BigInt(Number(2n**55n + 7n)), 2n**55n + 8n);
|
||||
assertEq(BigInt(Number(2n**55n + 8n)), 2n**55n + 8n);
|
||||
assertEq(BigInt(Number(2n**55n + 9n)), 2n**55n + 8n);
|
||||
assertEq(BigInt(Number(2n**55n + 10n)), 2n**55n + 8n);
|
||||
assertEq(BigInt(Number(2n**55n + 11n)), 2n**55n + 8n);
|
||||
assertEq(BigInt(Number(2n**55n + 12n)), 2n**55n + 16n);
|
||||
assertEq(BigInt(Number(2n**55n + 13n)), 2n**55n + 16n);
|
||||
assertEq(BigInt(Number(2n**55n + 14n)), 2n**55n + 16n);
|
||||
assertEq(BigInt(Number(2n**55n + 15n)), 2n**55n + 16n);
|
||||
assertEq(BigInt(Number(2n**55n + 16n)), 2n**55n + 16n);
|
||||
|
||||
|
||||
/**
|
||||
* Simple double-Digit on x64, triple-Digit on x86 tests.
|
||||
*/
|
||||
|
||||
// The tests below that aren't subtracting bits will have no bits in the
|
||||
// ultimate significand from the most-significant digit (because of the implicit
|
||||
// one being excluded).
|
||||
assertEq(BigInt(Number(2n**64n - 2n**11n)), 2n**64n - 2n**11n);
|
||||
assertEq(BigInt(Number(2n**64n - 2n**11n + 2n**10n - 1n)), 2n**64n - 2n**11n);
|
||||
assertEq(BigInt(Number(2n**64n - 2n**11n + 2n**10n)), 2n**64n);
|
||||
assertEq(BigInt(Number(2n**64n - 2n**10n)), 2n**64n);
|
||||
assertEq(BigInt(Number(2n**64n)), 2n**64n);
|
||||
assertEq(BigInt(Number(2n**64n + 1n)), 2n**64n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**5n)), 2n**64n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**10n)), 2n**64n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**11n)), 2n**64n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**11n + 1n)), 2n**64n + 2n**12n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**12n)), 2n**64n + 2n**12n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**12n + 1n)), 2n**64n + 2n**12n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**5n)), 2n**64n + 2n**12n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**10n)), 2n**64n + 2n**12n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**11n - 1n)), 2n**64n + 2n**12n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**11n)), 2n**64n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**11n + 1n)), 2n**64n + 2n**13n);
|
||||
|
||||
// These tests *will* have a bit from the most-significant digit in the ultimate
|
||||
// significand.
|
||||
assertEq(BigInt(Number(2n**65n - 2n**12n)), 2n**65n - 2n**12n);
|
||||
assertEq(BigInt(Number(2n**65n - 2n**12n + 2n**11n - 1n)), 2n**65n - 2n**12n);
|
||||
assertEq(BigInt(Number(2n**65n - 2n**12n + 2n**11n)), 2n**65n);
|
||||
assertEq(BigInt(Number(2n**65n - 2n**11n)), 2n**65n);
|
||||
assertEq(BigInt(Number(2n**65n)), 2n**65n);
|
||||
assertEq(BigInt(Number(2n**65n + 1n)), 2n**65n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**5n)), 2n**65n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**11n)), 2n**65n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**12n)), 2n**65n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**12n + 1n)), 2n**65n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**13n)), 2n**65n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**13n + 1n)), 2n**65n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**5n)), 2n**65n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**11n)), 2n**65n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**12n - 1n)), 2n**65n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**12n)), 2n**65n + 2n**14n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**12n + 1n)), 2n**65n + 2n**14n);
|
||||
|
||||
// ...and in these tests, the contributed bit from the most-significant digit
|
||||
// is additionally nonzero.
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n)), 2n**65n + 2n**64n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 1n)), 2n**65n + 2n**64n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**5n)), 2n**65n + 2n**64n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**11n)), 2n**65n + 2n**64n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**12n)), 2n**65n + 2n**64n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**12n + 1n)), 2n**65n + 2n**64n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n)), 2n**65n + 2n**64n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 1n)), 2n**65n + 2n**64n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**5n)), 2n**65n + 2n**64n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**11n)), 2n**65n + 2n**64n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**12n - 1n)), 2n**65n + 2n**64n + 2n**13n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**12n)), 2n**65n + 2n**64n + 2n**14n);
|
||||
assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**12n + 1n)), 2n**65n + 2n**64n + 2n**14n);
|
||||
|
||||
/**
|
||||
* Versions of the testing above with all the high-order bits massively bumped
|
||||
* upward to test that super-low bits, not just bits in high digits, are
|
||||
* properly accounted for in rounding.
|
||||
*/
|
||||
|
||||
// The tests below that aren't subtracting bits will have no bits in the
|
||||
// ultimate significand from the most-significant digit (because of the implicit
|
||||
// one being excluded).
|
||||
assertEq(BigInt(Number(2n**940n - 2n**887n + 1n)), 2n**940n - 2n**887n);
|
||||
assertEq(BigInt(Number(2n**940n - 2n**887n + 2n**886n - 1n)), 2n**940n - 2n**887n);
|
||||
assertEq(BigInt(Number(2n**940n - 2n**887n + 2n**886n)), 2n**940n);
|
||||
assertEq(BigInt(Number(2n**940n - 2n**886n)), 2n**940n);
|
||||
assertEq(BigInt(Number(2n**940n)), 2n**940n);
|
||||
assertEq(BigInt(Number(2n**940n + 1n)), 2n**940n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**880n)), 2n**940n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**885n)), 2n**940n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**887n)), 2n**940n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**887n + 1n)), 2n**940n + 2n**888n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**888n)), 2n**940n + 2n**888n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**888n + 1n)), 2n**940n + 2n**888n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**5n)), 2n**940n + 2n**888n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**12n)), 2n**940n + 2n**888n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**887n - 1n)), 2n**940n + 2n**888n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**887n)), 2n**940n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**887n + 1n)), 2n**940n + 2n**889n);
|
||||
|
||||
// These tests *will* have a bit from the most-significant digit in the ultimate
|
||||
// significand.
|
||||
assertEq(BigInt(Number(2n**941n - 2n**888n)), 2n**941n - 2n**888n);
|
||||
assertEq(BigInt(Number(2n**941n - 2n**888n + 2n**887n - 1n)), 2n**941n - 2n**888n);
|
||||
assertEq(BigInt(Number(2n**941n - 2n**888n + 2n**887n)), 2n**941n);
|
||||
assertEq(BigInt(Number(2n**941n - 2n**887n)), 2n**941n);
|
||||
assertEq(BigInt(Number(2n**941n)), 2n**941n);
|
||||
assertEq(BigInt(Number(2n**941n + 1n)), 2n**941n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**881n)), 2n**941n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**886n)), 2n**941n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**888n)), 2n**941n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**888n + 1n)), 2n**941n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**889n)), 2n**941n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**889n + 1n)), 2n**941n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**5n)), 2n**941n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**12n)), 2n**941n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**888n - 1n)), 2n**941n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**888n)), 2n**941n + 2n**890n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**888n + 1n)), 2n**941n + 2n**890n);
|
||||
|
||||
// ...and in these tests, the contributed bit from the most-significant digit
|
||||
// is additionally nonzero.
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n)), 2n**941n + 2n**940n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 1n)), 2n**941n + 2n**940n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**881n)), 2n**941n + 2n**940n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**886n)), 2n**941n + 2n**940n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**888n)), 2n**941n + 2n**940n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**888n + 1n)), 2n**941n + 2n**940n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n)), 2n**941n + 2n**940n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 1n)), 2n**941n + 2n**940n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**5n)), 2n**941n + 2n**940n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**12n)), 2n**941n + 2n**940n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**888n - 1n)), 2n**941n + 2n**940n + 2n**889n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**888n)), 2n**941n + 2n**940n + 2n**890n);
|
||||
assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**888n + 1n)), 2n**941n + 2n**940n + 2n**890n);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -2726,8 +2726,9 @@ double BigInt::numberValue(BigInt* x) {
|
|||
size_t length = x->digitLength();
|
||||
MOZ_ASSERT(length != 0);
|
||||
|
||||
// Fast path for the likely-common case of up to a uint64_t of magnitude
|
||||
// that doesn't exceed integral precision in IEEE-754.
|
||||
// Fast path for the likely-common case of up to a uint64_t of magnitude not
|
||||
// exceeding integral precision in IEEE-754. (Note that we *depend* on this
|
||||
// optimization being performed further down.)
|
||||
if (length <= 64 / DigitBits) {
|
||||
uint64_t magnitude = x->digit(0);
|
||||
if (DigitBits == 32 && length > 1) {
|
||||
|
@ -2760,62 +2761,165 @@ double BigInt::numberValue(BigInt* x) {
|
|||
const uint8_t msdIgnoredBits = msdLeadingZeroes + 1;
|
||||
const uint8_t msdIncludedBits = DigitBits - msdIgnoredBits;
|
||||
|
||||
uint8_t bitsFilled = msdIncludedBits;
|
||||
// We compute the final mantissa of the result, shifted upward to the top of
|
||||
// the `uint64_t` space -- plus an extra bit to detect potential rounding.
|
||||
constexpr uint8_t BitsNeededForShiftedMantissa = SignificandWidth + 1;
|
||||
|
||||
// Shift `msd`'s contributed bits upward to remove high-order zeroes and
|
||||
// the highest set bit (which is implicit in IEEE-754 integral values so
|
||||
// must be removed) and to add low-order zeroes.
|
||||
// Shift `msd`'s contributed bits upward to remove high-order zeroes and the
|
||||
// highest set bit (which is implicit in IEEE-754 integral values so must be
|
||||
// removed) and to add low-order zeroes. (Lower-order garbage bits are
|
||||
// discarded when `shiftedMantissa` is converted to a real mantissa.)
|
||||
uint64_t shiftedMantissa =
|
||||
msdIncludedBits == 0 ? 0 : uint64_t(msd) << (64 - msdIncludedBits);
|
||||
|
||||
// Add in bits from the next one or two digits if `msd` didn't contain all
|
||||
// bits necessary to define the result. (The extra bit allows us to
|
||||
// properly round an inexact overall result.) Any lower bits that are
|
||||
// uselessly set will be shifted away when `shiftedMantissa` is converted to
|
||||
// a real mantissa.
|
||||
if (bitsFilled < SignificandWidth + 1) {
|
||||
// If the extra bit is set, correctly rounding the result may require
|
||||
// examining all lower-order bits. Also compute 1) the index of the Digit
|
||||
// storing the extra bit, and 2) whether bits beneath the extra bit in that
|
||||
// Digit are nonzero so we can round if needed.
|
||||
size_t digitContainingExtraBit;
|
||||
Digit bitsBeneathExtraBitInDigitContainingExtraBit;
|
||||
|
||||
// Add shifted bits to `shiftedMantissa` until we have a complete mantissa and
|
||||
// an extra bit.
|
||||
if (msdIncludedBits >= BitsNeededForShiftedMantissa) {
|
||||
// DigitBits=64 (necessarily for msdIncludedBits ≥ SignificandWidth+1;
|
||||
// | C++ compiler range analysis ought eliminate this
|
||||
// | check on 32-bit)
|
||||
// _________|__________
|
||||
// / |
|
||||
// msdIncludedBits
|
||||
// ________|________
|
||||
// / |
|
||||
// [001···················|
|
||||
// \_/\_____________/\__|
|
||||
// | | |
|
||||
// msdIgnoredBits | bits below the extra bit (may be no bits)
|
||||
// BitsNeededForShiftedMantissa=SignificandWidth+1
|
||||
digitContainingExtraBit = length - 1;
|
||||
|
||||
const uint8_t countOfBitsInDigitBelowExtraBit =
|
||||
DigitBits - BitsNeededForShiftedMantissa - msdIgnoredBits;
|
||||
bitsBeneathExtraBitInDigitContainingExtraBit =
|
||||
msd & ((Digit(1) << countOfBitsInDigitBelowExtraBit) - 1);
|
||||
} else {
|
||||
MOZ_ASSERT(length >= 2,
|
||||
"single-Digit numbers with this few bits should have been "
|
||||
"handled by the fast-path above");
|
||||
|
||||
Digit second = x->digit(length - 2);
|
||||
if (DigitBits == 32) {
|
||||
shiftedMantissa |= uint64_t(second) << msdIgnoredBits;
|
||||
bitsFilled += DigitBits;
|
||||
if (DigitBits == 64) {
|
||||
shiftedMantissa |= second >> msdIncludedBits;
|
||||
|
||||
digitContainingExtraBit = length - 2;
|
||||
|
||||
// msdIncludedBits + DigitBits
|
||||
// ________|_________
|
||||
// / |
|
||||
// DigitBits=64
|
||||
// msdIncludedBits |
|
||||
// __|___ _____|___
|
||||
// / \ / |
|
||||
// [001········|···········|
|
||||
// \_/\_____________/\___|
|
||||
// | | |
|
||||
// msdIgnoredBits | bits below the extra bit (always more than one)
|
||||
// |
|
||||
// BitsNeededForShiftedMantissa=SignificandWidth+1
|
||||
const uint8_t countOfBitsInSecondDigitBelowExtraBit =
|
||||
(msdIncludedBits + DigitBits) - BitsNeededForShiftedMantissa;
|
||||
|
||||
bitsBeneathExtraBitInDigitContainingExtraBit =
|
||||
second << (DigitBits - countOfBitsInSecondDigitBelowExtraBit);
|
||||
} else {
|
||||
shiftedMantissa |= uint64_t(second) << msdIgnoredBits;
|
||||
|
||||
if (msdIncludedBits + DigitBits >= BitsNeededForShiftedMantissa) {
|
||||
digitContainingExtraBit = length - 2;
|
||||
|
||||
// msdIncludedBits + DigitBits
|
||||
// ______|________
|
||||
// / |
|
||||
// DigitBits=32
|
||||
// msdIncludedBits |
|
||||
// _|_ _____|___
|
||||
// / \ / |
|
||||
// [001·····|···········|
|
||||
// \___________/\__|
|
||||
// | |
|
||||
// | bits below the extra bit (may be no bits)
|
||||
// BitsNeededForShiftedMantissa=SignificandWidth+1
|
||||
const uint8_t countOfBitsInSecondDigitBelowExtraBit =
|
||||
(msdIncludedBits + DigitBits) - BitsNeededForShiftedMantissa;
|
||||
|
||||
bitsBeneathExtraBitInDigitContainingExtraBit =
|
||||
second & ((Digit(1) << countOfBitsInSecondDigitBelowExtraBit) - 1);
|
||||
} else {
|
||||
MOZ_ASSERT(length >= 3,
|
||||
"we must have at least three digits here, because "
|
||||
"`msdIncludedBits + 32 < BitsNeededForShiftedMantissa` "
|
||||
"guarantees `x < 2**53` -- and therefore the "
|
||||
"MaxIntegralPrecisionDouble optimization above will have "
|
||||
"handled two-digit cases");
|
||||
|
||||
// Add in bits from another digit, if any, if we still have unfilled
|
||||
// significand bits.
|
||||
if (bitsFilled < SignificandWidth + 1 && length >= 3) {
|
||||
Digit third = x->digit(length - 3);
|
||||
shiftedMantissa |= uint64_t(third) >> msdIncludedBits;
|
||||
// The second and third 32-bit digits contributed 64 bits total, filling
|
||||
// well beyond the mantissa.
|
||||
bitsFilled = 64;
|
||||
|
||||
digitContainingExtraBit = length - 3;
|
||||
|
||||
// msdIncludedBits + DigitBits + DigitBits
|
||||
// ____________|______________
|
||||
// / |
|
||||
// DigitBits=32
|
||||
// msdIncludedBits | DigitBits=32
|
||||
// _|_ _____|___ ____|____
|
||||
// / \ / \ / |
|
||||
// [001·····|···········|···········|
|
||||
// \____________________/\_____|
|
||||
// | |
|
||||
// | bits below the extra bit
|
||||
// BitsNeededForShiftedMantissa=SignificandWidth+1
|
||||
static_assert(2 * DigitBits > BitsNeededForShiftedMantissa,
|
||||
"two 32-bit digits should more than fill a mantissa");
|
||||
const uint8_t countOfBitsInThirdDigitBelowExtraBit =
|
||||
msdIncludedBits + 2 * DigitBits - BitsNeededForShiftedMantissa;
|
||||
|
||||
// Shift out the mantissa bits and the extra bit.
|
||||
bitsBeneathExtraBitInDigitContainingExtraBit =
|
||||
third << (DigitBits - countOfBitsInThirdDigitBelowExtraBit);
|
||||
}
|
||||
} else {
|
||||
shiftedMantissa |= second >> msdIncludedBits;
|
||||
// A full 64-bit digit's worth of bits (some from the most significant
|
||||
// digit, the rest from the next) fills well beyond the mantissa.
|
||||
bitsFilled = 64;
|
||||
}
|
||||
}
|
||||
|
||||
// Round the overall result, if necessary. (It's possible we don't need to
|
||||
// round -- the number might not have enough bits to round.)
|
||||
if (bitsFilled >= SignificandWidth + 1) {
|
||||
constexpr uint64_t LeastSignificantBit = uint64_t(1)
|
||||
<< (64 - SignificandWidth);
|
||||
constexpr uint64_t ExtraBit = LeastSignificantBit >> 1;
|
||||
constexpr uint64_t LeastSignificantBit = uint64_t(1)
|
||||
<< (64 - SignificandWidth);
|
||||
constexpr uint64_t ExtraBit = LeastSignificantBit >> 1;
|
||||
|
||||
// When the first bit outside the significand is set, the overall value
|
||||
// is rounded: downward (i.e. no change to the bits) if the least
|
||||
// significant bit in the significand is zero, upward if it instead is
|
||||
// one.
|
||||
if ((shiftedMantissa & ExtraBit) &&
|
||||
(shiftedMantissa & LeastSignificantBit)) {
|
||||
// We're rounding upward: add to the significand bits. If they
|
||||
// overflow, the exponent must also be increased. If *that*
|
||||
// overflows, return the appropriate infinity.
|
||||
// The extra bit must be set for rounding to change the mantissa.
|
||||
if ((shiftedMantissa & ExtraBit) != 0) {
|
||||
bool shouldRoundUp;
|
||||
if (shiftedMantissa & LeastSignificantBit) {
|
||||
// If the lowest mantissa bit is set, it doesn't matter what lower bits
|
||||
// are: nearest-even rounds up regardless.
|
||||
shouldRoundUp = true;
|
||||
} else {
|
||||
// If the lowest mantissa bit is unset, *all* lower bits are relevant.
|
||||
// All-zero bits below the extra bit situates `x` halfway between two
|
||||
// values, and the nearest *even* value lies downward. But if any bit
|
||||
// below the extra bit is set, `x` is closer to the rounded-up value.
|
||||
shouldRoundUp = bitsBeneathExtraBitInDigitContainingExtraBit != 0;
|
||||
if (!shouldRoundUp) {
|
||||
while (digitContainingExtraBit-- > 0) {
|
||||
if (x->digit(digitContainingExtraBit) != 0) {
|
||||
shouldRoundUp = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldRoundUp) {
|
||||
// Add one to the significand bits. If they overflow, the exponent must
|
||||
// also be increased. If *that* overflows, return the correct infinity.
|
||||
uint64_t before = shiftedMantissa;
|
||||
shiftedMantissa += ExtraBit;
|
||||
if (shiftedMantissa < before) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче