Nomenclature and Identities

Three logarithm bases are commonly used in engineering and computing:

\[ \ln(x) = \log_e(x) \qquad \log(x) = \log_{10}(x) \qquad \lg(x) = \log_2(x) \]

Key identities (valid for any base f):

\[ f(a \cdot b) = f(a) + f(b) \qquad f(a/b) = f(a) - f(b) \qquad f(a^b) = b \cdot f(a) \]

Conversion between bases:

\[ \lg(x) = \frac{\ln(x)}{\ln(2)} = \frac{\log(x)}{\log(2)} \qquad \ln(x) = \frac{\lg(x)}{\lg(e)} \]

Borchardt's Algorithm

A simple rational approximation to the natural logarithm:

\[ \ln(x) \approx \frac{6(x-1)}{x + 1 + 4\sqrt{x}} \]

Accurate to about 3 significant figures for \(x\) near 1. For a PIC without hardware square root, this alone is not practical, but serves as a useful reference.

Factoring Method for Binary Logarithms

The identity \(f(a \cdot b) = f(a) + f(b)\) lets us decompose any number into factors whose logarithms we know. For binary logarithms, we factor \(x\) as:

\[ x = 2^n \cdot c, \qquad 1 \le c \le 2 \]
\[ \lg(x) = n + \lg(c) \]

Finding \(n\) is easy: it equals the position of the most significant bit. The challenge is computing \(\lg(c)\) for \(c \in [1, 2)\).

Method 3a — Factors of the form \(2^i/(2^i - 1)\)

Build a lookup table:

\[ \text{log2arr}[i] = \lg\!\left(\frac{2^i}{2^i - 1}\right), \qquad i = 1, 2, \ldots, M \]

The first values: \(\lg(2), \lg(4/3), \lg(8/7), \lg(16/15), \ldots\)

Algorithm (Knuth Vol.1, section 1.2.3, exercise 25):

// Input: 16-bit x > 0. Output: y = lg(x)
// L1. Initialize
y = 0;
z = x >> 1;
k = 1;

// L2–L5. Main loop
while(x != 1) {
    if(x - z >= 1) {        // L3: Compare
        x = x - z;          // L4: Reduce
        z = x >> k;
        y = y + log2arr[k]; //     Add partial log
    } else {
        z = z >> 1;         // L5: Shift
        k = k + 1;
    }
}

The division \(x / (2^k/(2^k-1))\) simplifies to a shift:

\[ x \cdot \frac{2^k - 1}{2^k} = x - \frac{x}{2^k} = x - (x \gg k) \]

Method 3b — Factors of the form \(1 + 2^{-(i+1)}\)

Alternative table:

\[ \text{log2arr}[i] = \lg\!\left(1 + 2^{-(i+1)}\right), \qquad i = 0, 1, \ldots, M \]

Values: \(\lg(3/2), \lg(5/4), \lg(9/8), \lg(17/16), \ldots\)

for(i = 1, d = 0.5; i < M; i++, d /= 2) {
    if(x > 1 + d) {
        x /= (1 + d);
        g += log2arr[i-1];
    }
}

The division by \((1 + 2^{-i})\) can be expanded as a series:

\[ \frac{x}{1 + 2^{-i}} = x - x \cdot 2^{-i} + x \cdot 2^{-2i} - \cdots = x - (x \gg i) + (x \gg 2i) - \cdots \]

Table Look-up with Linear Interpolation

After range-reducing \(x\) to \([1, 2)\) using bit manipulation, apply linear interpolation between tabulated values:

\[ \lg(x) \approx (x - a)\cdot\frac{\lg(b) - \lg(a)}{b - a} + \lg(a) \]

When \(a\) and \(b\) are consecutive table entries separated by a power of 2, the division reduces to a right shift:

\[ \lg(x) \approx \text{(index bits of } x) + \text{interpolation from fractional bits} \]
// Scale x so MSB is in bit 15
g = 15;
while(g && !(x & 0x8000)) { x <<= 1; g--; }
if(!g) return 0;

x <<= 1;                    // Normalize: remove known MSB
j = x >> 12;                // 4-bit table index
x_minus_a = x & 0x0FFF;    // Fractional part

// Linear interpolation (shift instead of divide)
gf = log_table[j] + (x_minus_a * (log_table[j+1] - log_table[j])) >> 12;
Example: Finding lg(0x3456) with a 16-entry table of lg(0x1000·i):
lg(0x3456) = (0x3456 − 0x3000) × lg(4/3)/0x1000 + lg(0x3000) ≈ 13.697
True value: ~13.710. Error < 0.1%. ✓

Series Expansions

Useful series for computing natural logarithms without tables:

\[ \ln(1+x) = x - \frac{x^2}{2} + \frac{x^3}{3} - \frac{x^4}{4} + \cdots, \quad |x| < 1 \]
\[ \ln(x) = \left(\frac{x-1}{x}\right) + \frac{1}{2}\left(\frac{x-1}{x}\right)^2 + \frac{1}{3}\left(\frac{x-1}{x}\right)^3 + \cdots, \quad x \ge \tfrac{1}{2} \]
\[ \ln\!\left(\frac{x+1}{x-1}\right) = 2\left(\frac{1}{x} + \frac{1}{3x^3} + \frac{1}{5x^5} + \cdots\right), \quad |x| \ge 1 \]

Algorithm Comparison

MethodOperations/callRAMFlashBest for
Math libraryManyLowHighComputers with FPU
Borchardt~5Very lowLowRough estimates
Factoring 3a~M shiftsM wordsLow8-bit MCUs, no multiply
Factoring 3b~M shiftsM wordsLow8-bit MCUs, no multiply
Table + interpolation2 mult + 1 shiftN wordsMediumSpeed + accuracy balance
Series expansionMany multVery lowLowArbitrary precision
Fixed-point scaling warningThe log2arr[] tables must be scaled appropriately for fixed-point arithmetic. If the sum of all entries (≈ 1.79 for method 3a) is less than the maximum possible logarithm, some values may be underestimated — unless factors are repeated, as in the factoring algorithm. Always verify the algorithm handles your full input range.