Value GranularityRounderPreferredNumbers::roundDown(Value value) {
    uassertNonNegativeNumber(value);

    if (value.coerceToDouble() == 0.0) {
        return value;
    }

    if (value.getType() == BSONType::NumberDecimal) {
        Decimal128 number = value.getDecimal();
        Decimal128 multiplier = Decimal128(1);

        // '_baseSeries' contains doubles, so we create a vector that contains the Decimal128
        // versions of the numbers in '_baseSeries' to make it easier to compare values to 'number'.
        vector<Decimal128> decimalSeries;
        for (auto&& doubleNumber : _baseSeries) {
            decimalSeries.push_back(Decimal128(doubleNumber));
        }

        while (number.isLessEqual(decimalSeries.front().multiply(multiplier))) {
            multiplier = multiplier.divide(Decimal128(10));
        }

        Decimal128 previousMax;
        while (number.isGreater(decimalSeries.back().multiply(multiplier))) {
            previousMax = decimalSeries.back().multiply(multiplier);
            multiplier = multiplier.multiply(Decimal128(10));
            if (number.isLessEqual(decimalSeries.front().multiply(multiplier))) {
                // The number is less than or equal to the current min, so it must round down to the
                // previous max. For example, rounding down 0.8 in the E6 series.
                return Value(previousMax);
            }
        }

        // After scaling up or down, 'number' should now fall into the range spanned by
        // decimalSeries[i] * multiplier for all i in decimalSeries.
        invariant(number.isGreater(decimalSeries.front().multiply(multiplier)) &&
                  number.isLessEqual(decimalSeries.back().multiply(multiplier)));

        // Get an iterator pointing to the first element in '_baseSeries' that is greater than or
        // equal to 'number'.
        auto iterator =
            std::lower_bound(decimalSeries.begin(),
                             decimalSeries.end(),
                             number,
                             [multiplier](Decimal128 seriesNumber, Decimal128 roundingNumber) {
                                 return seriesNumber.multiply(multiplier).isLess(roundingNumber);
                             });

        // We need to move the iterator back by one so that we round down to a number that is
        // strictly less than the value we are rounding.
        return Value(Value((*(iterator - 1)).multiply(multiplier)));
    } else {
        double number = value.coerceToDouble();
        double multiplier = 1.0;

        while (number <= (_baseSeries.front() * multiplier)) {
            multiplier /= 10.0;
        }

        double previousMax;
        while (number > (_baseSeries.back() * multiplier)) {
            previousMax = _baseSeries.back() * multiplier;
            multiplier *= 10.0;
            if (number <= _baseSeries.front() * multiplier) {
                // The number is less than or equal to the current min, so it must round down to the
                // previous max. For example, rounding down 0.8 in the E6 series.
                return Value(previousMax);
            }
        }

        // After scaling up or down, 'number' should now fall into the range spanned by
        // _baseSeries[i] * multiplier for all i in _baseSeries.
        invariant(number > (_baseSeries.front() * multiplier) &&
                  number <= (_baseSeries.back() * multiplier));

        // Get an iterator pointing to the first element in '_baseSeries' that is greater than or
        // equal to 'number'.
        auto iterator = std::lower_bound(_baseSeries.begin(),
                                         _baseSeries.end(),
                                         number,
                                         [multiplier](double seriesNumber, double roundingNumber) {
                                             return (seriesNumber * multiplier) < roundingNumber;
                                         });

        // We need to move the iterator back by one so that we round down to a number that is
        // strictly less than the value we are rounding.
        return Value(Value(*(iterator - 1) * multiplier));
    }
}
Value GranularityRounderPreferredNumbers::roundUp(Value value) {
    uassertNonNegativeNumber(value);

    if (value.coerceToDouble() == 0.0) {
        return value;
    }

    if (value.getType() == BSONType::NumberDecimal) {
        Decimal128 number = value.getDecimal();
        Decimal128 multiplier = Decimal128(1);

        // '_baseSeries' contains doubles, so we create a vector that contains the Decimal128
        // versions of the numbers in '_baseSeries' to make it easier to compare values to 'number'.
        vector<Decimal128> decimalSeries;
        for (auto&& doubleNumber : _baseSeries) {
            decimalSeries.push_back(Decimal128(doubleNumber));
        }

        while (number.isGreaterEqual(decimalSeries.back().multiply(multiplier))) {
            multiplier = multiplier.multiply(Decimal128(10));
        }

        Decimal128 previousMin;
        while (number.isLess(decimalSeries.front().multiply(multiplier))) {
            previousMin = decimalSeries.front().multiply(multiplier);
            multiplier = multiplier.divide(Decimal128(10));
            if (number.isGreaterEqual(decimalSeries.back().multiply(multiplier))) {
                // The number was between the previous min and the current max, so it must round up
                // to the previous min. For example, rounding up 0.8 in the E6 series.
                return Value(previousMin);
            }
        }

        // After scaling up or down, 'number' should now fall into the range spanned by
        // decimalSeries[i] * multiplier for all i in decimalSeries.
        invariant(number.isGreaterEqual(decimalSeries.front().multiply(multiplier)) &&
                  number.isLess(decimalSeries.back().multiply(multiplier)));

        // Get an iterator pointing to the first element in '_baseSeries' that is greater
        // than'number'.
        auto iterator =
            std::upper_bound(decimalSeries.begin(),
                             decimalSeries.end(),
                             number,
                             [multiplier](Decimal128 roundingNumber, Decimal128 seriesNumber) {
                                 return roundingNumber.isLess(seriesNumber.multiply(multiplier));
                             });

        return Value((*iterator).multiply(multiplier));
    } else {
        double number = value.coerceToDouble();
        double multiplier = 1.0;

        while (number >= (_baseSeries.back() * multiplier)) {
            multiplier *= 10.0;
        }

        double previousMin;
        while (number < (_baseSeries.front() * multiplier)) {
            previousMin = _baseSeries.front() * multiplier;
            multiplier /= 10.0;
            if (number >= (_baseSeries.back() * multiplier)) {
                // The number was between the previous min and the current max, so it must round up
                // to the previous min. For example, rounding up 0.8 in the E6 series.
                return Value(previousMin);
            }
        }

        // After scaling up or down, 'number' should now fall into the range spanned by
        // _baseSeries[i] * multiplier for all i in _baseSeries.
        invariant(number >= (_baseSeries.front() * multiplier) &&
                  number < (_baseSeries.back() * multiplier));

        // Get an iterator pointing to the first element in '_baseSeries' that is greater
        // than'number'.
        auto iterator = std::upper_bound(_baseSeries.begin(),
                                         _baseSeries.end(),
                                         number,
                                         [multiplier](double roundingNumber, double seriesNumber) {
                                             return roundingNumber < (seriesNumber * multiplier);
                                         });
        return Value(*iterator * multiplier);
    }
}