[SERVER-39487] Aggregation operator $sqrt output for NumberDecimal is the same as $exp Created: 11/Feb/19  Updated: 29/Oct/23  Resolved: 20/Feb/19

Status: Closed
Project: Core Server
Component/s: Aggregation Framework
Affects Version/s: 4.0.5, 4.1.6
Fix Version/s: 3.4.21, 3.6.12, 4.0.7, 4.1.9

Type: Bug Priority: Critical - P2
Reporter: Wan Bachtiar Assignee: James Wahlin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Backports
Backwards Compatibility: Fully Compatible
Operating System: ALL
Backport Requested:
v4.0, v3.6, v3.4
Sprint: Query 2019-02-25
Participants:

 Description   

Using the following documents:

db.test.insert({value:NumberDecimal("25")});
db.test.insert({value:NumberDecimal(25)});

Running aggregation operator $sqrt as below:

db.test.aggregate([{
    "$addFields":{
        "sqrt": {"$sqrt": "$value"}, 
        "exp": {"$exp": "$value"}, 
    }
}])

Produces:

      {
        "_id": ObjectId("..."),
        "value": NumberDecimal("25"),
        "sqrt": NumberDecimal("72004899337.38587252416135146612616"),
        "exp": NumberDecimal("72004899337.38587252416135146612616")
      },
      {
        "_id": ObjectId("..."),
        "value": NumberDecimal("25.0000000000000"),
        "sqrt": NumberDecimal("72004899337.38587252416135146612616"),
        "exp": NumberDecimal("72004899337.38587252416135146612616")
      }

Note that the output of the $sqrt is the same as the output of $exp.
Looking at the code, the method Decimal128::squareRoot is exactly the same as Decimal128::exponential :

Decimal128::squareRoot:
https://github.com/mongodb/mongo/blob/r4.1.6/src/mongo/platform/decimal128.cpp#L720

Decimal128::exponential:
https://github.com/mongodb/mongo/blob/r4.1.6/src/mongo/platform/decimal128.cpp#L627

A workaround is to convert the decimal to double first i.e. $toDouble, to bypass the squareRoot method call in expression: https://github.com/mongodb/mongo/blob/r4.1.6/src/mongo/db/pipeline/expression.cpp#L4091

For example:

db.test.aggregate([{
    "$addFields":{
        "sqrt": {"$sqrt": {"$toDouble":"$value"}}, 
        "exp": {"$exp": "$value"}, 
    }
}])



 Comments   
Comment by Githook User [ 18/Mar/19 ]

Author:

{'email': 'james@mongodb.com', 'name': 'James Wahlin', 'username': 'jameswahlin'}

Message: SERVER-39487 Decimal128::squareRoot() returns result for Decimal128::exponential()

(cherry picked from commit 5aa3f6dbc5e31beaf40e0828f7a24ecf71fb42f9)
(cherry picked from commit c1760b39b29dc412ca1c20361c500e18e90c71cd)
(cherry picked from commit 477ceade3dae70498c0a6b4c89007ac98934e1c6)
Branch: v3.4
https://github.com/mongodb/mongo/commit/78ea71891f577b11a3129557948bed6c39692ae3

Comment by Githook User [ 15/Mar/19 ]

Author:

{'email': 'james@mongodb.com', 'name': 'James Wahlin', 'username': 'jameswahlin'}

Message: SERVER-39487 Decimal128::squareRoot() returns result for Decimal128::exponential()

(cherry picked from commit 5aa3f6dbc5e31beaf40e0828f7a24ecf71fb42f9)
(cherry picked from commit c1760b39b29dc412ca1c20361c500e18e90c71cd)
Branch: v3.6
https://github.com/mongodb/mongo/commit/477ceade3dae70498c0a6b4c89007ac98934e1c6

Comment by Githook User [ 22/Feb/19 ]

Author:

{'name': 'James Wahlin', 'email': 'james@mongodb.com', 'username': 'jameswahlin'}

Message: SERVER-39487 Decimal128::squareRoot() returns result for Decimal128::exponential()

(cherry picked from commit 5aa3f6dbc5e31beaf40e0828f7a24ecf71fb42f9)
Branch: v4.0
https://github.com/mongodb/mongo/commit/c1760b39b29dc412ca1c20361c500e18e90c71cd

Comment by Githook User [ 20/Feb/19 ]

Author:

{'name': 'James Wahlin', 'email': 'james@mongodb.com', 'username': 'jameswahlin'}

Message: SERVER-39487 Decimal128::squareRoot() returns result for Decimal128::exponential()
Branch: master
https://github.com/mongodb/mongo/commit/5aa3f6dbc5e31beaf40e0828f7a24ecf71fb42f9

Comment by Andy Schwerin [ 12/Feb/19 ]

Not strictly related, but the overload of exponential that takes no flags is throwing away the caller-supplied rounding mode argument. The implementation of `squareRoot` that takes user flags is correct. The version that does not is delegating to the `exponential` by accident. This would be a good opportunity to also expand our C++ unit test coverage of the wrapper.

Generated at Thu Feb 08 04:52:13 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.