Skip to content

Commit d32eb21

Browse files
wqian94MongoDB Bot
authored and
MongoDB Bot
committed
SERVER-99739: Round floating points in QueryTester results to 15 digits (#31473)
GitOrigin-RevId: 4e629e2476c5c1952f8cac7a75a3b03f2821686f
1 parent 69605fc commit d32eb21

File tree

4 files changed

+66
-2
lines changed

4 files changed

+66
-2
lines changed

src/mongo/db/query/query_tester/test.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,13 @@ NormalizationOptsSet Test::parseResultType(const std::string& type) {
164164
NormalizationOpts::kSortArrays | NormalizationOpts::kNormalizeNumerics},
165165
{":sortFull",
166166
NormalizationOpts::kSortResults | NormalizationOpts::kSortBSON |
167-
NormalizationOpts::kSortArrays},
167+
NormalizationOpts::kSortArrays | NormalizationOpts::kRoundFloatingPointNumerics},
168168
{":sortBSONNormalizeNumerics",
169169
NormalizationOpts::kSortResults | NormalizationOpts::kSortBSON |
170170
NormalizationOpts::kNormalizeNumerics},
171-
{":sortBSON", NormalizationOpts::kSortResults | NormalizationOpts::kSortBSON},
171+
{":sortBSON",
172+
NormalizationOpts::kSortResults | NormalizationOpts::kSortBSON |
173+
NormalizationOpts::kRoundFloatingPointNumerics},
172174
{":sortResultsNormalizeNumerics",
173175
NormalizationOpts::kSortResults | NormalizationOpts::kNormalizeNumerics},
174176
{":normalizeNumerics", NormalizationOpts::kNormalizeNumerics},

src/mongo/shell/shell_utils.cpp

+51
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,54 @@ BSONObj normalizeNumerics(const BSONObj& input) {
919919
return bob.obj();
920920
}
921921

922+
void roundFloatingPointNumericElementsHelper(const BSONObj& input, BSONObjBuilder& bob);
923+
924+
void roundFloatingPointNumericElements(const BSONElement& el, BSONObjBuilder& bob) {
925+
switch (el.type()) {
926+
case NumberDouble: {
927+
// Take advantage of Decimal128's ability to round to 15 digits at construction time.
928+
bob.append(el.fieldName(),
929+
Decimal128(el.numberDouble(), Decimal128::kRoundTo15Digits).toDouble());
930+
break;
931+
}
932+
case Array: {
933+
BSONObjBuilder sub(bob.subarrayStart(el.fieldNameStringData()));
934+
for (const auto& child : el.Array()) {
935+
roundFloatingPointNumericElements(child, sub);
936+
}
937+
sub.doneFast();
938+
break;
939+
}
940+
case Object: {
941+
BSONObjBuilder sub(bob.subobjStart(el.fieldNameStringData()));
942+
roundFloatingPointNumericElementsHelper(el.Obj(), sub);
943+
sub.doneFast();
944+
break;
945+
}
946+
default:
947+
bob.append(el);
948+
break;
949+
}
950+
}
951+
952+
void roundFloatingPointNumericElementsHelper(const BSONObj& input, BSONObjBuilder& bob) {
953+
BSONObjIterator it(input);
954+
while (it.more()) {
955+
roundFloatingPointNumericElements(it.next(), bob);
956+
}
957+
}
958+
959+
/**
960+
* Returns a new BSONObj with the same field/value pairings, but with floating-point types rounded
961+
* to 15 digits of precision. For example, 1.000000000000001 and NumberDecimal('1') would
962+
* be normalized into the same number.
963+
*/
964+
BSONObj roundFloatingPointNumerics(const BSONObj& input) {
965+
BSONObjBuilder bob(input.objsize());
966+
roundFloatingPointNumericElementsHelper(input, bob);
967+
return bob.obj();
968+
}
969+
922970
void removeNullAndUndefinedElementsHelper(const BSONObj& input, BSONObjBuilder& bob);
923971

924972
template <typename Builder>
@@ -986,6 +1034,9 @@ BSONObj normalizeBSONObj(const BSONObj& input, NormalizationOptsSet opts) {
9861034
if (isSet(opts, NormalizationOpts::kConflateNullAndMissing)) {
9871035
result = removeNullAndUndefined(result);
9881036
}
1037+
if (isSet(opts, NormalizationOpts::kRoundFloatingPointNumerics)) {
1038+
result = roundFloatingPointNumerics(result);
1039+
}
9891040
if (isSet(opts, NormalizationOpts::kNormalizeNumerics)) {
9901041
result = normalizeNumerics(result);
9911042
}

src/mongo/shell/shell_utils.h

+2
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ enum class NormalizationOpts : uint32_t {
125125
kNormalizeNumerics = 1 << 3,
126126
// Set this bit to treat null and missing as the same value.
127127
kConflateNullAndMissing = 1 << 4,
128+
// Set this bit to round floating points to 15 digits of precision.
129+
kRoundFloatingPointNumerics = 1 << 5,
128130
};
129131
using NormalizationOptsSet = NormalizationOpts;
130132

src/mongo/shell/shell_utils_test.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -402,5 +402,14 @@ TEST(NormalizationOpts, NormalizeFullConflateNullAndMissing) {
402402
"c: 1.000000000000000000000000000000000 } }";
403403
ASSERT_EQ(normalizeBSONObj(bson, opts).toString(), expected);
404404
}
405+
406+
TEST(NormalizationOpts, RoundedFloatingPointNumericsAreEqual) {
407+
auto bson = fromjson("{a: {z: 1.234567890123456789, y: [9.876543210987654321, 1]}}");
408+
auto opts = NormalizationOpts::kRoundFloatingPointNumerics | NormalizationOpts::kSortBSON |
409+
NormalizationOpts::kSortArrays;
410+
411+
auto expected = "{ a: { y: [ 1, 9.87654321098765 ], z: 1.23456789012346 } }";
412+
ASSERT_EQ(normalizeBSONObj(bson, opts).toString(), expected);
413+
}
405414
} // namespace
406415
} // namespace mongo

0 commit comments

Comments
 (0)