Brief Introduction to the Implementation Approach in glibc:
For the logarithm of any base, we can utilize the change of base formula:
logkx=lnklnx(1)
The term lnk in equation (1) is a constant, so for logarithms of any base, we only need to calculate lnx.
Computation of lnx
In advanced calculus, we learned the following Taylor series:
ln(1+x)=x−21x2+31x3−41x4+⋯=k=1∑∞k(−1)kxk(2)
Suppose we want to find lnx; naturally, we can set t=x−1, then:
ln(x)=ln(1+t)=k=1∑∞k(−1)ktk(2)
However, expanding the series to infinity in practical calculations is often not feasible. If we expand it to the nth term, the Taylor series with the Peano remainder term can be expressed as:
ln(1+t)=t−21t2+31t3−41t4+⋯=k=1∑nk(−1)ktk+o(tn)(3)
Note that the Peano remainder term here is o(tn), representing the error term. If t>1 (or x>2), the error in the above formula may become significantly large with the increase of t or x.
However, another formula is available:
lnx=2(x+1x−1+31(x+1x−1)3+51(x+1x−1)5+…)=2k=0∑∞2k+11(x+1x−1)2k+1(4)
Here's an informal proof for equation (4):
Replace x in equation (2) with x1 and −x1, respectively:
ln(1+x1)ln(1−x1)=ln(xx+1)=k=1∑∞k(−1)kxk1=−k=1∑∞kxk1
Note:
ln(xx−1)⟹−ln(xx−1)⟹ln(x−1x)=−k=1∑∞kxk1=k=1∑∞kxk1=k=1∑∞kxk1
Then:
ln(xx+1)+ln(x−1x)=ln(x−1x+1)k=1∑nkxk(−1)k+k=1∑nkxk1=2k=0∑n2k+11x2k+11
This yields:
ln(x−1x+1)=2k=0∑n2k+11x2k+11
Let z=(x−1)(x+1), then x=(z+1)(z−1). Substituting this into the above formula gives equation (4).
The advantage of this formula is that if we expand it to the nth term:
lnx=2k=0∑n2k+11(x+1x−1)2k+1+o((x+1x−1)2k+1)(5)
The remainder term is o((x+1)2k+1(x−1)), and as limx→+∞(x+1x−1)2k+1=1, the remainder term ensures that the error remains within the range of 1.
However, this is still not sufficient, as the error of 1 is still too large. According to the analysis of the remainder term above, the value of x should be closer to 1 for higher precision.
Considering the IEEE 754 floating-point standard, we know that any floating-point number is represented in the computer as:
x=1.xxx×2exp
This means that we can directly obtain the exponent (exp) and the fractional part (1.xxx) using bitwise operations.
Since the floating-point number is already in this form, we can directly use the fractional part 1.xxx. If we calculate ln(1.xxx) using the earlier formula, it is equivalent to calculating ln(2expx). According to the logarithmic formula:
ln(2expx)=lnx−exp×ln2
Therefore:
lnx=ln(2expx)+exp×ln2
This completes the calculation of lnx, equivalent to computing the logarithm of any base.
However, this is a general overview, and glibc employs various precision improvement techniques in its implementation.