xref: /btstack/3rd-party/lc3-google/tables/fastmath.py (revision 6897da5c53aac5b1f90f41b5b15d0bd43d61dfff)
14930cef6SMatthias Ringwald#!/usr/bin/env python3
24930cef6SMatthias Ringwald#
34930cef6SMatthias Ringwald# Copyright 2022 Google LLC
44930cef6SMatthias Ringwald#
54930cef6SMatthias Ringwald# Licensed under the Apache License, Version 2.0 (the "License");
64930cef6SMatthias Ringwald# you may not use this file except in compliance with the License.
74930cef6SMatthias Ringwald# You may obtain a copy of the License at
84930cef6SMatthias Ringwald#
94930cef6SMatthias Ringwald#     http://www.apache.org/licenses/LICENSE-2.0
104930cef6SMatthias Ringwald#
114930cef6SMatthias Ringwald# Unless required by applicable law or agreed to in writing, software
124930cef6SMatthias Ringwald# distributed under the License is distributed on an "AS IS" BASIS,
134930cef6SMatthias Ringwald# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144930cef6SMatthias Ringwald# See the License for the specific language governing permissions and
154930cef6SMatthias Ringwald# limitations under the License.
164930cef6SMatthias Ringwald#
174930cef6SMatthias Ringwald
184930cef6SMatthias Ringwaldimport numpy as np
194930cef6SMatthias Ringwaldimport matplotlib.pyplot as plt
204930cef6SMatthias Ringwald
214930cef6SMatthias Ringwald
22*6897da5cSDirk Helbigdef fast_exp2(x, t, p):
234930cef6SMatthias Ringwald
244930cef6SMatthias Ringwald    p = p.astype(np.float32)
254930cef6SMatthias Ringwald    x = x.astype(np.float32)
264930cef6SMatthias Ringwald
27*6897da5cSDirk Helbig    m = ((x + 0.5/8) % (1/8)) - (0.5/8)
28*6897da5cSDirk Helbig    e = int((x - m) * 8)
294930cef6SMatthias Ringwald
30*6897da5cSDirk Helbig    y = ((((p[0]*m) + p[1])*m + p[2])*m + p[3])*m + p[4]
31*6897da5cSDirk Helbig    y = y * 2**(e // 8) * t[e % 8]
32*6897da5cSDirk Helbig
33*6897da5cSDirk Helbig    return y.astype(np.float32)
344930cef6SMatthias Ringwald
354930cef6SMatthias Ringwalddef approx_exp2():
364930cef6SMatthias Ringwald
37*6897da5cSDirk Helbig    x = np.arange(0, 1/8, step=1e-6)
38*6897da5cSDirk Helbig    p = np.polyfit(x, 2 ** x, 4)
39*6897da5cSDirk Helbig    t = [ 2**(i/8) for i in range(8) ]
404930cef6SMatthias Ringwald
41*6897da5cSDirk Helbig    x =  np.arange(-10, 10, step=1e-3)
42*6897da5cSDirk Helbig    y = [ fast_exp2(x[i], t, p) for i in range(len(x)) ]
43*6897da5cSDirk Helbig
444930cef6SMatthias Ringwald    e = np.abs(y - 2**x) / (2 ** x)
454930cef6SMatthias Ringwald
46*6897da5cSDirk Helbig    print('{{ {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, \n'
47*6897da5cSDirk Helbig           '  {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, '.format(*t))
48*6897da5cSDirk Helbig    print('{{ {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e} }}'.format(*p))
494930cef6SMatthias Ringwald    print('Max relative error: ', np.max(e))
504930cef6SMatthias Ringwald    print('Max RMS error: ', np.sqrt(np.mean(e ** 2)))
514930cef6SMatthias Ringwald
524930cef6SMatthias Ringwald    if False:
534930cef6SMatthias Ringwald        fig, (ax1, ax2) = plt.subplots(2)
544930cef6SMatthias Ringwald
554930cef6SMatthias Ringwald        ax1.plot(x, 2**x, label='Reference')
564930cef6SMatthias Ringwald        ax1.plot(x, y, label='Approximation')
574930cef6SMatthias Ringwald        ax1.legend()
584930cef6SMatthias Ringwald
594930cef6SMatthias Ringwald        ax2.plot(x, e, label='Relative Error')
604930cef6SMatthias Ringwald        ax2.legend()
614930cef6SMatthias Ringwald
624930cef6SMatthias Ringwald        plt.show()
634930cef6SMatthias Ringwald
644930cef6SMatthias Ringwald
654930cef6SMatthias Ringwalddef fast_log2(x, p):
664930cef6SMatthias Ringwald
674930cef6SMatthias Ringwald    p = p.astype(np.float32)
684930cef6SMatthias Ringwald    x = x.astype(np.float32)
694930cef6SMatthias Ringwald
704930cef6SMatthias Ringwald    (x, e) = np.frexp(x)
714930cef6SMatthias Ringwald
724930cef6SMatthias Ringwald    y = ((((p[0]*x) + p[1])*x + p[2])*x + p[3])*x + p[4]
734930cef6SMatthias Ringwald
744930cef6SMatthias Ringwald    return (e ) + y.astype(np.float32)
754930cef6SMatthias Ringwald
764930cef6SMatthias Ringwalddef approx_log2():
774930cef6SMatthias Ringwald
784930cef6SMatthias Ringwald    x = np.logspace(-1, 0, base=2, num=100)
794930cef6SMatthias Ringwald    p = np.polyfit(x, np.log2(x), 4)
804930cef6SMatthias Ringwald
814930cef6SMatthias Ringwald    x = np.logspace(-2, 5, num=10000)
824930cef6SMatthias Ringwald    y = [ fast_log2(x[i], p) for i in range(len(x)) ]
834930cef6SMatthias Ringwald    e = np.abs(y - np.log2(x))
844930cef6SMatthias Ringwald
854930cef6SMatthias Ringwald    print('{{ {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e} }}'
864930cef6SMatthias Ringwald                .format(p[0], p[1], p[2], p[3], p[4]))
874930cef6SMatthias Ringwald    print('Max absolute error: ', np.max(e))
884930cef6SMatthias Ringwald    print('Max RMS error: ', np.sqrt(np.mean(e ** 2)))
894930cef6SMatthias Ringwald
904930cef6SMatthias Ringwald    if False:
914930cef6SMatthias Ringwald        fig, (ax1, ax2) = plt.subplots(2)
924930cef6SMatthias Ringwald
934930cef6SMatthias Ringwald        ax1.plot(x, np.log2(x),  label='Reference')
944930cef6SMatthias Ringwald        ax1.plot(x, y, label='Approximation')
954930cef6SMatthias Ringwald        ax1.legend()
964930cef6SMatthias Ringwald
974930cef6SMatthias Ringwald        ax2.plot(x, e, label = 'Absolute error')
984930cef6SMatthias Ringwald        ax2.legend()
994930cef6SMatthias Ringwald
1004930cef6SMatthias Ringwald        plt.show()
1014930cef6SMatthias Ringwald
1024930cef6SMatthias Ringwald
1034930cef6SMatthias Ringwalddef table_db_q16():
1044930cef6SMatthias Ringwald
1054930cef6SMatthias Ringwald    k = 10 * np.log10(2);
1064930cef6SMatthias Ringwald
1074930cef6SMatthias Ringwald    for i in range(32):
1084930cef6SMatthias Ringwald        a = k * np.log2(np.ldexp(32 + i  , -5)) - (i // 16) * (k/2);
1094930cef6SMatthias Ringwald        b = k * np.log2(np.ldexp(32 + i+1, -5)) - (i // 16) * (k/2);
1104930cef6SMatthias Ringwald
1114930cef6SMatthias Ringwald        an = np.ldexp(a, 15) + 0.5
1124930cef6SMatthias Ringwald        bn = np.ldexp(b - a, 15) + 0.5
1134930cef6SMatthias Ringwald        print('{{ {:5d}, {:4d} }},'
1144930cef6SMatthias Ringwald            .format(int(np.ldexp(a, 15) + 0.5),
1154930cef6SMatthias Ringwald                    int(np.ldexp(b - a, 15) + 0.5)),
1164930cef6SMatthias Ringwald            end = ' ' if i % 4 < 3 else '\n')
1174930cef6SMatthias Ringwald
1184930cef6SMatthias Ringwald
1194930cef6SMatthias Ringwaldif __name__ == '__main__':
1204930cef6SMatthias Ringwald
1214930cef6SMatthias Ringwald    print('\n--- Approximation of 2^n ---')
1224930cef6SMatthias Ringwald    approx_exp2()
1234930cef6SMatthias Ringwald
1244930cef6SMatthias Ringwald    print('\n--- Approximation of log2(n) ---')
1254930cef6SMatthias Ringwald    approx_log2()
1264930cef6SMatthias Ringwald
1274930cef6SMatthias Ringwald    print('\n--- Table of fixed Q16 dB ---')
1284930cef6SMatthias Ringwald    table_db_q16()
1294930cef6SMatthias Ringwald
1304930cef6SMatthias Ringwald    print('')
131