Table of Contents
OverviewMathematical Background and Algorithm PrinciplesDetailed Implementation of log2f
- • Algorithm Principles and Code Explanation
- • Numerical Stability Analysis
- • Handling of Subnormal NumbersDetailed Implementation of log10f
- • Algorithm Principles and Code Explanation
- • Numerical Stability Analysis
- • Handling of Subnormal NumbersDetailed Implementation of logf
- • Algorithm Principles and Code Explanation
- • Numerical Stability Analysis
- • Handling of Subnormal NumbersPerformance Optimization StrategiesCompliance with StandardsConclusion
Overview
Logarithmic functions have wide applications in scientific computing, signal processing, data compression, and other fields. The musl libc provides a complete implementation of the logarithmic function family, including <span>log2f</span> (base-2 logarithm), <span>log10f</span> (base-10 logarithm), and <span>logf</span> (natural logarithm). These functions are designed with careful algorithms and numerical optimizations to ensure excellent numerical precision while maintaining performance.
Mathematical Background and Algorithm Principles
Basic Properties of Logarithmic Functions
Logarithmic functions have the following important properties:
- •
- •
- •
- • (Change of Base Formula)
Algorithm Strategy
The implementation of logarithmic functions in musl adopts a unified strategy:
- 1. Parameter Normalization: Normalize the input to a specific range
- 2. Table Lookup Approximation: Use precomputed lookup tables to obtain approximate values
- 3. Polynomial Correction: Use low-order polynomials to correct residuals
- 4. Result Reconstruction: Combine parts to obtain the final value
Detailed Implementation of log2f
Algorithm Principles and Code Explanation
<span>log2f</span> calculates using a combination of table lookup and polynomial approximation methods.
Data Structures and Constants
#define LOG2F_TABLE_BITS 4
#define LOG2F_POLY_ORDER 4
const struct log2f_data __log2f_data = {
.tab = {
{ 0x1.661ec79f8f3bep+0, -0x1.efec65b963019p-2 },
// ... 15 entries
{ 0x1.767dcf5534862p-1, 0x1.ce0a44eb17bccp-2 },
},
.poly = {
-0x1.712b6f70a7e4dp-2, 0x1.ecabf496832ep-2, -0x1.715479ffae3dep-1,
0x1.715475f35c8b8p0,
}
};
Lookup Table Design:
- • 16 entries ( )
- • Each entry contains
<span>invc</span>(reciprocal value) and<span>logc</span>(logarithmic value) - • The entries cover the range to ensure that normalized inputs fall within this range
Input Processing and Special Value Checks
ix = asuint(x);
if (WANT_ROUNDING && predict_false(ix == 0x3f800000))
return 0;
if (predict_false(ix - 0x00800000 >= 0x7f800000 - 0x00800000)) {
if (ix * 2 == 0)
return __math_divzerof(1);
if (ix == 0x7f800000)
return x;
if ((ix & 0x80000000) || ix * 2 >= 0xff000000)
return __math_invalidf(x);
ix = asuint(x * 0x1p23f);
ix -= 23 << 23;
}
Handling of Special Cases:
- • :
- • : return (division by zero)
- • : return
- • or NaN: return NaN
- • Subnormal numbers: normalize by scaling
Parameter Normalization and Range Reduction
tmp = ix - OFF;
i = (tmp >> (23 - LOG2F_TABLE_BITS)) % N;
top = tmp & 0xff800000;
iz = ix - top;
k = (int32_t)tmp >> 23;
invc = T[i].invc;
logc = T[i].logc;
z = (double_t)asfloat(iz);
Mathematical Principles:
Decompose as:
where , .
Then:
Further decompose as:
where is the center value from the lookup table, and is a small residual.
Polynomial Approximation
r = z * invc - 1;
y0 = logc + (double_t)k;
r2 = r * r;
y = A[1] * r + A[2];
y = A[0] * r2 + y;
p = A[3] * r + y0;
y = y * r2 + p;
Approximation Formula:
where is approximated using a polynomial.
Numerical Stability Analysis
Error Sources:
- 1. Entry Error: Precomputed has finite precision
- 2. Polynomial Approximation Error: Maximum error of the 4th degree polynomial within the target range
- 3. Rounding Error in Calculations: Rounding of intermediate double precision calculations
Error Control:
- • Use double precision for intermediate calculations
- • Polynomial coefficients optimized for the target range
- • Entry design ensures that is very small, improving polynomial approximation accuracy
Handling of Subnormal Numbers
Normalization of Subnormal Numbers:
ix = asuint(x * 0x1p23f);
ix -= 23 << 23;
Subnormal numbers are converted to normal numbers by multiplying by while adjusting the exponent for compensation.
Detailed Implementation of log10f
Algorithm Principles and Code Explanation
<span>log10f</span> calculates based on the change of base formula, but optimizes performance using a direct approximation method.
Constant Definitions
static const float
ivln10hi = 4.3432617188e-01, /* 0x3ede6000 */
ivln10lo = -3.1689971365e-05, /* 0xb804ead9 */
log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */
log10_2lo = 7.9034151668e-07, /* 0x355427db */
Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
Constant Design:
- •
<span>ivln10hi</span>and<span>ivln10lo</span>: High and low parts decomposition of - •
<span>log10_2hi</span>and<span>log10_2lo</span>: High and low parts decomposition of - •
<span>Lg1</span>–<span>Lg4</span>: Coefficients of the polynomial approximation
Input Processing and Range Reduction
ix = u.i;
k = 0;
if (ix < 0x00800000 || ix>>31) {
if (ix<<1 == 0)
return -1/(x*x);
if (ix>>31)
return (x-x)/0.0f;
k -= 25;
x *= 0x1p25f;
u.f = x;
ix = u.i;
}
Special Cases:
- • : return
- • : return NaN
- • Subnormal numbers: normalize by scaling
Range Reduction to
ix += 0x3f800000 - 0x3f3504f3;
k += (int)(ix>>23) - 0x7f;
ix = (ix & 0x007fffff) + 0x3f3504f3;
u.i = ix;
x = u.f;
Normalize to the range while recording the exponent adjustment .
Rational Function Approximation
f = x - 1.0f;
s = f/(2.0f + f);
z = s*s;
w = z*z;
t1= w*(Lg2+w*Lg4);
t2= z*(Lg1+w*Lg3);
R = t2 + t1;
hfsq = 0.5f*f*f;
Mathematical Principles:Using the transformation:
Then:
Actual use of optimized rational function approximation.
High Precision Calculation
hi = f - hfsq;
u.f = hi;
u.i &= 0xfffff000;
hi = u.f;
lo = f - hi - hfsq + s*(hfsq+R);
Using high/low separation techniques to reduce rounding errors.
Final Result Combination
dk = k;
return dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi + dk*log10_2hi;
Reconstruction Formula:
where is calculated through .
Numerical Stability Analysis
Precision Assurance:
- • Use high/low separation to reduce rounding errors
- • Rational function approximation error is less than
- • High and low parts decomposition of constants ensures accurate multiplication
Handling of Subnormal Numbers
Normalize subnormal numbers by multiplying by while adjusting the exponent :
k -= 25;
x *= 0x1p25f;
Detailed Implementation of logf
Algorithm Principles and Code Explanation
<span>logf</span> calculates using a similar table lookup + polynomial approximation method as <span>log2f</span>.
Data Structures and Constants
#define LOGF_TABLE_BITS 4
#define LOGF_POLY_ORDER 4
const struct logf_data __logf_data = {
.tab = {
{ 0x1.661ec79f8f3bep+0, -0x1.57bf7808caadep-2 },
// ... 15 entries
{ 0x1.767dcf5534862p-1, 0x1.4043057b6ee09p-2 },
},
.ln2 = 0x1.62e42fefa39efp-1,
.poly = {
-0x1.00ea348b88334p-2, 0x1.5575b0be00b6ap-2, -0x1.ffffef20a4123p-2,
}
};
Lookup Table Design:
- • 16 entries, covering the range
- • Contains high precision values of
- • 3rd degree polynomial (4th order, but the leading coefficient is 1)
Input Processing and Parameter Normalization
ix = asuint(x);
if (WANT_ROUNDING && predict_false(ix == 0x3f800000))
return 0;
if (predict_false(ix - 0x00800000 >= 0x7f800000 - 0x00800000)) {
// Special case handling, same as log2f
}
Special case handling is identical to that of <span>log2f</span>.
Range Reduction
tmp = ix - OFF;
i = (tmp >> (23 - LOGF_TABLE_BITS)) % N;
k = (int32_t)tmp >> 23;
iz = ix - (tmp & 0xff800000);
invc = T[i].invc;
logc = T[i].logc;
z = (double_t)asfloat(iz);
Decompose as:
where .
Polynomial Approximation
r = z * invc - 1;
y0 = logc + (double_t)k * Ln2;
r2 = r * r;
y = A[1] * r + A[2];
y = A[0] * r2 + y;
y = y * r2 + (y0 + r);
Approximation Formula:
where is approximated using a 3rd degree polynomial.
Numerical Stability Analysis
Error Control:
- • Entries and polynomial coefficients optimized for the target range
- • Use double precision for intermediate calculations
- • Polynomial design ensures that the function value and first derivative match at
Precision Assurance: Error is less than 2 ULP across the entire domain.
Handling of Subnormal Numbers
Normalization method for subnormal numbers is the same as that of <span>log2f</span>:
ix = asuint(x * 0x1p23f);
ix -= 23 << 23;
Performance Optimization Strategies
Algorithm-Level Optimizations
- 1. Unified Infrastructure: The three logarithmic functions share a similar table lookup and polynomial approximation framework
- 2. Range Reduction: Convert arbitrary inputs to a small range to improve polynomial approximation accuracy
- 3. Table Optimization: 16-entry tables balance precision and cache efficiency
Implementation-Level Optimizations
- 1. Bit Manipulation: Directly manipulate floating-point bit patterns to quickly extract exponents and mantissas
- 2. Double Precision Intermediate Calculations: Use double precision for critical calculations to reduce rounding errors
- 3. Pipelined Polynomial Calculations: Optimize the order of polynomial evaluations to reduce instruction dependencies
Fast Path for Special Values
- • Provide quick returns for cases
- • Early checks and handling for special values (0, infinity, NaN)
- • Use
<span>predict_false</span>to hint the compiler to optimize rare paths
Compliance with Standards
Compliance with IEEE 754 Standard
- 1. Handling of Special Values:
- •
- •
- •
- • (when )
- •
Preservation of Mathematical Properties
- • Monotonically increasing function
- • Satisfies the basic algebraic properties of logarithmic functions
- • Maintains continuity within the domain
Conclusion
The implementation of the logarithmic function family in musl libc demonstrates a high level of engineering practice in numerical computation:
Subtlety of Algorithm Design
- 1. Unified Architecture: The three logarithmic functions share a core algorithm framework, reducing code duplication
- 2. Precise Range Reduction: Quickly normalize inputs to the optimal range through bit manipulation
- 3. Optimized Approximations: Use the most suitable approximation method based on the characteristics of different functions
Guarantee of Numerical Stability
Through multi-layer control mechanisms:
- • Numerical optimization of entries and polynomial coefficients
- • Precision maintenance of double precision intermediate calculations
- • Error control through high/low separation
- • Special handling of boundary cases
Engineering Excellence
- 1. Balance of Performance and Precision: Optimize performance while ensuring precision
- 2. Portability: Independent of specific hardware features
- 3. Maintainability: Clear structural design and ample comments
The implementations of these three logarithmic functions are a model for numerical computation library design, with design philosophies including:
- • Layered Processing: Use different precision algorithms based on input ranges
- • Utilization of Mathematical Identities: Optimize calculations based on the algebraic properties of logarithmic functions
- • Error Analysis Driven: Guide algorithm selection based on rigorous error analysis
Compared to directly using the change of base formula, these specially optimized implementations:
- • Provide higher precision within their respective domains
- • Offer correct behavior for boundary cases
- • Maintain good performance while ensuring precision
This perfect balance between algorithmic innovation, numerical stability, and engineering practice makes the logarithmic function family in musl libc a reliable foundation for high-quality mathematical computation, providing a solid numerical basis for applications in scientific computing, engineering analysis, and machine learning.