xref: /btstack/3rd-party/lc3-google/src/fastmath.h (revision 4930cef6e21e6da2d7571b9259c7f0fb8bed3d01)
1*4930cef6SMatthias Ringwald /******************************************************************************
2*4930cef6SMatthias Ringwald  *
3*4930cef6SMatthias Ringwald  *  Copyright 2022 Google LLC
4*4930cef6SMatthias Ringwald  *
5*4930cef6SMatthias Ringwald  *  Licensed under the Apache License, Version 2.0 (the "License");
6*4930cef6SMatthias Ringwald  *  you may not use this file except in compliance with the License.
7*4930cef6SMatthias Ringwald  *  You may obtain a copy of the License at:
8*4930cef6SMatthias Ringwald  *
9*4930cef6SMatthias Ringwald  *  http://www.apache.org/licenses/LICENSE-2.0
10*4930cef6SMatthias Ringwald  *
11*4930cef6SMatthias Ringwald  *  Unless required by applicable law or agreed to in writing, software
12*4930cef6SMatthias Ringwald  *  distributed under the License is distributed on an "AS IS" BASIS,
13*4930cef6SMatthias Ringwald  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*4930cef6SMatthias Ringwald  *  See the License for the specific language governing permissions and
15*4930cef6SMatthias Ringwald  *  limitations under the License.
16*4930cef6SMatthias Ringwald  *
17*4930cef6SMatthias Ringwald  ******************************************************************************/
18*4930cef6SMatthias Ringwald 
19*4930cef6SMatthias Ringwald /**
20*4930cef6SMatthias Ringwald  * LC3 - Mathematics function approximation
21*4930cef6SMatthias Ringwald  */
22*4930cef6SMatthias Ringwald 
23*4930cef6SMatthias Ringwald #ifndef __LC3_FASTMATH_H
24*4930cef6SMatthias Ringwald #define __LC3_FASTMATH_H
25*4930cef6SMatthias Ringwald 
26*4930cef6SMatthias Ringwald #include <stdint.h>
27*4930cef6SMatthias Ringwald #include <math.h>
28*4930cef6SMatthias Ringwald 
29*4930cef6SMatthias Ringwald 
30*4930cef6SMatthias Ringwald /**
31*4930cef6SMatthias Ringwald  * Fast 2^n approximation
32*4930cef6SMatthias Ringwald  * x               Operand, range -8 to 8
33*4930cef6SMatthias Ringwald  * return          2^x approximation (max relative error ~ 7e-6)
34*4930cef6SMatthias Ringwald  */
35*4930cef6SMatthias Ringwald static inline float fast_exp2f(float x)
36*4930cef6SMatthias Ringwald {
37*4930cef6SMatthias Ringwald     float y;
38*4930cef6SMatthias Ringwald 
39*4930cef6SMatthias Ringwald     /* --- Polynomial approx in range -0.5 to 0.5 --- */
40*4930cef6SMatthias Ringwald 
41*4930cef6SMatthias Ringwald     static const float c[] = { 1.27191277e-09, 1.47415221e-07,
42*4930cef6SMatthias Ringwald         1.35510312e-05, 9.38375815e-04, 4.33216946e-02 };
43*4930cef6SMatthias Ringwald 
44*4930cef6SMatthias Ringwald     y = (    c[0]) * x;
45*4930cef6SMatthias Ringwald     y = (y + c[1]) * x;
46*4930cef6SMatthias Ringwald     y = (y + c[2]) * x;
47*4930cef6SMatthias Ringwald     y = (y + c[3]) * x;
48*4930cef6SMatthias Ringwald     y = (y + c[4]) * x;
49*4930cef6SMatthias Ringwald     y = (y + 1.f);
50*4930cef6SMatthias Ringwald 
51*4930cef6SMatthias Ringwald     /* --- Raise to the power of 16  --- */
52*4930cef6SMatthias Ringwald 
53*4930cef6SMatthias Ringwald     y = y*y;
54*4930cef6SMatthias Ringwald     y = y*y;
55*4930cef6SMatthias Ringwald     y = y*y;
56*4930cef6SMatthias Ringwald     y = y*y;
57*4930cef6SMatthias Ringwald 
58*4930cef6SMatthias Ringwald     return y;
59*4930cef6SMatthias Ringwald }
60*4930cef6SMatthias Ringwald 
61*4930cef6SMatthias Ringwald /**
62*4930cef6SMatthias Ringwald  * Fast log2(x) approximation
63*4930cef6SMatthias Ringwald  * x               Operand, greater than 0
64*4930cef6SMatthias Ringwald  * return          log2(x) approximation (max absolute error ~ 1e-4)
65*4930cef6SMatthias Ringwald  */
66*4930cef6SMatthias Ringwald static inline float fast_log2f(float x)
67*4930cef6SMatthias Ringwald {
68*4930cef6SMatthias Ringwald     float y;
69*4930cef6SMatthias Ringwald     int e;
70*4930cef6SMatthias Ringwald 
71*4930cef6SMatthias Ringwald     /* --- Polynomial approx in range 0.5 to 1 --- */
72*4930cef6SMatthias Ringwald 
73*4930cef6SMatthias Ringwald     static const float c[] = {
74*4930cef6SMatthias Ringwald         -1.29479677, 5.11769018, -8.42295281, 8.10557963, -3.50567360 };
75*4930cef6SMatthias Ringwald 
76*4930cef6SMatthias Ringwald     x = frexpf(x, &e);
77*4930cef6SMatthias Ringwald 
78*4930cef6SMatthias Ringwald     y = (    c[0]) * x;
79*4930cef6SMatthias Ringwald     y = (y + c[1]) * x;
80*4930cef6SMatthias Ringwald     y = (y + c[2]) * x;
81*4930cef6SMatthias Ringwald     y = (y + c[3]) * x;
82*4930cef6SMatthias Ringwald     y = (y + c[4]);
83*4930cef6SMatthias Ringwald 
84*4930cef6SMatthias Ringwald     /* --- Add log2f(2^e) and return --- */
85*4930cef6SMatthias Ringwald 
86*4930cef6SMatthias Ringwald     return e + y;
87*4930cef6SMatthias Ringwald }
88*4930cef6SMatthias Ringwald 
89*4930cef6SMatthias Ringwald /**
90*4930cef6SMatthias Ringwald  * Fast log10(x) approximation
91*4930cef6SMatthias Ringwald  * x               Operand, greater than 0
92*4930cef6SMatthias Ringwald  * return          log10(x) approximation (max absolute error ~ 1e-4)
93*4930cef6SMatthias Ringwald  */
94*4930cef6SMatthias Ringwald static inline float fast_log10f(float x)
95*4930cef6SMatthias Ringwald {
96*4930cef6SMatthias Ringwald     return log10f(2) * fast_log2f(x);
97*4930cef6SMatthias Ringwald }
98*4930cef6SMatthias Ringwald 
99*4930cef6SMatthias Ringwald /**
100*4930cef6SMatthias Ringwald  * Fast `10 * log10(x)` (or dB) approximation in fixed Q16
101*4930cef6SMatthias Ringwald  * x               Operand, in range 2^-63 to 2^63 (1e-19 to 1e19)
102*4930cef6SMatthias Ringwald  * return          10 * log10(x) in fixed Q16 (-190 to 192 dB)
103*4930cef6SMatthias Ringwald  *
104*4930cef6SMatthias Ringwald  * - The 0 value is accepted and return the minimum value ~ -191dB
105*4930cef6SMatthias Ringwald  * - This function assumed that float 32 bits is coded IEEE 754
106*4930cef6SMatthias Ringwald  */
107*4930cef6SMatthias Ringwald static inline int32_t fast_db_q16(float x)
108*4930cef6SMatthias Ringwald {
109*4930cef6SMatthias Ringwald     /* --- Table in Q15 --- */
110*4930cef6SMatthias Ringwald 
111*4930cef6SMatthias Ringwald     static const uint16_t t[][2] = {
112*4930cef6SMatthias Ringwald 
113*4930cef6SMatthias Ringwald         /* [n][0] = 10 * log10(2) * log2(1 + n/32), with n = [0..15]     */
114*4930cef6SMatthias Ringwald         /* [n][1] = [n+1][0] - [n][0] (while defining [16][0])           */
115*4930cef6SMatthias Ringwald 
116*4930cef6SMatthias Ringwald         {     0, 4379 }, {  4379, 4248 }, {  8627, 4125 }, { 12753, 4009 },
117*4930cef6SMatthias Ringwald         { 16762, 3899 }, { 20661, 3795 }, { 24456, 3697 }, { 28153, 3603 },
118*4930cef6SMatthias Ringwald         { 31755, 3514 }, { 35269, 3429 }, { 38699, 3349 }, { 42047, 3272 },
119*4930cef6SMatthias Ringwald         { 45319, 3198 }, { 48517, 3128 }, { 51645, 3061 }, { 54705, 2996 },
120*4930cef6SMatthias Ringwald 
121*4930cef6SMatthias Ringwald         /* [n][0] = 10 * log10(2) * log2(1 + n/32) - 10 * log10(2) / 2,  */
122*4930cef6SMatthias Ringwald         /*     with n = [16..31]                                         */
123*4930cef6SMatthias Ringwald         /* [n][1] = [n+1][0] - [n][0] (while defining [32][0])           */
124*4930cef6SMatthias Ringwald 
125*4930cef6SMatthias Ringwald         {  8381, 2934 }, { 11315, 2875 }, { 14190, 2818 }, { 17008, 2763 },
126*4930cef6SMatthias Ringwald         { 19772, 2711 }, { 22482, 2660 }, { 25142, 2611 }, { 27754, 2564 },
127*4930cef6SMatthias Ringwald         { 30318, 2519 }, { 32837, 2475 }, { 35312, 2433 }, { 37744, 2392 },
128*4930cef6SMatthias Ringwald         { 40136, 2352 }, { 42489, 2314 }, { 44803, 2277 }, { 47080, 2241 },
129*4930cef6SMatthias Ringwald 
130*4930cef6SMatthias Ringwald     };
131*4930cef6SMatthias Ringwald 
132*4930cef6SMatthias Ringwald     /* --- Approximation ---
133*4930cef6SMatthias Ringwald      *
134*4930cef6SMatthias Ringwald      *   10 * log10(x^2) = 10 * log10(2) * log2(x^2)
135*4930cef6SMatthias Ringwald      *
136*4930cef6SMatthias Ringwald      *   And log2(x^2) = 2 * log2( (1 + m) * 2^e )
137*4930cef6SMatthias Ringwald      *                 = 2 * (e + log2(1 + m)) , with m in range [0..1]
138*4930cef6SMatthias Ringwald      *
139*4930cef6SMatthias Ringwald      * Split the float values in :
140*4930cef6SMatthias Ringwald      *   e2  Double value of the exponent (2 * e + k)
141*4930cef6SMatthias Ringwald      *   hi  High 5 bits of mantissa, for precalculated result `t[hi][0]`
142*4930cef6SMatthias Ringwald      *   lo  Low 16 bits of mantissa, for linear interpolation `t[hi][1]`
143*4930cef6SMatthias Ringwald      *
144*4930cef6SMatthias Ringwald      * Two cases, from the range of the mantissa :
145*4930cef6SMatthias Ringwald      *   0 to 0.5   `k = 0`, use 1st part of the table
146*4930cef6SMatthias Ringwald      *   0.5 to 1   `k = 1`, use 2nd part of the table  */
147*4930cef6SMatthias Ringwald 
148*4930cef6SMatthias Ringwald     union { float f; uint32_t u; } x2 = { .f = x*x };
149*4930cef6SMatthias Ringwald 
150*4930cef6SMatthias Ringwald     int e2 = (int)(x2.u >> 22) - 2*127;
151*4930cef6SMatthias Ringwald     int hi = (x2.u >> 18) & 0x1f;
152*4930cef6SMatthias Ringwald     int lo = (x2.u >>  2) & 0xffff;
153*4930cef6SMatthias Ringwald 
154*4930cef6SMatthias Ringwald     return e2 * 49321 + t[hi][0] + ((t[hi][1] * lo) >> 16);
155*4930cef6SMatthias Ringwald }
156*4930cef6SMatthias Ringwald 
157*4930cef6SMatthias Ringwald 
158*4930cef6SMatthias Ringwald #endif /* __LC3_FASTMATH_H */
159