Value GranularityRounderPowersOfTwo::roundDown(Value value) { uassertNonNegativeNumber(value); if (value.coerceToDouble() == 0.0) { return value; } Value exp; if (value.getType() == BSONType::NumberDouble) { exp = Value(static_cast<int>(std::ceil(std::log2(value.getDouble())) - 1.0)); } else if (value.getType() == BSONType::NumberDecimal) { Decimal128 input = value.getDecimal(); exp = Value(Decimal128( static_cast<int>((std::ceil(input.logarithm(Decimal128(2)).toDouble()) - 1.0)))); } else { long long number = value.getLong(); int leadingZeros = countLeadingZeros64(number); int trailingZeros = countTrailingZeros64(number); if (leadingZeros + trailingZeros == 63) { // If number is a power of 2, then we need to subtract an extra 1 so we round down to // the next power of 2. exp = Value(63 - leadingZeros - 1); } else { exp = Value(63 - leadingZeros); } } return ExpressionPow::create(getExpCtx(), Value(2), exp)->evaluate(Document()); }
Value GranularityRounderPowersOfTwo::roundUp(Value value) { uassertNonNegativeNumber(value); if (value.coerceToDouble() == 0.0) { return value; } Value exp; if (value.getType() == BSONType::NumberDouble) { exp = Value(static_cast<int>(std::floor(std::log2(value.getDouble())) + 1.0)); } else if (value.getType() == BSONType::NumberDecimal) { Decimal128 input = value.getDecimal(); exp = Value(Decimal128( static_cast<int>((std::floor(input.logarithm(Decimal128(2)).toDouble()) + 1.0)))); } else { long long number = value.getLong(); // We can find the log_2 of 'number' by counting the number of leading zeros to find its // first bit set. This is safe to do because we are working with positive values. exp = Value(63 - countLeadingZeros64(number) + 1); } return ExpressionPow::create(getExpCtx(), Value(2), exp)->evaluate(Document()); }