Principle:ClickHouse ClickHouse Math Compatibility Functions
| Knowledge Sources | |
|---|---|
| Domains | Mathematics, Portability |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
Provide portable, high-accuracy implementations of mathematical functions with consistent behavior across platforms.
Description
This principle addresses inconsistencies in math library implementations across different systems, particularly for extended precision (long double) operations and edge cases. By providing standalone implementations derived from well-tested sources (musl libc, ARM optimized math), applications can achieve consistent numerical results regardless of the underlying system's math library quality. The implementations use carefully crafted polynomial approximations, lookup tables for range reduction, and extended precision arithmetic to maintain accuracy while handling special cases (infinities, NaN, signed zeros) according to IEEE 754 standards.
Usage
Apply this principle when numerical reproducibility across platforms is critical, when targeting systems with known poor math library implementations, or when extended precision computations are required but platform support is inconsistent.
Theoretical Basis
Mathematical function approximation relies on several fundamental techniques:
- Range Reduction: Transform input to a smaller range where polynomial approximations converge rapidly. For example, `log(x)` decomposes x as `2^k * z` where z is in a narrow range, then `log(x) = k*ln(2) + log(z)`.
- Polynomial Approximation: Use Taylor series or minimax polynomials to approximate functions. For `log(1+x)` with small x: `log(1+x) ≈ x - x²/2 + x³/3 - ...` The coefficients are chosen to minimize maximum error over the range.
- Lookup Tables: Precompute function values at carefully chosen points. For `log(x)`, split [1,2) into subintervals and store `{1/c, log(c)}` for each subinterval's center c. This reduces the approximation problem to small perturbations around known values.
- Extended Precision: Use split representation (high and low parts) to maintain extra precision bits beyond the native type. For example, `ln(2)` is stored as `ln2hi + ln2lo` where their sum has ~100 bits of accuracy even though each is 64 bits.
- Special Case Handling: IEEE 754 defines specific behaviors for edge cases. For example, `pow(-0, -odd) = -infinity` while `pow(+0, -odd) = +infinity`. Correct handling requires explicit checks and branches.
The `pow(x,y)` function uses the identity `x^y = exp(y*log(x))`, but careful handling is needed:
- Check for integer y to avoid complex results for negative x
- Handle signed zeros and infinities per IEEE 754
- Use FMA (fused multiply-add) when available to reduce rounding errors
- Detect overflow/underflow conditions early to return infinity/zero