diff options
-rw-r--r-- | src/mongo/db/index/s2_key_generator_test.cpp | 25 | ||||
-rwxr-xr-x | src/third_party/s2/util/math/mathutil.cc | 13 | ||||
-rwxr-xr-x | src/third_party/s2/util/math/mathutil.h | 71 |
3 files changed, 30 insertions, 79 deletions
diff --git a/src/mongo/db/index/s2_key_generator_test.cpp b/src/mongo/db/index/s2_key_generator_test.cpp index 23a321ddc68..d88c8e04919 100644 --- a/src/mongo/db/index/s2_key_generator_test.cpp +++ b/src/mongo/db/index/s2_key_generator_test.cpp @@ -27,12 +27,12 @@ * it in the license file. */ - #include "mongo/platform/basic.h" #include "mongo/db/index/expression_keys_private.h" #include <algorithm> +#include <s2.h> #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/simple_bsonobj_comparator.h" @@ -687,4 +687,27 @@ TEST_F(S2KeyGeneratorTest, MidPathSingleElementArrayIsConsideredMultikey) { assertMultikeyPathsEqual(MultikeyPaths{{0U}, MultikeyComponents{}}, actualMultikeyPaths); } +// Test which verifies that the rounding functions used by s2 follow 'round to even' rounding +// behavior. +TEST_F(S2KeyGeneratorTest, VerifyS2RoundingBehavior) { + const double roundDownToEven = 2.5; + ASSERT_EQ(2, MathUtil::FastIntRound(roundDownToEven)); + ASSERT_EQ(2LL, MathUtil::FastInt64Round(roundDownToEven)); + + const double roundUpToEven = 3.5; + ASSERT_EQ(4, MathUtil::FastIntRound(roundUpToEven)); + ASSERT_EQ(4LL, MathUtil::FastInt64Round(roundUpToEven)); + + const double roundDownToEvenNegative = -3.5; + ASSERT_EQ(-4, MathUtil::FastIntRound(roundDownToEvenNegative)); + ASSERT_EQ(-4LL, MathUtil::FastInt64Round(roundDownToEvenNegative)); + + const double roundUpToEvenNegative = -2.5; + ASSERT_EQ(-2, MathUtil::FastIntRound(roundUpToEvenNegative)); + ASSERT_EQ(-2LL, MathUtil::FastInt64Round(roundUpToEvenNegative)); + + const double point = 944920918.5; + ASSERT_EQ(944920918, MathUtil::FastIntRound(point)); + ASSERT_EQ(944920918LL, MathUtil::FastInt64Round(point)); +} } // namespace diff --git a/src/third_party/s2/util/math/mathutil.cc b/src/third_party/s2/util/math/mathutil.cc index 7ca3b890f8a..35ab462027c 100755 --- a/src/third_party/s2/util/math/mathutil.cc +++ b/src/third_party/s2/util/math/mathutil.cc @@ -16,19 +16,6 @@ using std::vector; #include "base/integral_types.h" #include "base/logging.h" - template <class IntOut, class FloatIn> - IntOut MathUtil::Round(FloatIn x) { - COMPILE_ASSERT(!MathLimits<FloatIn>::kIsInteger, FloatIn_is_integer); - COMPILE_ASSERT(MathLimits<IntOut>::kIsInteger, IntOut_is_not_integer); - - // We don't use sgn(x) below because there is no need to distinguish the - // (x == 0) case. Also note that there are specialized faster versions - // of this function for Intel processors at the bottom of this file. - return static_cast<IntOut>(x < 0 ? (x - 0.5) : (x + 0.5)); - } - -template int MathUtil::Round<int,double>(double x); - MathUtil::QuadraticRootType MathUtil::RealRootsForQuadratic(long double a, long double b, long double c, diff --git a/src/third_party/s2/util/math/mathutil.h b/src/third_party/s2/util/math/mathutil.h index bf607475b64..74ac26c5838 100755 --- a/src/third_party/s2/util/math/mathutil.h +++ b/src/third_party/s2/util/math/mathutil.h @@ -317,33 +317,6 @@ class MathUtil { vector<bool>* shards_to_read); // -------------------------------------------------------------------- - // Round, IntRound - // These functions round a floating-point number to an integer. They - // work for positive or negative numbers. - // - // Values that are halfway between two integers may be rounded up or - // down, for example IntRound(0.5) == 0 and IntRound(1.5) == 2. This - // allows these functions to be implemented efficiently on Intel - // processors (see the template specializations at the bottom of this - // file). You should not use these functions if you care about which - // way such half-integers are rounded. - // - // Example usage: - // double y, z; - // int x = IntRound(y + 3.7); - // int64 b = Round<int64>(0.3 * z); - // - // Note that the floating-point template parameter is typically inferred - // from the argument type, i.e. there is no need to specify it explicitly. - // -------------------------------------------------------------------- - template <class IntOut, class FloatIn> - static IntOut Round(FloatIn x); - - // Example usage: IntRound(3.6) (no need for IntRound<double>(3.6)). - template <class FloatIn> - static int IntRound(FloatIn x) { return Round<int>(x); } - - // -------------------------------------------------------------------- // FastIntRound, FastInt64Round // Fast routines for converting floating-point numbers to integers. // @@ -356,11 +329,10 @@ class MathUtil { // floating-point pipeline (unless programs are compiled specifically // for the Pentium 4, which has a new instruction to avoid this). // - // Numbers that are halfway between two integers may be rounded up or - // down. This is because the conversion is done using the default + // Numbers that are halfway between two integers follow the deafult // rounding mode, which rounds towards the closest even number in case // of ties. So for example, FastIntRound(0.5) == 0, but - // FastIntRound(1.5) == 2. These functions should only be used with + // FastIntRound(1.5) == 2. These functions should only be used with // applications that don't care about which way such half-integers are // rounded. // @@ -368,10 +340,8 @@ class MathUtil { // functions (for "int" and "int64" only), but it's safer to call them // directly. // - // This functions are equivalent to lrint() and llrint() as defined in - // the ISO C99 standard. Unfortunately this standard does not seem to - // widely adopted yet and these functions are not available by default. - // -------------------------------------------------------------------- + // This functions are equivalent to rint() and llrint(). + // -------------------------------------------------------------------- static int32 FastIntRound(double x) { // This function is not templatized because gcc doesn't seem to be able @@ -399,7 +369,7 @@ class MathUtil { return result; #endif // if defined __x86_64__ || ... #else - return Round<int32, double>(x); + return static_cast<int32>(rint(x)); #endif // if defined __GNUC__ && ... } @@ -425,7 +395,7 @@ class MathUtil { return result; #endif // if defined __i386__ #else - return Round<int64, double>(x); + return static_cast<int64>(llrint(x)); #endif // if defined __GNUC__ && ... } @@ -686,35 +656,6 @@ class MathUtil { } }; -// ========================================================================= // - -#if (defined __i386__ || defined __x86_64__) && defined __GNUC__ - -// We define template specializations of Round() to get the more efficient -// Intel versions when possible. Note that gcc does not currently support -// partial specialization of templatized functions. -template<> -inline int32 MathUtil::Round<int32, double>(double x) { - return FastIntRound(x); -} - -template<> -inline int32 MathUtil::Round<int32, float>(float x) { - return FastIntRound(x); -} - -template<> -inline int64 MathUtil::Round<int64, double>(double x) { - return FastInt64Round(x); -} - -template<> -inline int64 MathUtil::Round<int64, float>(float x) { - return FastInt64Round(x); -} - -#endif - template<typename T> bool MathUtil::WithinFraction(const T x, const T y, const T fraction) { // not just "0 <= fraction" to fool the compiler for unsigned types |