#pragma once #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int BAD_ARGUMENTS; } class DDSketchLogarithmicMapping { public: explicit DDSketchLogarithmicMapping(Float64 relative_accuracy_, Float64 offset_ = 0.0) : relative_accuracy(relative_accuracy_), offset(offset_) { if (relative_accuracy <= 0 || relative_accuracy >= 1) { throw Exception(ErrorCodes::BAD_ARGUMENTS, "Relative accuracy must be between 0 and 1 but is {}", relative_accuracy); } gamma = (1 + relative_accuracy) / (1 - relative_accuracy); multiplier = 1 / std::log(gamma); min_possible = std::numeric_limits::min() * gamma; max_possible = std::numeric_limits::max() / gamma; } ~DDSketchLogarithmicMapping() = default; int key(Float64 value) const { if (value < min_possible || value > max_possible) { throw Exception(ErrorCodes::BAD_ARGUMENTS, "Value {} is out of range [{}, {}]", value, min_possible, max_possible); } return static_cast(logGamma(value) + offset); } Float64 value(int key) const { return lowerBound(key) * (1 + relative_accuracy); } Float64 logGamma(Float64 value) const { return std::log(value) * multiplier; } Float64 powGamma(Float64 value) const { return std::exp(value / multiplier); } Float64 lowerBound(int index) const { return powGamma(static_cast(index) - offset); } Float64 getGamma() const { return gamma; } Float64 getMinPossible() const { return min_possible; } [[maybe_unused]] Float64 getMaxPossible() const { return max_possible; } void serialize(WriteBuffer& buf) const { writeBinary(gamma, buf); writeBinary(offset, buf); } void deserialize(ReadBuffer& buf) { readBinary(gamma, buf); readBinary(offset, buf); if (gamma <= 1.0) { throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid gamma value after deserialization: {}", gamma); } multiplier = 1 / std::log(gamma); min_possible = std::numeric_limits::min() * gamma; max_possible = std::numeric_limits::max() / gamma; } protected: Float64 relative_accuracy; Float64 gamma; Float64 min_possible; Float64 max_possible; Float64 multiplier; Float64 offset; }; }