Int96.cpp (2516B)
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 "builtin/temporal/Int96.h" 8 9 #include "mozilla/Assertions.h" 10 #include "mozilla/Casting.h" 11 #include "mozilla/FloatingPoint.h" 12 #include "mozilla/Maybe.h" 13 14 #include <cmath> 15 #include <stdint.h> 16 17 #include "jsnum.h" 18 19 using namespace js; 20 using namespace js::temporal; 21 22 mozilla::Maybe<Int96> Int96::fromInteger(double value) { 23 MOZ_ASSERT(IsInteger(value)); 24 25 // Fast path for the common case. 26 int64_t intValue; 27 if (mozilla::NumberEqualsInt64(value, &intValue)) { 28 return mozilla::Some(Int96{intValue}); 29 } 30 31 // First double integer which requires more than three digits. 32 constexpr double maximum = 0x1p+96; 33 34 // Reject if the value needs more than 96 bits. 35 if (std::abs(value) >= maximum) { 36 return mozilla::Nothing(); 37 } 38 39 // Inlined version of |BigInt::createFromDouble()| for DigitBits=32. See the 40 // comments in |BigInt::createFromDouble()| for how this code works. 41 constexpr int DigitBits = 32; 42 43 // The number can't have more than three digits when it's below |maximum|. 44 Int96::Digits digits = {}; 45 46 int exponent = int(mozilla::ExponentComponent(value)); 47 MOZ_ASSERT(0 <= exponent && exponent <= 95, 48 "exponent is lower than exponent of 0x1p+96"); 49 50 int length = exponent / DigitBits + 1; 51 MOZ_ASSERT(1 <= length && length <= 3); 52 53 using Double = mozilla::FloatingPoint<double>; 54 uint64_t mantissa = 55 mozilla::BitwiseCast<uint64_t>(value) & Double::kSignificandBits; 56 57 // Add implicit high bit. 58 mantissa |= 1ull << Double::kSignificandWidth; 59 60 // 0-indexed position of the double's most significant bit within the `msd`. 61 int msdTopBit = exponent % DigitBits; 62 63 // First, build the MSD by shifting the mantissa appropriately. 64 int remainingMantissaBits = int(Double::kSignificandWidth - msdTopBit); 65 digits[--length] = mantissa >> remainingMantissaBits; 66 67 // Fill in digits containing mantissa contributions. 68 mantissa = mantissa << (64 - remainingMantissaBits); 69 if (mantissa) { 70 MOZ_ASSERT(length > 0); 71 digits[--length] = uint32_t(mantissa >> 32); 72 73 if (uint32_t(mantissa)) { 74 MOZ_ASSERT(length > 0); 75 digits[--length] = uint32_t(mantissa); 76 } 77 } 78 79 return mozilla::Some(Int96{digits, value < 0}); 80 }