diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2019-06-16 14:43:09 -0400 |
---|---|---|
committer | Billy Donahue <billy.donahue@mongodb.com> | 2019-06-16 14:43:09 -0400 |
commit | 58df54d9c73b28bddfb2d83014f653f0c06ef44e (patch) | |
tree | 172189ec94c58019f531adaf731cfe31c2ea5346 /src/mongo/platform | |
parent | e039271638d6dba34e5b64834e3f12e87aeb6455 (diff) | |
download | mongo-58df54d9c73b28bddfb2d83014f653f0c06ef44e.tar.gz |
Revert "SERVER-24374 Make Decimal128 integer ctors constexpr"
This reverts commit e039271638d6dba34e5b64834e3f12e87aeb6455.
Diffstat (limited to 'src/mongo/platform')
-rw-r--r-- | src/mongo/platform/decimal128.cpp | 31 | ||||
-rw-r--r-- | src/mongo/platform/decimal128.h | 99 | ||||
-rw-r--r-- | src/mongo/platform/decimal128_test.cpp | 125 |
3 files changed, 122 insertions, 133 deletions
diff --git a/src/mongo/platform/decimal128.cpp b/src/mongo/platform/decimal128.cpp index a48a310bf74..18d59af7490 100644 --- a/src/mongo/platform/decimal128.cpp +++ b/src/mongo/platform/decimal128.cpp @@ -187,6 +187,15 @@ BID_UINT128 decimal128ToLibraryType(Decimal128::Value value) { } } // namespace +Decimal128::Decimal128(std::int32_t int32Value) + : _value(libraryTypeToValue(bid128_from_int32(int32Value))) {} + +Decimal128::Decimal128(std::int64_t int64Value) + : _value(libraryTypeToValue(bid128_from_int64(int64Value))) {} + +Decimal128::Decimal128(std::uint64_t uint64Value) + : _value(libraryTypeToValue(bid128_from_uint64(uint64Value))) {} + /** * Quantize a doubleValue argument to a Decimal128 with exactly 15 digits * of precision. @@ -283,8 +292,8 @@ Decimal128::Decimal128(double doubleValue, // Check if the quantization was done correctly: _value stores exactly 15 // decimal digits of precision (15 digits can fit into the low 64 bits of the decimal) - std::uint64_t kSmallest15DigitInt = 1E14; // A 1 with 14 zeros - std::uint64_t kLargest15DigitInt = 1E15 - 1; // 15 nines + uint64_t kSmallest15DigitInt = 1E14; // A 1 with 14 zeros + uint64_t kLargest15DigitInt = 1E15 - 1; // 15 nines if (getCoefficientLow() > kLargest15DigitInt) { // If we didn't precisely get 15 digits of precision, the original base 10 exponent // guess was 1 off, so quantize once more with base10Exp + 1 @@ -315,6 +324,10 @@ Decimal128::Decimal128(std::string stringValue, _value = libraryTypeToValue(dec128); } +Decimal128::Value Decimal128::getValue() const { + return _value; +} + Decimal128 Decimal128::toAbs() const { BID_UINT128 dec128 = decimal128ToLibraryType(_value); dec128 = bid128_abs(dec128); @@ -448,12 +461,12 @@ std::int32_t Decimal128::toInt(std::uint32_t* signalingFlags, RoundingMode round } } -std::int64_t Decimal128::toLong(RoundingMode roundMode) const { +int64_t Decimal128::toLong(RoundingMode roundMode) const { std::uint32_t throwAwayFlag = 0; return toLong(&throwAwayFlag, roundMode); } -std::int64_t Decimal128::toLong(std::uint32_t* signalingFlags, RoundingMode roundMode) const { +int64_t Decimal128::toLong(std::uint32_t* signalingFlags, RoundingMode roundMode) const { BID_UINT128 dec128 = decimal128ToLibraryType(_value); switch (roundMode) { case kRoundTiesToEven: @@ -900,10 +913,10 @@ Decimal128 Decimal128::quantize(const Decimal128& reference, auto normalizedThis = this->normalize(); auto normalizedReferenceExponent = - static_cast<std::int32_t>(reference.normalize().getBiasedExponent()); + static_cast<int32_t>(reference.normalize().getBiasedExponent()); if (normalizedReferenceExponent != 0 && - (static_cast<std::int32_t>(normalizedThis.getBiasedExponent()) - - normalizedReferenceExponent) > 33) { + (static_cast<int32_t>(normalizedThis.getBiasedExponent()) - normalizedReferenceExponent) > + 33) { return normalizedThis; } return nonNormalizingQuantize(reference, signalingFlags, roundMode); @@ -976,7 +989,7 @@ const std::uint64_t t17 = 100ull * 1000 * 1000 * 1000 * 1000 * 1000; // Computed by running the calculations in Python, and verified with static_assert. const std::uint64_t t34lo64 = 4003012203950112767ULL; #if defined(__GNUC__) -MONGO_STATIC_ASSERT(t34lo64 == t17 * t17 - 1); +static_assert(t34lo64 == t17 * t17 - 1, "precomputed constant is wrong"); #endif // Mod t17 by 2^32 to get the low 32 bits of t17's binary representation const std::uint64_t t17lo32 = t17 % (1ull << 32); @@ -1001,7 +1014,7 @@ const Decimal128 Decimal128::kSmallestNegative(1, 0, 0, 1); // Get the representation of 0 (0E0). const Decimal128 Decimal128::kNormalizedZero(Decimal128::Value( - {0, static_cast<std::uint64_t>(Decimal128::kExponentBias) << Decimal128::kExponentFieldPos})); + {0, static_cast<uint64_t>(Decimal128::kExponentBias) << Decimal128::kExponentFieldPos})); // Shift the format of the combination bits to the right position to get Inf and NaN // +Inf = 0111 1000 ... ... = 0x78 ... ..., -Inf = 1111 1000 ... ... = 0xf8 ... ... diff --git a/src/mongo/platform/decimal128.h b/src/mongo/platform/decimal128.h index 3295e28a2b9..7b96d8e2611 100644 --- a/src/mongo/platform/decimal128.h +++ b/src/mongo/platform/decimal128.h @@ -33,13 +33,11 @@ #include <cstdint> #include <iostream> #include <string> -#include <type_traits> #include <utility> #include "mongo/config.h" #include "mongo/util/assert_util.h" -#include "mongo/util/if_constexpr.h" namespace mongo { @@ -77,11 +75,10 @@ public: static const Decimal128 kPiOver180; static const Decimal128 k180OverPi; - static constexpr std::uint32_t kMaxBiasedExponent = 6143 + 6144; + static const uint32_t kMaxBiasedExponent = 6143 + 6144; // Biased exponent of a Decimal128 with least significant digit in the units place - static constexpr std::int32_t kExponentBias = 6143 + 33; - static constexpr std::uint32_t kInfinityExponent = - kMaxBiasedExponent + 1; // internal convention only + static const int32_t kExponentBias = 6143 + 33; + static const uint32_t kInfinityExponent = kMaxBiasedExponent + 1; // internal convention only /** * This struct holds the raw data for IEEE 754-2008 data types @@ -127,17 +124,17 @@ public: kInexact = 0x20, }; - constexpr static bool hasFlag(std::uint32_t signalingFlags, SignalingFlag f) { + static bool hasFlag(std::uint32_t signalingFlags, SignalingFlag f) { return ((signalingFlags & f) != 0u); } /** * Returns true if a valid Decimal can be constructed from the given arguments. */ - constexpr static bool isValid(std::uint64_t sign, - std::uint64_t exponent, - std::uint64_t coefficientHigh, - std::uint64_t coefficientLow) { + static bool isValid(uint64_t sign, + uint64_t exponent, + uint64_t coefficientHigh, + uint64_t coefficientLow) { if (coefficientHigh >= 0x1ed09bead87c0 && (coefficientHigh != 0x1ed09bead87c0 || coefficientLow != 0x378d8e63ffffffff)) { return false; @@ -152,10 +149,7 @@ public: /** * Construct a 0E0 valued Decimal128. */ - constexpr Decimal128() - : _value{0, - static_cast<std::uint64_t>(Decimal128::kExponentBias) - << Decimal128::kExponentFieldPos} {} + Decimal128() : _value(kNormalizedZero._value) {} /** * This constructor takes in a raw decimal128 type, which consists of two @@ -168,15 +162,16 @@ public: * Constructs a Decimal128 from parts, dealing with proper encoding of the combination field. * Assumes that the value will be inside the valid range of finite values. (No NaN/Inf, etc.) */ - constexpr Decimal128(std::uint64_t sign, - std::uint64_t exponent, - std::uint64_t coefficientHigh, - std::uint64_t coefficientLow) - : _value(_valueFromParts(sign, exponent, coefficientHigh, coefficientLow)) {} + Decimal128(uint64_t sign, uint64_t exponent, uint64_t coefficientHigh, uint64_t coefficientLow) + : _value( + Value{coefficientLow, + (sign << kSignFieldPos) | (exponent << kExponentFieldPos) | coefficientHigh}) { + dassert(isValid(sign, exponent, coefficientHigh, coefficientLow)); + } - template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>> - constexpr explicit Decimal128(T v) - : Decimal128(v < 0 ? 1 : 0, kExponentBias, 0, _makeCoefficientLow(v)) {} + explicit Decimal128(std::int32_t int32Value); + explicit Decimal128(std::int64_t int64Value); + explicit Decimal128(std::uint64_t uint64Value); /** * This constructor takes a double and constructs a Decimal128 object given a roundMode, either @@ -212,15 +207,13 @@ public: /** * This function gets the inner Value struct storing a Decimal128 value. */ - constexpr Value getValue() const { - return _value; - } + Value getValue() const; /** * Extracts the biased exponent from the combination field. */ - constexpr std::uint32_t getBiasedExponent() const { - const std::uint64_t combo = _getCombinationField(); + uint32_t getBiasedExponent() const { + const uint64_t combo = _getCombinationField(); if (combo < kCombinationNonCanonical) return combo >> 3; @@ -233,7 +226,7 @@ public: * Returns the high 49 bits of the 113-bit binary encoded coefficient. Returns 0 for * non-canonical or non-finite numbers. */ - constexpr std::uint64_t getCoefficientHigh() const { + uint64_t getCoefficientHigh() const { return _getCombinationField() < kCombinationNonCanonical ? _value.high64 & kCanonicalCoefficientHighFieldMask : 0; @@ -243,7 +236,7 @@ public: * Returns the low 64 bits of the 113-bit binary encoded coefficient. Returns 0 for * non-canonical or non-finite numbers. */ - constexpr std::uint64_t getCoefficientLow() const { + uint64_t getCoefficientLow() const { return _getCombinationField() < kCombinationNonCanonical ? _value.low64 : 0; } @@ -526,16 +519,15 @@ public: } private: - constexpr static std::uint8_t kSignFieldPos = 64 - 1; - constexpr static std::uint8_t kCombinationFieldPos = kSignFieldPos - 17; - constexpr static std::uint64_t kCombinationFieldMask = (1 << 17) - 1; - constexpr static std::uint64_t kExponentFieldPos = kCombinationFieldPos + 3; - constexpr static std::uint64_t kCoefficientContinuationFieldMask = - (1ull << kCombinationFieldPos) - 1; - constexpr static std::uint64_t kCombinationNonCanonical = 3 << 15; - constexpr static std::uint64_t kCombinationInfinity = 0x1e << 12; - constexpr static std::uint64_t kCombinationNaN = 0x1f << 12; - constexpr static std::uint64_t kCanonicalCoefficientHighFieldMask = (1ull << 49) - 1; + static const uint8_t kSignFieldPos = 64 - 1; + static const uint8_t kCombinationFieldPos = kSignFieldPos - 17; + static const uint64_t kCombinationFieldMask = (1 << 17) - 1; + static const uint64_t kExponentFieldPos = kCombinationFieldPos + 3; + static const uint64_t kCoefficientContinuationFieldMask = (1ull << kCombinationFieldPos) - 1; + static const uint64_t kCombinationNonCanonical = 3 << 15; + static const uint64_t kCombinationInfinity = 0x1e << 12; + static const uint64_t kCombinationNaN = 0x1f << 12; + static const uint64_t kCanonicalCoefficientHighFieldMask = (1ull << 49) - 1; std::string _convertToScientificNotation(StringData coefficient, int adjustedExponent) const; std::string _convertToStandardDecimalNotation(StringData coefficient, int exponent) const; @@ -550,35 +542,10 @@ private: std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const; - constexpr std::uint64_t _getCombinationField() const { + uint64_t _getCombinationField() const { return (_value.high64 >> kCombinationFieldPos) & kCombinationFieldMask; } - constexpr static Value _valueFromParts(std::uint64_t sign, - std::uint64_t exponent, - std::uint64_t coefficientHigh, - std::uint64_t coefficientLow) { - // For constexpr's sake the invariant must be compiled only if !isValid(). - if (!isValid(sign, exponent, coefficientHigh, coefficientLow)) { - invariant(false, "invalid arguments to Decimal128()"); - } - - return Value{coefficientLow, - (sign << kSignFieldPos) | (exponent << kExponentFieldPos) | coefficientHigh}; - } - - // Constructs the absolute value of v as a uint64_t in a constexpr-permitted way. - template <typename T> - constexpr std::uint64_t _makeCoefficientLow(T i) { - // if constexpr to avoid MSVC warnings. - IF_CONSTEXPR(std::is_signed_v<T>) { - return i < 0 ? static_cast<std::uint64_t>(-i) : static_cast<std::uint64_t>(i); - } - else { - return static_cast<std::uint64_t>(i); - } - } - Value _value; }; } // namespace mongo diff --git a/src/mongo/platform/decimal128_test.cpp b/src/mongo/platform/decimal128_test.cpp index 4881c369216..1f0362e6a3a 100644 --- a/src/mongo/platform/decimal128_test.cpp +++ b/src/mongo/platform/decimal128_test.cpp @@ -31,7 +31,6 @@ #include <array> #include <cmath> -#include <fmt/format.h> #include <memory> #include <string> #include <utility> @@ -41,68 +40,80 @@ namespace mongo { -using namespace fmt::literals; - // Tests for Decimal128 constructors TEST(Decimal128Test, TestDefaultConstructor) { Decimal128 d; ASSERT_TRUE(d.isBinaryEqual(Decimal128(0))); } -template <typename T> -using Lim = std::numeric_limits<T>; - -TEST(Decimal128Test, TestConstructor) { - // High bits of a positive Decimal128 with exponent 1. - constexpr uint64_t posHigh = 0x3040000000000000; - // High bits of a negative Decimal128 with exponent 1. - constexpr uint64_t negHigh = 0xb040000000000000; - -#define TEST_CTOR(N, HIGH64, LOW64) \ - ASSERT_EQ(Decimal128{N}.getValue().high64, static_cast<uint64_t>(HIGH64)); \ - ASSERT_EQ(Decimal128{N}.getValue().low64, static_cast<uint64_t>(LOW64)); - - TEST_CTOR(int8_t{0}, posHigh, 0); // +0E+0 - TEST_CTOR(Lim<int8_t>::lowest(), negHigh, uint64_t{1} << 7); - TEST_CTOR(Lim<int8_t>::max(), posHigh, (uint64_t{1} << 7) - 1); - TEST_CTOR(int8_t{5}, posHigh, 0x5); - - TEST_CTOR(uint8_t{0}, posHigh, 0); - TEST_CTOR(Lim<uint8_t>::max(), posHigh, (uint64_t{1} << 8) - 1); - TEST_CTOR(uint8_t{5}, posHigh, 0x5); - - TEST_CTOR(int16_t{0}, posHigh, 0); - TEST_CTOR(Lim<int16_t>::lowest(), negHigh, uint64_t{1} << 15); - TEST_CTOR(Lim<int16_t>::max(), posHigh, (uint64_t{1} << 15) - 1); - TEST_CTOR(int16_t{5}, posHigh, 0x5); - - TEST_CTOR(uint16_t{0}, posHigh, 0); - TEST_CTOR(Lim<uint16_t>::max(), posHigh, (uint64_t{1} << 16) - 1); - TEST_CTOR(uint16_t{5}, posHigh, 0x5); +TEST(Decimal128Test, TestInt32ConstructorZero) { + int32_t intZero = 0; + Decimal128 d(intZero); + Decimal128::Value val = d.getValue(); + // 0x3040000000000000 0000000000000000 = +0E+0 + uint64_t highBytes = 0x3040000000000000ull; + uint64_t lowBytes = 0x0000000000000000ull; + ASSERT_EQUALS(val.high64, highBytes); + ASSERT_EQUALS(val.low64, lowBytes); +} - TEST_CTOR(int32_t{0}, posHigh, 0); - TEST_CTOR(Lim<int32_t>::lowest(), negHigh, uint64_t{1} << 31); - TEST_CTOR(Lim<int32_t>::max(), posHigh, (uint64_t{1} << 31) - 1); - TEST_CTOR(int32_t{5}, posHigh, 0x5); +TEST(Decimal128Test, TestInt32ConstructorMax) { + int32_t intMax = std::numeric_limits<int32_t>::max(); + Decimal128 d(intMax); + Decimal128::Value val = d.getValue(); + // 0x3040000000000000 000000007fffffff = +2147483647E+0 + uint64_t highBytes = 0x3040000000000000ull; + uint64_t lowBytes = 0x000000007fffffffull; + ASSERT_EQUALS(val.high64, highBytes); + ASSERT_EQUALS(val.low64, lowBytes); +} - TEST_CTOR(uint32_t{0}, posHigh, 0); - TEST_CTOR(Lim<uint32_t>::max(), posHigh, (uint64_t{1} << 32) - 1); - TEST_CTOR(uint32_t{5}, posHigh, 0x5); +TEST(Decimal128Test, TestInt32ConstructorMin) { + int32_t intMin = std::numeric_limits<int32_t>::lowest(); + Decimal128 d(intMin); + Decimal128::Value val = d.getValue(); + // 0xb040000000000000 000000007fffffff = -2147483648E+0 + uint64_t highBytes = 0xb040000000000000ull; + uint64_t lowBytes = 0x0000000080000000ull; + ASSERT_EQUALS(val.high64, highBytes); + ASSERT_EQUALS(val.low64, lowBytes); +} - TEST_CTOR(int64_t{0}, posHigh, 0); - TEST_CTOR(Lim<int64_t>::lowest(), negHigh, uint64_t{1} << 63); - TEST_CTOR(Lim<int64_t>::max(), posHigh, (uint64_t{1} << 63) - 1); - TEST_CTOR(int64_t{5}, posHigh, 0x5); +TEST(Decimal128Test, TestInt64ConstructorZero) { + int64_t longZero = 0; + Decimal128 d(longZero); + Decimal128::Value val = d.getValue(); + // 0x3040000000000000 0000000000000000 = +0E+0 + uint64_t highBytes = 0x3040000000000000ull; + uint64_t lowBytes = 0x0000000000000000ull; + ASSERT_EQUALS(val.high64, highBytes); + ASSERT_EQUALS(val.low64, lowBytes); +} - TEST_CTOR(uint64_t{0}, posHigh, 0); - TEST_CTOR(Lim<uint64_t>::max(), posHigh, Lim<uint64_t>::max()); - TEST_CTOR(uint64_t{5}, posHigh, 0x5); +TEST(Decimal128Test, TestInt64ConstructorMax) { + int64_t longMax = std::numeric_limits<long long>::max(); + Decimal128 d(longMax); + Decimal128::Value val = d.getValue(); + // 0x3040000000000000 7fffffffffffffff = +9223372036854775807E+0 + uint64_t highBytes = 0x3040000000000000ull; + uint64_t lowBytes = 0x7fffffffffffffffull; + ASSERT_EQUALS(val.high64, highBytes); + ASSERT_EQUALS(val.low64, lowBytes); +} -#undef TEST_CTOR +TEST(Decimal128Test, TestInt64ConstructorMin) { + int64_t longMin = std::numeric_limits<long long>::lowest(); + Decimal128 d(longMin); + Decimal128::Value val = d.getValue(); + // 0xb040000000000000 8000000000000000 = -9223372036854775808E+0 + uint64_t highBytes = 0xb040000000000000; + uint64_t lowBytes = 0x8000000000000000; + ASSERT_EQUALS(val.high64, highBytes); + ASSERT_EQUALS(val.low64, lowBytes); } TEST(Decimal128Test, TestPartsConstructor) { - constexpr Decimal128 expected(10); + Decimal128 expected(10); Decimal128 val(0LL, Decimal128::kExponentBias, 0LL, 10LL); ASSERT_EQUALS(val.getValue().low64, expected.getValue().low64); ASSERT_EQUALS(val.getValue().low64, expected.getValue().low64); @@ -287,19 +298,17 @@ TEST(Decimal128Test, TestNonCanonicalDecimal) { // when encountered. However, the exponent and sign still matter. // 0x6c10000000000000 0000000000000000 = non-canonical 0, all ignored bits clear - constexpr Decimal128 nonCanonical0E0(Decimal128::Value{0, 0x6c10000000000000ull}); + Decimal128 nonCanonical0E0(Decimal128::Value{0, 0x6c10000000000000ull}); std::string zeroE0 = nonCanonical0E0.toString(); ASSERT_EQUALS(zeroE0, "0"); // 0xec100000deadbeef 0123456789abcdef = non-canonical -0, random stuff in ignored bits - constexpr Decimal128 nonCanonicalM0E0( - Decimal128::Value{0x0123456789abcdefull, 0xec100000deadbeefull}); + Decimal128 nonCanonicalM0E0(Decimal128::Value{0x0123456789abcdefull, 0xec100000deadbeefull}); std::string minusZeroE0 = nonCanonicalM0E0.toString(); ASSERT_EQUALS(minusZeroE0, "-0"); // 0x6c11fffffffffffff ffffffffffffffff = non-canonical 0.000, all ignored bits set - constexpr Decimal128 nonCanonical0E3( - Decimal128::Value{0xffffffffffffffffull, 0x6c11ffffffffffffull}); + Decimal128 nonCanonical0E3(Decimal128::Value{0xffffffffffffffffull, 0x6c11ffffffffffffull}); std::string zeroE3 = nonCanonical0E3.toString(); ASSERT_EQUALS(zeroE3, "0E+3"); @@ -318,13 +327,13 @@ TEST(Decimal128Test, TestNonCanonicalDecimal) { // Tests for absolute value function TEST(Decimal128Test, TestAbsValuePos) { - constexpr Decimal128 d(25); + Decimal128 d(25); Decimal128 dAbs = d.toAbs(); ASSERT_TRUE(dAbs.isEqual(d)); } TEST(Decimal128Test, TestAbsValueNeg) { - constexpr Decimal128 d(-25); + Decimal128 d(-25); Decimal128 dAbs = d.toAbs(); ASSERT_TRUE(dAbs.isEqual(Decimal128(25))); } @@ -949,8 +958,8 @@ TEST(Decimal128Test, TestDecimal128DivideSignaling) { // Test Decimal128 special comparisons TEST(Decimal128Test, TestDecimal128IsZero) { - constexpr Decimal128 d1(0); - constexpr Decimal128 d2(500); + Decimal128 d1(0); + Decimal128 d2(500); ASSERT_TRUE(d1.isZero()); ASSERT_FALSE(d2.isZero()); } |