summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Meredith <pmeredit@gmail.com>2018-10-12 16:59:29 -0400
committerCharlie Swanson <charlie.swanson@mongodb.com>2018-12-22 21:20:56 -0500
commit43cd5d0e35df926eeaacec3f8d676bb5f6dd287b (patch)
tree42040670b45de7a3dcde2bf8c59f1f89cd4d01a3
parent8195b17e78a2f0617289e1d8f3b318e1f2c8f077 (diff)
downloadmongo-43cd5d0e35df926eeaacec3f8d676bb5f6dd287b.tar.gz
SERVER-32930 Add trigonometric expressions to aggregation
Closes #1287 Signed-off-by: Charlie Swanson <charlie.swanson@mongodb.com>
-rw-r--r--jstests/aggregation/expressions/expression_trigonometric.js254
-rw-r--r--src/mongo/db/pipeline/SConscript2
-rw-r--r--src/mongo/db/pipeline/expression.h46
-rw-r--r--src/mongo/db/pipeline/expression_trigonometric.cpp220
-rw-r--r--src/mongo/db/pipeline/expression_trigonometric.h237
-rw-r--r--src/mongo/db/pipeline/expression_trigonometric_test.cpp1406
-rw-r--r--src/mongo/platform/decimal128.cpp152
-rw-r--r--src/mongo/platform/decimal128.h88
-rw-r--r--src/mongo/platform/decimal128_test.cpp263
9 files changed, 2666 insertions, 2 deletions
diff --git a/jstests/aggregation/expressions/expression_trigonometric.js b/jstests/aggregation/expressions/expression_trigonometric.js
new file mode 100644
index 00000000000..192e9743b62
--- /dev/null
+++ b/jstests/aggregation/expressions/expression_trigonometric.js
@@ -0,0 +1,254 @@
+// SERVER-32930: Basic integration tests for trigonometric aggregation expressions.
+
+(function() {
+ "use strict";
+ // For assertErrorCode.
+ load("jstests/aggregation/extras/utils.js");
+
+ const coll = db.expression_trigonometric;
+ coll.drop();
+ // We need at least one document in the collection in order to test expressions, add it here.
+ assert.commandWorked(coll.insert({}));
+
+ // Helper for testing that op returns expResult.
+ function testOp(op, expResult) {
+ const pipeline = [{$project: {_id: 0, result: op}}];
+ assert.eq(coll.aggregate(pipeline).toArray(), [{result: expResult}]);
+ }
+
+ // Helper for testing that the aggregation expression 'op' returns expResult, approximately,
+ // since NumberDecimal has so many representations for a given number (0 versus 0e-40 for
+ // instance).
+ function testOpApprox(op, expResult) {
+ const pipeline = [{$project: {_id: 0, result: {$abs: {$subtract: [op, expResult]}}}}];
+ assert.lt(coll.aggregate(pipeline).toArray(), [{result: NumberDecimal("0.00000005")}]);
+ }
+
+ // Simple successful int input.
+ testOp({$acos: NumberInt(1)}, 0);
+ testOp({$acosh: NumberInt(1)}, 0);
+ testOp({$asin: NumberInt(0)}, 0);
+ testOp({$asinh: NumberInt(0)}, 0);
+ testOp({$atan: NumberInt(0)}, 0);
+ testOp({$atan2: [NumberInt(0), NumberInt(1)]}, 0);
+ testOp({$atan2: [NumberInt(0), NumberInt(0)]}, 0);
+ testOp({$atanh: NumberInt(0)}, 0);
+ testOp({$cos: NumberInt(0)}, 1);
+ testOp({$cosh: NumberInt(0)}, 1);
+ testOp({$sin: NumberInt(0)}, 0);
+ testOp({$sinh: NumberInt(0)}, 0);
+ testOp({$tan: NumberInt(0)}, 0);
+ testOp({$tanh: NumberInt(0)}, 0);
+ testOp({$degreesToRadians: NumberInt(0)}, 0);
+ testOp({$radiansToDegrees: NumberInt(0)}, 0);
+
+ // Simple successful long input.
+ testOp({$acos: NumberLong(1)}, 0);
+ testOp({$acosh: NumberLong(1)}, 0);
+ testOp({$asin: NumberLong(0)}, 0);
+ testOp({$asinh: NumberLong(0)}, 0);
+ testOp({$atan: NumberLong(0)}, 0);
+ testOp({$atan2: [NumberLong(0), NumberLong(1)]}, 0);
+ testOp({$atan2: [NumberLong(0), NumberLong(0)]}, 0);
+ testOp({$atanh: NumberLong(0)}, 0);
+ testOp({$cos: NumberLong(0)}, 1);
+ testOp({$cosh: NumberLong(0)}, 1);
+ testOp({$sin: NumberLong(0)}, 0);
+ testOp({$sinh: NumberLong(0)}, 0);
+ testOp({$tan: NumberLong(0)}, 0);
+ testOp({$tanh: NumberLong(0)}, 0);
+ testOp({$degreesToRadians: NumberLong(0)}, 0);
+ testOp({$radiansToDegrees: NumberLong(0)}, 0);
+
+ // Simple successful double input.
+ testOp({$acos: 1}, 0);
+ testOp({$acosh: 1}, 0);
+ testOp({$asin: 0}, 0);
+ testOp({$asinh: 0}, 0);
+ testOp({$atan: 0}, 0);
+ testOp({$atan2: [0, 1]}, 0);
+ testOp({$atan2: [0, 0]}, 0);
+ testOp({$atanh: 0}, 0);
+ testOp({$cos: 0}, 1);
+ testOp({$cosh: 0}, 1);
+ testOp({$sin: 0}, 0);
+ testOp({$sinh: 0}, 0);
+ testOp({$tan: 0}, 0);
+ testOp({$tanh: 0}, 0);
+ testOp({$degreesToRadians: 0}, 0);
+ testOp({$radiansToDegrees: 0}, 0);
+
+ // Simple successful decimal input.
+ testOpApprox({$acos: NumberDecimal(1)}, NumberDecimal(0));
+ testOpApprox({$acosh: NumberDecimal(1)}, NumberDecimal(0));
+ testOpApprox({$asin: NumberDecimal(0)}, NumberDecimal(0));
+ testOpApprox({$asinh: NumberDecimal(0)}, NumberDecimal(0));
+ testOpApprox({$atan: NumberDecimal(0)}, NumberDecimal(0));
+ testOpApprox({$atan2: [NumberDecimal(0), 1]}, NumberDecimal(0));
+ testOpApprox({$atan2: [NumberDecimal(0), 0]}, NumberDecimal(0));
+ testOpApprox({$atanh: NumberDecimal(0)}, NumberDecimal(0));
+ testOpApprox({$cos: NumberDecimal(0)}, NumberDecimal(1));
+ testOpApprox({$cosh: NumberDecimal(0)}, NumberDecimal(1));
+ testOpApprox({$sin: NumberDecimal(0)}, NumberDecimal(0));
+ testOpApprox({$sinh: NumberDecimal(0)}, NumberDecimal(0));
+ testOpApprox({$tan: NumberDecimal(0)}, NumberDecimal(0));
+ testOpApprox({$tanh: NumberDecimal(0)}, NumberDecimal(0));
+ testOpApprox({$degreesToRadians: NumberDecimal(0)}, NumberDecimal(0));
+ testOpApprox({$radiansToDegrees: NumberDecimal(0)}, NumberDecimal(0));
+
+ // Infinity input produces out of bounds error.
+ assertErrorCode(coll, [{$project: {a: {$acos: -Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acos: NumberDecimal('-Infinity')}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acos: Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acos: NumberDecimal('Infinity')}}}], 50989);
+
+ assertErrorCode(coll, [{$project: {a: {$acosh: -Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acosh: NumberDecimal('-Infinity')}}}], 50989);
+
+ assertErrorCode(coll, [{$project: {a: {$asin: -Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: NumberDecimal('-Infinity')}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: NumberDecimal('Infinity')}}}], 50989);
+
+ assertErrorCode(coll, [{$project: {a: {$atanh: -Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: NumberDecimal('-Infinity')}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: NumberDecimal('Infinity')}}}], 50989);
+
+ assertErrorCode(coll, [{$project: {a: {$cos: -Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$cos: NumberDecimal('-Infinity')}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$cos: Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$cos: NumberDecimal('Infinity')}}}], 50989);
+
+ assertErrorCode(coll, [{$project: {a: {$sin: -Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$sin: NumberDecimal('-Infinity')}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$sin: Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$sin: NumberDecimal('Infinity')}}}], 50989);
+
+ assertErrorCode(coll, [{$project: {a: {$tan: -Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$tan: NumberDecimal('-Infinity')}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$tan: Infinity}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$tan: NumberDecimal('Infinity')}}}], 50989);
+
+ // Infinity input produces Infinity as output.
+ testOp({$acosh: NumberDecimal('Infinity')}, NumberDecimal('Infinity'));
+ testOp({$acosh: Infinity}, Infinity);
+
+ testOp({$asinh: NumberDecimal('Infinity')}, NumberDecimal('Infinity'));
+ testOp({$asinh: NumberDecimal('-Infinity')}, NumberDecimal('-Infinity'));
+ testOp({$asinh: Infinity}, Infinity);
+ testOp({$asinh: -Infinity}, -Infinity);
+ testOp({$cosh: NumberDecimal('Infinity')}, NumberDecimal('Infinity'));
+ testOp({$cosh: NumberDecimal('-Infinity')}, NumberDecimal('Infinity'));
+ testOp({$cosh: Infinity}, Infinity);
+ testOp({$cosh: -Infinity}, Infinity);
+ testOp({$sinh: NumberDecimal('Infinity')}, NumberDecimal('Infinity'));
+ testOp({$sinh: NumberDecimal('-Infinity')}, NumberDecimal('-Infinity'));
+ testOp({$sinh: Infinity}, Infinity);
+ testOp({$sinh: -Infinity}, -Infinity);
+
+ // Infinity produces finite output (due to asymptotic bounds).
+ testOpApprox({$atan: NumberDecimal('Infinity')}, NumberDecimal(Math.PI / 2));
+ testOpApprox({$atan: NumberDecimal('-Infinity')}, NumberDecimal(Math.Pi / 2));
+ testOpApprox({$atan: Infinity}, Math.PI / 2);
+ testOpApprox({$atan: -Infinity}, -Math.PI / 2);
+
+ testOpApprox({$atan2: [NumberDecimal('Infinity'), 0]}, NumberDecimal(Math.PI / 2));
+ testOpApprox({$atan2: [NumberDecimal('-Infinity'), 0]}, NumberDecimal(-Math.PI / 2));
+ testOpApprox({$atan2: [NumberDecimal('-Infinity'), NumberDecimal("Infinity")]},
+ NumberDecimal(-Math.PI / 4));
+ testOpApprox({$atan2: [NumberDecimal('-Infinity'), NumberDecimal("-Infinity")]},
+ NumberDecimal(-3 * Math.PI / 4));
+ testOpApprox({$atan2: [NumberDecimal('0'), NumberDecimal("-Infinity")]},
+ NumberDecimal(Math.PI));
+ testOpApprox({$atan2: [NumberDecimal('0'), NumberDecimal("Infinity")]}, NumberDecimal(0));
+
+ testOp({$tanh: NumberDecimal('Infinity')}, NumberDecimal('1'));
+ testOp({$tanh: NumberDecimal('-Infinity')}, NumberDecimal('-1'));
+
+ // Finite input produces infinite outputs.
+ testOp({$atanh: NumberDecimal(1)}, NumberDecimal('Infinity'));
+ testOp({$atanh: NumberDecimal(-1)}, NumberDecimal('-Infinity'));
+ testOp({$atanh: 1}, Infinity);
+ testOp({$atanh: -1}, -Infinity);
+
+ testOp({$tanh: Infinity}, 1);
+ testOp({$tanh: -Infinity}, -1);
+
+ // Int argument out of bounds.
+ assertErrorCode(coll, [{$project: {a: {$acos: NumberInt(-2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acos: NumberInt(2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: NumberInt(-2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: NumberInt(2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acosh: NumberInt(0)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: NumberInt(2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: NumberInt(-2)}}}], 50989);
+
+ // Long argument out of bounds.
+ assertErrorCode(coll, [{$project: {a: {$acos: NumberLong(-2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acos: NumberLong(2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: NumberLong(-2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: NumberLong(2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acosh: NumberLong(0)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: NumberLong(2)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: NumberLong(-2)}}}], 50989);
+
+ // Double argument out of bounds.
+ assertErrorCode(coll, [{$project: {a: {$acos: -1.1}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acos: 1.1}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: -1.1}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: 1.1}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acosh: 0.9}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: -1.00001}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: 1.00001}}}], 50989);
+
+ // Decimal argument out of bounds.
+ assertErrorCode(coll, [{$project: {a: {$acos: NumberDecimal(-1.1)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acos: NumberDecimal(1.1)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: NumberDecimal(-1.1)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$asin: NumberDecimal(1.1)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$acosh: NumberDecimal(0.9)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: NumberDecimal(-1.00001)}}}], 50989);
+ assertErrorCode(coll, [{$project: {a: {$atanh: NumberDecimal(1.000001)}}}], 50989);
+
+ // Check NaN is preserved.
+ ["$acos", "$asin", "$atan", "$cos", "$sin", "$tan"].forEach(op => {
+ testOp({[op]: NaN}, NaN);
+ testOp({[op]: NumberDecimal(NaN)}, NumberDecimal(NaN));
+ // Check the hyperbolic version of each function.
+ testOp({[op + 'h']: NaN}, NaN);
+ testOp({[op + 'h']: NumberDecimal(NaN)}, NumberDecimal(NaN));
+ });
+
+ ["$radiansToDegrees", "$degreesToRadians"].forEach(op => {
+ testOp({[op]: NaN}, NaN);
+ testOp({[op]: NumberDecimal(NaN)}, NumberDecimal(NaN));
+ testOp({[op]: -Infinity}, -Infinity);
+ testOp({[op]: NumberDecimal(-Infinity)}, NumberDecimal(-Infinity));
+ testOp({[op]: Infinity}, Infinity);
+ testOp({[op]: NumberDecimal(Infinity)}, NumberDecimal(Infinity));
+ });
+
+ testOp({$atan2: [NumberDecimal('NaN'), NumberDecimal('NaN')]}, NumberDecimal('NaN'));
+ testOp({$atan2: [NumberDecimal('NaN'), NumberDecimal('0')]}, NumberDecimal('NaN'));
+ testOp({$atan2: [NumberDecimal('0'), NumberDecimal('NaN')]}, NumberDecimal('NaN'));
+
+ // Non-numeric input.
+ assertErrorCode(coll, [{$project: {a: {$acos: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$acosh: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$asin: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$asinh: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$atan: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$atan2: ["string", "string"]}}}], 51044);
+ assertErrorCode(coll, [{$project: {a: {$atan2: ["string", 0.0]}}}], 51044);
+ assertErrorCode(coll, [{$project: {a: {$atan2: [0.0, "string"]}}}], 51045);
+ assertErrorCode(coll, [{$project: {a: {$atanh: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$cos: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$cosh: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$sin: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$sinh: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$tan: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$tanh: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$degreesToRadians: "string"}}}], 28765);
+ assertErrorCode(coll, [{$project: {a: {$radiansToDegrees: "string"}}}], 28765);
+}());
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript
index 71270f0e72f..bfd47c1a11d 100644
--- a/src/mongo/db/pipeline/SConscript
+++ b/src/mongo/db/pipeline/SConscript
@@ -135,6 +135,7 @@ env.Library(
target='expression',
source=[
'expression.cpp',
+ 'expression_trigonometric.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/query/datetime/date_time_support',
@@ -445,6 +446,7 @@ env.CppUnitTest(
'expression_convert_test.cpp',
'expression_date_test.cpp',
'expression_test.cpp',
+ 'expression_trigonometric_test.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/query/query_test_service_context',
diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h
index 82e8f245be0..31d1e185d34 100644
--- a/src/mongo/db/pipeline/expression.h
+++ b/src/mongo/db/pipeline/expression.h
@@ -435,7 +435,7 @@ public:
explicit ExpressionSingleNumericArg(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<SubClass, 1>(expCtx) {}
- virtual ~ExpressionSingleNumericArg() {}
+ virtual ~ExpressionSingleNumericArg() = default;
Value evaluate(const Document& root) const final {
Value arg = this->vpOperand[0]->evaluate(root);
@@ -454,6 +454,49 @@ public:
};
/**
+ * Inherit from this class if your expression takes exactly two numeric arguments.
+ */
+template <typename SubClass>
+class ExpressionTwoNumericArgs : public ExpressionFixedArity<SubClass, 2> {
+public:
+ explicit ExpressionTwoNumericArgs(const boost::intrusive_ptr<ExpressionContext>& expCtx)
+ : ExpressionFixedArity<SubClass, 2>(expCtx) {}
+
+ virtual ~ExpressionTwoNumericArgs() = default;
+
+ /**
+ * Evaluate performs the type checking necessary to make sure that both arguments are numeric,
+ * then calls the evaluateNumericArgs on the two numeric args:
+ * 1. If either input is nullish, it returns null.
+ * 2. If either input is not numeric, it throws an error.
+ * 3. Call evaluateNumericArgs on the two numeric args.
+ */
+ Value evaluate(const Document& root) const final {
+ Value arg1 = this->vpOperand[0]->evaluate(root);
+ if (arg1.nullish())
+ return Value(BSONNULL);
+ uassert(51044,
+ str::stream() << this->getOpName() << " only supports numeric types, not "
+ << typeName(arg1.getType()),
+ arg1.numeric());
+ Value arg2 = this->vpOperand[1]->evaluate(root);
+ if (arg2.nullish())
+ return Value(BSONNULL);
+ uassert(51045,
+ str::stream() << this->getOpName() << " only supports numeric types, not "
+ << typeName(arg2.getType()),
+ arg2.numeric());
+
+ return evaluateNumericArgs(arg1, arg2);
+ }
+
+ /**
+ * Evaluate the expression on exactly two numeric arguments.
+ */
+ virtual Value evaluateNumericArgs(const Value& numericArg1, const Value& numericArg2) const = 0;
+};
+
+/**
* A constant expression. Repeated calls to evaluate() will always return the same thing.
*/
class ExpressionConstant final : public Expression {
@@ -665,7 +708,6 @@ public:
const char* getOpName() const final;
};
-
class ExpressionAdd final : public ExpressionVariadic<ExpressionAdd> {
public:
explicit ExpressionAdd(const boost::intrusive_ptr<ExpressionContext>& expCtx)
diff --git a/src/mongo/db/pipeline/expression_trigonometric.cpp b/src/mongo/db/pipeline/expression_trigonometric.cpp
new file mode 100644
index 00000000000..6fdf7cdcc4e
--- /dev/null
+++ b/src/mongo/db/pipeline/expression_trigonometric.cpp
@@ -0,0 +1,220 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "expression_trigonometric.h"
+
+namespace mongo {
+
+/* ----------------------- Inclusive Bounded Trigonometric Functions ---------------------------- */
+
+#define CREATE_BOUNDED_TRIGONOMETRIC_CLASS(className, funcName, boundType, lowerBound, upperBound) \
+ class Expression##className final \
+ : public ExpressionBoundedTrigonometric<Expression##className, boundType> { \
+ public: \
+ explicit Expression##className(const boost::intrusive_ptr<ExpressionContext>& expCtx) \
+ : ExpressionBoundedTrigonometric(expCtx) {} \
+ double getLowerBound() const final { \
+ return lowerBound; \
+ } \
+ \
+ double getUpperBound() const final { \
+ return upperBound; \
+ } \
+ \
+ double doubleFunc(double arg) const final { \
+ return std::funcName(arg); \
+ } \
+ \
+ Decimal128 decimalFunc(Decimal128 arg) const final { \
+ return arg.funcName(); \
+ } \
+ \
+ const char* getOpName() const final { \
+ return "$" #funcName; \
+ } \
+ }; \
+ REGISTER_EXPRESSION(funcName, Expression##className::parse);
+
+
+/**
+ * Inclusive Bounds
+ */
+CREATE_BOUNDED_TRIGONOMETRIC_CLASS(ArcCosine, acos, InclusiveBoundType, -1.0, 1.0);
+
+CREATE_BOUNDED_TRIGONOMETRIC_CLASS(ArcSine, asin, InclusiveBoundType, -1.0, 1.0);
+
+CREATE_BOUNDED_TRIGONOMETRIC_CLASS(HyperbolicArcTangent, atanh, InclusiveBoundType, -1.0, 1.0);
+
+CREATE_BOUNDED_TRIGONOMETRIC_CLASS(
+ HyperbolicArcCosine, acosh, InclusiveBoundType, 1.0, std::numeric_limits<double>::infinity());
+
+/**
+ * Exclusive Bounds
+ */
+CREATE_BOUNDED_TRIGONOMETRIC_CLASS(Cosine,
+ cos,
+ ExclusiveBoundType,
+ -std::numeric_limits<double>::infinity(),
+ std::numeric_limits<double>::infinity());
+
+CREATE_BOUNDED_TRIGONOMETRIC_CLASS(Sine,
+ sin,
+ ExclusiveBoundType,
+ -std::numeric_limits<double>::infinity(),
+ std::numeric_limits<double>::infinity());
+
+CREATE_BOUNDED_TRIGONOMETRIC_CLASS(Tangent,
+ tan,
+ ExclusiveBoundType,
+ -std::numeric_limits<double>::infinity(),
+ std::numeric_limits<double>::infinity());
+
+#undef CREATE_BOUNDED_TRIGONOMETRIC_CLASS
+
+/* ----------------------- Unbounded Trigonometric Functions ---------------------------- */
+
+
+#define CREATE_TRIGONOMETRIC_CLASS(className, funcName) \
+ class Expression##className final \
+ : public ExpressionUnboundedTrigonometric<Expression##className> { \
+ public: \
+ explicit Expression##className(const boost::intrusive_ptr<ExpressionContext>& expCtx) \
+ : ExpressionUnboundedTrigonometric(expCtx) {} \
+ \
+ double doubleFunc(double arg) const final { \
+ return std::funcName(arg); \
+ } \
+ \
+ Decimal128 decimalFunc(Decimal128 arg) const final { \
+ return arg.funcName(); \
+ } \
+ \
+ const char* getOpName() const final { \
+ return "$" #funcName; \
+ } \
+ }; \
+ REGISTER_EXPRESSION(funcName, Expression##className::parse);
+
+CREATE_TRIGONOMETRIC_CLASS(ArcTangent, atan);
+CREATE_TRIGONOMETRIC_CLASS(HyperbolicArcSine, asinh);
+CREATE_TRIGONOMETRIC_CLASS(HyperbolicCosine, cosh);
+CREATE_TRIGONOMETRIC_CLASS(HyperbolicSine, sinh);
+CREATE_TRIGONOMETRIC_CLASS(HyperbolicTangent, tanh);
+
+#undef CREATE_TRIGONOMETRIC_CLASS
+
+
+/* ----------------------- ExpressionArcTangent2 ---------------------------- */
+
+class ExpressionArcTangent2 final : public ExpressionTwoNumericArgs<ExpressionArcTangent2> {
+public:
+ explicit ExpressionArcTangent2(const boost::intrusive_ptr<ExpressionContext>& expCtx)
+ : ExpressionTwoNumericArgs(expCtx) {}
+
+ Value evaluateNumericArgs(const Value& numericArg1, const Value& numericArg2) const final {
+ auto totalType = BSONType::NumberDouble;
+ // If the type of either argument is NumberDecimal, we promote to Decimal128.
+ if (numericArg1.getType() == BSONType::NumberDecimal ||
+ numericArg2.getType() == BSONType::NumberDecimal) {
+ totalType = BSONType::NumberDecimal;
+ }
+ switch (totalType) {
+ case BSONType::NumberDecimal: {
+ auto dec = numericArg1.coerceToDecimal();
+ return Value(dec.atan2(numericArg2.coerceToDecimal()));
+ }
+ case BSONType::NumberDouble: {
+ return Value(
+ std::atan2(numericArg1.coerceToDouble(), numericArg2.coerceToDouble()));
+ }
+ default:
+ MONGO_UNREACHABLE;
+ }
+ }
+
+ const char* getOpName() const final {
+ return "$atan2";
+ }
+};
+REGISTER_EXPRESSION(atan2, ExpressionArcTangent2::parse);
+
+
+/* ----------------------- ExpressionDegreesToRadians and ExpressionRadiansToDegrees ---- */
+
+static constexpr double kDoublePi = 3.141592653589793;
+static constexpr double kDoublePiOver180 = kDoublePi / 180.0;
+static constexpr double kDouble180OverPi = 180.0 / kDoublePi;
+
+static Value doDegreeRadiansConversion(const Value& numericArg,
+ Decimal128 decimalFactor,
+ double doubleFactor) {
+ switch (numericArg.getType()) {
+ case BSONType::NumberDecimal:
+ return Value(numericArg.getDecimal().multiply(decimalFactor));
+ default:
+ return Value(numericArg.coerceToDouble() * doubleFactor);
+ }
+}
+
+class ExpressionDegreesToRadians final
+ : public ExpressionSingleNumericArg<ExpressionDegreesToRadians> {
+public:
+ explicit ExpressionDegreesToRadians(const boost::intrusive_ptr<ExpressionContext>& expCtx)
+ : ExpressionSingleNumericArg(expCtx) {}
+
+ Value evaluateNumericArg(const Value& numericArg) const final {
+ return doDegreeRadiansConversion(numericArg, Decimal128::kPiOver180, kDoublePiOver180);
+ }
+
+ const char* getOpName() const final {
+ return "$degreesToRadians";
+ }
+};
+
+REGISTER_EXPRESSION(degreesToRadians, ExpressionDegreesToRadians::parse);
+
+class ExpressionRadiansToDegrees final
+ : public ExpressionSingleNumericArg<ExpressionRadiansToDegrees> {
+public:
+ explicit ExpressionRadiansToDegrees(const boost::intrusive_ptr<ExpressionContext>& expCtx)
+ : ExpressionSingleNumericArg(expCtx) {}
+
+ Value evaluateNumericArg(const Value& numericArg) const final {
+ return doDegreeRadiansConversion(numericArg, Decimal128::k180OverPi, kDouble180OverPi);
+ }
+
+ const char* getOpName() const final {
+ return "$radiansToDegrees";
+ }
+};
+
+REGISTER_EXPRESSION(radiansToDegrees, ExpressionRadiansToDegrees::parse);
+} // namespace mongo
diff --git a/src/mongo/db/pipeline/expression_trigonometric.h b/src/mongo/db/pipeline/expression_trigonometric.h
new file mode 100644
index 00000000000..41f10ca2e29
--- /dev/null
+++ b/src/mongo/db/pipeline/expression_trigonometric.h
@@ -0,0 +1,237 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include "expression.h"
+
+namespace mongo {
+
+/**
+ * InclusiveBoundType defines the necessary configuration for inclusively bounded trig functions.
+ */
+struct InclusiveBoundType {
+ // We use a static method rather than a field because the value, as an std::string, would need
+ // to be initialized out of line. This method will be inlined, and result in no overhead.
+ static std::string leftBracket() {
+ return "[";
+ }
+
+ static std::string rightBracket() {
+ return "]";
+ }
+
+ static bool checkUpperBound(double input, double bound) {
+ return input <= bound;
+ }
+
+ static bool checkUpperBound(Decimal128 input, double bound) {
+ return input.isLessEqual(Decimal128(bound));
+ }
+
+ static bool checkLowerBound(double input, double bound) {
+ return input >= bound;
+ }
+
+ static bool checkLowerBound(Decimal128 input, double bound) {
+ return input.isGreaterEqual(Decimal128(bound));
+ }
+};
+
+/**
+ * ExclusiveBoundType defines the necessary configuration for exclusively bounded trig functions.
+ */
+struct ExclusiveBoundType {
+ // We use a static method rather than a field because the value, as an std::string, would need
+ // to be initialized out of line. This method will be inlined, and result in no overhead.
+ static std::string leftBracket() {
+ return "(";
+ }
+
+ static std::string rightBracket() {
+ return ")";
+ }
+
+ static bool checkUpperBound(double input, double bound) {
+ return input < bound;
+ }
+
+ static bool checkUpperBound(Decimal128 input, double bound) {
+ return input.isLess(Decimal128(bound));
+ }
+
+ static bool checkLowerBound(double input, double bound) {
+ return input > bound;
+ }
+
+ static bool checkLowerBound(Decimal128 input, double bound) {
+ return input.isGreater(Decimal128(bound));
+ }
+};
+
+/**
+ * ExpressionBoundedTrigonometric is the type of all trigonometric functions that take one argument
+ * and have lower and upper bounds, either inclusive or exclusive, as defined by the BoundType
+ * template argument.
+ */
+template <typename BoundedTrigType, typename BoundType>
+class ExpressionBoundedTrigonometric : public ExpressionSingleNumericArg<BoundedTrigType> {
+public:
+ explicit ExpressionBoundedTrigonometric(const boost::intrusive_ptr<ExpressionContext>& expCtx)
+ : ExpressionSingleNumericArg<BoundedTrigType>(expCtx) {}
+
+ std::string toString(double d) const {
+ return str::stream() << d;
+ }
+
+ std::string toString(Decimal128 d) const {
+ return d.toString();
+ }
+
+ bool isnan(double d) const {
+ return std::isnan(d);
+ }
+
+ bool isnan(Decimal128 d) const {
+ return d.isNaN();
+ }
+
+ template <typename T>
+ bool checkBounds(T input) const {
+ return BoundType::checkLowerBound(input, getLowerBound()) &&
+ BoundType::checkUpperBound(input, getUpperBound());
+ }
+
+ /**
+ * assertBounds uasserts if checkBounds returns false, meaning that the input is out of bounds.
+ */
+ template <typename T>
+ void assertBounds(T input) const {
+ uassert(50989,
+ str::stream() << "cannot apply " << getOpName() << " to " << toString(input)
+ << ", value must in "
+ << BoundType::leftBracket()
+ << getLowerBound()
+ << ","
+ << getUpperBound()
+ << BoundType::rightBracket(),
+ checkBounds(input));
+ }
+
+ /**
+ * evaluateNumericArg evaluates the implented trig function on one numericArg.
+ */
+ Value evaluateNumericArg(const Value& numericArg) const {
+ switch (numericArg.getType()) {
+ case BSONType::NumberDouble: {
+ auto input = numericArg.getDouble();
+ if (isnan(input)) {
+ return numericArg;
+ }
+ assertBounds(input);
+ return Value(doubleFunc(input));
+ }
+ case BSONType::NumberDecimal: {
+ auto input = numericArg.getDecimal();
+ if (isnan(input)) {
+ return numericArg;
+ }
+ assertBounds(input);
+ return Value(decimalFunc(input));
+ }
+ default: {
+ auto input = static_cast<double>(numericArg.getLong());
+ if (isnan(input)) {
+ return numericArg;
+ }
+ assertBounds(input);
+ return Value(doubleFunc(input));
+ }
+ }
+ }
+
+ /**
+ * Since bounds are always either +/-Infinity or integral values, double has enough precision.
+ */
+ virtual double getLowerBound() const = 0;
+ virtual double getUpperBound() const = 0;
+ /**
+ * doubleFunc performs the double version of the implemented trig function, e.g. std::sin()
+ */
+ virtual double doubleFunc(double x) const = 0;
+ /**
+ * decimalFunc performs the decimal128 version of the implemented trig function, e.g. d.sin()
+ */
+ virtual Decimal128 decimalFunc(Decimal128 x) const = 0;
+ /**
+ * getOpName returns the name of the operation, e.g., $sin
+ */
+ virtual const char* getOpName() const = 0;
+};
+
+/**
+ * ExpressionUnboundedTrigonometric is the type for all trigonometric functions that do not have
+ * upper or lower bounds.
+ */
+template <typename TrigType>
+class ExpressionUnboundedTrigonometric : public ExpressionSingleNumericArg<TrigType> {
+public:
+ explicit ExpressionUnboundedTrigonometric(const boost::intrusive_ptr<ExpressionContext>& expCtx)
+ : ExpressionSingleNumericArg<TrigType>(expCtx) {}
+
+ /**
+ * evaluateNumericArg evaluates the implented trig function on one numericArg.
+ */
+ Value evaluateNumericArg(const Value& numericArg) const override {
+ switch (numericArg.getType()) {
+ case BSONType::NumberDouble:
+ return Value(doubleFunc(numericArg.getDouble()));
+ case BSONType::NumberDecimal:
+ return Value(decimalFunc(numericArg.getDecimal()));
+ default: {
+ auto num = static_cast<double>(numericArg.getLong());
+ return Value(doubleFunc(num));
+ }
+ }
+ }
+
+ /**
+ * doubleFunc performs the double version of the implemented trig function, e.g. std::sinh()
+ */
+ virtual double doubleFunc(double x) const = 0;
+ /**
+ * decimalFunc performs the decimal128 version of the implemented trig function, e.g. d.sinh()
+ */
+ virtual Decimal128 decimalFunc(Decimal128 x) const = 0;
+ /**
+ * getOpName returns the name of the operation, e.g., $sinh
+ */
+ virtual const char* getOpName() const = 0;
+};
+} // namespace mongo
diff --git a/src/mongo/db/pipeline/expression_trigonometric_test.cpp b/src/mongo/db/pipeline/expression_trigonometric_test.cpp
new file mode 100644
index 00000000000..35756404dd4
--- /dev/null
+++ b/src/mongo/db/pipeline/expression_trigonometric_test.cpp
@@ -0,0 +1,1406 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/pipeline/expression_trigonometric.h"
+
+#include "mongo/db/pipeline/document_value_test_util.h"
+#include "mongo/db/pipeline/expression_context_for_test.h"
+#include "mongo/unittest/unittest.h"
+
+namespace expression_tests {
+
+using boost::intrusive_ptr;
+using namespace mongo;
+
+// assertApproxEq is a helper function for asserting approximate results.
+static void assertApproxEq(const Value& evaluated, const Value& expected) {
+ ASSERT_EQ(evaluated.getType(), expected.getType());
+ if (expected.nullish()) {
+ ASSERT_VALUE_EQ(expected, evaluated);
+ } else {
+ ASSERT_VALUE_LT(
+ Value(evaluated.coerceToDecimal().subtract(expected.coerceToDecimal()).toAbs()),
+ Value(Decimal128(".000001")));
+ }
+}
+
+// A testing class for testing approximately equal results for one argument numeric expressions.
+static void assertEvaluates(const std::string& expressionName, Value input, Value output) {
+ intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
+ auto obj = BSON(expressionName << BSON_ARRAY(input));
+ auto vps = expCtx->variablesParseState;
+ auto expression = Expression::parseExpression(expCtx, obj, vps);
+ Value result = expression->evaluate(Document());
+ ASSERT_EQUALS(result.getType(), output.getType());
+ assertApproxEq(result, output);
+}
+
+
+// A testing class for testing approximately equal results for two argument numeric expressions.
+static void assertEvaluates(const std::string& expressionName,
+ Value input1,
+ Value input2,
+ Value output) {
+ intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
+ auto obj = BSON(expressionName << BSON_ARRAY(input1 << input2));
+ auto vps = expCtx->variablesParseState;
+ auto expression = Expression::parseExpression(expCtx, obj, vps);
+ Value result = expression->evaluate(Document());
+ ASSERT_EQUALS(result.getType(), output.getType());
+ assertApproxEq(result, output);
+}
+
+/* ------------------------- ExpressionArcSine -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of asin, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionArcSineTest, IntArg) {
+ assertEvaluates("$asin", Value(0), Value(0.0));
+ assertEvaluates("$asin", Value(1), Value(1.57079632679));
+}
+
+TEST(ExpressionArcSineTest, LongArg) {
+ assertEvaluates("$asin", Value(0LL), Value(0.0));
+ assertEvaluates("$asin", Value(1LL), Value(1.57079632679));
+}
+
+TEST(ExpressionArcSineTest, DoubleArg) {
+ assertEvaluates("$asin", Value(0.0), Value(0.0));
+ assertEvaluates("$asin", Value(0.1), Value(0.100167421162));
+ assertEvaluates("$asin", Value(0.2), Value(0.20135792079));
+ assertEvaluates("$asin", Value(0.3), Value(0.304692654015));
+ assertEvaluates("$asin", Value(0.4), Value(0.411516846067));
+ assertEvaluates("$asin", Value(0.5), Value(0.523598775598));
+ assertEvaluates("$asin", Value(0.6), Value(0.643501108793));
+ assertEvaluates("$asin", Value(0.7), Value(0.775397496611));
+ assertEvaluates("$asin", Value(0.8), Value(0.927295218002));
+ assertEvaluates("$asin", Value(0.9), Value(1.119769515));
+ assertEvaluates("$asin", Value(1.0), Value(1.57079632679));
+}
+
+TEST(ExpressionArcSineTest, DecimalArg) {
+ assertEvaluates("$asin", Value(Decimal128("0.0")), Value(Decimal128("0.0")));
+ assertEvaluates("$asin", Value(Decimal128("0.1")), Value(Decimal128("0.100167421162")));
+ assertEvaluates("$asin", Value(Decimal128("0.2")), Value(Decimal128("0.20135792079")));
+ assertEvaluates("$asin", Value(Decimal128("0.3")), Value(Decimal128("0.304692654015")));
+ assertEvaluates("$asin", Value(Decimal128("0.4")), Value(Decimal128("0.411516846067")));
+ assertEvaluates("$asin", Value(Decimal128("0.5")), Value(Decimal128("0.523598775598")));
+ assertEvaluates("$asin", Value(Decimal128("0.6")), Value(Decimal128("0.643501108793")));
+ assertEvaluates("$asin", Value(Decimal128("0.7")), Value(Decimal128("0.775397496611")));
+ assertEvaluates("$asin", Value(Decimal128("0.8")), Value(Decimal128("0.927295218002")));
+ assertEvaluates("$asin", Value(Decimal128("0.9")), Value(Decimal128("1.119769515")));
+ assertEvaluates("$asin", Value(Decimal128("1.0")), Value(Decimal128("1.57079632679")));
+}
+
+TEST(ExpressionArcSineTest, NullArg) {
+ assertEvaluates("$asin", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionArcCosine -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of acos, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionArcCosineTest, IntArg) {
+ assertEvaluates("$acos", Value(0), Value(1.57079632679));
+ assertEvaluates("$acos", Value(1), Value(0.0));
+}
+
+TEST(ExpressionArcCosineTest, LongArg) {
+ assertEvaluates("$acos", Value(0LL), Value(1.57079632679));
+ assertEvaluates("$acos", Value(1LL), Value(0.0));
+}
+
+TEST(ExpressionArcCosineTest, DoubleArg) {
+ assertEvaluates("$acos", Value(0.0), Value(1.57079632679));
+ assertEvaluates("$acos", Value(0.1), Value(1.47062890563));
+ assertEvaluates("$acos", Value(0.2), Value(1.369438406));
+ assertEvaluates("$acos", Value(0.3), Value(1.26610367278));
+ assertEvaluates("$acos", Value(0.4), Value(1.15927948073));
+ assertEvaluates("$acos", Value(0.5), Value(1.0471975512));
+ assertEvaluates("$acos", Value(0.6), Value(0.927295218002));
+ assertEvaluates("$acos", Value(0.7), Value(0.795398830184));
+ assertEvaluates("$acos", Value(0.8), Value(0.643501108793));
+ assertEvaluates("$acos", Value(0.9), Value(0.451026811796));
+ assertEvaluates("$acos", Value(1.0), Value(0.0));
+}
+
+TEST(ExpressionArcCosineTest, DecimalArg) {
+ assertEvaluates("$acos", Value(Decimal128("0.0")), Value(Decimal128("1.57079632679")));
+ assertEvaluates("$acos", Value(Decimal128("0.1")), Value(Decimal128("1.47062890563")));
+ assertEvaluates("$acos", Value(Decimal128("0.2")), Value(Decimal128("1.369438406")));
+ assertEvaluates("$acos", Value(Decimal128("0.3")), Value(Decimal128("1.26610367278")));
+ assertEvaluates("$acos", Value(Decimal128("0.4")), Value(Decimal128("1.15927948073")));
+ assertEvaluates("$acos", Value(Decimal128("0.5")), Value(Decimal128("1.0471975512")));
+ assertEvaluates("$acos", Value(Decimal128("0.6")), Value(Decimal128("0.927295218002")));
+ assertEvaluates("$acos", Value(Decimal128("0.7")), Value(Decimal128("0.795398830184")));
+ assertEvaluates("$acos", Value(Decimal128("0.8")), Value(Decimal128("0.643501108793")));
+ assertEvaluates("$acos", Value(Decimal128("0.9")), Value(Decimal128("0.451026811796")));
+ assertEvaluates("$acos", Value(Decimal128("1.0")), Value(Decimal128("0.0")));
+}
+
+TEST(ExpressionArcCosineTest, NullArg) {
+ assertEvaluates("$acos", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionArcTangent -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of atan, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionArcTangentTest, IntArg) {
+ assertEvaluates("$atan", Value(-1), Value(-0.785398163397));
+ assertEvaluates("$atan", Value(0), Value(0.0));
+ assertEvaluates("$atan", Value(1), Value(0.785398163397));
+}
+
+TEST(ExpressionArcTangentTest, LongArg) {
+ assertEvaluates("$atan", Value(-1LL), Value(-0.785398163397));
+ assertEvaluates("$atan", Value(0LL), Value(0.0));
+ assertEvaluates("$atan", Value(1LL), Value(0.785398163397));
+}
+
+TEST(ExpressionArcTangentTest, DoubleArg) {
+ assertEvaluates("$atan", Value(-1.5), Value(-0.982793723247));
+ assertEvaluates("$atan", Value(-1.0471975512), Value(-0.80844879263));
+ assertEvaluates("$atan", Value(-0.785398163397), Value(-0.665773750028));
+ assertEvaluates("$atan", Value(0), Value(0.0));
+ assertEvaluates("$atan", Value(0.785398163397), Value(0.665773750028));
+ assertEvaluates("$atan", Value(1.0471975512), Value(0.80844879263));
+ assertEvaluates("$atan", Value(1.5), Value(0.982793723247));
+}
+
+TEST(ExpressionArcTangentTest, DecimalArg) {
+ assertEvaluates("$atan", Value(Decimal128("-1.5")), Value(Decimal128("-0.982793723247")));
+ assertEvaluates(
+ "$atan", Value(Decimal128("-1.0471975512")), Value(Decimal128("-0.80844879263")));
+ assertEvaluates(
+ "$atan", Value(Decimal128("-0.785398163397")), Value(Decimal128("-0.665773750028")));
+ assertEvaluates("$atan", Value(Decimal128("0")), Value(Decimal128("0.0")));
+ assertEvaluates(
+ "$atan", Value(Decimal128("0.785398163397")), Value(Decimal128("0.665773750028")));
+ assertEvaluates("$atan", Value(Decimal128("1.0471975512")), Value(Decimal128("0.80844879263")));
+ assertEvaluates("$atan", Value(Decimal128("1.5")), Value(Decimal128("0.982793723247")));
+}
+
+TEST(ExpressionArcTangentTest, NullArg) {
+ assertEvaluates("$atan", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionArcTangent2 -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of atan2, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionArcTangent2Test, TwoIntArgs) {
+ assertEvaluates("$atan2", Value(1), Value(0), Value(1.57079632679));
+ assertEvaluates("$atan2", Value(0), Value(1), Value(0.0));
+ assertEvaluates("$atan2", Value(-1), Value(0), Value(-1.57079632679));
+ assertEvaluates("$atan2", Value(0), Value(-1), Value(3.14159265359));
+}
+
+TEST(ExpressionArcTangent2Test, TwoLongArg) {
+ assertEvaluates("$atan2", Value(1LL), Value(0LL), Value(1.57079632679));
+ assertEvaluates("$atan2", Value(0LL), Value(1LL), Value(0.0));
+ assertEvaluates("$atan2", Value(-1LL), Value(0LL), Value(-1.57079632679));
+ assertEvaluates("$atan2", Value(0LL), Value(-1LL), Value(3.14159265359));
+}
+
+TEST(ExpressionArcTangent2Test, LongIntArg) {
+ assertEvaluates("$atan2", Value(1LL), Value(0), Value(1.57079632679));
+ assertEvaluates("$atan2", Value(0LL), Value(1), Value(0.0));
+ assertEvaluates("$atan2", Value(-1LL), Value(0), Value(-1.57079632679));
+ assertEvaluates("$atan2", Value(0LL), Value(-1), Value(3.14159265359));
+}
+
+TEST(ExpressionArcTangent2Test, IntLongArg) {
+ assertEvaluates("$atan2", Value(1), Value(0LL), Value(1.57079632679));
+ assertEvaluates("$atan2", Value(0), Value(1LL), Value(0.0));
+ assertEvaluates("$atan2", Value(-1), Value(0LL), Value(-1.57079632679));
+ assertEvaluates("$atan2", Value(0), Value(-1LL), Value(3.14159265359));
+}
+
+TEST(ExpressionArcTangent2Test, TwoDoubleArg) {
+ assertEvaluates("$atan2", Value(1.0), Value(0.0), Value(1.57079632679));
+ assertEvaluates("$atan2", Value(0.866025403784), Value(0.5), Value(1.0471975512));
+ assertEvaluates("$atan2", Value(0.707106781187), Value(0.707106781187), Value(0.785398163397));
+ assertEvaluates("$atan2", Value(0.5), Value(0.866025403784), Value(0.523598775598));
+ assertEvaluates("$atan2", Value(6.12323399574e-17), Value(1.0), Value(6.12323399574e-17));
+ assertEvaluates("$atan2", Value(-0.5), Value(0.866025403784), Value(-0.523598775598));
+ assertEvaluates(
+ "$atan2", Value(-0.707106781187), Value(0.707106781187), Value(-0.785398163397));
+ assertEvaluates("$atan2", Value(-0.866025403784), Value(0.5), Value(-1.0471975512));
+ assertEvaluates("$atan2", Value(-1.0), Value(1.22464679915e-16), Value(-1.57079632679));
+ assertEvaluates("$atan2", Value(-0.866025403784), Value(-0.5), Value(-2.09439510239));
+ assertEvaluates(
+ "$atan2", Value(-0.707106781187), Value(-0.707106781187), Value(-2.35619449019));
+ assertEvaluates("$atan2", Value(-0.5), Value(-0.866025403784), Value(-2.61799387799));
+ assertEvaluates("$atan2", Value(-1.83697019872e-16), Value(-1.0), Value(-3.14159265359));
+ assertEvaluates("$atan2", Value(0.5), Value(-0.866025403784), Value(2.61799387799));
+ assertEvaluates("$atan2", Value(0.707106781187), Value(-0.707106781187), Value(2.35619449019));
+ assertEvaluates("$atan2", Value(0.866025403784), Value(-0.5), Value(2.09439510239));
+ assertEvaluates("$atan2", Value(1.0), Value(-2.44929359829e-16), Value(1.57079632679));
+}
+
+TEST(ExpressionArcTangent2Test, TwoDecimalArg) {
+ assertEvaluates("$atan2",
+ Value(Decimal128("1.0")),
+ Value(Decimal128("0.0")),
+ Value(Decimal128("1.57079632679")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.866025403784")),
+ Value(Decimal128("0.5")),
+ Value(Decimal128("1.0471975512")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.707106781187")),
+ Value(Decimal128("0.707106781187")),
+ Value(Decimal128("0.785398163397")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.5")),
+ Value(Decimal128("0.866025403784")),
+ Value(Decimal128("0.523598775598")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("6.12323399574e-17")),
+ Value(Decimal128("1.0")),
+ Value(Decimal128("6.12323399574e-17")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.5")),
+ Value(Decimal128("0.866025403784")),
+ Value(Decimal128("-0.523598775598")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.707106781187")),
+ Value(Decimal128("0.707106781187")),
+ Value(Decimal128("-0.785398163397")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.866025403784")),
+ Value(Decimal128("0.5")),
+ Value(Decimal128("-1.0471975512")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-1.0")),
+ Value(Decimal128("1.22464679915e-16")),
+ Value(Decimal128("-1.57079632679")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.866025403784")),
+ Value(Decimal128("-0.5")),
+ Value(Decimal128("-2.09439510239")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.707106781187")),
+ Value(Decimal128("-0.707106781187")),
+ Value(Decimal128("-2.35619449019")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.5")),
+ Value(Decimal128("-0.866025403784")),
+ Value(Decimal128("-2.61799387799")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-1.83697019872e-16")),
+ Value(Decimal128("-1.0")),
+ Value(Decimal128("-3.14159265359")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.5")),
+ Value(Decimal128("-0.866025403784")),
+ Value(Decimal128("2.61799387799")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.707106781187")),
+ Value(Decimal128("-0.707106781187")),
+ Value(Decimal128("2.35619449019")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.866025403784")),
+ Value(Decimal128("-0.5")),
+ Value(Decimal128("2.09439510239")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("1.0")),
+ Value(Decimal128("-2.44929359829e-16")),
+ Value(Decimal128("1.57079632679")));
+}
+
+TEST(ExpressionArcTangent2Test, DoubleDecimalArg) {
+ assertEvaluates(
+ "$atan2", Value(1.0), Value(Decimal128("0.0")), Value(Decimal128("1.57079632679")));
+ assertEvaluates("$atan2",
+ Value(0.866025403784),
+ Value(Decimal128("0.5")),
+ Value(Decimal128("1.0471975512")));
+ assertEvaluates("$atan2",
+ Value(0.707106781187),
+ Value(Decimal128("0.707106781187")),
+ Value(Decimal128("0.785398163397")));
+ assertEvaluates("$atan2",
+ Value(0.5),
+ Value(Decimal128("0.866025403784")),
+ Value(Decimal128("0.523598775598")));
+ assertEvaluates("$atan2",
+ Value(6.12323399574e-17),
+ Value(Decimal128("1.0")),
+ Value(Decimal128("6.12323399574e-17")));
+ assertEvaluates("$atan2",
+ Value(-0.5),
+ Value(Decimal128("0.866025403784")),
+ Value(Decimal128("-0.523598775598")));
+ assertEvaluates("$atan2",
+ Value(-0.707106781187),
+ Value(Decimal128("0.707106781187")),
+ Value(Decimal128("-0.785398163397")));
+ assertEvaluates("$atan2",
+ Value(-0.866025403784),
+ Value(Decimal128("0.5")),
+ Value(Decimal128("-1.0471975512")));
+ assertEvaluates("$atan2",
+ Value(-1.0),
+ Value(Decimal128("1.22464679915e-16")),
+ Value(Decimal128("-1.57079632679")));
+ assertEvaluates("$atan2",
+ Value(-0.866025403784),
+ Value(Decimal128("-0.5")),
+ Value(Decimal128("-2.09439510239")));
+ assertEvaluates("$atan2",
+ Value(-0.707106781187),
+ Value(Decimal128("-0.707106781187")),
+ Value(Decimal128("-2.35619449019")));
+ assertEvaluates("$atan2",
+ Value(-0.5),
+ Value(Decimal128("-0.866025403784")),
+ Value(Decimal128("-2.61799387799")));
+ assertEvaluates("$atan2",
+ Value(-1.83697019872e-16),
+ Value(Decimal128("-1.0")),
+ Value(Decimal128("-3.14159265359")));
+ assertEvaluates("$atan2",
+ Value(0.5),
+ Value(Decimal128("-0.866025403784")),
+ Value(Decimal128("2.61799387799")));
+ assertEvaluates("$atan2",
+ Value(0.707106781187),
+ Value(Decimal128("-0.707106781187")),
+ Value(Decimal128("2.35619449019")));
+ assertEvaluates("$atan2",
+ Value(0.866025403784),
+ Value(Decimal128("-0.5")),
+ Value(Decimal128("2.09439510239")));
+ assertEvaluates("$atan2",
+ Value(1.0),
+ Value(Decimal128("-2.44929359829e-16")),
+ Value(Decimal128("1.57079632679")));
+}
+
+TEST(ExpressionArcTangent2Test, DecimalDoubleArg) {
+ assertEvaluates(
+ "$atan2", Value(Decimal128("1.0")), Value(0.0), Value(Decimal128("1.57079632679")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.866025403784")),
+ Value(0.5),
+ Value(Decimal128("1.0471975512")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.707106781187")),
+ Value(0.707106781187),
+ Value(Decimal128("0.785398163397")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.5")),
+ Value(0.866025403784),
+ Value(Decimal128("0.523598775598")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("6.12323399574e-17")),
+ Value(1.0),
+ Value(Decimal128("6.12323399574e-17")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.5")),
+ Value(0.866025403784),
+ Value(Decimal128("-0.523598775598")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.707106781187")),
+ Value(0.707106781187),
+ Value(Decimal128("-0.785398163397")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.866025403784")),
+ Value(0.5),
+ Value(Decimal128("-1.0471975512")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-1.0")),
+ Value(1.22464679915e-16),
+ Value(Decimal128("-1.57079632679")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.866025403784")),
+ Value(-0.5),
+ Value(Decimal128("-2.09439510239")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.707106781187")),
+ Value(-0.707106781187),
+ Value(Decimal128("-2.35619449019")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-0.5")),
+ Value(-0.866025403784),
+ Value(Decimal128("-2.61799387799")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("-1.83697019872e-16")),
+ Value(-1.0),
+ Value(Decimal128("-3.14159265359")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.5")),
+ Value(-0.866025403784),
+ Value(Decimal128("2.61799387799")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.707106781187")),
+ Value(-0.707106781187),
+ Value(Decimal128("2.35619449019")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("0.866025403784")),
+ Value(-0.5),
+ Value(Decimal128("2.09439510239")));
+ assertEvaluates("$atan2",
+ Value(Decimal128("1.0")),
+ Value(-2.44929359829e-16),
+ Value(Decimal128("1.57079632679")));
+}
+
+TEST(ExpressionArcTangent2Test, NullArg) {
+ assertEvaluates("$atan2", Value(BSONNULL), Value(BSONNULL), Value(BSONNULL));
+ assertEvaluates("$atan2", Value(1), Value(BSONNULL), Value(BSONNULL));
+ assertEvaluates("$atan2", Value(BSONNULL), Value(1), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionCosine -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of acos, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionCosineTest, IntArg) {
+ assertEvaluates("$cos", Value(0), Value(1.0));
+ assertEvaluates("$cos", Value(1), Value(0.540302305868));
+ assertEvaluates("$cos", Value(2), Value(-0.416146836547));
+ assertEvaluates("$cos", Value(3), Value(-0.9899924966));
+ assertEvaluates("$cos", Value(4), Value(-0.653643620864));
+ assertEvaluates("$cos", Value(5), Value(0.283662185463));
+ assertEvaluates("$cos", Value(6), Value(0.96017028665));
+}
+
+TEST(ExpressionCosineTest, LongArg) {
+ assertEvaluates("$cos", Value(0LL), Value(1.0));
+ assertEvaluates("$cos", Value(1LL), Value(0.540302305868));
+ assertEvaluates("$cos", Value(2LL), Value(-0.416146836547));
+ assertEvaluates("$cos", Value(3LL), Value(-0.9899924966));
+ assertEvaluates("$cos", Value(4LL), Value(-0.653643620864));
+ assertEvaluates("$cos", Value(5LL), Value(0.283662185463));
+ assertEvaluates("$cos", Value(6LL), Value(0.96017028665));
+}
+
+TEST(ExpressionCosineTest, DoubleArg) {
+ assertEvaluates("$cos", Value(0.0), Value(1.0));
+ assertEvaluates("$cos", Value(0.523598775598), Value(0.866025403784));
+ assertEvaluates("$cos", Value(0.785398163397), Value(0.707106781187));
+ assertEvaluates("$cos", Value(1.0471975512), Value(0.5));
+ assertEvaluates("$cos", Value(1.57079632679), Value(6.12323399574e-17));
+ assertEvaluates("$cos", Value(2.09439510239), Value(-0.5));
+ assertEvaluates("$cos", Value(2.35619449019), Value(-0.707106781187));
+ assertEvaluates("$cos", Value(2.61799387799), Value(-0.866025403784));
+ assertEvaluates("$cos", Value(3.14159265359), Value(-1.0));
+ assertEvaluates("$cos", Value(3.66519142919), Value(-0.866025403784));
+ assertEvaluates("$cos", Value(3.92699081699), Value(-0.707106781187));
+ assertEvaluates("$cos", Value(4.18879020479), Value(-0.5));
+ assertEvaluates("$cos", Value(4.71238898038), Value(-1.83697019872e-16));
+ assertEvaluates("$cos", Value(5.23598775598), Value(0.5));
+ assertEvaluates("$cos", Value(5.49778714378), Value(0.707106781187));
+ assertEvaluates("$cos", Value(5.75958653158), Value(0.866025403784));
+ assertEvaluates("$cos", Value(6.28318530718), Value(1.0));
+}
+
+TEST(ExpressionCosineTest, DecimalArg) {
+ assertEvaluates("$cos", Value(Decimal128("0.0")), Value(Decimal128("1.0")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("0.523598775598")), Value(Decimal128("0.866025403784")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("0.785398163397")), Value(Decimal128("0.707106781187")));
+ assertEvaluates("$cos", Value(Decimal128("1.0471975512")), Value(Decimal128("0.5")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("1.57079632679")), Value(Decimal128("6.12323399574e-17")));
+ assertEvaluates("$cos", Value(Decimal128("2.09439510239")), Value(Decimal128("-0.5")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("2.35619449019")), Value(Decimal128("-0.707106781187")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("2.61799387799")), Value(Decimal128("-0.866025403784")));
+ assertEvaluates("$cos", Value(Decimal128("3.14159265359")), Value(Decimal128("-1.0")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("3.66519142919")), Value(Decimal128("-0.866025403784")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("3.92699081699")), Value(Decimal128("-0.707106781187")));
+ assertEvaluates("$cos", Value(Decimal128("4.18879020479")), Value(Decimal128("-0.5")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("4.71238898038")), Value(Decimal128("-1.83697019872e-16")));
+ assertEvaluates("$cos", Value(Decimal128("5.23598775598")), Value(Decimal128("0.5")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("5.49778714378")), Value(Decimal128("0.707106781187")));
+ assertEvaluates(
+ "$cos", Value(Decimal128("5.75958653158")), Value(Decimal128("0.866025403784")));
+ assertEvaluates("$cos", Value(Decimal128("6.28318530718")), Value(Decimal128("1.0")));
+}
+
+TEST(ExpressionCosineTest, NullArg) {
+ assertEvaluates("$cos", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionHyperbolicCosine -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of cosh, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionHyperbolicCosineTest, IntArg) {
+ assertEvaluates("$cosh", Value(0), Value(1.0));
+ assertEvaluates("$cosh", Value(1), Value(1.54308063482));
+ assertEvaluates("$cosh", Value(2), Value(3.76219569108));
+ assertEvaluates("$cosh", Value(3), Value(10.0676619958));
+ assertEvaluates("$cosh", Value(4), Value(27.308232836));
+ assertEvaluates("$cosh", Value(5), Value(74.2099485248));
+ assertEvaluates("$cosh", Value(6), Value(201.715636122));
+}
+
+TEST(ExpressionHyperbolicCosineTest, LongArg) {
+ assertEvaluates("$cosh", Value(0LL), Value(1.0));
+ assertEvaluates("$cosh", Value(1LL), Value(1.54308063482));
+ assertEvaluates("$cosh", Value(2LL), Value(3.76219569108));
+ assertEvaluates("$cosh", Value(3LL), Value(10.0676619958));
+ assertEvaluates("$cosh", Value(4LL), Value(27.308232836));
+ assertEvaluates("$cosh", Value(5LL), Value(74.2099485248));
+ assertEvaluates("$cosh", Value(6LL), Value(201.715636122));
+}
+
+TEST(ExpressionHyperbolicCosineTest, DoubleArg) {
+ assertEvaluates("$cosh", Value(0.0), Value(1.0));
+ assertEvaluates("$cosh", Value(0.523598775598), Value(1.14023832108));
+ assertEvaluates("$cosh", Value(0.785398163397), Value(1.32460908925));
+ assertEvaluates("$cosh", Value(1.0471975512), Value(1.6002868577));
+ assertEvaluates("$cosh", Value(1.57079632679), Value(2.50917847866));
+ assertEvaluates("$cosh", Value(2.09439510239), Value(4.12183605387));
+ assertEvaluates("$cosh", Value(2.35619449019), Value(5.32275214952));
+ assertEvaluates("$cosh", Value(2.61799387799), Value(6.89057236498));
+ assertEvaluates("$cosh", Value(3.14159265359), Value(11.5919532755));
+ assertEvaluates("$cosh", Value(3.66519142919), Value(19.5446063168));
+ assertEvaluates("$cosh", Value(3.92699081699), Value(25.3868611924));
+ assertEvaluates("$cosh", Value(4.18879020479), Value(32.97906491));
+ assertEvaluates("$cosh", Value(4.71238898038), Value(55.6633808904));
+ assertEvaluates("$cosh", Value(5.23598775598), Value(93.9599750339));
+ assertEvaluates("$cosh", Value(5.49778714378), Value(122.07757934));
+ assertEvaluates("$cosh", Value(5.75958653158), Value(158.610147472));
+ assertEvaluates("$cosh", Value(6.28318530718), Value(267.746761484));
+}
+
+TEST(ExpressionHyperbolicCosineTest, DecimalArg) {
+ assertEvaluates("$cosh", Value(Decimal128("0.0")), Value(Decimal128("1.0")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("0.523598775598")), Value(Decimal128("1.14023832108")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("0.785398163397")), Value(Decimal128("1.32460908925")));
+ assertEvaluates("$cosh", Value(Decimal128("1.0471975512")), Value(Decimal128("1.6002868577")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("1.57079632679")), Value(Decimal128("2.50917847866")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("2.09439510239")), Value(Decimal128("4.12183605387")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("2.35619449019")), Value(Decimal128("5.32275214952")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("2.61799387799")), Value(Decimal128("6.89057236498")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("3.14159265359")), Value(Decimal128("11.5919532755")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("3.66519142919")), Value(Decimal128("19.5446063168")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("3.92699081699")), Value(Decimal128("25.3868611924")));
+ assertEvaluates("$cosh", Value(Decimal128("4.18879020479")), Value(Decimal128("32.97906491")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("4.71238898038")), Value(Decimal128("55.6633808904")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("5.23598775598")), Value(Decimal128("93.9599750339")));
+ assertEvaluates("$cosh", Value(Decimal128("5.49778714378")), Value(Decimal128("122.07757934")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("5.75958653158")), Value(Decimal128("158.610147472")));
+ assertEvaluates(
+ "$cosh", Value(Decimal128("6.28318530718")), Value(Decimal128("267.746761484")));
+}
+
+TEST(ExpressionHyperbolicCosineTest, NullArg) {
+ assertEvaluates("$cosh", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionSine -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of sin, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionSineTest, IntArg) {
+ assertEvaluates("$sin", Value(0), Value(0.0));
+ assertEvaluates("$sin", Value(1), Value(0.841470984808));
+ assertEvaluates("$sin", Value(2), Value(0.909297426826));
+ assertEvaluates("$sin", Value(3), Value(0.14112000806));
+ assertEvaluates("$sin", Value(4), Value(-0.756802495308));
+ assertEvaluates("$sin", Value(5), Value(-0.958924274663));
+ assertEvaluates("$sin", Value(6), Value(-0.279415498199));
+}
+
+TEST(ExpressionSineTest, LongArg) {
+ assertEvaluates("$sin", Value(0LL), Value(0.0));
+ assertEvaluates("$sin", Value(1LL), Value(0.841470984808));
+ assertEvaluates("$sin", Value(2LL), Value(0.909297426826));
+ assertEvaluates("$sin", Value(3LL), Value(0.14112000806));
+ assertEvaluates("$sin", Value(4LL), Value(-0.756802495308));
+ assertEvaluates("$sin", Value(5LL), Value(-0.958924274663));
+ assertEvaluates("$sin", Value(6LL), Value(-0.279415498199));
+}
+
+TEST(ExpressionSineTest, DoubleArg) {
+ assertEvaluates("$sin", Value(0.0), Value(0.0));
+ assertEvaluates("$sin", Value(0.523598775598), Value(0.5));
+ assertEvaluates("$sin", Value(0.785398163397), Value(0.707106781187));
+ assertEvaluates("$sin", Value(1.0471975512), Value(0.866025403784));
+ assertEvaluates("$sin", Value(1.57079632679), Value(1.0));
+ assertEvaluates("$sin", Value(2.09439510239), Value(0.866025403784));
+ assertEvaluates("$sin", Value(2.35619449019), Value(0.707106781187));
+ assertEvaluates("$sin", Value(2.61799387799), Value(0.5));
+ assertEvaluates("$sin", Value(3.14159265359), Value(1.22464679915e-16));
+ assertEvaluates("$sin", Value(3.66519142919), Value(-0.5));
+ assertEvaluates("$sin", Value(3.92699081699), Value(-0.707106781187));
+ assertEvaluates("$sin", Value(4.18879020479), Value(-0.866025403784));
+ assertEvaluates("$sin", Value(4.71238898038), Value(-1.0));
+ assertEvaluates("$sin", Value(5.23598775598), Value(-0.866025403784));
+ assertEvaluates("$sin", Value(5.49778714378), Value(-0.707106781187));
+ assertEvaluates("$sin", Value(5.75958653158), Value(-0.5));
+ assertEvaluates("$sin", Value(6.28318530718), Value(-2.44929359829e-16));
+}
+
+TEST(ExpressionSineTest, DecimalArg) {
+ assertEvaluates("$sin", Value(Decimal128("0.0")), Value(Decimal128("0.0")));
+ assertEvaluates("$sin", Value(Decimal128("0.523598775598")), Value(Decimal128("0.5")));
+ assertEvaluates(
+ "$sin", Value(Decimal128("0.785398163397")), Value(Decimal128("0.707106781187")));
+ assertEvaluates("$sin", Value(Decimal128("1.0471975512")), Value(Decimal128("0.866025403784")));
+ assertEvaluates("$sin", Value(Decimal128("1.57079632679")), Value(Decimal128("1.0")));
+ assertEvaluates(
+ "$sin", Value(Decimal128("2.09439510239")), Value(Decimal128("0.866025403784")));
+ assertEvaluates(
+ "$sin", Value(Decimal128("2.35619449019")), Value(Decimal128("0.707106781187")));
+ assertEvaluates("$sin", Value(Decimal128("2.61799387799")), Value(Decimal128("0.5")));
+ assertEvaluates(
+ "$sin", Value(Decimal128("3.14159265359")), Value(Decimal128("1.22464679915e-16")));
+ assertEvaluates("$sin", Value(Decimal128("3.66519142919")), Value(Decimal128("-0.5")));
+ assertEvaluates(
+ "$sin", Value(Decimal128("3.92699081699")), Value(Decimal128("-0.707106781187")));
+ assertEvaluates(
+ "$sin", Value(Decimal128("4.18879020479")), Value(Decimal128("-0.866025403784")));
+ assertEvaluates("$sin", Value(Decimal128("4.71238898038")), Value(Decimal128("-1.0")));
+ assertEvaluates(
+ "$sin", Value(Decimal128("5.23598775598")), Value(Decimal128("-0.866025403784")));
+ assertEvaluates(
+ "$sin", Value(Decimal128("5.49778714378")), Value(Decimal128("-0.707106781187")));
+ assertEvaluates("$sin", Value(Decimal128("5.75958653158")), Value(Decimal128("-0.5")));
+ assertEvaluates(
+ "$sin", Value(Decimal128("6.28318530718")), Value(Decimal128("-2.44929359829e-16")));
+}
+
+TEST(ExpressionSineTest, NullArg) {
+ assertEvaluates("$sin", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionHyperbolicSine -------------------------- */
+/*
+ * Test values were generated using the 64 bit std version of sinh, and help
+ * ensure that we are calling the correct functions.
+ */
+
+TEST(ExpressionHyperbolicSineTest, IntArg) {
+ assertEvaluates("$sinh", Value(0), Value(0.0));
+ assertEvaluates("$sinh", Value(1), Value(1.17520119364));
+ assertEvaluates("$sinh", Value(2), Value(3.62686040785));
+ assertEvaluates("$sinh", Value(3), Value(10.0178749274));
+ assertEvaluates("$sinh", Value(4), Value(27.2899171971));
+ assertEvaluates("$sinh", Value(5), Value(74.2032105778));
+ assertEvaluates("$sinh", Value(6), Value(201.71315737));
+}
+
+TEST(ExpressionHyperbolicSineTest, LongArg) {
+ assertEvaluates("$sinh", Value(0LL), Value(0.0));
+ assertEvaluates("$sinh", Value(1LL), Value(1.17520119364));
+ assertEvaluates("$sinh", Value(2LL), Value(3.62686040785));
+ assertEvaluates("$sinh", Value(3LL), Value(10.0178749274));
+ assertEvaluates("$sinh", Value(4LL), Value(27.2899171971));
+ assertEvaluates("$sinh", Value(5LL), Value(74.2032105778));
+ assertEvaluates("$sinh", Value(6LL), Value(201.71315737));
+}
+
+TEST(ExpressionHyperbolicSineTest, DoubleArg) {
+ assertEvaluates("$sinh", Value(0.0), Value(0.0));
+ assertEvaluates("$sinh", Value(0.523598775598), Value(0.547853473888));
+ assertEvaluates("$sinh", Value(0.785398163397), Value(0.868670961486));
+ assertEvaluates("$sinh", Value(1.0471975512), Value(1.24936705052));
+ assertEvaluates("$sinh", Value(1.57079632679), Value(2.30129890231));
+ assertEvaluates("$sinh", Value(2.09439510239), Value(3.9986913428));
+ assertEvaluates("$sinh", Value(2.35619449019), Value(5.22797192468));
+ assertEvaluates("$sinh", Value(2.61799387799), Value(6.81762330413));
+ assertEvaluates("$sinh", Value(3.14159265359), Value(11.5487393573));
+ assertEvaluates("$sinh", Value(3.66519142919), Value(19.5190070464));
+ assertEvaluates("$sinh", Value(3.92699081699), Value(25.3671583194));
+ assertEvaluates("$sinh", Value(4.18879020479), Value(32.9639002901));
+ assertEvaluates("$sinh", Value(4.71238898038), Value(55.6543975994));
+ assertEvaluates("$sinh", Value(5.23598775598), Value(93.9546534685));
+ assertEvaluates("$sinh", Value(5.49778714378), Value(122.073483515));
+ assertEvaluates("$sinh", Value(5.75958653158), Value(158.606995057));
+ assertEvaluates("$sinh", Value(6.28318530718), Value(267.744894041));
+}
+
+TEST(ExpressionHyperbolicSineTest, DecimalArg) {
+ assertEvaluates("$sinh", Value(Decimal128("0.0")), Value(Decimal128("0.0")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("0.523598775598")), Value(Decimal128("0.547853473888")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("0.785398163397")), Value(Decimal128("0.868670961486")));
+ assertEvaluates("$sinh", Value(Decimal128("1.0471975512")), Value(Decimal128("1.24936705052")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("1.57079632679")), Value(Decimal128("2.30129890231")));
+ assertEvaluates("$sinh", Value(Decimal128("2.09439510239")), Value(Decimal128("3.9986913428")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("2.35619449019")), Value(Decimal128("5.22797192468")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("2.61799387799")), Value(Decimal128("6.81762330413")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("3.14159265359")), Value(Decimal128("11.5487393573")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("3.66519142919")), Value(Decimal128("19.5190070464")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("3.92699081699")), Value(Decimal128("25.3671583194")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("4.18879020479")), Value(Decimal128("32.9639002901")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("4.71238898038")), Value(Decimal128("55.6543975994")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("5.23598775598")), Value(Decimal128("93.9546534685")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("5.49778714378")), Value(Decimal128("122.073483515")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("5.75958653158")), Value(Decimal128("158.606995057")));
+ assertEvaluates(
+ "$sinh", Value(Decimal128("6.28318530718")), Value(Decimal128("267.744894041")));
+}
+
+TEST(ExpressionHyperbolicSineTest, NullArg) {
+ assertEvaluates("$sinh", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionTangent -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of tan, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionTangentTest, IntArg) {
+ assertEvaluates("$tan", Value(-1), Value(-1.55740772465));
+ assertEvaluates("$tan", Value(0), Value(0.0));
+ assertEvaluates("$tan", Value(1), Value(1.55740772465));
+}
+
+TEST(ExpressionTangentTest, LongArg) {
+ assertEvaluates("$tan", Value(-1LL), Value(-1.55740772465));
+ assertEvaluates("$tan", Value(0LL), Value(0.0));
+ assertEvaluates("$tan", Value(1LL), Value(1.55740772465));
+}
+
+TEST(ExpressionTangentTest, DoubleArg) {
+ assertEvaluates("$tan", Value(-1.5), Value(-14.1014199472));
+ assertEvaluates("$tan", Value(-1.0471975512), Value(-1.73205080757));
+ assertEvaluates("$tan", Value(-0.785398163397), Value(-1.0));
+ assertEvaluates("$tan", Value(0), Value(0.0));
+ assertEvaluates("$tan", Value(0.785398163397), Value(1.0));
+ assertEvaluates("$tan", Value(1.0471975512), Value(1.73205080757));
+ assertEvaluates("$tan", Value(1.5), Value(14.1014199472));
+}
+
+TEST(ExpressionTangentTest, DecimalArg) {
+ assertEvaluates("$tan", Value(Decimal128("-1.5")), Value(Decimal128("-14.1014199472")));
+ assertEvaluates(
+ "$tan", Value(Decimal128("-1.0471975512")), Value(Decimal128("-1.73205080757")));
+ assertEvaluates("$tan", Value(Decimal128("-0.785398163397")), Value(Decimal128("-1.0")));
+ assertEvaluates("$tan", Value(Decimal128("0")), Value(Decimal128("0.0")));
+ assertEvaluates("$tan", Value(Decimal128("0.785398163397")), Value(Decimal128("1.0")));
+ assertEvaluates("$tan", Value(Decimal128("1.0471975512")), Value(Decimal128("1.73205080757")));
+ assertEvaluates("$tan", Value(Decimal128("1.5")), Value(Decimal128("14.1014199472")));
+}
+
+TEST(ExpressionTangentTest, NullArg) {
+ assertEvaluates("$tan", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionHyperbolicTangent -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of tanh, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+TEST(ExpressionHyperbolicTangentTest, IntArg) {
+ assertEvaluates("$tanh", Value(0), Value(0.0));
+ assertEvaluates("$tanh", Value(1), Value(0.761594155956));
+ assertEvaluates("$tanh", Value(2), Value(0.964027580076));
+ assertEvaluates("$tanh", Value(3), Value(0.995054753687));
+ assertEvaluates("$tanh", Value(4), Value(0.999329299739));
+ assertEvaluates("$tanh", Value(5), Value(0.999909204263));
+ assertEvaluates("$tanh", Value(6), Value(0.999987711651));
+}
+
+TEST(ExpressionHyperbolicTangentTest, LongArg) {
+ assertEvaluates("$tanh", Value(0LL), Value(0.0));
+ assertEvaluates("$tanh", Value(1LL), Value(0.761594155956));
+ assertEvaluates("$tanh", Value(2LL), Value(0.964027580076));
+ assertEvaluates("$tanh", Value(3LL), Value(0.995054753687));
+ assertEvaluates("$tanh", Value(4LL), Value(0.999329299739));
+ assertEvaluates("$tanh", Value(5LL), Value(0.999909204263));
+ assertEvaluates("$tanh", Value(6LL), Value(0.999987711651));
+}
+
+TEST(ExpressionHyperbolicTangentTest, DoubleArg) {
+ assertEvaluates("$tanh", Value(0.0), Value(0.0));
+ assertEvaluates("$tanh", Value(0.523598775598), Value(0.480472778156));
+ assertEvaluates("$tanh", Value(0.785398163397), Value(0.655794202633));
+ assertEvaluates("$tanh", Value(1.0471975512), Value(0.780714435359));
+ assertEvaluates("$tanh", Value(1.57079632679), Value(0.917152335667));
+ assertEvaluates("$tanh", Value(2.09439510239), Value(0.970123821166));
+ assertEvaluates("$tanh", Value(2.35619449019), Value(0.982193380007));
+ assertEvaluates("$tanh", Value(2.61799387799), Value(0.989413207353));
+ assertEvaluates("$tanh", Value(3.14159265359), Value(0.996272076221));
+ assertEvaluates("$tanh", Value(3.66519142919), Value(0.998690213046));
+ assertEvaluates("$tanh", Value(3.92699081699), Value(0.999223894879));
+ assertEvaluates("$tanh", Value(4.18879020479), Value(0.999540174353));
+ assertEvaluates("$tanh", Value(4.71238898038), Value(0.999838613989));
+ assertEvaluates("$tanh", Value(5.23598775598), Value(0.999943363486));
+ assertEvaluates("$tanh", Value(5.49778714378), Value(0.999966449));
+ assertEvaluates("$tanh", Value(5.75958653158), Value(0.99998012476));
+ assertEvaluates("$tanh", Value(6.28318530718), Value(0.99999302534));
+}
+
+TEST(ExpressionHyperbolicTangentTest, DecimalArg) {
+ assertEvaluates("$tanh", Value(Decimal128("0.0")), Value(Decimal128("0.0")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("0.523598775598")), Value(Decimal128("0.480472778156")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("0.785398163397")), Value(Decimal128("0.655794202633")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("1.0471975512")), Value(Decimal128("0.780714435359")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("1.57079632679")), Value(Decimal128("0.917152335667")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("2.09439510239")), Value(Decimal128("0.970123821166")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("2.35619449019")), Value(Decimal128("0.982193380007")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("2.61799387799")), Value(Decimal128("0.989413207353")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("3.14159265359")), Value(Decimal128("0.996272076221")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("3.66519142919")), Value(Decimal128("0.998690213046")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("3.92699081699")), Value(Decimal128("0.999223894879")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("4.18879020479")), Value(Decimal128("0.999540174353")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("4.71238898038")), Value(Decimal128("0.999838613989")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("5.23598775598")), Value(Decimal128("0.999943363486")));
+ assertEvaluates("$tanh", Value(Decimal128("5.49778714378")), Value(Decimal128("0.999966449")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("5.75958653158")), Value(Decimal128("0.99998012476")));
+ assertEvaluates(
+ "$tanh", Value(Decimal128("6.28318530718")), Value(Decimal128("0.99999302534")));
+}
+
+TEST(ExpressionHyperbolicTangentTest, NullArg) {
+ assertEvaluates("$tanh", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionHyperbolicArcCosine -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of acosh, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionHyperbolicArcCosineTest, IntArg) {
+ assertEvaluates("$acosh", Value(1), Value(0.000000));
+ assertEvaluates("$acosh", Value(2), Value(1.316958));
+ assertEvaluates("$acosh", Value(3), Value(1.762747));
+ assertEvaluates("$acosh", Value(4), Value(2.063437));
+ assertEvaluates("$acosh", Value(5), Value(2.292432));
+ assertEvaluates("$acosh", Value(6), Value(2.477889));
+ assertEvaluates("$acosh", Value(7), Value(2.633916));
+ assertEvaluates("$acosh", Value(8), Value(2.768659));
+ assertEvaluates("$acosh", Value(9), Value(2.887271));
+}
+
+TEST(ExpressionHyperbolicArcCosineTest, LongArg) {
+ assertEvaluates("$acosh", Value(1LL), Value(0.000000));
+ assertEvaluates("$acosh", Value(2LL), Value(1.316958));
+ assertEvaluates("$acosh", Value(3LL), Value(1.762747));
+ assertEvaluates("$acosh", Value(4LL), Value(2.063437));
+ assertEvaluates("$acosh", Value(5LL), Value(2.292432));
+ assertEvaluates("$acosh", Value(6LL), Value(2.477889));
+ assertEvaluates("$acosh", Value(7LL), Value(2.633916));
+ assertEvaluates("$acosh", Value(8LL), Value(2.768659));
+ assertEvaluates("$acosh", Value(9LL), Value(2.887271));
+}
+
+TEST(ExpressionHyperbolicArcCosineTest, DoubleArg) {
+ assertEvaluates("$acosh", Value(1.000000), Value(0.000000));
+ assertEvaluates("$acosh", Value(1.200000), Value(0.622363));
+ assertEvaluates("$acosh", Value(1.400000), Value(0.867015));
+ assertEvaluates("$acosh", Value(1.600000), Value(1.046968));
+ assertEvaluates("$acosh", Value(1.800000), Value(1.192911));
+ assertEvaluates("$acosh", Value(2.000000), Value(1.316958));
+ assertEvaluates("$acosh", Value(2.200000), Value(1.425417));
+ assertEvaluates("$acosh", Value(2.400000), Value(1.522079));
+ assertEvaluates("$acosh", Value(2.600000), Value(1.609438));
+ assertEvaluates("$acosh", Value(2.800000), Value(1.689236));
+ assertEvaluates("$acosh", Value(3.000000), Value(1.762747));
+ assertEvaluates("$acosh", Value(3.200000), Value(1.830938));
+ assertEvaluates("$acosh", Value(3.400000), Value(1.894559));
+ assertEvaluates("$acosh", Value(3.600000), Value(1.954208));
+ assertEvaluates("$acosh", Value(3.800000), Value(2.010367));
+ assertEvaluates("$acosh", Value(4.000000), Value(2.063437));
+ assertEvaluates("$acosh", Value(4.200000), Value(2.113748));
+ assertEvaluates("$acosh", Value(4.400000), Value(2.161581));
+ assertEvaluates("$acosh", Value(4.600000), Value(2.207174));
+ assertEvaluates("$acosh", Value(4.800000), Value(2.250731));
+ assertEvaluates("$acosh", Value(5.000000), Value(2.292432));
+ assertEvaluates("$acosh", Value(5.200000), Value(2.332429));
+ assertEvaluates("$acosh", Value(5.400000), Value(2.370860));
+ assertEvaluates("$acosh", Value(5.600000), Value(2.407845));
+ assertEvaluates("$acosh", Value(5.800000), Value(2.443489));
+ assertEvaluates("$acosh", Value(6.000000), Value(2.477889));
+ assertEvaluates("$acosh", Value(6.200000), Value(2.511128));
+ assertEvaluates("$acosh", Value(6.400000), Value(2.543285));
+ assertEvaluates("$acosh", Value(6.600000), Value(2.574428));
+ assertEvaluates("$acosh", Value(6.800000), Value(2.604619));
+ assertEvaluates("$acosh", Value(7.000000), Value(2.633916));
+ assertEvaluates("$acosh", Value(7.200000), Value(2.662370));
+ assertEvaluates("$acosh", Value(7.400000), Value(2.690030));
+ assertEvaluates("$acosh", Value(7.600000), Value(2.716939));
+ assertEvaluates("$acosh", Value(7.800000), Value(2.743136));
+ assertEvaluates("$acosh", Value(8.000000), Value(2.768659));
+ assertEvaluates("$acosh", Value(8.200000), Value(2.793542));
+ assertEvaluates("$acosh", Value(8.400000), Value(2.817817));
+ assertEvaluates("$acosh", Value(8.600000), Value(2.841512));
+ assertEvaluates("$acosh", Value(8.800000), Value(2.864655));
+ assertEvaluates("$acosh", Value(9.000000), Value(2.887271));
+ assertEvaluates("$acosh", Value(9.200000), Value(2.909384));
+ assertEvaluates("$acosh", Value(9.400000), Value(2.931015));
+ assertEvaluates("$acosh", Value(9.600000), Value(2.952187));
+ assertEvaluates("$acosh", Value(9.800000), Value(2.972916));
+ assertEvaluates("$acosh", Value(10.000000), Value(2.993223));
+}
+
+TEST(ExpressionHyperbolicArcCosineTest, DecimalArg) {
+ assertEvaluates("$acosh", Value(Decimal128(1.000000)), Value(Decimal128(0.000000)));
+ assertEvaluates("$acosh", Value(Decimal128(1.200000)), Value(Decimal128(0.622363)));
+ assertEvaluates("$acosh", Value(Decimal128(1.400000)), Value(Decimal128(0.867015)));
+ assertEvaluates("$acosh", Value(Decimal128(1.600000)), Value(Decimal128(1.046968)));
+ assertEvaluates("$acosh", Value(Decimal128(1.800000)), Value(Decimal128(1.192911)));
+ assertEvaluates("$acosh", Value(Decimal128(2.000000)), Value(Decimal128(1.316958)));
+ assertEvaluates("$acosh", Value(Decimal128(2.200000)), Value(Decimal128(1.425417)));
+ assertEvaluates("$acosh", Value(Decimal128(2.400000)), Value(Decimal128(1.522079)));
+ assertEvaluates("$acosh", Value(Decimal128(2.600000)), Value(Decimal128(1.609438)));
+ assertEvaluates("$acosh", Value(Decimal128(2.800000)), Value(Decimal128(1.689236)));
+ assertEvaluates("$acosh", Value(Decimal128(3.000000)), Value(Decimal128(1.762747)));
+ assertEvaluates("$acosh", Value(Decimal128(3.200000)), Value(Decimal128(1.830938)));
+ assertEvaluates("$acosh", Value(Decimal128(3.400000)), Value(Decimal128(1.894559)));
+ assertEvaluates("$acosh", Value(Decimal128(3.600000)), Value(Decimal128(1.954208)));
+ assertEvaluates("$acosh", Value(Decimal128(3.800000)), Value(Decimal128(2.010367)));
+ assertEvaluates("$acosh", Value(Decimal128(4.000000)), Value(Decimal128(2.063437)));
+ assertEvaluates("$acosh", Value(Decimal128(4.200000)), Value(Decimal128(2.113748)));
+ assertEvaluates("$acosh", Value(Decimal128(4.400000)), Value(Decimal128(2.161581)));
+ assertEvaluates("$acosh", Value(Decimal128(4.600000)), Value(Decimal128(2.207174)));
+ assertEvaluates("$acosh", Value(Decimal128(4.800000)), Value(Decimal128(2.250731)));
+ assertEvaluates("$acosh", Value(Decimal128(5.000000)), Value(Decimal128(2.292432)));
+ assertEvaluates("$acosh", Value(Decimal128(5.200000)), Value(Decimal128(2.332429)));
+ assertEvaluates("$acosh", Value(Decimal128(5.400000)), Value(Decimal128(2.370860)));
+ assertEvaluates("$acosh", Value(Decimal128(5.600000)), Value(Decimal128(2.407845)));
+ assertEvaluates("$acosh", Value(Decimal128(5.800000)), Value(Decimal128(2.443489)));
+ assertEvaluates("$acosh", Value(Decimal128(6.000000)), Value(Decimal128(2.477889)));
+ assertEvaluates("$acosh", Value(Decimal128(6.200000)), Value(Decimal128(2.511128)));
+ assertEvaluates("$acosh", Value(Decimal128(6.400000)), Value(Decimal128(2.543285)));
+ assertEvaluates("$acosh", Value(Decimal128(6.600000)), Value(Decimal128(2.574428)));
+ assertEvaluates("$acosh", Value(Decimal128(6.800000)), Value(Decimal128(2.604619)));
+ assertEvaluates("$acosh", Value(Decimal128(7.000000)), Value(Decimal128(2.633916)));
+ assertEvaluates("$acosh", Value(Decimal128(7.200000)), Value(Decimal128(2.662370)));
+ assertEvaluates("$acosh", Value(Decimal128(7.400000)), Value(Decimal128(2.690030)));
+ assertEvaluates("$acosh", Value(Decimal128(7.600000)), Value(Decimal128(2.716939)));
+ assertEvaluates("$acosh", Value(Decimal128(7.800000)), Value(Decimal128(2.743136)));
+ assertEvaluates("$acosh", Value(Decimal128(8.000000)), Value(Decimal128(2.768659)));
+ assertEvaluates("$acosh", Value(Decimal128(8.200000)), Value(Decimal128(2.793542)));
+ assertEvaluates("$acosh", Value(Decimal128(8.400000)), Value(Decimal128(2.817817)));
+ assertEvaluates("$acosh", Value(Decimal128(8.600000)), Value(Decimal128(2.841512)));
+ assertEvaluates("$acosh", Value(Decimal128(8.800000)), Value(Decimal128(2.864655)));
+ assertEvaluates("$acosh", Value(Decimal128(9.000000)), Value(Decimal128(2.887271)));
+ assertEvaluates("$acosh", Value(Decimal128(9.200000)), Value(Decimal128(2.909384)));
+ assertEvaluates("$acosh", Value(Decimal128(9.400000)), Value(Decimal128(2.931015)));
+ assertEvaluates("$acosh", Value(Decimal128(9.600000)), Value(Decimal128(2.952187)));
+ assertEvaluates("$acosh", Value(Decimal128(9.800000)), Value(Decimal128(2.972916)));
+ assertEvaluates("$acosh", Value(Decimal128(10.000000)), Value(Decimal128(2.993223)));
+}
+
+TEST(ExpressionHyperbolicArcCosineTest, NullArg) {
+ assertEvaluates("$acosh", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionHyperbolicArcSine -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of asinh, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+
+TEST(ExpressionHyperbolicArcSineTest, IntArg) {
+ assertEvaluates("$asinh", Value(1), Value(0.881374));
+ assertEvaluates("$asinh", Value(2), Value(1.443635));
+ assertEvaluates("$asinh", Value(3), Value(1.818446));
+ assertEvaluates("$asinh", Value(4), Value(2.094713));
+ assertEvaluates("$asinh", Value(5), Value(2.312438));
+ assertEvaluates("$asinh", Value(6), Value(2.491780));
+ assertEvaluates("$asinh", Value(7), Value(2.644121));
+ assertEvaluates("$asinh", Value(8), Value(2.776472));
+ assertEvaluates("$asinh", Value(9), Value(2.893444));
+}
+
+TEST(ExpressionHyperbolicArcSineTest, LongArg) {
+ assertEvaluates("$asinh", Value(1LL), Value(0.881374));
+ assertEvaluates("$asinh", Value(2LL), Value(1.443635));
+ assertEvaluates("$asinh", Value(3LL), Value(1.818446));
+ assertEvaluates("$asinh", Value(4LL), Value(2.094713));
+ assertEvaluates("$asinh", Value(5LL), Value(2.312438));
+ assertEvaluates("$asinh", Value(6LL), Value(2.491780));
+ assertEvaluates("$asinh", Value(7LL), Value(2.644121));
+ assertEvaluates("$asinh", Value(8LL), Value(2.776472));
+ assertEvaluates("$asinh", Value(9LL), Value(2.893444));
+}
+
+TEST(ExpressionHyperbolicArcSineTest, DoubleArg) {
+ assertEvaluates("$asinh", Value(1.000000), Value(0.881374));
+ assertEvaluates("$asinh", Value(1.200000), Value(1.015973));
+ assertEvaluates("$asinh", Value(1.400000), Value(1.137982));
+ assertEvaluates("$asinh", Value(1.600000), Value(1.248983));
+ assertEvaluates("$asinh", Value(1.800000), Value(1.350441));
+ assertEvaluates("$asinh", Value(2.000000), Value(1.443635));
+ assertEvaluates("$asinh", Value(2.200000), Value(1.529660));
+ assertEvaluates("$asinh", Value(2.400000), Value(1.609438));
+ assertEvaluates("$asinh", Value(2.600000), Value(1.683743));
+ assertEvaluates("$asinh", Value(2.800000), Value(1.753229));
+ assertEvaluates("$asinh", Value(3.000000), Value(1.818446));
+ assertEvaluates("$asinh", Value(3.200000), Value(1.879864));
+ assertEvaluates("$asinh", Value(3.400000), Value(1.937879));
+ assertEvaluates("$asinh", Value(3.600000), Value(1.992836));
+ assertEvaluates("$asinh", Value(3.800000), Value(2.045028));
+ assertEvaluates("$asinh", Value(4.000000), Value(2.094713));
+ assertEvaluates("$asinh", Value(4.200000), Value(2.142112));
+ assertEvaluates("$asinh", Value(4.400000), Value(2.187422));
+ assertEvaluates("$asinh", Value(4.600000), Value(2.230814));
+ assertEvaluates("$asinh", Value(4.800000), Value(2.272441));
+ assertEvaluates("$asinh", Value(5.000000), Value(2.312438));
+ assertEvaluates("$asinh", Value(5.200000), Value(2.350926));
+ assertEvaluates("$asinh", Value(5.400000), Value(2.388011));
+ assertEvaluates("$asinh", Value(5.600000), Value(2.423792));
+ assertEvaluates("$asinh", Value(5.800000), Value(2.458355));
+ assertEvaluates("$asinh", Value(6.000000), Value(2.491780));
+ assertEvaluates("$asinh", Value(6.200000), Value(2.524138));
+ assertEvaluates("$asinh", Value(6.400000), Value(2.555494));
+ assertEvaluates("$asinh", Value(6.600000), Value(2.585907));
+ assertEvaluates("$asinh", Value(6.800000), Value(2.615433));
+ assertEvaluates("$asinh", Value(7.000000), Value(2.644121));
+ assertEvaluates("$asinh", Value(7.200000), Value(2.672016));
+ assertEvaluates("$asinh", Value(7.400000), Value(2.699162));
+ assertEvaluates("$asinh", Value(7.600000), Value(2.725596));
+ assertEvaluates("$asinh", Value(7.800000), Value(2.751355));
+ assertEvaluates("$asinh", Value(8.000000), Value(2.776472));
+ assertEvaluates("$asinh", Value(8.200000), Value(2.800979));
+ assertEvaluates("$asinh", Value(8.400000), Value(2.824903));
+ assertEvaluates("$asinh", Value(8.600000), Value(2.848273));
+ assertEvaluates("$asinh", Value(8.800000), Value(2.871112));
+ assertEvaluates("$asinh", Value(9.000000), Value(2.893444));
+ assertEvaluates("$asinh", Value(9.200000), Value(2.915291));
+ assertEvaluates("$asinh", Value(9.400000), Value(2.936674));
+ assertEvaluates("$asinh", Value(9.600000), Value(2.957612));
+ assertEvaluates("$asinh", Value(9.800000), Value(2.978123));
+ assertEvaluates("$asinh", Value(10.000000), Value(2.998223));
+}
+
+TEST(ExpressionHyperbolicArcSineTest, DecimalArg) {
+ assertEvaluates("$asinh", Value(Decimal128(1.000000)), Value(Decimal128(0.881374)));
+ assertEvaluates("$asinh", Value(Decimal128(1.200000)), Value(Decimal128(1.015973)));
+ assertEvaluates("$asinh", Value(Decimal128(1.400000)), Value(Decimal128(1.137982)));
+ assertEvaluates("$asinh", Value(Decimal128(1.600000)), Value(Decimal128(1.248983)));
+ assertEvaluates("$asinh", Value(Decimal128(1.800000)), Value(Decimal128(1.350441)));
+ assertEvaluates("$asinh", Value(Decimal128(2.000000)), Value(Decimal128(1.443635)));
+ assertEvaluates("$asinh", Value(Decimal128(2.200000)), Value(Decimal128(1.529660)));
+ assertEvaluates("$asinh", Value(Decimal128(2.400000)), Value(Decimal128(1.609438)));
+ assertEvaluates("$asinh", Value(Decimal128(2.600000)), Value(Decimal128(1.683743)));
+ assertEvaluates("$asinh", Value(Decimal128(2.800000)), Value(Decimal128(1.753229)));
+ assertEvaluates("$asinh", Value(Decimal128(3.000000)), Value(Decimal128(1.818446)));
+ assertEvaluates("$asinh", Value(Decimal128(3.200000)), Value(Decimal128(1.879864)));
+ assertEvaluates("$asinh", Value(Decimal128(3.400000)), Value(Decimal128(1.937879)));
+ assertEvaluates("$asinh", Value(Decimal128(3.600000)), Value(Decimal128(1.992836)));
+ assertEvaluates("$asinh", Value(Decimal128(3.800000)), Value(Decimal128(2.045028)));
+ assertEvaluates("$asinh", Value(Decimal128(4.000000)), Value(Decimal128(2.094713)));
+ assertEvaluates("$asinh", Value(Decimal128(4.200000)), Value(Decimal128(2.142112)));
+ assertEvaluates("$asinh", Value(Decimal128(4.400000)), Value(Decimal128(2.187422)));
+ assertEvaluates("$asinh", Value(Decimal128(4.600000)), Value(Decimal128(2.230814)));
+ assertEvaluates("$asinh", Value(Decimal128(4.800000)), Value(Decimal128(2.272441)));
+ assertEvaluates("$asinh", Value(Decimal128(5.000000)), Value(Decimal128(2.312438)));
+ assertEvaluates("$asinh", Value(Decimal128(5.200000)), Value(Decimal128(2.350926)));
+ assertEvaluates("$asinh", Value(Decimal128(5.400000)), Value(Decimal128(2.388011)));
+ assertEvaluates("$asinh", Value(Decimal128(5.600000)), Value(Decimal128(2.423792)));
+ assertEvaluates("$asinh", Value(Decimal128(5.800000)), Value(Decimal128(2.458355)));
+ assertEvaluates("$asinh", Value(Decimal128(6.000000)), Value(Decimal128(2.491780)));
+ assertEvaluates("$asinh", Value(Decimal128(6.200000)), Value(Decimal128(2.524138)));
+ assertEvaluates("$asinh", Value(Decimal128(6.400000)), Value(Decimal128(2.555494)));
+ assertEvaluates("$asinh", Value(Decimal128(6.600000)), Value(Decimal128(2.585907)));
+ assertEvaluates("$asinh", Value(Decimal128(6.800000)), Value(Decimal128(2.615433)));
+ assertEvaluates("$asinh", Value(Decimal128(7.000000)), Value(Decimal128(2.644121)));
+ assertEvaluates("$asinh", Value(Decimal128(7.200000)), Value(Decimal128(2.672016)));
+ assertEvaluates("$asinh", Value(Decimal128(7.400000)), Value(Decimal128(2.699162)));
+ assertEvaluates("$asinh", Value(Decimal128(7.600000)), Value(Decimal128(2.725596)));
+ assertEvaluates("$asinh", Value(Decimal128(7.800000)), Value(Decimal128(2.751355)));
+ assertEvaluates("$asinh", Value(Decimal128(8.000000)), Value(Decimal128(2.776472)));
+ assertEvaluates("$asinh", Value(Decimal128(8.200000)), Value(Decimal128(2.800979)));
+ assertEvaluates("$asinh", Value(Decimal128(8.400000)), Value(Decimal128(2.824903)));
+ assertEvaluates("$asinh", Value(Decimal128(8.600000)), Value(Decimal128(2.848273)));
+ assertEvaluates("$asinh", Value(Decimal128(8.800000)), Value(Decimal128(2.871112)));
+ assertEvaluates("$asinh", Value(Decimal128(9.000000)), Value(Decimal128(2.893444)));
+ assertEvaluates("$asinh", Value(Decimal128(9.200000)), Value(Decimal128(2.915291)));
+ assertEvaluates("$asinh", Value(Decimal128(9.400000)), Value(Decimal128(2.936674)));
+ assertEvaluates("$asinh", Value(Decimal128(9.600000)), Value(Decimal128(2.957612)));
+ assertEvaluates("$asinh", Value(Decimal128(9.800000)), Value(Decimal128(2.978123)));
+ assertEvaluates("$asinh", Value(Decimal128(10.000000)), Value(Decimal128(2.998223)));
+}
+
+TEST(ExpressionHyperbolicArcSineTest, NullArg) {
+ assertEvaluates("$asinh", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionHyperbolicArcTangent -------------------------- */
+/**
+ * Test values were generated using the 64 bit std version of tanh, and help
+ * ensure that we are calling the correct functions.
+ *
+ */
+TEST(ExpressionHyperbolicArcTangentTest, IntArg) {
+ assertEvaluates("$atanh", Value(0), Value(0.000000));
+}
+
+TEST(ExpressionHyperbolicArcTangentTest, LongArg) {
+ assertEvaluates("$atanh", Value(0LL), Value(0.000000));
+}
+
+TEST(ExpressionHyperbolicArcTangentTest, DoubleArg) {
+ assertEvaluates("$atanh", Value(-0.990000), Value(-2.646652));
+ assertEvaluates("$atanh", Value(-0.790000), Value(-1.071432));
+ assertEvaluates("$atanh", Value(-0.590000), Value(-0.677666));
+ assertEvaluates("$atanh", Value(-0.390000), Value(-0.411800));
+ assertEvaluates("$atanh", Value(-0.190000), Value(-0.192337));
+ assertEvaluates("$atanh", Value(0.010000), Value(0.010000));
+ assertEvaluates("$atanh", Value(0.210000), Value(0.213171));
+ assertEvaluates("$atanh", Value(0.410000), Value(0.435611));
+ assertEvaluates("$atanh", Value(0.610000), Value(0.708921));
+ assertEvaluates("$atanh", Value(0.810000), Value(1.127029));
+}
+
+TEST(ExpressionHyperbolicArcTangentTest, DecimalArg) {
+ assertEvaluates("$atanh", Value(Decimal128(-0.990000)), Value(Decimal128(-2.646652)));
+ assertEvaluates("$atanh", Value(Decimal128(-0.790000)), Value(Decimal128(-1.071432)));
+ assertEvaluates("$atanh", Value(Decimal128(-0.590000)), Value(Decimal128(-0.677666)));
+ assertEvaluates("$atanh", Value(Decimal128(-0.390000)), Value(Decimal128(-0.411800)));
+ assertEvaluates("$atanh", Value(Decimal128(-0.190000)), Value(Decimal128(-0.192337)));
+ assertEvaluates("$atanh", Value(Decimal128(0.010000)), Value(Decimal128(0.010000)));
+ assertEvaluates("$atanh", Value(Decimal128(0.210000)), Value(Decimal128(0.213171)));
+ assertEvaluates("$atanh", Value(Decimal128(0.410000)), Value(Decimal128(0.435611)));
+ assertEvaluates("$atanh", Value(Decimal128(0.610000)), Value(Decimal128(0.708921)));
+ assertEvaluates("$atanh", Value(Decimal128(0.810000)), Value(Decimal128(1.127029)));
+}
+
+TEST(ExpressionHyperbolicArcTangentTest, NullArg) {
+ assertEvaluates("$atanh", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionRadiansToDegrees -------------------------- */
+TEST(ExpressionRadiansToDegreesTest, IntArg) {
+ assertEvaluates("$radiansToDegrees", Value(0), Value(0.0));
+ assertEvaluates("$radiansToDegrees", Value(1), Value(57.2957795131));
+ assertEvaluates("$radiansToDegrees", Value(2), Value(114.591559026));
+ assertEvaluates("$radiansToDegrees", Value(3), Value(171.887338539));
+ assertEvaluates("$radiansToDegrees", Value(4), Value(229.183118052));
+ assertEvaluates("$radiansToDegrees", Value(5), Value(286.478897565));
+ assertEvaluates("$radiansToDegrees", Value(6), Value(343.774677078));
+}
+
+TEST(ExpressionRadiansToDegreesTest, LongArg) {
+ assertEvaluates("$radiansToDegrees", Value(0LL), Value(0.0));
+ assertEvaluates("$radiansToDegrees", Value(1LL), Value(57.2957795131));
+ assertEvaluates("$radiansToDegrees", Value(2LL), Value(114.591559026));
+ assertEvaluates("$radiansToDegrees", Value(3LL), Value(171.887338539));
+ assertEvaluates("$radiansToDegrees", Value(4LL), Value(229.183118052));
+ assertEvaluates("$radiansToDegrees", Value(5LL), Value(286.478897565));
+ assertEvaluates("$radiansToDegrees", Value(6LL), Value(343.774677078));
+}
+
+TEST(ExpressionRadiansToDegreesTest, DoubleArg) {
+ assertEvaluates("$radiansToDegrees", Value(0.0), Value(0.0));
+ assertEvaluates("$radiansToDegrees", Value(0.523598775598), Value(30.0));
+ assertEvaluates("$radiansToDegrees", Value(0.785398163397), Value(45.0));
+ assertEvaluates("$radiansToDegrees", Value(1.0471975512), Value(60.0));
+ assertEvaluates("$radiansToDegrees", Value(1.57079632679), Value(90.0));
+ assertEvaluates("$radiansToDegrees", Value(2.09439510239), Value(120.0));
+ assertEvaluates("$radiansToDegrees", Value(2.35619449019), Value(135.0));
+ assertEvaluates("$radiansToDegrees", Value(2.61799387799), Value(150.0));
+ assertEvaluates("$radiansToDegrees", Value(3.14159265359), Value(180.0));
+ assertEvaluates("$radiansToDegrees", Value(3.66519142919), Value(210.0));
+ assertEvaluates("$radiansToDegrees", Value(3.92699081699), Value(225.0));
+ assertEvaluates("$radiansToDegrees", Value(4.18879020479), Value(240.0));
+ assertEvaluates("$radiansToDegrees", Value(4.71238898038), Value(270.0));
+ assertEvaluates("$radiansToDegrees", Value(5.23598775598), Value(300.0));
+ assertEvaluates("$radiansToDegrees", Value(5.49778714378), Value(315.0));
+ assertEvaluates("$radiansToDegrees", Value(5.75958653158), Value(330.0));
+ assertEvaluates("$radiansToDegrees", Value(6.28318530718), Value(360.0));
+}
+
+TEST(ExpressionRadiansToDegreesTest, DecimalArg) {
+ assertEvaluates("$radiansToDegrees", Value(Decimal128("0.0")), Value(Decimal128("0.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("0.523598775598")), Value(Decimal128("30.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("0.785398163397")), Value(Decimal128("45.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("1.0471975512")), Value(Decimal128("60.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("1.57079632679")), Value(Decimal128("90.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("2.09439510239")), Value(Decimal128("120.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("2.35619449019")), Value(Decimal128("135.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("2.61799387799")), Value(Decimal128("150.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("3.14159265359")), Value(Decimal128("180.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("3.66519142919")), Value(Decimal128("210.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("3.92699081699")), Value(Decimal128("225.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("4.18879020479")), Value(Decimal128("240.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("4.71238898038")), Value(Decimal128("270.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("5.23598775598")), Value(Decimal128("300.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("5.49778714378")), Value(Decimal128("315.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("5.75958653158")), Value(Decimal128("330.0")));
+ assertEvaluates(
+ "$radiansToDegrees", Value(Decimal128("6.28318530718")), Value(Decimal128("360.0")));
+}
+
+TEST(ExpressionRadiansToDegreesTest, NullArg) {
+ assertEvaluates("$radiansToDegrees", Value(BSONNULL), Value(BSONNULL));
+}
+
+/* ------------------------- ExpressionDegreesToRadians -------------------------- */
+TEST(ExpressionDegreesToRadiansTest, IntArg) {
+ assertEvaluates("$degreesToRadians", Value(0), Value(0.0));
+ assertEvaluates("$degreesToRadians", Value(45), Value(0.785398163397));
+ assertEvaluates("$degreesToRadians", Value(90), Value(1.57079632679));
+ assertEvaluates("$degreesToRadians", Value(135), Value(2.35619449019));
+ assertEvaluates("$degreesToRadians", Value(180), Value(3.14159265359));
+ assertEvaluates("$degreesToRadians", Value(225), Value(3.92699081699));
+ assertEvaluates("$degreesToRadians", Value(270), Value(4.71238898038));
+ assertEvaluates("$degreesToRadians", Value(315), Value(5.49778714378));
+ assertEvaluates("$degreesToRadians", Value(360), Value(6.28318530718));
+}
+
+TEST(ExpressionDegreesToRadiansTest, LongArg) {
+ assertEvaluates("$degreesToRadians", Value(0LL), Value(0.0));
+ assertEvaluates("$degreesToRadians", Value(45LL), Value(0.785398163397));
+ assertEvaluates("$degreesToRadians", Value(90LL), Value(1.57079632679));
+ assertEvaluates("$degreesToRadians", Value(135LL), Value(2.35619449019));
+ assertEvaluates("$degreesToRadians", Value(180LL), Value(3.14159265359));
+ assertEvaluates("$degreesToRadians", Value(225LL), Value(3.92699081699));
+ assertEvaluates("$degreesToRadians", Value(270LL), Value(4.71238898038));
+ assertEvaluates("$degreesToRadians", Value(315LL), Value(5.49778714378));
+ assertEvaluates("$degreesToRadians", Value(360LL), Value(6.28318530718));
+}
+
+TEST(ExpressionDegreesToRadiansTest, DoubleArg) {
+ assertEvaluates("$degreesToRadians", Value(0), Value(0.0));
+ assertEvaluates("$degreesToRadians", Value(45), Value(0.785398163397));
+ assertEvaluates("$degreesToRadians", Value(90), Value(1.57079632679));
+ assertEvaluates("$degreesToRadians", Value(135), Value(2.35619449019));
+ assertEvaluates("$degreesToRadians", Value(180), Value(3.14159265359));
+ assertEvaluates("$degreesToRadians", Value(225), Value(3.92699081699));
+ assertEvaluates("$degreesToRadians", Value(270), Value(4.71238898038));
+ assertEvaluates("$degreesToRadians", Value(315), Value(5.49778714378));
+ assertEvaluates("$degreesToRadians", Value(360), Value(6.28318530718));
+}
+
+TEST(ExpressionDegreesToRadiansTest, DecimalArg) {
+ assertEvaluates("$degreesToRadians", Value(Decimal128("0")), Value(Decimal128("0.0")));
+ assertEvaluates(
+ "$degreesToRadians", Value(Decimal128("45")), Value(Decimal128("0.785398163397")));
+ assertEvaluates(
+ "$degreesToRadians", Value(Decimal128("90")), Value(Decimal128("1.57079632679")));
+ assertEvaluates(
+ "$degreesToRadians", Value(Decimal128("135")), Value(Decimal128("2.35619449019")));
+ assertEvaluates(
+ "$degreesToRadians", Value(Decimal128("180")), Value(Decimal128("3.14159265359")));
+ assertEvaluates(
+ "$degreesToRadians", Value(Decimal128("225")), Value(Decimal128("3.92699081699")));
+ assertEvaluates(
+ "$degreesToRadians", Value(Decimal128("270")), Value(Decimal128("4.71238898038")));
+ assertEvaluates(
+ "$degreesToRadians", Value(Decimal128("315")), Value(Decimal128("5.49778714378")));
+ assertEvaluates(
+ "$degreesToRadians", Value(Decimal128("360")), Value(Decimal128("6.28318530718")));
+}
+
+TEST(ExpressionDegreesToRadiansTest, NullArg) {
+ assertEvaluates("$degreesToRadians", Value(BSONNULL), Value(BSONNULL));
+}
+} // namespace expression_trigonometric_test
diff --git a/src/mongo/platform/decimal128.cpp b/src/mongo/platform/decimal128.cpp
index 51b7ffe5269..2a0f6b0c1ea 100644
--- a/src/mongo/platform/decimal128.cpp
+++ b/src/mongo/platform/decimal128.cpp
@@ -322,6 +322,110 @@ Decimal128 Decimal128::toAbs() const {
return Decimal128(libraryTypeToValue(dec128));
}
+Decimal128 Decimal128::acos(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return acos(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::acos(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_acos(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
+Decimal128 Decimal128::acosh(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return acosh(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::acosh(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_acosh(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
+Decimal128 Decimal128::asin(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return asin(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::asin(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_asin(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
+Decimal128 Decimal128::asinh(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return asinh(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::asinh(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_asinh(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
+Decimal128 Decimal128::atan(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return atan(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::atan(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_atan(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
+Decimal128 Decimal128::atan2(const Decimal128& other, RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return atan2(other, &throwAwayFlag, roundMode);
+}
+
+Decimal128 Decimal128::atan2(const Decimal128& other,
+ std::uint32_t* signalingFlags,
+ RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ BID_UINT128 divisor = decimal128ToLibraryType(other.getValue());
+ current = bid128_atan2(current, divisor, roundMode, signalingFlags);
+ Decimal128::Value value = libraryTypeToValue(current);
+ Decimal128 result(value);
+ return result;
+}
+
+Decimal128 Decimal128::atanh(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return atanh(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::atanh(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_atanh(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
+Decimal128 Decimal128::cosh(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return cosh(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::cosh(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_cosh(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
+Decimal128 Decimal128::cos(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return cos(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::cos(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_cos(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
std::int32_t Decimal128::toInt(RoundingMode roundMode) const {
std::uint32_t throwAwayFlag = 0;
return toInt(&throwAwayFlag, roundMode);
@@ -424,6 +528,28 @@ double Decimal128::toDouble(std::uint32_t* signalingFlags, RoundingMode roundMod
return bid128_to_binary64(dec128, roundMode, signalingFlags);
}
+Decimal128 Decimal128::sin(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return sin(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::sin(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_sin(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
+Decimal128 Decimal128::sinh(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return sinh(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::sinh(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_sinh(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
std::string Decimal128::toString() const {
// If the decimal is a variant of NaN (i.e. sNaN, -NaN, +NaN, etc...) or a variant of
// Inf (i.e. +Inf, Inf, -Inf), return either NaN, Infinity, or -Infinity
@@ -490,6 +616,28 @@ std::string Decimal128::toString() const {
return result;
}
+Decimal128 Decimal128::tanh(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return tanh(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::tanh(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_tanh(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
+Decimal128 Decimal128::tan(RoundingMode roundMode) const {
+ std::uint32_t throwAwayFlag = 0;
+ return tan(&throwAwayFlag);
+}
+
+Decimal128 Decimal128::tan(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+ BID_UINT128 current = decimal128ToLibraryType(_value);
+ current = bid128_tan(current, roundMode, signalingFlags);
+ return Decimal128{libraryTypeToValue(current)};
+}
+
std::string Decimal128::_convertToScientificNotation(StringData coefficient,
int adjustedExponent) const {
int cLength = coefficient.size();
@@ -822,6 +970,10 @@ const Decimal128 Decimal128::kNegativeInfinity(Decimal128::Value({0ull, 0xf8ull
const Decimal128 Decimal128::kPositiveNaN(Decimal128::Value({0ull, 0x7cull << 56}));
const Decimal128 Decimal128::kNegativeNaN(Decimal128::Value({0ull, 0xfcull << 56}));
+const Decimal128 Decimal128::kPi("3.14159265358979323846264338327950288419716939937510");
+const Decimal128 Decimal128::kPiOver180(Decimal128::kPi.divide(Decimal128("180")));
+const Decimal128 Decimal128::k180OverPi(Decimal128("180").divide(Decimal128::kPi));
+
std::ostream& operator<<(std::ostream& stream, const Decimal128& value) {
return stream << value.toString();
}
diff --git a/src/mongo/platform/decimal128.h b/src/mongo/platform/decimal128.h
index 5a1508317aa..525d3fbf994 100644
--- a/src/mongo/platform/decimal128.h
+++ b/src/mongo/platform/decimal128.h
@@ -72,6 +72,10 @@ public:
static const Decimal128 kPositiveNaN;
static const Decimal128 kNegativeNaN;
+ static const Decimal128 kPi;
+ static const Decimal128 kPiOver180;
+ static const Decimal128 k180OverPi;
+
static const uint32_t kMaxBiasedExponent = 6143 + 6144;
// Biased exponent of a Decimal128 with least significant digit in the units place
static const int32_t kExponentBias = 6143 + 33;
@@ -242,6 +246,90 @@ public:
Decimal128 toAbs() const;
/**
+ * Returns the acos value of this.
+ */
+ Decimal128 acos(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 acos(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the acosh value of this.
+ */
+ Decimal128 acosh(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 acosh(std::uint32_t* signalingFlags,
+ RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the asin value of this.
+ */
+ Decimal128 asin(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 asin(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the asinh value of this.
+ */
+ Decimal128 asinh(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 asinh(std::uint32_t* signalingFlags,
+ RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the atan value of this.
+ */
+ Decimal128 atan(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 atan(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the atan2(this, other) rather than atan2(other,this), which
+ * would produce different results.
+ */
+ Decimal128 atan2(const Decimal128& other, RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 atan2(const Decimal128& other,
+ std::uint32_t* signalingFlags,
+ RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the atanh value of this.
+ */
+ Decimal128 atanh(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 atanh(std::uint32_t* signalingFlags,
+ RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the cos value of this.
+ */
+ Decimal128 cos(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 cos(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the cosh value of this.
+ */
+ Decimal128 cosh(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 cosh(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the sin value of this.
+ */
+ Decimal128 sin(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 sin(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the sinh value of this.
+ */
+ Decimal128 sinh(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 sinh(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
+ /**
+ * Returns the tan value of this.
+ */
+ Decimal128 tan(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 tan(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
+
+ /**
+ * Returns the tanh value of this.
+ */
+ Decimal128 tanh(RoundingMode roundMode = kRoundTiesToEven) const;
+ Decimal128 tanh(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
+
+
+ /**
* Returns `this` with inverted sign bit
*/
Decimal128 negate() const {
diff --git a/src/mongo/platform/decimal128_test.cpp b/src/mongo/platform/decimal128_test.cpp
index 14621296664..760a3c79762 100644
--- a/src/mongo/platform/decimal128_test.cpp
+++ b/src/mongo/platform/decimal128_test.cpp
@@ -1292,4 +1292,267 @@ 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")));
+}
+
+/**
+ * A few tests need exact comparisons to test boundary conditions
+ */
+
+void assertDecimal128ExactlyEqual(Decimal128 x, Decimal128 y) {
+ ASSERT_EQUALS(x.getValue().high64, y.getValue().high64);
+ ASSERT_EQUALS(x.getValue().low64, y.getValue().low64);
+}
+
+TEST(Decimal128Test, TestAsin) {
+ assertDecimal128ApproxEqual(Decimal128("-1.0").asin(), Decimal128("-1.57079632679"));
+ assertDecimal128ApproxEqual(Decimal128("-0.9").asin(), Decimal128("-1.119769515"));
+ assertDecimal128ApproxEqual(Decimal128("-0.8").asin(), Decimal128("-0.927295218002"));
+ assertDecimal128ApproxEqual(Decimal128("-0.7").asin(), Decimal128("-0.775397496611"));
+ assertDecimal128ApproxEqual(Decimal128("-0.6").asin(), Decimal128("-0.643501108793"));
+ assertDecimal128ApproxEqual(Decimal128("-0.5").asin(), Decimal128("-0.523598775598"));
+ assertDecimal128ApproxEqual(Decimal128("-0.4").asin(), Decimal128("-0.411516846067"));
+ assertDecimal128ApproxEqual(Decimal128("-0.3").asin(), Decimal128("-0.304692654015"));
+ assertDecimal128ApproxEqual(Decimal128("-0.2").asin(), Decimal128("-0.20135792079"));
+ assertDecimal128ApproxEqual(Decimal128("-0.1").asin(), Decimal128("-0.100167421162"));
+ assertDecimal128ApproxEqual(Decimal128("0.0").asin(), Decimal128("0.0"));
+ assertDecimal128ApproxEqual(Decimal128("0.1").asin(), Decimal128("0.100167421162"));
+ assertDecimal128ApproxEqual(Decimal128("0.2").asin(), Decimal128("0.20135792079"));
+ assertDecimal128ApproxEqual(Decimal128("0.3").asin(), Decimal128("0.304692654015"));
+ assertDecimal128ApproxEqual(Decimal128("0.4").asin(), Decimal128("0.411516846067"));
+ assertDecimal128ApproxEqual(Decimal128("0.5").asin(), Decimal128("0.523598775598"));
+ assertDecimal128ApproxEqual(Decimal128("0.6").asin(), Decimal128("0.643501108793"));
+ assertDecimal128ApproxEqual(Decimal128("0.7").asin(), Decimal128("0.775397496611"));
+ assertDecimal128ApproxEqual(Decimal128("0.8").asin(), Decimal128("0.927295218002"));
+ assertDecimal128ApproxEqual(Decimal128("0.9").asin(), Decimal128("1.119769515"));
+ assertDecimal128ApproxEqual(Decimal128("1.0").asin(), Decimal128("1.57079632679"));
+}
+
+TEST(Decimal128Test, TestAcos) {
+ // The intel decimal library has a bug at -1 where it returns 0.
+ //
+ // uncomment this test when we update to the new intel decimal library.
+ // assertDecimal128ExactlyEqual(Decimal128("-1").acos(), Decimal128::kPi);
+ assertDecimal128ExactlyEqual(Decimal128("-0.9999999999999999999999999999999997").acos(),
+ Decimal128("3.141592653589793213967745955447722"));
+ // Back to normal tests.
+ assertDecimal128ApproxEqual(Decimal128("-0.9").acos(), Decimal128("2.69056584179"));
+ assertDecimal128ApproxEqual(Decimal128("-0.8").acos(), Decimal128("2.4980915448"));
+ assertDecimal128ApproxEqual(Decimal128("-0.7").acos(), Decimal128("2.34619382341"));
+ assertDecimal128ApproxEqual(Decimal128("-0.6").acos(), Decimal128("2.21429743559"));
+ assertDecimal128ApproxEqual(Decimal128("-0.5").acos(), Decimal128("2.09439510239"));
+ assertDecimal128ApproxEqual(Decimal128("-0.4").acos(), Decimal128("1.98231317286"));
+ assertDecimal128ApproxEqual(Decimal128("-0.3").acos(), Decimal128("1.87548898081"));
+ assertDecimal128ApproxEqual(Decimal128("-0.2").acos(), Decimal128("1.77215424759"));
+ assertDecimal128ApproxEqual(Decimal128("-0.1").acos(), Decimal128("1.67096374796"));
+ assertDecimal128ApproxEqual(Decimal128("0.0").acos(), Decimal128("1.57079632679"));
+ assertDecimal128ApproxEqual(Decimal128("0.1").acos(), Decimal128("1.47062890563"));
+ assertDecimal128ApproxEqual(Decimal128("0.2").acos(), Decimal128("1.369438406"));
+ assertDecimal128ApproxEqual(Decimal128("0.3").acos(), Decimal128("1.26610367278"));
+ assertDecimal128ApproxEqual(Decimal128("0.4").acos(), Decimal128("1.15927948073"));
+ assertDecimal128ApproxEqual(Decimal128("0.5").acos(), Decimal128("1.0471975512"));
+ assertDecimal128ApproxEqual(Decimal128("0.6").acos(), Decimal128("0.927295218002"));
+ assertDecimal128ApproxEqual(Decimal128("0.7").acos(), Decimal128("0.795398830184"));
+ assertDecimal128ApproxEqual(Decimal128("0.8").acos(), Decimal128("0.643501108793"));
+ assertDecimal128ApproxEqual(Decimal128("0.9").acos(), Decimal128("0.451026811796"));
+ assertDecimal128ApproxEqual(Decimal128("1.0").acos(), Decimal128("0.0"));
+}
+
+TEST(Decimal128Test, TestAcosh) {
+ assertDecimal128ApproxEqual(Decimal128("1.0").acosh(), Decimal128("0.0"));
+ assertDecimal128ApproxEqual(Decimal128("1.1").acosh(), Decimal128("0.443568254385"));
+ assertDecimal128ApproxEqual(Decimal128("1.5").acosh(), Decimal128("0.962423650119"));
+ assertDecimal128ApproxEqual(Decimal128("2").acosh(), Decimal128("1.31695789692"));
+ assertDecimal128ApproxEqual(Decimal128("2.5").acosh(), Decimal128("1.56679923697"));
+ assertDecimal128ApproxEqual(Decimal128("3").acosh(), Decimal128("1.76274717404"));
+}
+
+
+TEST(Decimal128Test, TestAtanh) {
+ assertDecimal128ApproxEqual(Decimal128("-0.9").atanh(), Decimal128("-1.47221948958"));
+ assertDecimal128ApproxEqual(Decimal128("-0.8").atanh(), Decimal128("-1.09861228867"));
+ assertDecimal128ApproxEqual(Decimal128("-0.7").atanh(), Decimal128("-0.867300527694"));
+ assertDecimal128ApproxEqual(Decimal128("-0.6").atanh(), Decimal128("-0.69314718056"));
+ assertDecimal128ApproxEqual(Decimal128("-0.5").atanh(), Decimal128("-0.549306144334"));
+ assertDecimal128ApproxEqual(Decimal128("-0.4").atanh(), Decimal128("-0.423648930194"));
+ assertDecimal128ApproxEqual(Decimal128("-0.3").atanh(), Decimal128("-0.309519604203"));
+ assertDecimal128ApproxEqual(Decimal128("-0.2").atanh(), Decimal128("-0.202732554054"));
+ assertDecimal128ApproxEqual(Decimal128("-0.1").atanh(), Decimal128("-0.100335347731"));
+ assertDecimal128ApproxEqual(Decimal128("0.0").atanh(), Decimal128("0.0"));
+ assertDecimal128ApproxEqual(Decimal128("0.1").atanh(), Decimal128("0.100335347731"));
+ assertDecimal128ApproxEqual(Decimal128("0.2").atanh(), Decimal128("0.202732554054"));
+ assertDecimal128ApproxEqual(Decimal128("0.3").atanh(), Decimal128("0.309519604203"));
+ assertDecimal128ApproxEqual(Decimal128("0.4").atanh(), Decimal128("0.423648930194"));
+ assertDecimal128ApproxEqual(Decimal128("0.5").atanh(), Decimal128("0.549306144334"));
+ assertDecimal128ApproxEqual(Decimal128("0.6").atanh(), Decimal128("0.69314718056"));
+ assertDecimal128ApproxEqual(Decimal128("0.7").atanh(), Decimal128("0.867300527694"));
+ assertDecimal128ApproxEqual(Decimal128("0.8").atanh(), Decimal128("1.09861228867"));
+ assertDecimal128ApproxEqual(Decimal128("0.9").atanh(), Decimal128("1.47221948958"));
+}
+
+TEST(Decimal128Test, TestAtan) {
+ assertDecimal128ApproxEqual(Decimal128("-1.5").atan(), Decimal128("-0.982793723247"));
+ assertDecimal128ApproxEqual(Decimal128("-1.0471975512").atan(), Decimal128("-0.80844879263"));
+ assertDecimal128ApproxEqual(Decimal128("-0.785398163397").atan(),
+ Decimal128("-0.665773750028"));
+ assertDecimal128ApproxEqual(Decimal128("0").atan(), Decimal128("0.0"));
+ assertDecimal128ApproxEqual(Decimal128("0.785398163397").atan(), Decimal128("0.665773750028"));
+ assertDecimal128ApproxEqual(Decimal128("1.0471975512").atan(), Decimal128("0.80844879263"));
+ assertDecimal128ApproxEqual(Decimal128("1.5").atan(), Decimal128("0.982793723247"));
+}
+
+TEST(Decimal128Test, TestAtan2) {
+ assertDecimal128ApproxEqual(Decimal128("1.0").atan2(Decimal128("0.0")),
+ Decimal128("1.57079632679"));
+ assertDecimal128ApproxEqual(Decimal128("0.866025403784").atan2(Decimal128("0.5")),
+ Decimal128("1.0471975512"));
+ assertDecimal128ApproxEqual(Decimal128("0.707106781187").atan2(Decimal128("0.707106781187")),
+ Decimal128("0.785398163397"));
+ assertDecimal128ApproxEqual(Decimal128("0.5").atan2(Decimal128("0.866025403784")),
+ Decimal128("0.523598775598"));
+ assertDecimal128ApproxEqual(Decimal128("6.12323399574e-17").atan2(Decimal128("1.0")),
+ Decimal128("6.12323399574e-17"));
+ assertDecimal128ApproxEqual(Decimal128("-0.5").atan2(Decimal128("0.866025403784")),
+ Decimal128("-0.523598775598"));
+ assertDecimal128ApproxEqual(Decimal128("-0.707106781187").atan2(Decimal128("0.707106781187")),
+ Decimal128("-0.785398163397"));
+ assertDecimal128ApproxEqual(Decimal128("-0.866025403784").atan2(Decimal128("0.5")),
+ Decimal128("-1.0471975512"));
+ assertDecimal128ApproxEqual(Decimal128("-1.0").atan2(Decimal128("1.22464679915e-16")),
+ Decimal128("-1.57079632679"));
+ assertDecimal128ApproxEqual(Decimal128("-0.866025403784").atan2(Decimal128("-0.5")),
+ Decimal128("-2.09439510239"));
+ assertDecimal128ApproxEqual(Decimal128("-0.707106781187").atan2(Decimal128("-0.707106781187")),
+ Decimal128("-2.35619449019"));
+ assertDecimal128ApproxEqual(Decimal128("-0.5").atan2(Decimal128("-0.866025403784")),
+ Decimal128("-2.61799387799"));
+ assertDecimal128ApproxEqual(Decimal128("-1.83697019872e-16").atan2(Decimal128("-1.0")),
+ Decimal128("-3.14159265359"));
+ assertDecimal128ApproxEqual(Decimal128("0.5").atan2(Decimal128("-0.866025403784")),
+ Decimal128("2.61799387799"));
+ assertDecimal128ApproxEqual(Decimal128("0.707106781187").atan2(Decimal128("-0.707106781187")),
+ Decimal128("2.35619449019"));
+ assertDecimal128ApproxEqual(Decimal128("0.866025403784").atan2(Decimal128("-0.5")),
+ Decimal128("2.09439510239"));
+ assertDecimal128ApproxEqual(Decimal128("1.0").atan2(Decimal128("-2.44929359829e-16")),
+ Decimal128("1.57079632679"));
+}
+
+TEST(Decimal128Test, TestCos) {
+ assertDecimal128ApproxEqual(Decimal128("0.0").cos(), Decimal128("1.0"));
+ assertDecimal128ApproxEqual(Decimal128("0.523598775598").cos(), Decimal128("0.866025403784"));
+ assertDecimal128ApproxEqual(Decimal128("0.785398163397").cos(), Decimal128("0.707106781187"));
+ assertDecimal128ApproxEqual(Decimal128("1.0471975512").cos(), Decimal128("0.5"));
+ assertDecimal128ApproxEqual(Decimal128("1.57079632679").cos(), Decimal128("6.12323399574e-17"));
+ assertDecimal128ApproxEqual(Decimal128("2.09439510239").cos(), Decimal128("-0.5"));
+ assertDecimal128ApproxEqual(Decimal128("2.35619449019").cos(), Decimal128("-0.707106781187"));
+ assertDecimal128ApproxEqual(Decimal128("2.61799387799").cos(), Decimal128("-0.866025403784"));
+ assertDecimal128ApproxEqual(Decimal128("3.14159265359").cos(), Decimal128("-1.0"));
+ assertDecimal128ApproxEqual(Decimal128("3.66519142919").cos(), Decimal128("-0.866025403784"));
+ assertDecimal128ApproxEqual(Decimal128("3.92699081699").cos(), Decimal128("-0.707106781187"));
+ assertDecimal128ApproxEqual(Decimal128("4.18879020479").cos(), Decimal128("-0.5"));
+ assertDecimal128ApproxEqual(Decimal128("4.71238898038").cos(),
+ Decimal128("-1.83697019872e-16"));
+ assertDecimal128ApproxEqual(Decimal128("5.23598775598").cos(), Decimal128("0.5"));
+ assertDecimal128ApproxEqual(Decimal128("5.49778714378").cos(), Decimal128("0.707106781187"));
+ assertDecimal128ApproxEqual(Decimal128("5.75958653158").cos(), Decimal128("0.866025403784"));
+ assertDecimal128ApproxEqual(Decimal128("6.28318530718").cos(), Decimal128("1.0"));
+}
+
+TEST(Decimal128Test, TestCosh) {
+ assertDecimal128ApproxEqual(Decimal128("0.0").cosh(), Decimal128("1.0"));
+ assertDecimal128ApproxEqual(Decimal128("0.523598775598").cosh(), Decimal128("1.14023832108"));
+ assertDecimal128ApproxEqual(Decimal128("0.785398163397").cosh(), Decimal128("1.32460908925"));
+ assertDecimal128ApproxEqual(Decimal128("1.0471975512").cosh(), Decimal128("1.6002868577"));
+ assertDecimal128ApproxEqual(Decimal128("1.57079632679").cosh(), Decimal128("2.50917847866"));
+ assertDecimal128ApproxEqual(Decimal128("2.09439510239").cosh(), Decimal128("4.12183605387"));
+ assertDecimal128ApproxEqual(Decimal128("2.35619449019").cosh(), Decimal128("5.32275214952"));
+ assertDecimal128ApproxEqual(Decimal128("2.61799387799").cosh(), Decimal128("6.89057236498"));
+ assertDecimal128ApproxEqual(Decimal128("3.14159265359").cosh(), Decimal128("11.5919532755"));
+ assertDecimal128ApproxEqual(Decimal128("3.66519142919").cosh(), Decimal128("19.5446063168"));
+ assertDecimal128ApproxEqual(Decimal128("3.92699081699").cosh(), Decimal128("25.3868611924"));
+ assertDecimal128ApproxEqual(Decimal128("4.18879020479").cosh(), Decimal128("32.97906491"));
+ assertDecimal128ApproxEqual(Decimal128("4.71238898038").cosh(), Decimal128("55.6633808904"));
+ assertDecimal128ApproxEqual(Decimal128("5.23598775598").cosh(), Decimal128("93.9599750339"));
+ assertDecimal128ApproxEqual(Decimal128("5.49778714378").cosh(), Decimal128("122.07757934"));
+ assertDecimal128ApproxEqual(Decimal128("5.75958653158").cosh(), Decimal128("158.610147472"));
+ assertDecimal128ApproxEqual(Decimal128("6.28318530718").cosh(), Decimal128("267.746761484"));
+}
+
+TEST(Decimal128Test, TestSin) {
+ assertDecimal128ApproxEqual(Decimal128("0.0").sin(), Decimal128("0.0"));
+ assertDecimal128ApproxEqual(Decimal128("0.523598775598").sin(), Decimal128("0.5"));
+ assertDecimal128ApproxEqual(Decimal128("0.785398163397").sin(), Decimal128("0.707106781187"));
+ assertDecimal128ApproxEqual(Decimal128("1.0471975512").sin(), Decimal128("0.866025403784"));
+ assertDecimal128ApproxEqual(Decimal128("1.57079632679").sin(), Decimal128("1.0"));
+ assertDecimal128ApproxEqual(Decimal128("2.09439510239").sin(), Decimal128("0.866025403784"));
+ assertDecimal128ApproxEqual(Decimal128("2.35619449019").sin(), Decimal128("0.707106781187"));
+ assertDecimal128ApproxEqual(Decimal128("2.61799387799").sin(), Decimal128("0.5"));
+ assertDecimal128ApproxEqual(Decimal128("3.14159265359").sin(), Decimal128("1.22464679915e-16"));
+ assertDecimal128ApproxEqual(Decimal128("3.66519142919").sin(), Decimal128("-0.5"));
+ assertDecimal128ApproxEqual(Decimal128("3.92699081699").sin(), Decimal128("-0.707106781187"));
+ assertDecimal128ApproxEqual(Decimal128("4.18879020479").sin(), Decimal128("-0.866025403784"));
+ assertDecimal128ApproxEqual(Decimal128("4.71238898038").sin(), Decimal128("-1.0"));
+ assertDecimal128ApproxEqual(Decimal128("5.23598775598").sin(), Decimal128("-0.866025403784"));
+ assertDecimal128ApproxEqual(Decimal128("5.49778714378").sin(), Decimal128("-0.707106781187"));
+ assertDecimal128ApproxEqual(Decimal128("5.75958653158").sin(), Decimal128("-0.5"));
+ assertDecimal128ApproxEqual(Decimal128("6.28318530718").sin(),
+ Decimal128("-2.44929359829e-16"));
+}
+
+TEST(Decimal128Test, TestSinh) {
+ assertDecimal128ApproxEqual(Decimal128("0.0").sinh(), Decimal128("0.0"));
+ assertDecimal128ApproxEqual(Decimal128("0.523598775598").sinh(), Decimal128("0.547853473888"));
+ assertDecimal128ApproxEqual(Decimal128("0.785398163397").sinh(), Decimal128("0.868670961486"));
+ assertDecimal128ApproxEqual(Decimal128("1.0471975512").sinh(), Decimal128("1.24936705052"));
+ assertDecimal128ApproxEqual(Decimal128("1.57079632679").sinh(), Decimal128("2.30129890231"));
+ assertDecimal128ApproxEqual(Decimal128("2.09439510239").sinh(), Decimal128("3.9986913428"));
+ assertDecimal128ApproxEqual(Decimal128("2.35619449019").sinh(), Decimal128("5.22797192468"));
+ assertDecimal128ApproxEqual(Decimal128("2.61799387799").sinh(), Decimal128("6.81762330413"));
+ assertDecimal128ApproxEqual(Decimal128("3.14159265359").sinh(), Decimal128("11.5487393573"));
+ assertDecimal128ApproxEqual(Decimal128("3.66519142919").sinh(), Decimal128("19.5190070464"));
+ assertDecimal128ApproxEqual(Decimal128("3.92699081699").sinh(), Decimal128("25.3671583194"));
+ assertDecimal128ApproxEqual(Decimal128("4.18879020479").sinh(), Decimal128("32.9639002901"));
+ assertDecimal128ApproxEqual(Decimal128("4.71238898038").sinh(), Decimal128("55.6543975994"));
+ assertDecimal128ApproxEqual(Decimal128("5.23598775598").sinh(), Decimal128("93.9546534685"));
+ assertDecimal128ApproxEqual(Decimal128("5.49778714378").sinh(), Decimal128("122.073483515"));
+ assertDecimal128ApproxEqual(Decimal128("5.75958653158").sinh(), Decimal128("158.606995057"));
+ assertDecimal128ApproxEqual(Decimal128("6.28318530718").sinh(), Decimal128("267.744894041"));
+}
+
+TEST(Decimal128Test, TestTan) {
+ assertDecimal128ApproxEqual(Decimal128("-1.5").tan(), Decimal128("-14.1014199472"));
+ assertDecimal128ApproxEqual(Decimal128("-1.0471975512").tan(), Decimal128("-1.73205080757"));
+ assertDecimal128ApproxEqual(Decimal128("-0.785398163397").tan(), Decimal128("-1.0"));
+ assertDecimal128ApproxEqual(Decimal128("0").tan(), Decimal128("0.0"));
+ assertDecimal128ApproxEqual(Decimal128("0.785398163397").tan(), Decimal128("1.0"));
+ assertDecimal128ApproxEqual(Decimal128("1.0471975512").tan(), Decimal128("1.73205080757"));
+ assertDecimal128ApproxEqual(Decimal128("1.5").tan(), Decimal128("14.1014199472"));
+}
+
+TEST(Decimal128Test, TestTanh) {
+ assertDecimal128ApproxEqual(Decimal128("0.0").tanh(), Decimal128("0.0"));
+ assertDecimal128ApproxEqual(Decimal128("0.523598775598").tanh(), Decimal128("0.480472778156"));
+ assertDecimal128ApproxEqual(Decimal128("0.785398163397").tanh(), Decimal128("0.655794202633"));
+ assertDecimal128ApproxEqual(Decimal128("1.0471975512").tanh(), Decimal128("0.780714435359"));
+ assertDecimal128ApproxEqual(Decimal128("1.57079632679").tanh(), Decimal128("0.917152335667"));
+ assertDecimal128ApproxEqual(Decimal128("2.09439510239").tanh(), Decimal128("0.970123821166"));
+ assertDecimal128ApproxEqual(Decimal128("2.35619449019").tanh(), Decimal128("0.982193380007"));
+ assertDecimal128ApproxEqual(Decimal128("2.61799387799").tanh(), Decimal128("0.989413207353"));
+ assertDecimal128ApproxEqual(Decimal128("3.14159265359").tanh(), Decimal128("0.996272076221"));
+ assertDecimal128ApproxEqual(Decimal128("3.66519142919").tanh(), Decimal128("0.998690213046"));
+ assertDecimal128ApproxEqual(Decimal128("3.92699081699").tanh(), Decimal128("0.999223894879"));
+ assertDecimal128ApproxEqual(Decimal128("4.18879020479").tanh(), Decimal128("0.999540174353"));
+ assertDecimal128ApproxEqual(Decimal128("4.71238898038").tanh(), Decimal128("0.999838613989"));
+ assertDecimal128ApproxEqual(Decimal128("5.23598775598").tanh(), Decimal128("0.999943363486"));
+ assertDecimal128ApproxEqual(Decimal128("5.49778714378").tanh(), Decimal128("0.999966449"));
+ assertDecimal128ApproxEqual(Decimal128("5.75958653158").tanh(), Decimal128("0.99998012476"));
+ assertDecimal128ApproxEqual(Decimal128("6.28318530718").tanh(), Decimal128("0.99999302534"));
+}
} // namespace mongo