1*49fe348cSAndroid Build Coastguard Worker /******************************************************************************
2*49fe348cSAndroid Build Coastguard Worker *
3*49fe348cSAndroid Build Coastguard Worker * Copyright 2022 Google LLC
4*49fe348cSAndroid Build Coastguard Worker *
5*49fe348cSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
6*49fe348cSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*49fe348cSAndroid Build Coastguard Worker * You may obtain a copy of the License at:
8*49fe348cSAndroid Build Coastguard Worker *
9*49fe348cSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
10*49fe348cSAndroid Build Coastguard Worker *
11*49fe348cSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*49fe348cSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*49fe348cSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*49fe348cSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*49fe348cSAndroid Build Coastguard Worker * limitations under the License.
16*49fe348cSAndroid Build Coastguard Worker *
17*49fe348cSAndroid Build Coastguard Worker ******************************************************************************/
18*49fe348cSAndroid Build Coastguard Worker
19*49fe348cSAndroid Build Coastguard Worker #ifndef __LC3_FASTMATH_H
20*49fe348cSAndroid Build Coastguard Worker #define __LC3_FASTMATH_H
21*49fe348cSAndroid Build Coastguard Worker
22*49fe348cSAndroid Build Coastguard Worker #include <stdint.h>
23*49fe348cSAndroid Build Coastguard Worker #include <float.h>
24*49fe348cSAndroid Build Coastguard Worker #include <math.h>
25*49fe348cSAndroid Build Coastguard Worker
26*49fe348cSAndroid Build Coastguard Worker
27*49fe348cSAndroid Build Coastguard Worker /**
28*49fe348cSAndroid Build Coastguard Worker * IEEE 754 Floating point representation
29*49fe348cSAndroid Build Coastguard Worker */
30*49fe348cSAndroid Build Coastguard Worker
31*49fe348cSAndroid Build Coastguard Worker #define LC3_IEEE754_SIGN_SHL (31)
32*49fe348cSAndroid Build Coastguard Worker #define LC3_IEEE754_SIGN_MASK (1 << LC3_IEEE754_SIGN_SHL)
33*49fe348cSAndroid Build Coastguard Worker
34*49fe348cSAndroid Build Coastguard Worker #define LC3_IEEE754_EXP_SHL (23)
35*49fe348cSAndroid Build Coastguard Worker #define LC3_IEEE754_EXP_MASK (0xff << LC3_IEEE754_EXP_SHL)
36*49fe348cSAndroid Build Coastguard Worker #define LC3_IEEE754_EXP_BIAS (127)
37*49fe348cSAndroid Build Coastguard Worker
38*49fe348cSAndroid Build Coastguard Worker
39*49fe348cSAndroid Build Coastguard Worker /**
40*49fe348cSAndroid Build Coastguard Worker * Fast multiply floating-point number by integral power of 2
41*49fe348cSAndroid Build Coastguard Worker * x Operand, finite number
42*49fe348cSAndroid Build Coastguard Worker * exp Exponent such that 2^x is finite
43*49fe348cSAndroid Build Coastguard Worker * return 2^exp
44*49fe348cSAndroid Build Coastguard Worker */
lc3_ldexpf(float _x,int exp)45*49fe348cSAndroid Build Coastguard Worker static inline float lc3_ldexpf(float _x, int exp) {
46*49fe348cSAndroid Build Coastguard Worker union { float f; int32_t s; } x = { .f = _x };
47*49fe348cSAndroid Build Coastguard Worker
48*49fe348cSAndroid Build Coastguard Worker if (x.s & LC3_IEEE754_EXP_MASK)
49*49fe348cSAndroid Build Coastguard Worker x.s += exp << LC3_IEEE754_EXP_SHL;
50*49fe348cSAndroid Build Coastguard Worker
51*49fe348cSAndroid Build Coastguard Worker return x.f;
52*49fe348cSAndroid Build Coastguard Worker }
53*49fe348cSAndroid Build Coastguard Worker
54*49fe348cSAndroid Build Coastguard Worker /**
55*49fe348cSAndroid Build Coastguard Worker * Fast convert floating-point number to fractional and integral components
56*49fe348cSAndroid Build Coastguard Worker * x Operand, finite number
57*49fe348cSAndroid Build Coastguard Worker * exp Return the exponent part
58*49fe348cSAndroid Build Coastguard Worker * return The normalized fraction in [0.5:1[
59*49fe348cSAndroid Build Coastguard Worker */
lc3_frexpf(float _x,int * exp)60*49fe348cSAndroid Build Coastguard Worker static inline float lc3_frexpf(float _x, int *exp) {
61*49fe348cSAndroid Build Coastguard Worker union { float f; uint32_t u; } x = { .f = _x };
62*49fe348cSAndroid Build Coastguard Worker
63*49fe348cSAndroid Build Coastguard Worker int e = (x.u & LC3_IEEE754_EXP_MASK) >> LC3_IEEE754_EXP_SHL;
64*49fe348cSAndroid Build Coastguard Worker *exp = e - (LC3_IEEE754_EXP_BIAS - 1);
65*49fe348cSAndroid Build Coastguard Worker
66*49fe348cSAndroid Build Coastguard Worker x.u = (x.u & ~LC3_IEEE754_EXP_MASK) |
67*49fe348cSAndroid Build Coastguard Worker ((LC3_IEEE754_EXP_BIAS - 1) << LC3_IEEE754_EXP_SHL);
68*49fe348cSAndroid Build Coastguard Worker
69*49fe348cSAndroid Build Coastguard Worker return x.f;
70*49fe348cSAndroid Build Coastguard Worker }
71*49fe348cSAndroid Build Coastguard Worker
72*49fe348cSAndroid Build Coastguard Worker /**
73*49fe348cSAndroid Build Coastguard Worker * Fast 2^n approximation
74*49fe348cSAndroid Build Coastguard Worker * x Operand, range -100 to 100
75*49fe348cSAndroid Build Coastguard Worker * return 2^x approximation (max relative error ~ 4e-7)
76*49fe348cSAndroid Build Coastguard Worker */
lc3_exp2f(float x)77*49fe348cSAndroid Build Coastguard Worker static inline float lc3_exp2f(float x)
78*49fe348cSAndroid Build Coastguard Worker {
79*49fe348cSAndroid Build Coastguard Worker /* --- 2^(i/8) for i from 0 to 7 --- */
80*49fe348cSAndroid Build Coastguard Worker
81*49fe348cSAndroid Build Coastguard Worker static const float e[] = {
82*49fe348cSAndroid Build Coastguard Worker 1.00000000e+00, 1.09050773e+00, 1.18920712e+00, 1.29683955e+00,
83*49fe348cSAndroid Build Coastguard Worker 1.41421356e+00, 1.54221083e+00, 1.68179283e+00, 1.83400809e+00 };
84*49fe348cSAndroid Build Coastguard Worker
85*49fe348cSAndroid Build Coastguard Worker /* --- Polynomial approx in range 0 to 1/8 --- */
86*49fe348cSAndroid Build Coastguard Worker
87*49fe348cSAndroid Build Coastguard Worker static const float p[] = {
88*49fe348cSAndroid Build Coastguard Worker 1.00448128e-02, 5.54563260e-02, 2.40228756e-01, 6.93147140e-01 };
89*49fe348cSAndroid Build Coastguard Worker
90*49fe348cSAndroid Build Coastguard Worker /* --- Split the operand ---
91*49fe348cSAndroid Build Coastguard Worker *
92*49fe348cSAndroid Build Coastguard Worker * Such as x = k/8 + y, with k an integer, and |y| < 0.5/8
93*49fe348cSAndroid Build Coastguard Worker *
94*49fe348cSAndroid Build Coastguard Worker * Note that `fast-math` compiler option leads to rounding error,
95*49fe348cSAndroid Build Coastguard Worker * disable optimisation with `volatile`. */
96*49fe348cSAndroid Build Coastguard Worker
97*49fe348cSAndroid Build Coastguard Worker volatile union { float f; int32_t s; } v;
98*49fe348cSAndroid Build Coastguard Worker
99*49fe348cSAndroid Build Coastguard Worker v.f = x + 0x1.8p20f;
100*49fe348cSAndroid Build Coastguard Worker int k = v.s;
101*49fe348cSAndroid Build Coastguard Worker x -= v.f - 0x1.8p20f;
102*49fe348cSAndroid Build Coastguard Worker
103*49fe348cSAndroid Build Coastguard Worker /* --- Compute 2^x, with |x| < 1 ---
104*49fe348cSAndroid Build Coastguard Worker * Perform polynomial approximation in range -0.5/8 to 0.5/8,
105*49fe348cSAndroid Build Coastguard Worker * and muplity by precomputed value of 2^(i/8), i in [0:7] */
106*49fe348cSAndroid Build Coastguard Worker
107*49fe348cSAndroid Build Coastguard Worker union { float f; int32_t s; } y;
108*49fe348cSAndroid Build Coastguard Worker
109*49fe348cSAndroid Build Coastguard Worker y.f = ( p[0]) * x;
110*49fe348cSAndroid Build Coastguard Worker y.f = (y.f + p[1]) * x;
111*49fe348cSAndroid Build Coastguard Worker y.f = (y.f + p[2]) * x;
112*49fe348cSAndroid Build Coastguard Worker y.f = (y.f + p[3]) * x;
113*49fe348cSAndroid Build Coastguard Worker y.f = (y.f + 1.f) * e[k & 7];
114*49fe348cSAndroid Build Coastguard Worker
115*49fe348cSAndroid Build Coastguard Worker /* --- Add the exponent --- */
116*49fe348cSAndroid Build Coastguard Worker
117*49fe348cSAndroid Build Coastguard Worker y.s += (k >> 3) << LC3_IEEE754_EXP_SHL;
118*49fe348cSAndroid Build Coastguard Worker
119*49fe348cSAndroid Build Coastguard Worker return y.f;
120*49fe348cSAndroid Build Coastguard Worker }
121*49fe348cSAndroid Build Coastguard Worker
122*49fe348cSAndroid Build Coastguard Worker /**
123*49fe348cSAndroid Build Coastguard Worker * Fast log2(x) approximation
124*49fe348cSAndroid Build Coastguard Worker * x Operand, greater than 0
125*49fe348cSAndroid Build Coastguard Worker * return log2(x) approximation (max absolute error ~ 1e-4)
126*49fe348cSAndroid Build Coastguard Worker */
lc3_log2f(float x)127*49fe348cSAndroid Build Coastguard Worker static inline float lc3_log2f(float x)
128*49fe348cSAndroid Build Coastguard Worker {
129*49fe348cSAndroid Build Coastguard Worker float y;
130*49fe348cSAndroid Build Coastguard Worker int e;
131*49fe348cSAndroid Build Coastguard Worker
132*49fe348cSAndroid Build Coastguard Worker /* --- Polynomial approx in range 0.5 to 1 --- */
133*49fe348cSAndroid Build Coastguard Worker
134*49fe348cSAndroid Build Coastguard Worker static const float c[] = {
135*49fe348cSAndroid Build Coastguard Worker -1.29479677, 5.11769018, -8.42295281, 8.10557963, -3.50567360 };
136*49fe348cSAndroid Build Coastguard Worker
137*49fe348cSAndroid Build Coastguard Worker x = lc3_frexpf(x, &e);
138*49fe348cSAndroid Build Coastguard Worker
139*49fe348cSAndroid Build Coastguard Worker y = ( c[0]) * x;
140*49fe348cSAndroid Build Coastguard Worker y = (y + c[1]) * x;
141*49fe348cSAndroid Build Coastguard Worker y = (y + c[2]) * x;
142*49fe348cSAndroid Build Coastguard Worker y = (y + c[3]) * x;
143*49fe348cSAndroid Build Coastguard Worker y = (y + c[4]);
144*49fe348cSAndroid Build Coastguard Worker
145*49fe348cSAndroid Build Coastguard Worker /* --- Add log2f(2^e) and return --- */
146*49fe348cSAndroid Build Coastguard Worker
147*49fe348cSAndroid Build Coastguard Worker return e + y;
148*49fe348cSAndroid Build Coastguard Worker }
149*49fe348cSAndroid Build Coastguard Worker
150*49fe348cSAndroid Build Coastguard Worker /**
151*49fe348cSAndroid Build Coastguard Worker * Fast log10(x) approximation
152*49fe348cSAndroid Build Coastguard Worker * x Operand, greater than 0
153*49fe348cSAndroid Build Coastguard Worker * return log10(x) approximation (max absolute error ~ 1e-4)
154*49fe348cSAndroid Build Coastguard Worker */
lc3_log10f(float x)155*49fe348cSAndroid Build Coastguard Worker static inline float lc3_log10f(float x)
156*49fe348cSAndroid Build Coastguard Worker {
157*49fe348cSAndroid Build Coastguard Worker return log10f(2) * lc3_log2f(x);
158*49fe348cSAndroid Build Coastguard Worker }
159*49fe348cSAndroid Build Coastguard Worker
160*49fe348cSAndroid Build Coastguard Worker /**
161*49fe348cSAndroid Build Coastguard Worker * Fast `10 * log10(x)` (or dB) approximation in fixed Q16
162*49fe348cSAndroid Build Coastguard Worker * x Operand, in range 2^-63 to 2^63 (1e-19 to 1e19)
163*49fe348cSAndroid Build Coastguard Worker * return 10 * log10(x) in fixed Q16 (-190 to 192 dB)
164*49fe348cSAndroid Build Coastguard Worker *
165*49fe348cSAndroid Build Coastguard Worker * - The 0 value is accepted and return the minimum value ~ -191dB
166*49fe348cSAndroid Build Coastguard Worker * - This function assumed that float 32 bits is coded IEEE 754
167*49fe348cSAndroid Build Coastguard Worker */
lc3_db_q16(float x)168*49fe348cSAndroid Build Coastguard Worker static inline int32_t lc3_db_q16(float x)
169*49fe348cSAndroid Build Coastguard Worker {
170*49fe348cSAndroid Build Coastguard Worker /* --- Table in Q15 --- */
171*49fe348cSAndroid Build Coastguard Worker
172*49fe348cSAndroid Build Coastguard Worker static const uint16_t t[][2] = {
173*49fe348cSAndroid Build Coastguard Worker
174*49fe348cSAndroid Build Coastguard Worker /* [n][0] = 10 * log10(2) * log2(1 + n/32), with n = [0..15] */
175*49fe348cSAndroid Build Coastguard Worker /* [n][1] = [n+1][0] - [n][0] (while defining [16][0]) */
176*49fe348cSAndroid Build Coastguard Worker
177*49fe348cSAndroid Build Coastguard Worker { 0, 4379 }, { 4379, 4248 }, { 8627, 4125 }, { 12753, 4009 },
178*49fe348cSAndroid Build Coastguard Worker { 16762, 3899 }, { 20661, 3795 }, { 24456, 3697 }, { 28153, 3603 },
179*49fe348cSAndroid Build Coastguard Worker { 31755, 3514 }, { 35269, 3429 }, { 38699, 3349 }, { 42047, 3272 },
180*49fe348cSAndroid Build Coastguard Worker { 45319, 3198 }, { 48517, 3128 }, { 51645, 3061 }, { 54705, 2996 },
181*49fe348cSAndroid Build Coastguard Worker
182*49fe348cSAndroid Build Coastguard Worker /* [n][0] = 10 * log10(2) * log2(1 + n/32) - 10 * log10(2) / 2, */
183*49fe348cSAndroid Build Coastguard Worker /* with n = [16..31] */
184*49fe348cSAndroid Build Coastguard Worker /* [n][1] = [n+1][0] - [n][0] (while defining [32][0]) */
185*49fe348cSAndroid Build Coastguard Worker
186*49fe348cSAndroid Build Coastguard Worker { 8381, 2934 }, { 11315, 2875 }, { 14190, 2818 }, { 17008, 2763 },
187*49fe348cSAndroid Build Coastguard Worker { 19772, 2711 }, { 22482, 2660 }, { 25142, 2611 }, { 27754, 2564 },
188*49fe348cSAndroid Build Coastguard Worker { 30318, 2519 }, { 32837, 2475 }, { 35312, 2433 }, { 37744, 2392 },
189*49fe348cSAndroid Build Coastguard Worker { 40136, 2352 }, { 42489, 2314 }, { 44803, 2277 }, { 47080, 2241 },
190*49fe348cSAndroid Build Coastguard Worker
191*49fe348cSAndroid Build Coastguard Worker };
192*49fe348cSAndroid Build Coastguard Worker
193*49fe348cSAndroid Build Coastguard Worker /* --- Approximation ---
194*49fe348cSAndroid Build Coastguard Worker *
195*49fe348cSAndroid Build Coastguard Worker * 10 * log10(x^2) = 10 * log10(2) * log2(x^2)
196*49fe348cSAndroid Build Coastguard Worker *
197*49fe348cSAndroid Build Coastguard Worker * And log2(x^2) = 2 * log2( (1 + m) * 2^e )
198*49fe348cSAndroid Build Coastguard Worker * = 2 * (e + log2(1 + m)) , with m in range [0..1]
199*49fe348cSAndroid Build Coastguard Worker *
200*49fe348cSAndroid Build Coastguard Worker * Split the float values in :
201*49fe348cSAndroid Build Coastguard Worker * e2 Double value of the exponent (2 * e + k)
202*49fe348cSAndroid Build Coastguard Worker * hi High 5 bits of mantissa, for precalculated result `t[hi][0]`
203*49fe348cSAndroid Build Coastguard Worker * lo Low 16 bits of mantissa, for linear interpolation `t[hi][1]`
204*49fe348cSAndroid Build Coastguard Worker *
205*49fe348cSAndroid Build Coastguard Worker * Two cases, from the range of the mantissa :
206*49fe348cSAndroid Build Coastguard Worker * 0 to 0.5 `k = 0`, use 1st part of the table
207*49fe348cSAndroid Build Coastguard Worker * 0.5 to 1 `k = 1`, use 2nd part of the table */
208*49fe348cSAndroid Build Coastguard Worker
209*49fe348cSAndroid Build Coastguard Worker union { float f; uint32_t u; } x2 = { .f = x*x };
210*49fe348cSAndroid Build Coastguard Worker
211*49fe348cSAndroid Build Coastguard Worker int e2 = (int)(x2.u >> 22) - 2*127;
212*49fe348cSAndroid Build Coastguard Worker int hi = (x2.u >> 18) & 0x1f;
213*49fe348cSAndroid Build Coastguard Worker int lo = (x2.u >> 2) & 0xffff;
214*49fe348cSAndroid Build Coastguard Worker
215*49fe348cSAndroid Build Coastguard Worker return e2 * 49321 + t[hi][0] + ((t[hi][1] * lo) >> 16);
216*49fe348cSAndroid Build Coastguard Worker }
217*49fe348cSAndroid Build Coastguard Worker
218*49fe348cSAndroid Build Coastguard Worker
219*49fe348cSAndroid Build Coastguard Worker #endif /* __LC3_FASTMATH_H */
220