summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Wahlin <james@mongodb.com>2019-02-14 16:12:50 -0500
committerJames Wahlin <james@mongodb.com>2019-03-15 11:12:04 -0400
commit477ceade3dae70498c0a6b4c89007ac98934e1c6 (patch)
treef45b6286391f709c43132234a9247097a12f5d9f
parent48d999c08304b6ede2a9d1f9d9db974b59fe97e2 (diff)
downloadmongo-477ceade3dae70498c0a6b4c89007ac98934e1c6.tar.gz
SERVER-39487 Decimal128::squareRoot() returns result for Decimal128::exponential()
(cherry picked from commit 5aa3f6dbc5e31beaf40e0828f7a24ecf71fb42f9) (cherry picked from commit c1760b39b29dc412ca1c20361c500e18e90c71cd)
-rw-r--r--src/mongo/db/pipeline/expression_test.cpp88
-rw-r--r--src/mongo/platform/decimal128.cpp6
-rw-r--r--src/mongo/platform/decimal128_test.cpp32
3 files changed, 123 insertions, 3 deletions
diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp
index 48e011d37be..532e298c1c1 100644
--- a/src/mongo/db/pipeline/expression_test.cpp
+++ b/src/mongo/db/pipeline/expression_test.cpp
@@ -976,6 +976,94 @@ TEST_F(ExpressionTruncTest, NullArg) {
assertEvaluates(Value(BSONNULL), Value(BSONNULL));
}
+/* ------------------------- ExpressionSqrt -------------------------- */
+
+class ExpressionSqrtTest : public ExpressionNaryTestOneArg {
+public:
+ virtual void assertEvaluates(Value input, Value output) override {
+ intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
+ _expr = new ExpressionSqrt(expCtx);
+ ExpressionNaryTestOneArg::assertEvaluates(input, output);
+ }
+};
+
+TEST_F(ExpressionSqrtTest, SqrtIntArg) {
+ assertEvaluates(Value(0), Value(0.0));
+ assertEvaluates(Value(1), Value(1.0));
+ assertEvaluates(Value(25), Value(5.0));
+}
+
+TEST_F(ExpressionSqrtTest, SqrtLongArg) {
+ assertEvaluates(Value(0LL), Value(0.0));
+ assertEvaluates(Value(1LL), Value(1.0));
+ assertEvaluates(Value(25LL), Value(5.0));
+ assertEvaluates(Value(40000000000LL), Value(200000.0));
+}
+
+TEST_F(ExpressionSqrtTest, SqrtDoubleArg) {
+ assertEvaluates(Value(0.0), Value(0.0));
+ assertEvaluates(Value(1.0), Value(1.0));
+ assertEvaluates(Value(25.0), Value(5.0));
+}
+
+TEST_F(ExpressionSqrtTest, SqrtDecimalArg) {
+ assertEvaluates(Value(Decimal128("0")), Value(Decimal128("0")));
+ assertEvaluates(Value(Decimal128("1")), Value(Decimal128("1")));
+ assertEvaluates(Value(Decimal128("25")), Value(Decimal128("5")));
+ assertEvaluates(Value(Decimal128("30.25")), Value(Decimal128("5.5")));
+}
+
+TEST_F(ExpressionSqrtTest, SqrtNullArg) {
+ assertEvaluates(Value(BSONNULL), Value(BSONNULL));
+}
+
+TEST_F(ExpressionSqrtTest, SqrtNaNArg) {
+ assertEvaluates(Value(std::numeric_limits<double>::quiet_NaN()),
+ Value(std::numeric_limits<double>::quiet_NaN()));
+}
+
+/* ------------------------- ExpressionExp -------------------------- */
+
+class ExpressionExpTest : public ExpressionNaryTestOneArg {
+public:
+ virtual void assertEvaluates(Value input, Value output) override {
+ intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
+ _expr = new ExpressionExp(expCtx);
+ ExpressionNaryTestOneArg::assertEvaluates(input, output);
+ }
+
+ const Decimal128 decimalE = Decimal128("2.718281828459045235360287471352662");
+};
+
+TEST_F(ExpressionExpTest, ExpIntArg) {
+ assertEvaluates(Value(0), Value(1.0));
+ assertEvaluates(Value(1), Value(exp(1.0)));
+}
+
+TEST_F(ExpressionExpTest, ExpLongArg) {
+ assertEvaluates(Value(0LL), Value(1.0));
+ assertEvaluates(Value(1LL), Value(exp(1.0)));
+}
+
+TEST_F(ExpressionExpTest, ExpDoubleArg) {
+ assertEvaluates(Value(0.0), Value(1.0));
+ assertEvaluates(Value(1.0), Value(exp(1.0)));
+}
+
+TEST_F(ExpressionExpTest, ExpDecimalArg) {
+ assertEvaluates(Value(Decimal128("0")), Value(Decimal128("1")));
+ assertEvaluates(Value(Decimal128("1")), Value(decimalE));
+}
+
+TEST_F(ExpressionExpTest, ExpNullArg) {
+ assertEvaluates(Value(BSONNULL), Value(BSONNULL));
+}
+
+TEST_F(ExpressionExpTest, ExpNaNArg) {
+ assertEvaluates(Value(std::numeric_limits<double>::quiet_NaN()),
+ Value(std::numeric_limits<double>::quiet_NaN()));
+}
+
/* ------------------------- Old-style tests -------------------------- */
namespace Add {
diff --git a/src/mongo/platform/decimal128.cpp b/src/mongo/platform/decimal128.cpp
index 51b7ffe5269..73d315acd9b 100644
--- a/src/mongo/platform/decimal128.cpp
+++ b/src/mongo/platform/decimal128.cpp
@@ -626,7 +626,7 @@ Decimal128 Decimal128::divide(const Decimal128& other,
Decimal128 Decimal128::exponential(RoundingMode roundMode) const {
std::uint32_t throwAwayFlag = 0;
- return exponential(&throwAwayFlag);
+ return exponential(&throwAwayFlag, roundMode);
}
Decimal128 Decimal128::exponential(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
@@ -637,7 +637,7 @@ Decimal128 Decimal128::exponential(std::uint32_t* signalingFlags, RoundingMode r
Decimal128 Decimal128::logarithm(RoundingMode roundMode) const {
std::uint32_t throwAwayFlag = 0;
- return logarithm(&throwAwayFlag);
+ return logarithm(&throwAwayFlag, roundMode);
}
Decimal128 Decimal128::logarithm(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
@@ -719,7 +719,7 @@ Decimal128 Decimal128::quantize(const Decimal128& reference,
Decimal128 Decimal128::squareRoot(RoundingMode roundMode) const {
std::uint32_t throwAwayFlag = 0;
- return exponential(&throwAwayFlag);
+ return squareRoot(&throwAwayFlag, roundMode);
}
Decimal128 Decimal128::squareRoot(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
diff --git a/src/mongo/platform/decimal128_test.cpp b/src/mongo/platform/decimal128_test.cpp
index 14621296664..bb38254d0ff 100644
--- a/src/mongo/platform/decimal128_test.cpp
+++ b/src/mongo/platform/decimal128_test.cpp
@@ -1292,4 +1292,36 @@ TEST(Decimal128Test, TestDecimal128GetLargestNegativeExponentZero) {
ASSERT_EQUALS(d.getValue().low64, largestNegativeExponentZeroLow64);
}
+/**
+ * Test data was generated using 64 bit versions of these functions, so we must test
+ * approximate results.
+ */
+
+void assertDecimal128ApproxEqual(Decimal128 x, Decimal128 y) {
+ ASSERT_TRUE(x.subtract(y).toAbs().isLess(Decimal128("0.00000005")));
+}
+
+TEST(Decimal128Test, TestExp) {
+ assertDecimal128ApproxEqual(Decimal128("-1").exponential(),
+ Decimal128("0.3678794411714423215955237701614609"));
+ assertDecimal128ApproxEqual(Decimal128("0").exponential(), Decimal128("1"));
+ assertDecimal128ApproxEqual(Decimal128("1").exponential(),
+ Decimal128("2.718281828459045235360287471352662"));
+ assertDecimal128ApproxEqual(Decimal128("1.5").exponential(),
+ Decimal128("4.481689070338064822602055460119276"));
+ assertDecimal128ApproxEqual(Decimal128("1.79769313486231E+308")
+ .exponential(Decimal128::RoundingMode::kRoundTowardNegative),
+ Decimal128("9.999999999999999999999999999999999E+6144"));
+}
+
+TEST(Decimal128Test, TestSqrt) {
+ assertDecimal128ApproxEqual(Decimal128("0").squareRoot(), Decimal128("0"));
+ assertDecimal128ApproxEqual(Decimal128("1").squareRoot(), Decimal128("1"));
+ assertDecimal128ApproxEqual(Decimal128("25").squareRoot(), Decimal128("5"));
+ assertDecimal128ApproxEqual(Decimal128("25.5").squareRoot(),
+ Decimal128("5.049752469181038976681692958534800"));
+ assertDecimal128ApproxEqual(Decimal128("1.79769313486231E+308")
+ .squareRoot(Decimal128::RoundingMode::kRoundTowardNegative),
+ Decimal128("1.340780792994257506864497209340836E+154"));
+}
} // namespace mongo