[][src]Function nikisas::ln

pub fn ln(x: f32) -> f32

Computes natural logarithm of a number.

Notes

Theoretical input domain is (0, max(f32)] ≈ (0, 3.40282347e+38], but near zero the values get quite inaccurate.

Examples

use nikisas::{ln, consts::E};
assert_eq!(ln(E), 1.0);

Implementation details

First, special cases are handled. If x is 1, then the result is simply 0. If x is near Euler's number, then the result is simply 1. Otherwise, the input x is decomposed into real y and integer k such that

  x = y * 2^n, where 1 ≤ y < 2

At this point, we might use

ln(x) = n * ln(2) + ln(y)

but that would lead to catastrophic cancellation for cases where n = -1 and y ≈ 2. Therefore, we adjust the decomposition if y > sqrt(2) as follows

  y <- y / 2
  n <- n + 1

This keeps the equality x = y * 2^n true, but avoids mentioned cancellation and shifts y to be symmetric around logarithm's root at 1, in range [1/sqrt(2), sqrt(2)].

For reasons unclear to me, polynomial approximation of ln(1 + z) for -a/2 ≤ z < a/2 is easier than of ln(z) for 1 - a/2 ≤ z < 1 + a/2. Thus, we set z = y - 1 and approximate ln(1 + z) using a polynomial in the form:

  ln(1 + z) ≈ z - 1/2 * z^2 + z^3 * P(z)

The "prefix" corresponds to coefficients of low-degree Taylor polynomial of ln(1 + z) in z = 0 and P is found using special minimax algorithm in Sollya.

The reconstruction then follows already mentioned identity:

  ln(x) = n * ln(2) + ln(y) = n * ln(2) + ln(1 + z)