Implementación eficiente de logaritmo natural (ln) y exponenciación

Implementación eficiente de logaritmo natural (ln) y exponenciación

Usar la serie de Taylor no es la forma más simple ni la más rápida de hacer esto. La mayoría de las implementaciones profesionales utilizan polinomios de aproximación. Te mostraré cómo generar uno en Maple (es un programa de álgebra computacional), usando el algoritmo Remez.

Para 3 dígitos de precisión, ejecute los siguientes comandos en Maple:

with(numapprox):
Digits := 8
minimax(ln(x), x = 1 .. 2, 4, 1, 'maxerror')
maxerror

Su respuesta es el siguiente polinomio:

-1.7417939 + (2.8212026 + (-1.4699568 + (0.44717955 - 0.056570851 * x) * x) * x) * x

Con el error máximo de:0.000061011436

Generamos un polinomio que se aproxima a ln(x), pero solo dentro del intervalo [1..2]. No es prudente aumentar el intervalo, porque eso aumentaría aún más el error máximo. En lugar de eso, haz la siguiente descomposición:

Entonces, primero encuentre la potencia más alta de 2, que aún es más pequeña que el número (consulte:¿Cuál es la forma más rápida/eficiente de encontrar el bit establecido más alto (msb) en un número entero en C?). Ese número es en realidad el logaritmo en base 2. Divida con ese valor, luego el resultado entra en el intervalo 1..2. Al final tendremos que sumar n*ln(2) para obtener el resultado final.

Un ejemplo de implementación para números>=1:

float ln(float y) {
    int log2;
    float divisor, x, result;

    log2 = msb((int)y); // See: https://stackoverflow.com/a/4970859/6630230
    divisor = (float)(1 << log2);
    x = y / divisor;    // normalized value between [1.0, 2.0]

    result = -1.7417939 + (2.8212026 + (-1.4699568 + (0.44717955 - 0.056570851 * x) * x) * x) * x;
    result += ((float)log2) * 0.69314718; // ln(2) = 0.69314718

    return result;
}

Aunque si planea usarlo solo en el intervalo [1.0, 2.0], entonces la función es como:

float ln(float x) {
    return -1.7417939 + (2.8212026 + (-1.4699568 + (0.44717955 - 0.056570851 * x) * x) * x) * x;
}

La serie de Taylor para e^x converge extremadamente rápido y puede ajustar su implementación con la precisión que necesita. (http://en.wikipedia.org/wiki/Taylor_series)

La serie de Taylor para log no es tan agradable...


¿Funcionaría la tabla básica con interpolación entre valores? Si los rangos de valores son limitados (lo que es probable en su caso; dudo que las lecturas de temperatura tengan un rango amplio) y no se requieren altas precisiones, puede funcionar. Debería ser fácil de probar en una máquina normal.

Este es uno de los muchos temas sobre la representación de tablas de funciones:¿Cálculo frente a tablas de búsqueda para el rendimiento del valor del seno?