openMSX
fast_log2.hh
Go to the documentation of this file.
1#ifndef FAST_LOG2_HH
2#define FAST_LOG2_HH
3
4// Based on:
5// fast_log
6// https://github.com/nadavrot/fast_log/tree/main
7// MIT License
8// Copyright (c) 2022 Nadav Rotem
9//
10// This version is modified/simplified to better suite openMSX:
11// * double -> float
12// * simplified fast_frexpf() (no longer works for negative or zero values)
13// * calculate log base-2 instead of natural-log.
14
15// Main advantage over std::log() or std::log2():
16// * A lot faster, and can be (auto-)vectorized (verified gcc-11 and above)
17// Main disadvantage:
18// * Not as accurate, max error: ~0.25%. std::log() is accurate to 1 ULP.
19
20#include <bit>
21#include <cstdint>
22#include <utility>
23
24// Similar to std::frexp():
25// decompose 'x' into 'm' and 'e' so that
26// x == m * pow(2, e)
27// with: 0.5 <= m < 1.0
28// This function has some limitations
29// * It doesn't work at all for negative values.
30// * It gives an inaccurate result for x=0 (it returns m=0.5, e=-126, that's
31// very close but not exact).
32// These limitations allow this version to be much faster: it can easily be
33// inlined and it's suitable for (auto-)vectorization.
34inline std::pair<float, int> fast_frexpf(float x)
35{
36 // See: https://en.wikipedia.org/wiki/IEEE_754#Basic_and_interchange_formats
37 auto bits = std::bit_cast<uint32_t>(x);
38 //if (bits == 0) return {0.0f, 0};
39 auto mantissa = bits & 0x007fffff;
40 auto exponent = bits >> 23; // note: wrong if x < 0
41 auto frac = std::bit_cast<float>(mantissa | 0x3f000000);
42 return {frac, exponent - 126};
43}
44
45// Compute a fast _approximation_ for the base-2 logarithm of 'x'.
46inline float fast_log2(float x)
47{
48 auto [m, exp] = fast_frexpf(x); // split x into: x == pow(2, exp) * m
49
50 // Use a degree-3 polynomial to approximate log2(m) over the interval [0.5, 1)
51 // val = a*pow(m,3) + b*pow(m,2) + c*m + d
52 static constexpr float a = 1.33755322f;
53 static constexpr float b = -4.42852392f;
54 static constexpr float c = 6.30371424f;
55 static constexpr float d = -3.21430967f;
56 float val = d + m * (c + m * (b + m * a));
57
58 return float(exp) + val;
59}
60
61#endif
float fast_log2(float x)
Definition fast_log2.hh:46
std::pair< float, int > fast_frexpf(float x)
Definition fast_log2.hh:34