Implementation:ClickHouse ClickHouse Decimal
| Knowledge Sources | |
|---|---|
| Domains | Numeric_Types, Data_Types |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
A fixed-precision decimal arithmetic type that stores decimal values as scaled integers to avoid floating-point rounding errors.
Description
The `Decimal` template class provides exact decimal arithmetic by storing values as integers with an associated scale (number of decimal places). It supports four precision levels: `Decimal32` (7 digits), `Decimal64` (18 digits), `Decimal128` (38 digits), and `Decimal256` (76 digits). All arithmetic operations are performed on the underlying integer representation, ensuring no rounding errors occur as they would with floating-point types.
The implementation includes:
- Arithmetic operators (+, -, *, /, %)
- Bitwise operators (&, |, ~)
- Comparison operators
- Conversion between different decimal precisions
- Special handling for overflow in accumulation operations
- Hash functions for use in hash tables
Two specialized types `DateTime64` and `Time64` inherit from `Decimal64` to represent high-precision timestamps.
Usage
Use this implementation when you need to:
- Store monetary values without rounding errors
- Perform exact decimal arithmetic (financial calculations)
- Represent fixed-point numbers with specific precision
- Store timestamps with sub-second precision (DateTime64)
- Avoid accumulation of floating-point errors in calculations
Code Reference
Source Location
- Repository: ClickHouse
- File: base/base/Decimal.h
- Lines: 1-219
Signature
template <typename T>
struct Decimal {
using NativeType = T;
T value;
constexpr Decimal() = default;
constexpr Decimal(const T & value_);
template <typename U> constexpr Decimal(const Decimal<U> & x);
template <typename U> constexpr U convertTo() const;
const Decimal<T> & operator += (const T & x);
const Decimal<T> & operator -= (const T & x);
const Decimal<T> & operator *= (const T & x);
const Decimal<T> & operator /= (const T & x);
const Decimal<T> & operator %= (const T & x);
void NO_SANITIZE_UNDEFINED addOverflow(const T & x);
};
using Decimal32 = Decimal<Int32>;
using Decimal64 = Decimal<Int64>;
using Decimal128 = Decimal<Int128>;
using Decimal256 = Decimal<Int256>;
class DateTime64 : public Decimal64;
class Time64 : public Decimal64;
Import
#include <base/Decimal.h>
I/O Contract
| Input | Type | Description |
|---|---|---|
| value | T (Int32/Int64/Int128/Int256) | Raw integer value representing the decimal |
| scale | implicit | Number of decimal places (stored elsewhere, not in Decimal itself) |
| Output | Type | Description |
|---|---|---|
| value | T | Raw integer representation |
| result | Decimal<T> | Result of arithmetic operations |
Usage Examples
#include <base/Decimal.h>
// Create decimal values (scale managed separately in ClickHouse)
Decimal64 price(12345); // Represents 1.2345 with scale=4
Decimal64 quantity(10000); // Represents 10.000 with scale=3
// Arithmetic operations
Decimal64 sum = price + quantity;
Decimal64 diff = price - quantity;
Decimal64 product = price * quantity;
Decimal64 quotient = price / quantity;
// Comparison
bool is_greater = price > quantity;
bool is_equal = price == quantity;
// Conversion between precisions
Decimal128 high_precision(price);
Decimal32 low_precision(static_cast<Int32>(price.value));
// DateTime64 for timestamps
DateTime64 timestamp(1234567890000000); // Microseconds since epoch
// Hash for use in hash tables
std::hash<Decimal64> hasher;
size_t hash_value = hasher(price);
// Bitwise operations
Decimal64 masked = price & Decimal64(0xFFFF);
Decimal64 combined = price | quantity;