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