├── .gitignore ├── CMakeLists.txt ├── atan.hpp ├── common.hpp ├── cos.hpp ├── exp.hpp ├── exp10.hpp ├── exp2.hpp ├── graphs ├── cosine.py ├── db_to_gain.py ├── denormalise_hz.py ├── gain_to_db.py ├── hz_to_midi.py ├── midi_to_hz.py ├── normalise_hz.py ├── ratio_to_midi_offset.py ├── sine.py ├── sqrt.py ├── tan.py └── tanh.py ├── log.hpp ├── log10.hpp ├── log2.hpp ├── main.cpp ├── pow.hpp ├── sin.hpp ├── sqrt.hpp ├── tan.hpp └── tanh.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .vscode 3 | build -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.7) 2 | project(fastmaths) 3 | set(CMAKE_CXX_STANDARD 20) 4 | add_executable(main main.cpp) -------------------------------------------------------------------------------- /atan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | // https://nghiaho.com/?p=997 4 | static inline double rajan_wang_joyal_may(double x) noexcept { 5 | // M_PI_4 0.785398163397448309616 6 | return M_PI_4 * x - x*(fabs(x) - 1)*(0.2447 + 0.0663*fabs(x)); 7 | } 8 | 9 | // https://mazzo.li/posts/vectorized-atan2.html 10 | inline float mazzoli_scalar(float x) { 11 | static const float a1 = 0.99997726f; 12 | static const float a3 = -0.33262347f; 13 | static const float a5 = 0.19354346f; 14 | static const float a7 = -0.11643287f; 15 | static const float a9 = 0.05265332f; 16 | static const float a11 = -0.01172120f; 17 | 18 | float x_sq = x*x; 19 | return x * (a1 + x_sq * (a3 + x_sq * (a5 + x_sq * (a7 + x_sq * (a9 + x_sq * a11))))); 20 | } 21 | -------------------------------------------------------------------------------- /common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define SIGN_MASK_32 0x80000000 3 | 4 | 5 | template 6 | D convert_type(T v) { 7 | union { T a; D b; } o { v }; 8 | return o.b; 9 | } 10 | -------------------------------------------------------------------------------- /cos.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "sin.hpp" 4 | 5 | namespace fast { 6 | namespace cos { 7 | 8 | template 9 | constexpr T stl(T x) noexcept { return std::cos(x); } 10 | 11 | // JUCE 12 | // https://github.com/juce-framework/JUCE/blob/master/modules/juce_dsp/maths/juce_FastMathApproximations.h 13 | template 14 | constexpr T pade (T x) noexcept { 15 | auto x2 = x * x; 16 | auto numerator = -(-39251520 + x2 * (18471600 + x2 * (-1075032 + 14615 * x2))); 17 | auto denominator = 39251520 + x2 * (1154160 + x2 * (16632 + x2 * 127)); 18 | return numerator / denominator; 19 | } 20 | 21 | // https://stackoverflow.com/a/28050328 22 | static inline float milianw(float x) noexcept { 23 | x *= 0.15915494309189535f; // 1 / 2π 24 | x -= 0.25f + std::floor(x + 0.25f); 25 | x *= 16 * (std::abs(x) - 0.5f); 26 | return x; 27 | } 28 | static inline float milianw_precise(float x) noexcept { 29 | x *= 0.15915494309189535f; // 1 / 2π 30 | x -= 0.25f + std::floor(x + 0.25f); 31 | x *= 16 * (std::abs(x) - 0.5f); 32 | x += 0.225f * x * (std::abs(x) - 1); 33 | return x; 34 | } 35 | 36 | // https://stackoverflow.com/a/71674578 37 | static inline float juha(float x) noexcept { 38 | return 4 * (0.5f - 0.31830988618f * x) * (1 - std::abs(0.5f - 0.31830988618f * x)); 39 | } 40 | 41 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fasttrig.h 42 | static inline float mineiro (float x) { 43 | static const float halfpi = 1.5707963267948966f; 44 | static const float halfpiminustwopi = -4.7123889803846899f; 45 | float offset = (x > halfpi) ? halfpiminustwopi : halfpi; 46 | return sin::mineiro (x + offset); 47 | } 48 | 49 | static inline float mineiro_faster (float x) 50 | { 51 | static const float twooverpi = 0.63661977236758134f; 52 | static const float p = 0.54641335845679634f; 53 | 54 | union { float f; uint32_t i; } vx = { x }; 55 | vx.i &= 0x7FFFFFFF; 56 | 57 | float qpprox = 1.0f - twooverpi * vx.f; 58 | 59 | return qpprox + p * qpprox * (1.0f - qpprox * qpprox); 60 | } 61 | 62 | // https://www.musicdsp.org/en/latest/Other/115-sin-cos-tan-approximation.html 63 | float wildmagic0 (float fAngle) noexcept { 64 | float fASqr = fAngle * fAngle; 65 | float fResult = 3.705e-02f; 66 | fResult *= fASqr; 67 | fResult -= 4.967e-01f; 68 | fResult *= fASqr; 69 | fResult += 1.0f; 70 | return fResult; 71 | } 72 | float wildmagic1 (float fAngle) noexcept { 73 | float fASqr = fAngle * fAngle; 74 | float fResult = -2.605e-07f; 75 | fResult *= fASqr; 76 | fResult += 2.47609e-05f; 77 | fResult *= fASqr; 78 | fResult -= 1.3888397e-03f; 79 | fResult *= fASqr; 80 | fResult += 4.16666418e-02f; 81 | fResult *= fASqr; 82 | fResult -= 4.999999963e-01f; 83 | fResult *= fASqr; 84 | fResult += 1.0f; 85 | return fResult; 86 | } 87 | 88 | } // namespace cos 89 | } // namespace fast 90 | -------------------------------------------------------------------------------- /exp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.hpp" 3 | 4 | namespace fast { 5 | namespace exp { 6 | 7 | template 8 | constexpr T stl(T x) noexcept { return std::exp(x); } 9 | 10 | 11 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 12 | /* 1065353216 + 1 */ 13 | static inline float ekmett_ub(float a) noexcept { 14 | union { float f; int x; } u; 15 | u.x = (int) (12102203 * a + 1065353217); 16 | return u.f; 17 | } 18 | 19 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 20 | /* 1065353216 - 722019 */ 21 | static inline float ekmett_lb(float a) { 22 | union { float f; int x; } u; 23 | u.x = (int) (12102203 * a + 1064631197); 24 | return u.f; 25 | } 26 | 27 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 28 | /* 1065353216 - 486411 = 1064866805 */ 29 | static inline float schraudolph(float a) noexcept { 30 | union { float f; int x; } u; 31 | u.x = (int) (12102203 * a + 1064866805); 32 | return u.f; 33 | } 34 | 35 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fastexp.h 36 | static inline float mineiro (float x) noexcept { 37 | // return exp2::mineiro (1.442695040f * p); 38 | float p = 1.442695040f * x; 39 | float offset = (p < 0) ? 1.0f : 0.0f; 40 | float clipp = (p < -126) ? -126.0f : p; 41 | int w = (int)clipp; 42 | float z = clipp - w + offset; 43 | union { uint32_t i; float f; } v = { static_cast ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) }; 44 | 45 | return v.f; 46 | } 47 | 48 | static inline float mineiro_faster (float x) noexcept { 49 | // return exp2::mineiro_faster (1.442695040f * p); 50 | float p = 1.442695040f * x; 51 | float clipp = (p < -126) ? -126.0f : p; 52 | union { uint32_t i; float f; } v = { static_cast ( (1 << 23) * (clipp + 126.94269504f) ) }; 53 | return v.f; 54 | } 55 | 56 | } // namespace exp 57 | } // namespace fast 58 | -------------------------------------------------------------------------------- /exp10.hpp: -------------------------------------------------------------------------------- 1 | #include "./common.hpp" 2 | #include "./pow.hpp" 3 | #include "./exp.hpp" 4 | // 10^x or pow(10, x) 5 | 6 | namespace fast { 7 | namespace exp10 { 8 | 9 | static inline float powx_stl(float x) { return pow::stl(10.0f, x); } 10 | static inline float powx_ekmett_fast(float x) { return pow::ekmett_fast(10.0f, x); } 11 | // static inline float powx_ekmett_fast_lb(float x) { return pow::ekmett_fast_lb(10.0f, x); } 12 | static inline float powx_ekmett_fast_lb(float b) noexcept { 13 | int i = (int)(b * 27262975 + 1064631197); 14 | return convert_type(i); 15 | } 16 | static inline float powx_ekmett_fast_ub(float x) { return pow::ekmett_fast_ub(10.0f, x); } 17 | static inline float powx_ekmett_fast_precise(float x) { return pow::ekmett_fast_precise(10.0f, x); } 18 | static inline float powx_ekmett_fast_better_precise(float x) { return pow::ekmett_fast_better_precise(10.0f, x); } 19 | 20 | 21 | 22 | static constexpr float ln10 = 2.30258509299404568402f; 23 | 24 | static inline float exp_stl(float x) noexcept { return exp::stl(x * ln10); } 25 | static inline float exp_ekmett_ub(float x) noexcept { return exp::ekmett_ub(x * ln10); } 26 | static inline float exp_ekmett_lb(float x) noexcept { return exp::ekmett_lb(x * ln10); } 27 | // static inline float exp_schraudolph(float x) noexcept { return exp::schraudolph(x * ln10); } 28 | static inline float exp_schraudolph(float a) noexcept { 29 | // int i = (int) (12102203 * a + 1064866805); 30 | int i = (int) (27866352.22018782f * a + 1064866805); 31 | return convert_type(i); 32 | 33 | } 34 | // static inline float exp_mineiro(float x) noexcept { return exp::mineiro(x * ln10); } 35 | static inline float exp_mineiro(float x) noexcept { 36 | // float p = 1.442695040f * ln10 * x; 37 | // float p = log2(10) * x; 38 | float p = 3.3219280948873626f * x; 39 | float offset = (p < 0) ? 1.0f : 0.0f; 40 | float clipp = (p < -126) ? -126.0f : p; 41 | int w = (int)clipp; 42 | float z = clipp - w + offset; 43 | union { uint32_t i; float f; } v = { static_cast ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) }; 44 | 45 | return v.f; 46 | } 47 | static inline float exp_mineiro_faster(float x) noexcept { return exp::mineiro_faster(x * ln10); } 48 | 49 | 50 | 51 | 52 | } // namespace exp10 53 | } // namespace fast 54 | -------------------------------------------------------------------------------- /exp2.hpp: -------------------------------------------------------------------------------- 1 | #include "./pow.hpp" 2 | #include "./exp.hpp" 3 | // 2^x or pow(2, x) 4 | 5 | namespace fast { 6 | namespace exp2 { 7 | 8 | static inline float stl(float x) noexcept { return std::exp2f(x); } 9 | 10 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fastexp.h 11 | static inline float mineiro (float p) noexcept { 12 | float offset = (p < 0) ? 1.0f : 0.0f; 13 | float clipp = (p < -126) ? -126.0f : p; 14 | int w = (int)clipp; 15 | float z = clipp - w + offset; 16 | union { uint32_t i; float f; } v = { static_cast ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) }; 17 | 18 | return v.f; 19 | } 20 | 21 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fastexp.h 22 | static inline float mineiro_faster (float p) noexcept { 23 | float clipp = (p < -126) ? -126.0f : p; 24 | union { uint32_t i; float f; } v = { static_cast ( (1 << 23) * (clipp + 126.94269504f) ) }; 25 | return v.f; 26 | } 27 | 28 | static inline float schraudolph(float a) noexcept { 29 | union { float f; int x; } u; 30 | u.x = (int) (8388607.888014112f * a + 1064866805); 31 | return u.f; 32 | } 33 | 34 | // https://www.musicdsp.org/en/latest/Other/50-base-2-exp.html 35 | static inline double desoras (const double val) noexcept { 36 | int e; 37 | double ret; 38 | 39 | if (val >= 0) { 40 | e = int (val); 41 | ret = val - (e - 1); 42 | ((*(1 + (int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20; 43 | } 44 | else { 45 | e = int (val + 1023); 46 | ret = val - (e - 1024); 47 | ((*(1 + (int *) &ret)) &= ~(2047 << 20)) += e << 20; 48 | } 49 | return (ret); 50 | } 51 | 52 | static inline double desoras_pos (const double val) noexcept { 53 | int e; 54 | double ret; 55 | 56 | e = int (val); 57 | ret = val - (e - 1); 58 | ((*(1 + (int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20; 59 | return (ret); 60 | } 61 | 62 | static inline float powx_stl(float x) noexcept { return pow::stl(2.0f, x); } 63 | static inline float powx_ekmett_fast(float x) noexcept { return pow::ekmett_fast(2.0f, x); } 64 | static inline float powx_ekmett_fast_lb(float x) noexcept { return pow::ekmett_fast_lb(2.0f, x); } 65 | static inline float powx_ekmett_fast_ub(float x) noexcept { return pow::ekmett_fast_ub(2.0f, x); } 66 | static inline float powx_ekmett_fast_precise(float x) noexcept { return pow::ekmett_fast_precise(2.0f, x); } 67 | static inline float powx_ekmett_fast_better_precise(float x) noexcept { return pow::ekmett_fast_better_precise(2.0f, x); } 68 | 69 | static constexpr float ln2 = 0.693147180559945309417f; 70 | 71 | static inline float exp_stl(float x) noexcept { return exp::stl(x * ln2); } 72 | static inline float exp_ekmett_ub(float x) noexcept { return exp::ekmett_ub(x * ln2); } 73 | static inline float exp_ekmett_lb(float x) noexcept { return exp::ekmett_lb(x * ln2); } 74 | static inline float exp_schraudolph(float x) noexcept { return exp::schraudolph(x * ln2); } 75 | static inline float exp_mineiro(float x) noexcept { return exp::mineiro(x * ln2); } 76 | static inline float exp_mineiro_faster(float x) noexcept { return exp::mineiro_faster(x * ln2); } 77 | 78 | } // namespace exp2 79 | } // namespace fast 80 | -------------------------------------------------------------------------------- /graphs/cosine.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import math 4 | 5 | """ 6 | Cos functions can be used in trigonometry, filter 7 | coefficients, and saturation algorithms. 8 | 9 | High precision is needed in generating filter coefficients, 10 | so pade is the only viable option, however it should be 11 | tested how much it effects the cutoff. 12 | For displaying a magnitude graph of a filters cutoff, you 13 | may be able to get away with the very fast functions. The 14 | inputs to cos functions are often well below π which is 15 | where these approximations are most accurate. The func 16 | mineiro_faster is likely a great choice, and perhaps 17 | milianw_precise, however their errors should be plotted 18 | before using them. 19 | 20 | In trigonometry for graphics, the fast wildmagic0 func 21 | yields fantastic speed and precision for right angle 22 | triangles, and mineiro_faster for any other triangle. 23 | In other contexts, milianw is a great function as it cycles 24 | and is cheap to process. 25 | 26 | In saturation, error will result in different tones, so you 27 | should experiment with the sound of different funcs that suit 28 | your needs. For cycling funcs, milianw and milianw_precise 29 | should work great. 30 | 31 | The following table compares the speed and error margin of 32 | different cos approxiamtions used in the following formula: 33 | cos(x) 34 | 35 | SEC xSPEED ERROR NAME 36 | 0.055628 pass 37 | 0.118301 0 stl 38 | 0.082529 2.32 0.000015 mineiro -- bad close to +/- 2π 39 | 0.079378 2.63 0.00001 wildmagic1 -- bad after +/- π 40 | 0.079035 2.67 0.00055 milianw_precise -- cycles well. slightly accurate 41 | 0.077439 2.87 0.00001 pade -- bad close to +/- 2π 42 | 0.071404 3.97 0.043 milianw -- cycles well. slightly rough 43 | 0.069655 4.46 0.0054 mineiro_faster -- bad after +/-π 44 | 0.066535 5.74 0.000005 wildmagic0 -- bad after +/- π/2 45 | 0.064191 7.31 bad juha -- bad before -π. decent up to 1.5π 46 | 47 | 48 | - pass = no processing 49 | - stl = cos(x) 50 | - xSpeed of the cos function calculated: (stl - pass) / (other_sec - pass) 51 | - Error is is taken at the worst point within +/- π, excexpt for the full cosine 52 | function, where is error is taken anywhere that looks bad 53 | """ 54 | 55 | stl = [1.000000000000,0.923879563808,0.707106828690,0.382683306932,-0.000000290067,-0.382683843374,-0.707106530666,-0.923879444599,-1.000000000000,-0.923879444599,-0.707106590271,-0.382683008909,0.000000139071,0.382683277130,0.707106769085,0.923879563808,1.000000000000,0.923879504204,0.707106649876,0.382683604956,0.000000011925,-0.382683575153,-0.707106828690,-0.923879504204,-1.000000000000,-0.923879504204,-0.707106769085,-0.382683396339,-0.000000043711,0.382683426142,0.707106769085,0.923879504204,1.000000000000,0.923879504204,0.707106769085,0.382683426142,-0.000000043711,-0.382683396339,-0.707106769085,-0.923879504204,-1.000000000000,-0.923879504204,-0.707106828690,-0.382683575153,0.000000011925,0.382683604956,0.707106649876,0.923879504204,1.000000000000,0.923879563808,0.707106769085,0.382683277130,0.000000139071,-0.382683008909,-0.707106590271,-0.923879444599,-1.000000000000,-0.923879444599,-0.707106530666,-0.382683843374,-0.000000290067,0.382683306932,0.707106828690,0.923879563808,1.000000000000,] 56 | pade = [-29.586977005005,-26.955038070679,-24.308603286743,-21.664678573608,-19.043243408203,-16.467382431030,-13.963229179382,-11.559699058533,-9.287981033325,-7.180664062500,-5.270432949066,-3.588338375092,-2.161610603333,-1.011082053185,-0.148441568017,0.426434338093,0.727641284466,0.784421980381,0.640869975090,0.353787839413,-0.011441354640,-0.386733770370,-0.708364546299,-0.924213588238,-1.000073552132,-0.923892438412,-0.707108378410,-0.382683575153,-0.000000094781,0.382683455944,0.707106769085,0.923879623413,1.000000000000,0.923879623413,0.707106769085,0.382683455944,-0.000000094781,-0.382683575153,-0.707108378410,-0.923892438412,-1.000073552132,-0.924213588238,-0.708364546299,-0.386733770370,-0.011441354640,0.353787839413,0.640869975090,0.784421980381,0.727641284466,0.426434338093,-0.148441568017,-1.011082053185,-2.161610603333,-3.588338375092,-5.270432949066,-7.180664062500,-9.287981033325,-11.559699058533,-13.963229179382,-16.467382431030,-19.043243408203,-21.664678573608,-24.308603286743,-26.955038070679,-29.586977005005,] 57 | milianw = [1.000000000000,0.937500000000,0.749999523163,0.437499284744,-0.000000953674,-0.437500715256,-0.750000000000,-0.937500000000,-1.000000000000,-0.937499761581,-0.749999523163,-0.437499284744,0.000000953674,0.437500000000,0.750000000000,0.937500238419,1.000000000000,0.937499880791,0.749999761581,0.437500000000,-0.000000000000,-0.437500357628,-0.750000238419,-0.937500000000,-1.000000000000,-0.937499940395,-0.750000000000,-0.437499821186,-0.000000000000,0.437500000000,0.750000000000,0.937500000000,1.000000000000,0.937500000000,0.750000000000,0.437500000000,-0.000000000000,-0.437499821186,-0.750000000000,-0.937499940395,-1.000000000000,-0.937500000000,-0.750000238419,-0.437500357628,-0.000000000000,0.437500000000,0.749999761581,0.937499880791,1.000000000000,0.937500238419,0.750000000000,0.437500000000,0.000000953674,-0.437499284744,-0.749999523163,-0.937499761581,-1.000000000000,-0.937500000000,-0.750000000000,-0.437500715256,-0.000000953674,0.437499284744,0.749999523163,0.937500000000,1.000000000000,] 58 | milianw_precise = [1.000000000000,0.924316406250,0.707811951637,0.382128208876,-0.000000739098,-0.382129609585,-0.707812488079,-0.924316406250,-1.000000000000,-0.924316108227,-0.707811951637,-0.382128208876,0.000000739098,0.382128894329,0.707812488079,0.924316704273,1.000000000000,0.924316287041,0.707812249660,0.382128894329,0.000000000000,-0.382129251957,-0.707812786102,-0.924316406250,-1.000000000000,-0.924316346645,-0.707812488079,-0.382128745317,0.000000000000,0.382128894329,0.707812488079,0.924316406250,1.000000000000,0.924316406250,0.707812488079,0.382128894329,0.000000000000,-0.382128745317,-0.707812488079,-0.924316346645,-1.000000000000,-0.924316406250,-0.707812786102,-0.382129251957,0.000000000000,0.382128894329,0.707812249660,0.924316287041,1.000000000000,0.924316704273,0.707812488079,0.382128894329,0.000000739098,-0.382128208876,-0.707811951637,-0.924316108227,-1.000000000000,-0.924316406250,-0.707812488079,-0.382129609585,-0.000000739098,0.382128208876,0.707811951637,0.924316406250,1.000000000000,] 59 | juha = [-63.000000000000,-59.062500000000,-55.250000000000,-51.562500000000,-47.999992370605,-44.562492370605,-41.250000000000,-38.062500000000,-35.000000000000,-32.062496185303,-29.249994277954,-26.562494277954,-23.999996185303,-21.562500000000,-19.250000000000,-17.062496185303,-15.000000000000,-13.062500000000,-11.250000000000,-9.562500000000,-8.000000000000,-6.562498569489,-5.249999046326,-4.062500000000,-3.000000000000,-2.062500000000,-1.250000000000,-0.562500000000,0.000000000000,0.437500000000,0.750000000000,0.937500000000,1.000000000000,0.937500000000,0.750000000000,0.437500000000,0.000000000000,-0.437499821186,-0.750000000000,-0.937499940395,-1.000000000000,-0.937500000000,-0.750000238419,-0.437500357628,-0.000000000000,0.562500000000,1.249999284744,2.062499284744,3.000000000000,4.062498092651,5.250000000000,6.562500000000,7.999997138977,9.562497138977,11.249997138977,13.062496185303,15.000000000000,17.062500000000,19.250000000000,21.562496185303,23.999996185303,26.562494277954,29.249994277954,32.062500000000,35.000000000000,] 60 | mineiro = [5901065.000000000000,3484812.250000000000,2006961.000000000000,1124276.375000000000,610730.000000000000,320544.312500000000,161842.468750000000,78189.406250000000,35907.546875000000,15544.092773437500,6273.890136718750,2326.371826171875,776.073181152344,225.732910156250,54.493064880371,10.192784309387,1.644728183746,0.726024925709,0.637736558914,0.375405341387,0.000000000000,-0.382704228163,-0.707092881203,-0.923892557621,-0.999986410141,-0.923892557621,-0.707092821598,-0.382703930140,0.000000000000,0.382704049349,0.707092881203,0.923892736435,0.999986410141,0.923892557621,0.707092881203,0.382703542709,-0.000000374052,-0.382703542709,-0.707092881203,-0.923892557621,-0.999986529350,-0.923892736435,-0.707093000412,-0.382704108953,0.000000000000,0.382704108953,0.707092761993,0.923892736435,0.999986767769,0.923892736435,0.707092881203,0.382703542709,0.000000000000,-0.375405102968,-0.637736558914,-0.726024925709,-1.644728183746,-10.192822456360,-54.493167877197,-225.732360839844,-776.073181152344,-2326.371826171875,-6273.893066406250,-15544.102539062500,-35907.593750000000,] 61 | mineiro_faster = [176.594879150391,157.609436035156,140.007049560547,123.736572265625,108.746780395508,94.986404418945,82.404251098633,70.949050903320,60.569602966309,51.214668273926,42.833045959473,35.373493194580,28.784790039062,23.015716552734,18.015026092529,13.731494903564,10.113920211792,7.111050605774,4.671673774719,2.744559764862,1.278480052948,0.222210049629,-0.475475430489,-0.865803122520,-1.000000000000,-0.929291784763,-0.704905033112,-0.378065466881,0.000000000000,0.378065645695,0.704905033112,0.929291844368,1.000000000000,0.929291844368,0.704905033112,0.378065645695,0.000000000000,-0.378065466881,-0.704905033112,-0.929291784763,-1.000000000000,-0.865803122520,-0.475475430489,0.222210049629,1.278480052948,2.744559764862,4.671673774719,7.111050605774,10.113920211792,13.731494903564,18.015026092529,23.015716552734,28.784790039062,35.373493194580,42.833045959473,51.214668273926,60.569602966309,70.949050903320,82.404251098633,94.986404418945,108.746780395508,123.736572265625,140.007049560547,157.609436035156,176.594879150391,] 62 | wildmagic0 = [846.470214843750,741.109252929688,645.757568359375,559.770568847656,482.524169921875,413.415863037109,351.864166259766,297.308380126953,249.209457397461,207.049316406250,170.331024169922,138.578735351562,111.337860107422,88.174850463867,68.677352905273,52.454139709473,39.135189056396,28.371538162231,19.835447311401,13.220292091370,8.240573883057,4.631977558136,2.151313304901,0.576543688774,-0.293225169182,-0.637738227844,-0.615593433380,-0.364243745804,0.000004768372,0.381993114948,0.707708120346,0.924283742905,1.000000000000,0.924283742905,0.707708120346,0.381993114948,0.000004768372,-0.364243745804,-0.615593433380,-0.637738227844,-0.293225169182,0.576543688774,2.151313304901,4.631977558136,8.240573883057,13.220292091370,19.835447311401,28.371538162231,39.135189056396,52.454139709473,68.677352905273,88.174850463867,111.337860107422,138.578735351562,170.331024169922,207.049316406250,249.209457397461,297.308380126953,351.864166259766,413.415863037109,482.524169921875,559.770568847656,645.757568359375,741.109252929688,846.470214843750,] 63 | wildmagic1 = [-14690.991210937500,-10356.614257812500,-7206.882812500000,-4945.788085937500,-3343.775390625000,-2224.655029296875,-1454.687255859375,-933.570129394531,-587.077453613281,-361.064331054688,-216.659011840820,-126.440277099609,-71.434371948242,-38.789386749268,-20.000970840454,-9.582588195801,-4.088638782501,-1.413572311401,-0.303036808968,-0.023871660233,-0.150409817696,-0.432957768440,-0.721932411194,-0.927607297897,-1.000758647919,-0.923993945122,-0.707117557526,-0.382683753967,-0.000000119209,0.382683455944,0.707106709480,0.923879504204,1.000000000000,0.923879504204,0.707106709480,0.382683455944,-0.000000119209,-0.382683753967,-0.707117557526,-0.923993945122,-1.000758647919,-0.927607297897,-0.721932411194,-0.432957768440,-0.150409817696,-0.023871660233,-0.303036808968,-1.413572311401,-4.088638782501,-9.582588195801,-20.000970840454,-38.789386749268,-71.434371948242,-126.440277099609,-216.659011840820,-361.064331054688,-587.077453613281,-933.570129394531,-1454.687255859375,-2224.655029296875,-3343.775390625000,-4945.788085937500,-7206.882812500000,-10356.614257812500,-14690.991210937500,] 64 | 65 | 66 | x_labels = [ 67 | '-4', '', '-3 3/4', '', '-3 1/2', '', '-3 1/4', '', 68 | '-3', '', '-2 3/4', '', '-2 1/2', '', '-2 1/4', '', 69 | '-2', '', '-1 3/4', '', '-1 1/2', '', '-1 1/4', '', 70 | '-π', '', '-3/4', '', '-π/2', '', '-π/4', '', 71 | '0', '', 'π/4', '', 'π/2', '', '3/4', '', 72 | 'π', '', '1 1/4', '', '1 1/2', '', '1 3/4', '', 73 | '2', '', '2 1/4', '', '2 1/2', '', '2 3/4', '', 74 | '3', '', '3 1/4', '', '3 1/2', '', '3 3/4', '', 75 | '4', 76 | ] 77 | 78 | class Styles: 79 | idx = 0 80 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 81 | 82 | def get(self): 83 | s = self.types[self.idx] 84 | self.idx = (self.idx + 1) & 3 85 | return s 86 | 87 | linestyles = Styles() 88 | 89 | fig, ax = plt.subplots() 90 | 91 | x_ticks = [i for i in range(len(x_labels))] 92 | x = [i for i in range(len(stl))] 93 | 94 | # plt.xlabel('phase 0-1') 95 | plt.xticks(ticks=x_ticks, labels=x_labels) 96 | plt.ylabel('mag') 97 | plt.ylim(-1, 1) 98 | plt.xlim(left=(-1.5 * math.pi), right=(1.5 * math.pi)) 99 | 100 | ax.plot(stl, label='stl', linestyle=linestyles.get()) 101 | ax.plot(pade, label='pade', linestyle=linestyles.get()) 102 | ax.plot(milianw, label='milianw', linestyle=linestyles.get()) 103 | ax.plot(milianw_precise, label='milianw_precise', linestyle=linestyles.get()) 104 | # ax.plot(juha, label='juha', linestyle=linestyles.get()) 105 | ax.plot(mineiro, label='mineiro', linestyle=linestyles.get()) 106 | ax.plot(mineiro_faster, label='mineiro_faster', linestyle=linestyles.get()) 107 | ax.plot(wildmagic0, label='wildmagic0', linestyle=linestyles.get()) 108 | ax.plot(wildmagic1, label='wildmagic1', linestyle=linestyles.get()) 109 | 110 | 111 | ax.legend() 112 | plt.show() 113 | -------------------------------------------------------------------------------- /graphs/db_to_gain.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | """ 5 | Converting dB into gain is often used in compressors, and rarely 6 | graphical contexts. High accuracy is an absolute must in 7 | compressors, but in graphics, small errors will result in an 8 | offset of fraction of a pixel. In the case of sidechaining a 9 | signal, lower accuracy may not be noticeable. 10 | 11 | This makes the exp_mineiro function the only viable option 12 | for an audio compressor. It's accurate enough to not introduce 13 | noticeable aliasing, and is considerably faster than using 14 | std::pow(10 ,x). 15 | When pinpoint accuracy is not needed such as when sidechaining 16 | or if used in graphics, the powx_ekmett_fast or exp_schraudolph 17 | function are excellent choices. 18 | 19 | The following table compares the speed and error margin of 20 | different exp10 approxiamtions used in the following formula: 21 | exp10(x / 20) 22 | pow(10, x / 20) 23 | 24 | SEC xSPEED ERROR NAME 25 | 0.055806 pass 26 | 0.185658 1 0 powx_stl 27 | 0.091151 3.67 bad powx_ekmett_fast_precise 28 | 0.090206 3.77 awful powx_ekmett_fast_better_precise 29 | 0.081461 5.06 0.000001 exp_mineiro 30 | 0.066710 11.90 0.15 exp_mineiro_faster 31 | 0.065474 13.43 0.042 exp_ekmett_lb 32 | 0.065244 13.75 0.04 exp_ekmett_ub 33 | 0.063323 17.27 0.023 powx_ekmett_fast 34 | 0.063199 17.56 0.03 exp_schraudolph 35 | 0.063058 17.90 0.044 powx_ekmett_fast_lb 36 | 0.063003 18.04 0.04 powx_ekmett_fast_ub 37 | 38 | - pass = no processing 39 | - stl = pow(10, x) 40 | - xSpeed of the exp10 function calculated: (stl - pass) / (other_sec - pass) 41 | - Error is in gain 42 | """ 43 | 44 | powx_stl = [0.000063095693,0.000089125053,0.000125892519,0.000177827940,0.000251188554,0.000354813354,0.000501187285,0.000707945612,0.001000000047,0.001412537065,0.001995261991,0.002818383276,0.003981071059,0.005623413250,0.007943280041,0.011220183223,0.015848929062,0.022387212142,0.031622774899,0.044668357819,0.063095726073,0.089125081897,0.125892534852,0.177827939391,0.251188635826,0.354813367128,0.501187205315,0.707945764065,1.000000000000,1.412537574768,1.995262384415,2.818382978439,3.981071949005,] 45 | powx_ekmett_fast = [0.000063993968,0.000094279647,0.000127060339,0.000187630765,0.000252263620,0.000373404473,0.000500813127,0.000743098557,0.000994205475,0.001478768885,0.001973554492,0.002942681313,0.003917396069,0.005855679512,0.007793933153,0.011651933193,0.015528440475,0.023185014725,0.030938148499,0.046132326126,0.061638593674,0.091789722443,0.122801780701,0.182628631592,0.244652748108,0.363355636597,0.487405776978,0.722908020020,0.971008300781,1.438217163086,1.934410095215,2.861206054688,3.853607177734,] 46 | powx_ekmett_fast_lb = [0.000077143777,0.000106898602,0.000151235610,0.000210745260,0.000296369195,0.000415386632,0.000580530614,0.000818565488,0.001136645675,0.001612722874,0.002224460244,0.003176614642,0.004351258278,0.006255567074,0.008507251740,0.012315809727,0.016623854637,0.024240970612,0.032466411591,0.047700881958,0.063370227814,0.093839168549,0.124307632446,0.184553146362,0.245491027832,0.362855911255,0.484731674194,0.713211059570,0.956962585449,1.401428222656,1.888923645020,2.752838134766,3.727844238281,] 47 | powx_ekmett_fast_ub = [0.000060684048,0.000090875663,0.000121418387,0.000181851909,0.000242937356,0.000363904983,0.000486075878,0.000728208572,0.000972550362,0.001457221806,0.001945905387,0.002916052938,0.003893420100,0.005835294724,0.007790029049,0.011677026749,0.015586495399,0.023366928101,0.031185865402,0.046759605408,0.062397241592,0.093570232391,0.124845981598,0.187243461609,0.249794960022,0.374691009521,0.499794006348,0.749794006348,1.000000000000,1.500411987305,2.001647949219,3.002471923828,4.006591796875,] 48 | powx_ekmett_fast_precise = [0.000060606002,0.000086021624,0.000129869921,0.000173913038,0.000256410654,0.000341881765,0.000506329467,0.000672267517,0.001000000047,0.001418442116,0.001960793743,0.002797193360,0.003846144769,0.005517241545,0.007547187153,0.011494317092,0.015624940395,0.022471848875,0.030769230798,0.043956160545,0.060606002808,0.086021617055,0.129869922996,0.173913046718,0.256410658360,0.341881781816,0.506329476833,0.672267556190,1.000000000000,1.487503051758,1.974998474121,2.924987792969,3.899993896484,] 49 | powx_ekmett_fast_better_precise = [0.000082747116,0.000096353615,0.000406226318,0.000472348416,0.000548873213,0.000638472091,0.000744808582,0.000873065786,0.001000000047,0.004272461403,0.004965832923,0.005771282595,0.006718446501,0.007848160341,0.009218933061,0.038614250720,0.044925946742,0.052205715328,0.060695417225,0.070722520351,0.082747116685,0.096353620291,0.406226336956,0.472348392010,0.548873186111,0.638472139835,0.744808614254,0.873065769672,1.000000000000,1.145389080048,1.342626810074,1.566239118576,1.821914434433,] 50 | exp_ekmett_lb = [0.000059870072,0.000089118257,0.000119531527,0.000177819282,0.000238645822,0.000354802236,0.000476455316,0.000707935542,0.000951241702,0.001412525773,0.001899138093,0.002818375826,0.003791600466,0.005623400211,0.007569819689,0.011220037937,0.015112936497,0.022386670113,0.030172348022,0.044666290283,0.060237884521,0.089118957520,0.120261669159,0.177809715271,0.240096092224,0.354764938354,0.479335784912,0.707817077637,0.956962585449,1.412216186523,1.910507202148,2.817596435547,3.814178466797,] 51 | exp_ekmett_ub = [0.000063958578,0.000094371848,0.000127499923,0.000188326463,0.000254165381,0.000375816599,0.000506658107,0.000749964267,0.001009978354,0.001496583223,0.002013266087,0.002986490726,0.004013180733,0.005959630013,0.007999598980,0.011892497540,0.015945792198,0.023731589317,0.031784534454,0.047356128693,0.063355445862,0.094498634338,0.126282691956,0.188569068909,0.251710891724,0.376283645630,0.501708984375,0.750854492188,1.000000000000,1.498291015625,1.996582031250,2.989746093750,3.986328125000,] 52 | exp_schraudolph = [0.000060727354,0.000090832822,0.000121246092,0.000181248412,0.000242074952,0.000361660495,0.000483313575,0.000721652061,0.000964958221,0.001439958811,0.001926571131,0.002873241901,0.003846466541,0.005733132362,0.007679551840,0.011439502239,0.015332400799,0.022825598717,0.030611276627,0.045544147491,0.061115741730,0.090874671936,0.122017383575,0.181321144104,0.243607521057,0.361787796021,0.486358642578,0.721862792969,0.971008300781,1.440307617188,1.938598632812,2.873779296875,3.870361328125,] 53 | exp_mineiro = [0.000063093845,0.000089125242,0.000125888735,0.000177828595,0.000251183286,0.000354815274,0.000501174480,0.000707946718,0.000999972224,0.001412540674,0.001995205879,0.002818405628,0.003980994225,0.005623430014,0.007943093777,0.011220216751,0.015848636627,0.022387385368,0.031622409821,0.044668674469,0.063095092773,0.089125633240,0.125890731812,0.177828788757,0.251186370850,0.354814529419,0.501182556152,0.707950592041,1.000000000000,1.412544250488,1.995285034180,2.818389892578,3.981079101562,] 54 | exp_mineiro_faster = [0.000060748309,0.000090874266,0.000121287536,0.000181331299,0.000242157839,0.000361826271,0.000483479351,0.000721983612,0.000965289772,0.001440621912,0.001927234232,0.002874568105,0.003847792745,0.005735754967,0.007682204247,0.011444807053,0.015337705612,0.022836208344,0.030621886253,0.045565366745,0.061136960983,0.090917110443,0.122059822083,0.181406021118,0.243692398071,0.361957550049,0.486528396606,0.722202301025,0.971347808838,1.440986633301,1.939277648926,2.875122070312,3.871704101562,] 55 | x_labels = [ 56 | -84, -81, -78, -75, 57 | -72, -69, -66, -63, 58 | -60, -57, -54, -51, 59 | -48, -45, -42, -39, 60 | -36, -33, -30, -27, 61 | -24, -21, -18, -15, 62 | -12, -9, -6, -3, 63 | 0, 3, 6, 9, 64 | 12 65 | ] 66 | 67 | class Styles: 68 | idx = 0 69 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 70 | 71 | def get(self): 72 | s = self.types[self.idx] 73 | self.idx = (self.idx + 1) & 3 74 | return s 75 | 76 | linestyles = Styles() 77 | 78 | fig, ax = plt.subplots() 79 | 80 | 81 | x_ticks = [i for i in range(len(x_labels))] 82 | x = [i for i in range(len(powx_stl))] 83 | 84 | plt.xlabel('dB') 85 | plt.xticks(ticks=x_ticks, labels=x_labels) 86 | plt.ylabel('Gain') 87 | 88 | ax.plot(powx_stl, label='powx_stl', linestyle=linestyles.get()) 89 | ax.plot(powx_ekmett_fast, label='powx_ekmett_fast', linestyle=linestyles.get()) 90 | ax.plot(powx_ekmett_fast_lb, label='powx_ekmett_fast_lb', linestyle=linestyles.get()) 91 | ax.plot(powx_ekmett_fast_ub, label='powx_ekmett_fast_ub', linestyle=linestyles.get()) 92 | ax.plot(powx_ekmett_fast_precise, label='powx_ekmett_fast_precise', linestyle=linestyles.get()) 93 | ax.plot(powx_ekmett_fast_better_precise, label='powx_ekmett_fast_better_precise', linestyle=linestyles.get()) 94 | ax.plot(exp_ekmett_lb, label='exp_ekmett_lb', linestyle=linestyles.get()) 95 | ax.plot(exp_ekmett_ub, label='exp_ekmett_ub', linestyle=linestyles.get()) 96 | ax.plot(exp_schraudolph, label='exp_schraudolph', linestyle=linestyles.get()) 97 | ax.plot(exp_mineiro, label='exp_mineiro', linestyle=linestyles.get()) 98 | ax.plot(exp_mineiro_faster, label='exp_mineiro_faster', linestyle=linestyles.get()) 99 | 100 | ax.legend() 101 | plt.show() 102 | -------------------------------------------------------------------------------- /graphs/denormalise_hz.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | """ 5 | Denormalising Hz is often done in graphical contexts. 6 | Errors will result in a pixel being offset a few places, 7 | or just a fraction. 8 | All the fastest pow functions will offset any on screen 9 | value by a few pixels. On small displays this won't be 10 | noticeable, but on large ones it could be. 11 | The standard mineiro function is the only viable fast option 12 | due to its accuracy. Unfortunately the speed improvements are 13 | only minor. 14 | The mineiro_faster can be a good option if the display is 15 | small so as to minimise the effects of the errors. 16 | 17 | The following table compares the speed and error margin of 18 | different exp2(x) approxiamtions used in the following formula: 19 | 20 * exp2(normalised * 10) 20 | 20 * pow(2, normalised * 10) 21 | 22 | (alternate) 5 * pow(2, 10 * normalised + 2) 23 | 24 | 25 | SEC xSPEED ERROR NAME 26 | 0.055390 pass 27 | 0.080395 1 0 exp2 28 | 0.191968 0.18 0 exp_stl 29 | 0.090972 0.7 0 powx_ekmett_fast_precise 30 | 0.090459 0.71 0 powx_ekmett_fast_better_precise 31 | 0.079863 1.02 desoras_pos 32 | 0.082704 0.91 0.15 exp_mineiro 33 | 0.080687 0.98 0 powx_stl 34 | 0.078116 1.1 0.15 mineiro -- amazing at all ranges 35 | 0.066564 2.23 600 exp_mineiro_faster 36 | 0.065485 2.47 1000 exp_ekmett_ub 37 | 0.065346 2.51 600 exp_schraudolph 38 | 0.063016 3.27 bad powx_ekmett_fast_ub 39 | 0.062933 3.31 bad powx_ekmett_fast 40 | 0.062901 3.32 1000 powx_ekmett_fast_lb 41 | 0.062945 3.3 600 schraudolph 42 | 0.062359 3.58 600 mineiro_faster 43 | 44 | - pass = no processing 45 | - stl = exp2 46 | - xSpeed of the exp2 function calculated: (exp2 - pass) / (other_sec - pass) 47 | - Error is in Hz 48 | """ 49 | 50 | class Styles: 51 | idx = 0 52 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 53 | 54 | def get(self): 55 | s = self.types[self.idx] 56 | self.idx = (self.idx + 1) & 3 57 | return s 58 | 59 | linestyles = Styles() 60 | 61 | fig, ax = plt.subplots() 62 | 63 | x_labels = [ 64 | 0.0, 0.025, 0.05, 0.075, 65 | 0.1, 0.125, 0.15, 0.175, 66 | 0.2, 0.225, 0.25, 0.275, 67 | 0.3, 0.325, 0.35, 0.375, 68 | 0.4, 0.425, 0.45, 0.475, 69 | 0.5, 0.525, 0.55, 0.575, 70 | 0.6, 0.625, 0.65, 0.675, 71 | 0.7, 0.725, 0.75, 0.775, 72 | 0.8, 0.825, 0.85, 0.875, 73 | 0.9, 0.925, 0.95, 0.975, 74 | 1.0, 75 | ] 76 | x_ticks = [i for i in range(len(x_labels))] 77 | 78 | plt.xlabel('Normalised Position') 79 | plt.xticks(ticks=x_ticks, labels=x_labels) 80 | plt.ylabel('Hz') 81 | 82 | exp2 = [20.0,23.784141540527,28.284271240234,33.635856628418,40.0,47.568283081055,56.568542480469,67.271713256836,80.0,95.136566162109,113.137084960938,134.543426513672,160.0,190.273132324219,226.274169921875,269.086853027344,320.0,380.546264648438,452.54833984375,538.173706054688,640.0,761.092529296875,905.0966796875,1076.347412109375,1280.0,1522.18505859375,1810.193359375,2152.69482421875,2560.0,3044.3701171875,3620.38671875,4305.3896484375,5120.0,6088.740234375,7240.7734375,8610.779296875,10240.0,12177.48046875,14481.546875,17221.55859375,20480.0,] 83 | mineiro = [20.0,23.783264160156,28.284454345703,33.634948730469,40.0,47.566528320312,56.568603515625,67.269897460938,80.0,95.133056640625,113.13720703125,134.539794921875,160.0,190.26611328125,226.2744140625,269.07958984375,320.0,380.5322265625,452.548828125,538.1591796875,640.0,761.064453125,905.09765625,1076.318359375,1280.0,1522.12890625,1810.1953125,2152.6171875,2559.98046875,3044.2578125,3620.3515625,4305.234375,5119.9609375,6088.515625,7240.703125,8610.46875,10239.921875,12177.03125,14481.40625,17220.9375,20479.84375,] 84 | mineiro_faster = [19.426956176758,23.853912353516,28.853912353516,33.853912353516,38.853912353516,47.70751953125,57.70751953125,67.70751953125,77.70751953125,95.4150390625,115.4150390625,135.4150390625,155.4150390625,190.830078125,230.830078125,270.830078125,310.830078125,381.66015625,461.66015625,541.66015625,621.66015625,763.3203125,923.3203125,1083.3203125,1243.3203125,1526.640625,1846.640625,2166.640625,2486.640625,3053.28125,3693.28125,4333.28125,4973.28125,6106.5625,7386.5625,8666.5625,9946.5625,12213.125,14773.125,17333.125,19893.125,] 85 | schraudolph = [19.420166015625,23.84033203125,28.84033203125,33.84033203125,38.84033203125,47.6806640625,57.6806640625,67.6806640625,77.6806640625,95.361328125,115.361328125,135.361328125,155.361328125,190.72265625,230.72265625,270.72265625,310.72265625,381.4453125,461.4453125,541.4453125,621.4453125,762.890625,922.890625,1082.890625,1242.890625,1525.78125,1845.78125,2165.78125,2485.78125,3051.5625,3691.5625,4331.5625,4971.5625,6103.125,7383.125,8663.125,9943.125,12206.25,14766.25,17326.25,19886.25,] 86 | desoras_pos = [20.0,25.0,30.0,35.0,40.0,50.0,60.0,70.0,80.0,100.0,120.0,140.0,160.0,200.0,240.0,280.0,320.0,400.0,480.0,560.0,640.0,800.0,960.0,1120.0,1280.0,1600.0,1920.0,2240.0,2560.0,3200.0,3840.0,4480.0,5120.0,6400.0,7680.0,8960.0,10240.0,12800.0,15360.0,17920.0,20480.0,] 87 | powx_stl = [20.0,23.784141540527,28.284271240234,33.635856628418,40.0,47.568283081055,56.568542480469,67.271713256836,80.0,95.136566162109,113.137084960938,134.543426513672,160.0,190.273132324219,226.274169921875,269.086853027344,320.0,380.546264648438,452.54833984375,538.173706054688,640.0,761.092529296875,905.0966796875,1076.347412109375,1280.0,1522.18505859375,1810.193359375,2152.69482421875,2560.0,3044.3701171875,3620.38671875,4305.3896484375,5120.0,6088.740234375,7240.7734375,8610.779296875,10240.0,12177.48046875,14481.546875,17221.55859375,20480.0,] 88 | powx_ekmett_fast = [19.420166015625,24.130249023438,29.420166015625,34.710083007812,40.0,50.579833984375,61.15966796875,71.739501953125,84.638671875,105.79833984375,126.9580078125,148.11767578125,178.5546875,220.8740234375,263.193359375,305.5126953125,375.6640625,460.302734375,544.94140625,629.580078125,788.4375,957.71484375,1126.9921875,1312.5390625,1651.09375,1989.66796875,2328.22265625,2773.5546875,3450.6640625,4127.7734375,4804.8828125,5843.984375,7198.203125,8552.421875,9906.640625,12281.71875,14990.15625,17698.59375,20407.03125,25750.9375,31167.8125,] 89 | powx_ekmett_fast_lb = [19.139251708984,23.278503417969,28.278503417969,33.278503417969,38.278503417969,46.557006835938,56.557006835938,66.557006835938,76.557006835938,93.114013671875,113.114013671875,133.114013671875,153.114013671875,186.22802734375,226.22802734375,266.22802734375,306.22802734375,372.4560546875,452.4560546875,532.4560546875,612.4560546875,744.912109375,904.912109375,1064.912109375,1224.912109375,1489.82421875,1809.82421875,2129.82421875,2449.82421875,2979.6484375,3619.6484375,4259.6484375,4899.6484375,5959.296875,7239.296875,8519.296875,9799.296875,11918.59375,14478.59375,17038.59375,19598.59375,] 90 | powx_ekmett_fast_ub = [20.0,25.430297851562,30.860748291016,36.291046142578,43.442993164062,54.303588867188,65.164184570312,76.024780273438,93.77197265625,115.4931640625,137.21435546875,158.935546875,201.3134765625,244.75830078125,288.20068359375,343.2861328125,430.1708984375,517.0556640625,603.9404296875,741.66015625,915.4296875,1089.19921875,1262.96875,1593.4765625,1941.03515625,2288.57421875,2712.2265625,3407.3046875,4102.3828125,4797.5,5865.15625,7255.3125,8645.46875,10035.625,12611.71875,15392.03125,18172.34375,21425.3125,26985.9375,32546.875,38107.5,] 91 | powx_ekmett_fast_precise = [20.0,25.0,30.0,35.0,40.0,50.0,60.0,70.0,80.0,100.0,120.0,140.0,160.0,200.0,240.0,280.0,320.0,400.0,480.0,560.0,640.0,800.0,960.0,1120.0,1280.0,1600.0,1920.0,2240.0,2560.0,3200.0,3840.0,4480.0,5120.0,6400.0,7680.0,8960.0,10240.0,12800.0,15360.0,17920.0,20480.0,] 92 | powx_ekmett_fast_better_precise = [20.0,25.483680725098,32.951416015625,42.34162902832,40.0,50.967361450195,65.90283203125,84.683258056641,80.0,101.934722900391,131.8056640625,169.366516113281,160.0,203.869445800781,263.611328125,338.733032226562,320.0,407.738891601562,527.22265625,677.466064453125,640.0,815.477783203125,1054.4453125,1354.93212890625,1280.0,1630.95556640625,2108.890625,2709.8642578125,2560.0,3261.9111328125,4217.78125,5419.728515625,5120.0,6523.822265625,8435.5625,10839.45703125,10240.0,13047.64453125,16871.125,21678.9140625,20480.0,] 93 | exp_stl = [20.0,23.784141540527,28.284271240234,33.635856628418,40.0,47.568283081055,56.568542480469,67.271713256836,80.0,95.136566162109,113.137084960938,134.543426513672,160.0,190.273162841797,226.274169921875,269.086822509766,320.0,380.546325683594,452.54833984375,538.173645019531,640.0,761.092651367188,905.0966796875,1076.347290039062,1280.0,1522.185302734375,1810.19384765625,2152.694580078125,2560.0,3044.37060546875,3620.385986328125,4305.38916015625,5120.0,6088.7412109375,7240.775390625,8610.7783203125,10240.0,12177.482421875,14481.5439453125,17221.556640625,20480.0,] 94 | exp_ekmett_ub = [20.0,25.0,30.0,35.0,40.0,50.0,60.0,70.0,80.0,100.0,120.0,140.0,160.0,200.0,240.0,280.0,320.0,400.0,480.0,560.0,640.0,800.0,960.0,1120.0,1280.0,1600.0,1920.0,2240.0,2560.0,3200.0,3840.0,4480.0,5120.0,6400.0,7680.0,8960.0,10240.0,12800.0,15360.0,17920.0,20480.0,] 95 | exp_schraudolph = [19.420166015625,23.84033203125,28.84033203125,33.84033203125,38.84033203125,47.6806640625,57.6806640625,67.6806640625,77.6806640625,95.361328125,115.361328125,135.361328125,155.361328125,190.72265625,230.72265625,270.72265625,310.72265625,381.4453125,461.4453125,541.4453125,621.4453125,762.890625,922.890625,1082.890625,1242.890625,1525.78125,1845.78125,2165.78125,2485.78125,3051.5625,3691.5625,4331.5625,4971.5625,6103.125,7383.125,8663.125,9943.125,12206.25,14766.25,17326.25,19886.25,] 96 | exp_mineiro = [20.0,23.783264160156,28.284454345703,33.634948730469,40.0,47.566528320312,56.568603515625,67.269897460938,80.0,95.133056640625,113.13720703125,134.539794921875,160.0,190.26611328125,226.2744140625,269.07958984375,320.0,380.5322265625,452.548828125,538.1591796875,640.0,761.064453125,905.09765625,1076.318359375,1280.0,1522.12890625,1810.1953125,2152.6171875,2559.98046875,3044.2578125,3620.3515625,4305.234375,5119.9609375,6088.515625,7240.703125,8610.46875,10239.921875,12177.03125,14481.40625,17220.9375,20479.84375,] 97 | exp_mineiro_faster = [19.426956176758,23.853912353516,28.853912353516,33.853912353516,38.853912353516,47.70751953125,57.70751953125,67.70751953125,77.70751953125,95.4150390625,115.4150390625,135.4150390625,155.4150390625,190.83251953125,230.830078125,270.830078125,310.830078125,381.66015625,461.66015625,541.66015625,621.66015625,763.3203125,923.3203125,1083.3203125,1243.3203125,1526.640625,1846.66015625,2166.640625,2486.640625,3053.28125,3693.28125,4333.28125,4973.28125,6106.5625,7386.5625,8666.5625,9946.5625,12213.125,14773.125,17333.125,19893.125,] 98 | 99 | x = [i for i in range(len(exp2))] 100 | 101 | ax.plot(exp2, label='exp2', linestyle=linestyles.get()) 102 | ax.plot(mineiro, label='mineiro', linestyle=linestyles.get()) 103 | ax.plot(mineiro_faster, label='mineiro_faster', linestyle=linestyles.get()) 104 | ax.plot(schraudolph, label='schraudolph', linestyle=linestyles.get()) 105 | # ax.plot(desoras_pos, label='desoras_pos', linestyle=linestyles.get()) 106 | # ax.plot(powx_stl, label='powx_stl', linestyle=linestyles.get()) 107 | # ax.plot(powx_ekmett_fast, label='powx_ekmett_fast', linestyle=linestyles.get()) 108 | # ax.plot(powx_ekmett_fast_lb, label='powx_ekmett_fast_lb', linestyle=linestyles.get()) 109 | # ax.plot(powx_ekmett_fast_ub, label='powx_ekmett_fast_ub', linestyle=linestyles.get()) 110 | # ax.plot(powx_ekmett_fast_precise, label='powx_ekmett_fast_precise', linestyle=linestyles.get()) 111 | # ax.plot(powx_ekmett_fast_better_precise, label='powx_ekmett_fast_better_precise', linestyle=linestyles.get()) 112 | # ax.plot(exp_stl, label='exp_stl', linestyle=linestyles.get()) 113 | # ax.plot(exp_ekmett_ub, label='exp_ekmett_ub', linestyle=linestyles.get()) 114 | # ax.plot(exp_schraudolph, label='exp_schraudolph', linestyle=linestyles.get()) 115 | # ax.plot(exp_mineiro, label='exp_mineiro', linestyle=linestyles.get()) 116 | # ax.plot(exp_mineiro_faster, label='exp_mineiro_faster', linestyle=linestyles.get()) 117 | 118 | ax.legend() 119 | plt.show() 120 | -------------------------------------------------------------------------------- /graphs/gain_to_db.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | """ 5 | Converting gain to dB is often done in compressors and when 6 | displaying volume in dB in GUIs. 7 | In audio, high precision is necessary, making log2_mineiro 8 | the only viable option. It offers high precision and is 9 | significantly faster than using std::log10. 10 | In graphics, errors may only cause a pixel to be off by a 11 | fraction, making log1_ankerl32 an excellent choice. 12 | 13 | The following table compares the speed and error margin of 14 | different log10 approxiamtions used in the following formula: 15 | log10(x) * 20 16 | 17 | SEC xSPEED ERROR NAME 18 | 0.055813 pass 19 | 0.178238 1 0 stl 20 | 0.098199 2.88 awful log1_njuffa 21 | 0.082548 4.57 bad newton 22 | 0.076831 5.82 awful log1_njuffa_faster 23 | 0.074206 6.65 0.0005 log2_mineiro 24 | 0.067856 10.16 0.36 log2_mineiro_faster 25 | 0.067668 10.32 0.5 log1_ekmett_ub 26 | 0.067658 10.33 0.5 log1_ekmett_lb 27 | 0.065508 12.62 0.34 log1_ankerl32 28 | 0.061177 22.82 bad jcook 29 | 30 | - pass = no processing 31 | - stl = log10(x) 32 | - xSpeed of the log10 function calculated: (stl - pass) / (other_sec - pass) 33 | - Error is in dB 34 | """ 35 | 36 | stl = [-84,-81,-78,-75,-72,-69,-66,-63,-60,-57,-54,-51,-48,-45,-42.000003814697,-39,-36,-33,-30,-27,-24,-21,-18,-15,-12,-9,-6,-3,0,3,5.999999523163,9,12,] 37 | # jcook = [-19.997476577759,-19.996435165405,-19.994966506958,-19.992887496948,-19.9899559021,-19.985813140869,-19.979961395264,-19.971702575684,-19.960039138794,-19.943578720093,-19.920349121094,-19.887582778931,-19.841388702393,-19.776321411133,-19.684772491455,-19.556171417236,-19.37593460083,-19.124118804932,-18.773862838745,-18.289663314819,-17.62596321106,-16.726726531982,-15.527370452881,-13.960817337036,-11.969599723816,-9.524361610413,-6.645577430725,-3.419947385788,0,3.419947385788,6.645576953888,9.524361610413,11.969599723816,] 38 | # newton = [-7.19820022583,-7.197948455811,-7.197592258453,-7.197088718414,-7.196377754211,-7.195373058319,-7.193953990936,-7.191950798035,-7.189118862152,-7.185120105743,-7.179470539093,-7.171492099762,-7.160220623016,-7.144300460815,-7.12181186676,-7.090046882629,-7.045177459717,-6.981796741486,-6.892270088196,-6.765809059143,-6.587178707123,-6.334857940674,-5.978443622589,-5.474996566772,-4.763857364655,-3.759346961975,-2.340438604355,-0.336176872253,2.494918346405,6.493947029114,12.142723083496,9.977328300476,17.063131332397,] 39 | # log1_njuffa = [2998.547119140625,3001.54736328125,3004.54736328125,3007.546875,3010.547119140625,3013.54736328125,3016.54736328125,3019.547119140625,3022.54736328125,3025.547119140625,3028.54736328125,3031.54736328125,3034.547119140625,3037.54736328125,3040.547119140625,3043.547119140625,3046.54736328125,3049.54736328125,3052.546875,3055.547119140625,3058.54736328125,3061.54736328125,3064.547119140625,3067.54736328125,3070.547119140625,3073.54736328125,3076.54736328125,-3,0,3,6,9,12,] 40 | # log1_njuffa_faster = [2998.547119140625,3001.54736328125,3004.54736328125,3007.546875,3010.547119140625,3013.547119140625,3016.54736328125,3019.547119140625,3022.54736328125,3025.547119140625,3028.54736328125,3031.546875,3034.547119140625,3037.54736328125,3040.547119140625,3043.547119140625,3046.54736328125,3049.547119140625,3052.546875,3055.547119140625,3058.54736328125,3061.54736328125,3064.547119140625,3067.546875,3070.547119140625,3073.54736328125,3076.54736328125,-3.000080823898,0,2.999919652939,6,8.999919891357,12,] 41 | log1_ankerl32 = [-83.736038208008,-81.168457031250,-77.730186462402,-75.168693542480,-71.724296569824,-69.168869018555,-65.718368530273,-63.168998718262,-59.712406158447,-57.16907119751,-53.706405639648,-51.169097900391,-47.700382232666,-45.169082641602,-41.694313049316,-39.169010162354,-35.688213348389,-33.168891906738,-29.682081222534,-27.168727874756,-23.675910949707,-21.168514251709,-17.669708251953,-15.168251037598,-11.663473129272,-9.167939186096,-5.657201766968,-3.167581081390,0.349102765322,2.832826614380,6.341178894043,8.833281517029,12.333322525024,] 42 | log1_ekmett_ub = [-83.566940307617,-80.999366760254,-77.561080932617,-74.999588012695,-71.555191040039,-68.999771118164,-65.549270629883,-62.999897003174,-59.543308258057,-56.999969482422,-53.537307739258,-51.000003814697,-47.531276702881,-44.999980926514,-41.525215148926,-38.999912261963,-35.519115447998,-32.999794006348,-29.512979507446,-26.999626159668,-23.506813049316,-20.999412536621,-17.500612258911,-14.999151229858,-11.494373321533,-8.998841285706,-5.488103866577,-2.998482227325,0.518201351166,3.001924991608,6.510277271271,9.002379417419,12.502422332764,] 43 | log1_ekmett_lb = [-84.085151672363,-81.517562866211,-78.079284667969,-75.517799377441,-72.073394775391,-69.517967224121,-66.067474365234,-63.518096923828,-60.061508178711,-57.518177032471,-54.055511474609,-51.518203735352,-48.04948425293,-45.518184661865,-42.04341506958,-39.518112182617,-36.037315368652,-33.517997741699,-30.031183242798,-27.517833709717,-24.025012969971,-21.517616271973,-18.018814086914,-15.517353057861,-12.01257610321,-9.517042160034,-6.006305217743,-3.516684055328,-0.000000717711,2.483722925186,5.992074966431,8.484177589417,11.984219551086,] 44 | log2_mineiro = [-84.000480651855,-80.999946594238,-78.000450134277,-74.999961853027,-72.000457763672,-68.999946594238,-66.000411987305,-62.999916076660,-60.000328063965,-56.999923706055,-54.000282287598,-50.999980926514,-48.000267028809,-44.999942779541,-42.000289916992,-38.999946594238,-36.000259399414,-32.999923706055,-30.000194549561,-26.999950408936,-24.000158309937,-20.999950408936,-18.000080108643,-14.999923706055,-12.000110626221,-8.999944686890,-6.000020503998,-2.999936342239,0.000038146973,3.000022172928,5.999965190887,9.000085830688,11.999979019165,] 45 | log2_mineiro_faster = [-83.740081787109,-81.172485351562,-77.734222412109,-75.172729492188,-71.728363037109,-69.172897338867,-65.722427368164,-63.172988891602,-59.716415405273,-57.173080444336,-53.710403442383,-51.173171997070,-47.704391479492,-45.173110961914,-41.698379516602,-39.173049926758,-35.692291259766,-33.172912597656,-29.686126708984,-27.172775268555,-23.679962158203,-21.172561645508,-17.673721313477,-15.172271728516,-11.667556762695,-9.171981811523,-5.661239624023,-3.171615600586,0.345077514648,2.828750610352,6.337127685547,8.829269409180,12.329330444336,] 46 | 47 | x_labels = [ 48 | -84, -81, -78, -75, 49 | -72, -69, -66, -63, 50 | -60, -57, -54, -51, 51 | -48, -45, -42, -39, 52 | -36, -33, -30, -27, 53 | -24, -21, -18, -15, 54 | -12, -9, -6, -3, 55 | 0, 3, 6, 9, 56 | 12 57 | ] 58 | 59 | class Styles: 60 | idx = 0 61 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 62 | 63 | def get(self): 64 | s = self.types[self.idx] 65 | self.idx = (self.idx + 1) & 3 66 | return s 67 | 68 | linestyles = Styles() 69 | 70 | fig, ax = plt.subplots() 71 | 72 | x_ticks = [i for i in range(len(x_labels))] 73 | x = [i for i in range(len(stl))] 74 | 75 | plt.xlabel('dB') 76 | plt.xticks(ticks=x_ticks, labels=x_labels) 77 | plt.ylabel('dB') 78 | 79 | ax.plot(stl, label='stl', linestyle=linestyles.get()) 80 | # ax.plot(jcook, label='jcook', linestyle=linestyles.get()) 81 | # ax.plot(newton, label='newton', linestyle=linestyles.get()) 82 | # ax.plot(log1_njuffa, label='log1_njuffa', linestyle=linestyles.get()) 83 | # ax.plot(log1_njuffa_faster, label='log1_njuffa_faster', linestyle=linestyles.get()) 84 | ax.plot(log1_ankerl32, label='log1_ankerl32', linestyle=linestyles.get()) 85 | ax.plot(log1_ekmett_ub, label='log1_ekmett_ub', linestyle=linestyles.get()) 86 | ax.plot(log1_ekmett_lb, label='log1_ekmett_lb', linestyle=linestyles.get()) 87 | ax.plot(log2_mineiro, label='log2_mineiro', linestyle=linestyles.get()) 88 | ax.plot(log2_mineiro_faster, label='log2_mineiro_faster', linestyle=linestyles.get()) 89 | 90 | ax.legend() 91 | plt.show() 92 | -------------------------------------------------------------------------------- /graphs/hz_to_midi.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | """ 5 | Paul Mineiro's log2 function is the clear winner in both 6 | speed and accuracy. The margin of error when converting 7 | Hz to midi is at worst 0.15ct. 8 | Any of the faster functions are only faster by about 9 | ~7%, while also increasing the margin of error to 30ct 10 | 11 | In applications where accuracy is not citical, the 12 | hz_to_midi algorithm could be modified to reduce the 13 | error caused by the log2 function. 14 | eg 1. if there is a linear a negative offset, the 15 | variable 69 could be incrased by a fraction to 69.3 16 | eg 2. if there is in exponential offset, the 17 | multiplication by 12 could be increased or decreased 18 | by a small fraction. 19 | The De Soras algorithm seems best suited for this. 20 | 21 | The following table compares the speed and error margin of 22 | different log2 approxiamtions used in the following formula: 23 | 69 + log2(Hz / 440) * 12 24 | 25 | SEC xSPEED ERROR NAME 26 | 0.055522 pass 27 | 0.175968 1 0 stl 28 | 0.095747 2.99 bad log1_njuffa 29 | 0.078736 5.18 bad newton 30 | 0.077620 5.44 bad log1_njuffa_faster 31 | 0.076514 5.73 0.0015 log1_mineiro 32 | 0.075569 5.99 0.04 lgeoffroy_accurate 33 | 0.073967 6.52 0.075 lgeoffroy 34 | 0.072461 7.09 0.0015 mineiro 35 | 0.070592 7.97 0.3 log1_mineiro_faster 36 | 0.068189 9.48 0.3 log1_ankerl32 37 | 0.067995 9.63 0.3 mineiro_faster 38 | 0.067818 9.77 1.0 log1_ekmett_lb 39 | 0.066792 10.68 1.0 desoras 40 | 0.064067 14.04 bad jcook 41 | 42 | 43 | - pass = no processing 44 | - stl = std::log2 45 | - xSpeed of the log2 function calculated: (stl_sec - pass) / (other_sec - pass) 46 | - Error is in semitones. I've recorded approximately the worst error 47 | between 1Hz (~-36midi) & 20Khz (~135midi) not the average error 48 | """ 49 | 50 | class Styles: 51 | idx = 0 52 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 53 | 54 | def get(self): 55 | s = self.types[self.idx] 56 | self.idx = (self.idx + 1) & 3 57 | return s 58 | 59 | linestyles = Styles() 60 | 61 | fig, ax = plt.subplots() 62 | 63 | x_labels = [1, 2, 5, 64 | 10, 20, 50, 65 | 100, 200, 500, 66 | 1000, 2000, 5000, 67 | 10000, 20000] 68 | x_ticks = [i for i in range(len(x_labels))] 69 | 70 | plt.xlabel('Frequency in Hz') 71 | plt.xticks(ticks=x_ticks, labels=x_labels) 72 | plt.ylabel('midi note number') 73 | 74 | stl = [-36.3763122559,-24.3763122559,-8.51318359375,3.48681640625,15.4868202209,31.3499603271,43.3499603271,55.3499603271,71.2130966187,83.2130966187,95.2130966187,111.07623291,123.07623291,135.07623291,] 75 | # log1_njuffa = [6107.62402344,6119.62402344,6135.48730469,6147.48730469,6159.48730469,6175.34960938,6187.34960938,6199.34960938,71.2130966187,83.2130966187,95.2130966187,111.07623291,123.07623291,135.07623291,] 76 | # newton = [51.7406425476,51.7936248779,51.9525756836,52.2174835205,52.7473106384,54.3367881775,56.9859199524,62.2841796875,78.1789550781,84.9971389771,98.6334991455,126.017326355,188.243408203,324.415100098,] 77 | # log1_njuffa_faster = [6107.62402344,6119.62402344,6135.48632812,6147.48632812,6159.48632812,6175.34960938,6187.34960938,6199.34960938,71.2132492065,83.2132415771,95.2132415771,111.076072693,123.076065063,135.076065063,] 78 | log1_mineiro = [-36.3778152466,-24.3778076172,-8.51318359375,3.48681640625,15.4868164062,31.348274231,43.348274231,55.348274231,71.2114105225,83.2115020752,95.2115020752,111.076293945,123.076293945,135.076293945,] 79 | lgeoffroy_accurate = [-36.4301376343,-24.4301376343,-8.51406860352,3.48593139648,15.4859313965,31.3960571289,43.3960571289,55.3960571289,71.1668243408,83.1668243408,95.1668243408,111.063247681,123.063247681,135.063247681,] 80 | lgeoffroy = [-36.4340820312,-24.4340820312,-8.52168273926,3.47831726074,15.4783172607,31.4096183777,43.4096183777,55.4096183777,71.1641540527,83.1641540527,95.1641540527,111.055114746,123.055114746,135.055114746,] 81 | mineiro = [-36.3778152466,-24.3778152466,-8.51318359375,3.48681640625,15.4868164062,31.348274231,43.348274231,55.348274231,71.2114105225,83.2115020752,95.2115020752,111.076293945,123.076293945,135.076293945,] 82 | log1_mineiro_faster = [-36.3486099243,-24.3486404419,-8.85771179199,3.14225769043,15.1422348022,31.5059585571,43.5059318542,55.5059051514,71.3239974976,83.3241043091,95.3242111206,110.73323822,122.733215332,134.733184814,] 83 | log1_ankerl32 = [-36.3405532837,-24.3405456543,-8.84963989258,3.15036010742,15.1503639221,31.513999939,43.513999939,55.513999939,71.3321762085,83.3321838379,95.3321838379,110.741271973,122.741271973,134.741271973,] 84 | mineiro_faster = [-36.3487243652,-24.3487243652,-8.85781860352,3.14218139648,15.1421813965,31.505859375,43.505859375,55.505859375,71.3239746094,83.3240661621,95.3240661621,110.733123779,122.733123779,134.733123779,] 85 | log1_ekmett_lb = [-37.0363616943,-25.0363616943,-9.54545593262,2.45454406738,14.4545440674,30.8181800842,42.8181800842,54.8181800842,70.6363601685,82.6363601685,94.6363601685,110.045455933,122.045455933,134.045455933,] 86 | # jcook = [34.1881980896,34.3460693359,34.8154525757,35.5838394165,37.0705032349,41.1664161682,46.9815979004,55.886100769,71.2321548462,82.5996017456,91.3581237793,98.3134231567,101.022705078,102.464828491,] 87 | desoras = [-37.036361694336,-25.036361694336,-9.545455932617,2.454544067383,14.454544067383,30.818183898926,42.818183898926,54.818183898926,70.636360168457,82.636367797852,94.636360168457,110.045455932617,122.045455932617,134.045455932617,] 88 | 89 | x = [i for i in range(len(stl))] 90 | 91 | ax.plot(stl, label='stl', linestyle=linestyles.get()) 92 | ax.plot(log1_mineiro, label='log1_mineiro', linestyle=linestyles.get()) 93 | ax.plot(lgeoffroy_accurate, label='lgeoffroy_accurate', linestyle=linestyles.get()) 94 | ax.plot(lgeoffroy, label='lgeoffroy', linestyle=linestyles.get()) 95 | ax.plot(mineiro, label='mineiro', linestyle=linestyles.get()) 96 | ax.plot(log1_mineiro_faster, label='log1_mineiro_faster', linestyle=linestyles.get()) 97 | ax.plot(log1_ankerl32, label='log1_ankerl32', linestyle=linestyles.get()) 98 | ax.plot(mineiro_faster, label='mineiro_faster', linestyle=linestyles.get()) 99 | ax.plot(log1_ekmett_lb, label='log1_ekmett_lb', linestyle=linestyles.get()) 100 | ax.plot(desoras, label='desoras', linestyle=linestyles.get()) 101 | 102 | 103 | ax.legend() 104 | 105 | # plt.plot(x, y) # Plot the chart 106 | plt.show() # display 107 | -------------------------------------------------------------------------------- /graphs/midi_to_hz.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | """ 5 | The standard mineiro function is the only viable fast option 6 | for accuracy, although the speed improvements are only minor. 7 | If accuracy at high frequencies isn't nececarry, then the 8 | powx_ekmett_fast_lb function is a great choice. 9 | 10 | The following table compares the speed and error margin of 11 | different exp2 approxiamtions used in the following formula: 12 | 440 * exp2((midi - 69) / 12) 13 | 440 * pow(2, (midi - 69) / 12) 14 | 15 | SEC xSPEED ERROR NAME 16 | 0.055390 pass 17 | 0.080395 1 0 exp2 18 | 0.191968 0.18 0 exp_stl 19 | 0.090972 0.7 1200 powx_ekmett_fast_precise 20 | 0.090459 0.71 bad powx_ekmett_fast_better_precise 21 | 0.083222 0.8 1200 desoras 22 | 0.082704 0.91 0.1 exp_mineiro 23 | 0.080687 0.98 0 powx_stl 24 | 0.078116 1.1 0.005 mineiro -- amazing at all ranges 25 | 0.066564 2.23 400 exp_mineiro_faster 26 | 0.065485 2.47 1200 exp_ekmett_ub 27 | 0.065346 2.51 400 exp_schraudolph 28 | 0.063016 3.27 bad powx_ekmett_fast_ub 29 | 0.062933 3.31 bad powx_ekmett_fast 30 | 0.062901 3.32 67 powx_ekmett_fast_lb -- amazing at low and high ranges. worst at 2khz 31 | 0.062945 3.3 400 schraudolph 32 | 0.062359 3.58 400 mineiro_faster 33 | 34 | - pass = no processing 35 | - stl = exp2 36 | - xSpeed of the exp2 function calculated: (exp2 - pass) / (other_sec - pass) 37 | - Error is in Hz 38 | """ 39 | 40 | class Styles: 41 | idx = 0 42 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 43 | 44 | def get(self): 45 | s = self.types[self.idx] 46 | self.idx = (self.idx + 1) & 3 47 | return s 48 | 49 | linestyles = Styles() 50 | 51 | fig, ax = plt.subplots() 52 | 53 | x_labels = [ 54 | -36.3, # 1Hz 55 | -24.3, # 2Hz 56 | -8.5, # 5Hz 57 | 3.4, # 10Hz 58 | 15.4, # 20Hz 59 | 31.3, # 50Hz 60 | 43.3, # 100Hz 61 | 55.3, # 200Hz 62 | 71.2, # 500Hz 63 | 83.2, # 1kHz 64 | 95.2, # 2kHz 65 | 111, # 5kHz 66 | 123, # 10kHz 67 | 135, # 20kHz 68 | ] 69 | x_ticks = [i for i in range(len(x_labels))] 70 | 71 | plt.xlabel('Midi') 72 | plt.xticks(ticks=x_ticks, labels=x_labels) 73 | plt.ylabel('Hz') 74 | 75 | exp2 = [1.000024437904,2.000043869019,5.000087261200,10.000148773193,20.000244140625,50.000442504883,100.000602722168,200.000656127930,499.999786376953,999.996826171875,1999.988281250000,4999.952148437500,9999.875976562500,19999.699218750000,] 76 | mineiro = [0.999985933304,1.999958753586,5.000100135803,10.000147819519,20.000400543213,49.998588562012,99.996337890625,199.992675781250,499.974975585938,999.949951171875,1999.873046875000,4999.951171875000,9999.902343750000,19999.804687500000,] 77 | mineiro_faster = [0.998051762581,1.996103525162,5.098814964294,10.197577476501,20.395154953003,49.643173217773,99.285926818848,198.571853637695,495.933227539062,991.866455078125,1983.706054687500,5100.605468750000,10201.210937500000,20402.207031250000,] 78 | schraudolph = [0.997468233109,1.994936466217,5.096480846405,10.192909240723,20.385818481445,49.624500274658,99.248580932617,198.497161865234,495.634460449219,991.262207031250,1982.524414062500,5098.188476562500,10196.376953125000,20392.753906250000,] 79 | desoras = [1.047299385071,2.094592094421,5.295790672302,10.591554641724,21.183057785034,51.219005584717,102.437782287598,204.875137329102,521.146545410156,1042.289550781250,2084.572265625000,5302.312500000000,10604.596679687500,21209.140625000000,] 80 | powx_stl = [1.000024437904,2.000043869019,5.000087261200,10.000148773193,20.000244140625,50.000442504883,100.000602722168,200.000656127930,499.999786376953,999.996826171875,1999.988281250000,4999.952148437500,9999.875976562500,19999.699218750000,] 81 | powx_ekmett_fast = [0.709634125233,1.469091176987,3.808965682983,8.016567230225,16.830301284790,44.621410369873,92.431907653809,191.241989135742,500.337524414062,1051.700439453125,2205.451660156250,5813.886718750000,12035.976562500000,24888.144531250000,] 82 | powx_ekmett_fast_lb = [0.973327159882,1.946654319763,4.999916553497,9.999780654907,19.999561309814,48.851985931396,97.703552246094,195.407104492188,483.274230957031,966.541748046875,1933.083496093750,4999.306640625000,9998.613281250000,19997.226562500000,] 83 | powx_ekmett_fast_ub = [0.628569424152,1.331102848053,3.411077260971,7.361021041870,15.905466079712,43.792667388916,92.319030761719,194.105453491211,528.129577636719,1131.998291015625,2415.488281250000,6364.638671875000,13335.136718750000,27882.207031250000,] 84 | powx_ekmett_fast_precise = [0.964870989323,1.929741978645,4.710827350616,9.421605110168,18.843210220337,48.352100372314,96.703552246094,193.407104492188,521.147155761719,1042.287597656250,2084.575195312500,5302.316894531250,10604.580078125000,21209.160156250000,] 85 | powx_ekmett_fast_better_precise = [0.786764979362,1.573529958725,4.347806930542,8.695521354675,17.391042709351,48.672695159912,97.345390319824,194.690780639648,522.970275878906,1045.940551757812,2091.857666015625,5836.724121093750,11673.324218750000,23346.648437500000,] 86 | exp_stl = [1.000024676323,2.000043630600,5.000087738037,10.000149726868,20.000242233276,50.000442504883,100.000602722168,200.000656127930,499.999786376953,999.996826171875,1999.988281250000,4999.952636718750,9999.875976562500,19999.701171875000,] 87 | exp_ekmett_ub = [1.047297716141,2.094595432281,5.295798778534,10.591545104980,21.183090209961,51.219043731689,102.437667846680,204.875335693359,521.147155761719,1042.287597656250,2084.575195312500,5302.290039062500,10604.580078125000,21209.160156250000,] 88 | exp_schraudolph = [0.997468233109,1.994936466217,5.096480846405,10.192909240723,20.385818481445,49.624500274658,99.248580932617,198.497161865234,495.634460449219,991.262207031250,1982.524414062500,5098.188476562500,10196.376953125000,20392.753906250000,] 89 | exp_mineiro = [0.999985933304,1.999958753586,5.000100135803,10.000147819519,20.000400543213,49.998588562012,99.996337890625,199.992675781250,499.974975585938,999.949951171875,1999.873046875000,4999.951171875000,9999.902343750000,19999.804687500000,] 90 | exp_mineiro_faster = [0.998051762581,1.996103525162,5.098814964294,10.197577476501,20.395154953003,49.643173217773,99.285926818848,198.571853637695,495.933227539062,991.866455078125,1983.706054687500,5100.605468750000,10201.210937500000,20402.207031250000,] 91 | 92 | x = [i for i in range(len(exp2))] 93 | 94 | 95 | ax.plot(exp2, label='exp2', linestyle=linestyles.get()) 96 | ax.plot(mineiro, label='mineiro', linestyle=linestyles.get()) 97 | ax.plot(mineiro_faster, label='mineiro_faster', linestyle=linestyles.get()) 98 | ax.plot(schraudolph, label='schraudolph', linestyle=linestyles.get()) 99 | ax.plot(desoras, label='desoras', linestyle=linestyles.get()) 100 | ax.plot(powx_stl, label='powx_stl', linestyle=linestyles.get()) 101 | ax.plot(powx_ekmett_fast, label='powx_ekmett_fast', linestyle=linestyles.get()) 102 | ax.plot(powx_ekmett_fast_lb, label='powx_ekmett_fast_lb', linestyle=linestyles.get()) 103 | ax.plot(powx_ekmett_fast_ub, label='powx_ekmett_fast_ub', linestyle=linestyles.get()) 104 | ax.plot(powx_ekmett_fast_precise, label='powx_ekmett_fast_precise', linestyle=linestyles.get()) 105 | ax.plot(powx_ekmett_fast_better_precise, label='powx_ekmett_fast_better_precise', linestyle=linestyles.get()) 106 | ax.plot(exp_stl, label='exp_stl', linestyle=linestyles.get()) 107 | ax.plot(exp_ekmett_ub, label='exp_ekmett_ub', linestyle=linestyles.get()) 108 | ax.plot(exp_schraudolph, label='exp_schraudolph', linestyle=linestyles.get()) 109 | ax.plot(exp_mineiro, label='exp_mineiro', linestyle=linestyles.get()) 110 | ax.plot(exp_mineiro_faster, label='exp_mineiro_faster', linestyle=linestyles.get()) 111 | 112 | ax.legend() 113 | plt.show() 114 | -------------------------------------------------------------------------------- /graphs/normalise_hz.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | """ 5 | Normalising Hz is usually done in graphical contexts. 6 | Any margin of error will result in a pixel being offset 7 | left or right by a pixel (or less!) 8 | All the fastest log functions work really great here, 9 | as their margin of error is very forgivable. 10 | The two fastest ankerl and ekmett use the same calcs 11 | they only differ in accuracy at different ranges. 12 | 13 | The following table compares the speed and error margin of 14 | different log approxiamtions used in the following formula: 15 | log(Hz / 20) / log(2) / 10 16 | log(Hz * 0.05) / (LN2 * 0.1) 17 | log(Hz * 0.05) * 0.14426950408889633 18 | 19 | SEC xSPEED ERROR NAME 20 | 0.055610 pass 21 | 0.176747 1 0 stl 22 | 0.093552 3.19 bad njuffa 23 | 0.081992 4.5 bad logNPlusOne 24 | 0.075357 6.13 bad njuffa_faster 25 | 0.073915 6.61 0.000 mineiro 26 | 0.067568 10.13 0.005 mineiro_faster 27 | 0.064840 13.12 0.006 ankerl32 - more accurate than ekmett around 0.5, less around 0 & 1 28 | 0.064824 13.14 0.01 ekmett_lb - very precise around 0 & 1, worst around 0.5 29 | 30 | - pass = no processing 31 | - stl = log 32 | - xSpeed of the log function calculated: (stl_sec - pass) / (other_sec - pass) 33 | """ 34 | 35 | class Styles: 36 | idx = 0 37 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 38 | 39 | def get(self): 40 | s = self.types[self.idx] 41 | self.idx = (self.idx + 1) & 3 42 | return s 43 | 44 | linestyles = Styles() 45 | 46 | fig, ax = plt.subplots() 47 | 48 | x_labels = [ 20, 50, 49 | 100, 200, 500, 50 | 1000, 2000, 5000, 51 | 10000, 20000] 52 | x_ticks = [i for i in range(len(x_labels))] 53 | 54 | plt.xlabel('Frequency in Hz') 55 | plt.xticks(ticks=x_ticks, labels=x_labels) 56 | 57 | stl = [0.000000000000,0.132192820311,0.232192829251,0.332192838192,0.464385658503,0.564385652542,0.664385676384,0.796578466892,0.896578490734,0.996578514576,] 58 | logNPlusOne = [0.100000001490,0.180733785033,0.258435070515,0.345058858395,0.460027545691,0.533334672451,0.586227059364,0.626697838306,0.642166435719,0.650339961052,] 59 | njuffa = [0.000000000000,0.132192820311,0.232192829251,0.332192838192,0.464385658503,0.564385652542,0.664385676384,0.796578466892,0.896578490734,0.996578514576,] 60 | njuffa_faster = [0.000000000000,0.132191956043,0.232191964984,0.332191973925,0.464386820793,0.564386844635,0.664386808872,0.796578526497,0.896578550339,0.996578574181,] 61 | ankerl32 = [0.005798471160,0.130798473954,0.230798497796,0.330798506737,0.462048500776,0.562048494816,0.662048459053,0.801110982895,0.901111006737,1.001111030579,] 62 | ekmett_lb = [-0.000000011921,0.125000000000,0.225000008941,0.325000047684,0.456250011921,0.556250035763,0.656250059605,0.795312523842,0.895312547684,0.995312571526,] 63 | mineiro = [-0.000000238419,0.132186457515,0.232186481357,0.332186460495,0.464381873608,0.564381897449,0.664381921291,0.796571612358,0.896571695805,0.996571660042,] 64 | mineiro_faster = [0.005731287878,0.130731031299,0.230730831623,0.330730646849,0.461981207132,0.561981022358,0.661980807781,0.801044046879,0.901043832302,1.001043677330,] 65 | 66 | 67 | x = [i for i in range(len(stl))] 68 | 69 | ax.plot(stl, label='stl', linestyle=linestyles.get()) 70 | # ax.plot(logNPlusOne, label='logNPlusOne', linestyle=linestyles.get()) 71 | # ax.plot(njuffa, label='njuffa', linestyle=linestyles.get()) 72 | # ax.plot(njuffa_faster, label='njuffa_faster', linestyle=linestyles.get()) 73 | ax.plot(ankerl32, label='ankerl32', linestyle=linestyles.get()) 74 | ax.plot(ekmett_lb, label='ekmett_lb', linestyle=linestyles.get()) 75 | ax.plot(mineiro, label='mineiro', linestyle=linestyles.get()) 76 | ax.plot(mineiro_faster, label='mineiro_faster', linestyle=linestyles.get()) 77 | 78 | ax.legend() 79 | plt.show() 80 | -------------------------------------------------------------------------------- /graphs/ratio_to_midi_offset.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | """ 5 | Paul Mineiro's log2 function is the clear winner in both 6 | speed and accuracy. The margin of error when converting 7 | Hz to midi is at worst 0.15ct. 8 | Any of the faster functions are only faster by about 9 | ~7%, while also increasing the margin of error to 30ct 10 | 11 | The following table compares the speed and error margin of 12 | different log2 approxiamtions used in the following formula: 13 | log2(ratio) * 12 14 | 15 | SEC xSPEED ERROR NAME 16 | 0.055522 pass 17 | 0.175968 1 0 stl 18 | 0.075569 5.99 0.06 lgeoffroy_accurate 19 | 0.073967 6.52 0.07 lgeoffroy 20 | 0.072461 7.09 0.0015 mineiro 21 | 0.068189 9.48 0.3 log1_ankerl32 22 | 0.067995 9.63 0.3 mineiro_faster 23 | 0.067818 9.77 1.0 log1_ekmett_lb 24 | 0.066792 10.68 1.0 desoras 25 | 0.064067 14.04 bad jcook 26 | 27 | 28 | - pass = no processing 29 | - stl = std::log2 30 | - xSpeed of the log2 function calculated: (stl_sec - pass) / (other_sec - pass) 31 | - Error is in semitones. I've recorded approximately the worst error 32 | between 1Hz (~-36midi) & 20Khz (~135midi) not the average error 33 | """ 34 | 35 | class Styles: 36 | idx = 0 37 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 38 | 39 | def get(self): 40 | s = self.types[self.idx] 41 | self.idx = (self.idx + 1) & 3 42 | return s 43 | 44 | linestyles = Styles() 45 | 46 | fig, ax = plt.subplots() 47 | 48 | x_labels = [0.125, 0.25, 0.5, 49 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 50 | 11, 12, 13, 14, 15, 16, 17, 18, 19, 51 | 21, 22, 23, 24, 25, 26, 27, 28, 29, 52 | 31, 32, 33, 34, 35, 36, 37, 38, 39, 53 | 41, 42, 43, 44, 45, 46, 47, 48.0] 54 | x_ticks = [i for i in range(len(x_labels))] 55 | 56 | plt.xlabel('Ratio') 57 | plt.xticks(ticks=x_ticks, labels=x_labels) 58 | plt.ylabel('midi offset') 59 | 60 | stl = [-36,-24,-12,0,12,19.019550323486,24,27.863136291504,31.019550323486,33.688259124756,36,38.039100646973,39.863136291504,41.513179779053,43.019550323486,44.405277252197,45.688259124756,46.882686614990,48,49.049552917480,50.039100646973,50.975131988525,52.707809448242,53.513179779053,54.282745361328,55.019546508789,55.726272583008,56.405281066895,57.058650970459,57.688259124756,58.295776367188,59.450355529785,60,60.532730102539,61.049552917480,61.551395416260,62.039100646973,62.513442993164,62.975131988525,63.424827575684,64.290626525879,64.707809448242,65.115173339844,65.513183593750,65.902236938477,66.282745361328,66.655067443848,67.019546508789,] 61 | lgeoffroy = [-35.934555053711,-23.934556961060,-11.934556961060,0.065443038940,12.065443038940,19.028011322021,24.065443038940,27.798599243164,31.028011322021,33.753677368164,36.065444946289,37.994987487793,39.798599243164,41.476272583008,43.028011322021,44.453811645508,45.753677368164,46.927612304688,48.065444946289,49.045955657959,49.994991302490,50.912532806396,52.653179168701,53.476272583008,54.267883300781,55.028011322021,55.756656646729,56.453811645508,57.119487762451,57.753677368164,58.356388092041,59.467353820801,60.065444946289,60.559638977051,61.045955657959,61.524410247803,61.994991302490,62.457698822021,62.912532806396,63.359504699707,64.229820251465,64.653182983398,65.068664550781,65.476272583008,65.876014709473,66.267883300781,66.651885986328,67.028015136719,] 62 | lgeoffroy_accurate = [-35.940723419189,-23.940723419189,-11.940722465515,0.059277534485,12.059277534485,19.034545898438,24.059276580811,27.805545806885,31.034545898438,33.746273040771,36.059276580811,37.99707031250,39.805545806885,41.484703063965,43.034545898438,44.455066680908,45.746273040771,46.908157348633,48.059280395508,49.044342041016,49.997074127197,50.917476654053,52.661293029785,53.484706878662,54.275791168213,55.034545898438,55.760971069336,56.455066680908,57.116832733154,57.746269226074,58.343376159668,59.440605163574,60.059280395508,60.555850982666,61.044342041016,61.524749755859,61.997074127197,62.461315155029,62.917476654053,63.365554809570,64.237457275391,64.661293029785,65.077041625977,65.484710693359,65.884292602539,66.275787353516,66.659210205078,67.034545898438,] 63 | mineiro = [-36.000030517578,-24.000028610229,-12.000028610229,-0.000028610229,11.999971389771,19.019420623779,23.999969482422,27.862375259399,31.019420623779,33.686668395996,35.999969482422,38.037422180176,39.862373352051,41.513160705566,43.019420623779,44.404411315918,45.686668395996,46.881126403809,47.999969482422,49.048072814941,50.037422180176,50.973827362061,52.707515716553,53.513160705566,54.282775878906,55.019416809082,55.725822448730,56.404415130615,57.057373046875,57.686668395996,58.294063568115,59.449333190918,59.999965667725,60.531768798828,61.048072814941,61.549705505371,62.037422180176,62.511901855469,62.973827362061,63.423786163330,64.290107727051,64.707519531250,65.115043640137,65.513160705566,65.902275085449,66.282775878906,66.655044555664,67.019416809082,] 64 | mineiro_faster = [-35.312347412109,-23.312347412109,-11.312347412109,0.687652587891,12.687652587891,18.687652587891,24.687652587891,27.687652587891,30.687652587891,33.687652587891,36.687652587891,38.187652587891,39.687652587891,41.187652587891,42.687652587891,44.187652587891,45.687652587891,47.187652587891,48.687652587891,49.437652587891,50.187652587891,50.937652587891,52.437652587891,53.187652587891,53.937652587891,54.687652587891,55.437652587891,56.187652587891,56.937652587891,57.687652587891,58.437652587891,59.937652587891,60.687652587891,61.062652587891,61.437652587891,61.812652587891,62.187652587891,62.562652587891,62.937652587891,63.312652587891,64.062652587891,64.437652587891,64.812652587891,65.187652587891,65.562652587891,65.937652587891,66.312652587891,66.687652587891,] 65 | desoras = [-36,-24,-12,0,12,18,24,27,30,33,36,37.50,39,40.50,42,43.50,45,46.50,48,48.750,49.50,50.250,51.750,52.50,53.250,54,54.750,55.50,56.250,57,57.750,59.250,60,60.3750,60.750,61.1250,61.50,61.8750,62.250,62.6250,63.3750,63.750,64.1250,64.50,64.8750,65.250,65.6250,66,] 66 | log1_ankerl32 = [-35.304180145264,-23.304183959961,-11.304183959961,0.695816457272,12.695816040039,18.695816040039,24.695817947388,27.695817947388,30.695817947388,33.695816040039,36.695819854736,38.195816040039,39.695816040039,41.195816040039,42.695816040039,44.195816040039,45.695816040039,47.195816040039,48.695816040039,49.445816040039,50.195816040039,50.945816040039,52.445816040039,53.195816040039,53.945816040039,54.695816040039,55.445816040039,56.195816040039,56.945816040039,57.695816040039,58.445816040039,59.945816040039,60.695816040039,61.070816040039,61.445816040039,61.820816040039,62.195816040039,62.570816040039,62.945816040039,63.320816040039,64.070816040039,64.445816040039,64.820816040039,65.195816040039,65.570816040039,65.945816040039,66.320816040039,66.695816040039,] 67 | log1_ekmett_lb = [-36,-24,-12.000001907349,-0.000001430511,11.999998092651,17.999996185303,23.999996185303,27,30,33,36,37.50,39.000003814697,40.499996185303,42,43.50,44.999996185303,46.499996185303,48,48.750,49.50,50.250,51.750,52.50,53.250,54,54.750,55.50,56.250,57,57.750,59.250,60,60.3750,60.750,61.1250,61.50,61.8750,62.250,62.6250,63.3750,63.750,64.1250,64.50,64.8750,65.250,65.6250,66,] 68 | 69 | x = [i for i in range(len(stl))] 70 | 71 | ax.plot(stl, label='stl', linestyle=linestyles.get()) 72 | # ax.plot(lgeoffroy_accurate, label='lgeoffroy_accurate', linestyle=linestyles.get()) 73 | # ax.plot(lgeoffroy, label='lgeoffroy', linestyle=linestyles.get()) 74 | ax.plot(mineiro, label='mineiro', linestyle=linestyles.get()) 75 | # ax.plot(log1_ankerl32, label='log1_ankerl32', linestyle=linestyles.get()) 76 | # ax.plot(mineiro_faster, label='mineiro_faster', linestyle=linestyles.get()) 77 | # ax.plot(log1_ekmett_lb, label='log1_ekmett_lb', linestyle=linestyles.get()) 78 | # ax.plot(desoras, label='desoras', linestyle=linestyles.get()) 79 | 80 | 81 | ax.legend() 82 | 83 | # plt.plot(x, y) # Plot the chart 84 | plt.show() # display 85 | -------------------------------------------------------------------------------- /graphs/sine.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import math 4 | 5 | """ 6 | Sin functions can be used in audio synthesis, trigonometry, filter 7 | coefficients, LFOs and saturation algorithms. 8 | 9 | In audio synthesis, errors will result in aliasing, making high precision is 10 | necessary. If the radians can be controlled to be within -/+ π, then the pade & 11 | sin_approx functions are great choices. If not, the mineiro_full function may 12 | be okay here, although the aliasing in your use case should be analysed before 13 | deciding to use it. 14 | 15 | High precision is also needed in generating filter coefficients, so again the 16 | pade & sin_approx functions may be good choices, however it should be tested 17 | how much they effect the cutoff. 18 | For displaying a magnitude graph of a filters cutoff, you may be able to get 19 | away with the very fast functions. The inputs to sin functions are often well 20 | below π which is where these approximations are most accurate. The func 21 | mineiro_faster is likely a great choice, and perhaps bluemangoo, however their 22 | errors should be plotted before using them. 23 | 24 | In trigonometry for graphics, the fast bluemangoo algorithm yields fantastic 25 | speed. It is bad after +/- π, however most right angle triangle trig only uses 26 | angles less than 90deg. The accuracy of wildmagic0 is also great for right 27 | angle triangles. 28 | 29 | LFO's can also take advantage of the fast bluemangoo algorithm. 30 | Often a sine LFO is implmented as: 31 | sin(-pi + phase_0_to1 * 2pi); 32 | This is so the phase can easily be cycled by using: 33 | phase_0_to1 += inc; 34 | phase_0_to1 -= (int)phase_0_to1; 35 | The sin function easily remains within +/- π bounds, making it a great choice. 36 | 37 | In saturation, error will result in different tones, so you should experiment 38 | with the sound of different funcs that suit your needs. For cycling funcs, 39 | mineiro_full_faster should work great. 40 | 41 | The following table compares the speed and error margin of different sin 42 | approxiamtions used in the following formula: 43 | sin(radians) 44 | 45 | SEC xSPEED ERROR NAME 46 | 0.055519 pass 47 | 0.117328 0 stl 48 | 0.139088 0.73 0.0000005 njuffa -- cycles well. extremely accurate 49 | 0.089681 1.8 0.000005 mineiro_full -- cycles well. very accurate 50 | 0.084139 2.15 0.000000 sin_approx -- bad close to +/- 2π. extremely accurate before 51 | 0.080947 2.43 0.00035 mineiro_full_faster -- cycles well. fairly accurate 52 | 0.080815 2.44 0.000025 wildmagic1 -- bad after +/- π 53 | 0.078929 2.64 0.000023 mineiro -- really bad after +/- π. very accurate before 54 | 0.078534 2.68 0.043 juha_fmod -- cycles well. slightly innacurate 55 | 0.077564 2.8 0.000001 pade -- really bad close to +/- 2π. extremely accurate before +/- 2π 56 | 0.071909 3.77 0.0007 slaru -- bad after +/- π 57 | 0.069258 4.49 0.00063 mineiro_faster -- bad after +/- π 58 | 0.067741 5.05 0.000025 wildmagic0 -- bad after +/- π/2 59 | 0.067358 5.22 trash bhaskara_radians -- do not use 60 | 0.067136 5.32 0.0007 lanceputnam_gamma -- bad after +/- π 61 | 0.063552 7.69 0.043 juha -- bad after +/- π 62 | 0.060302 12.92 0.043 bluemangoo -- bad after +/- π 63 | 64 | - pass = no processing 65 | - stl = sin(x) 66 | - xSpeed of the sin function calculated: (stl - pass) / (other_sec - pass) 67 | - Error is is taken at the worst point within +/- π, excexpt for the full sine 68 | function, where is error is taken anywhere that looks bad 69 | """ 70 | 71 | stl = [-0.000000349691,0.382683277130,0.707106769085,0.923879563808,1.000000000000,0.923879325390,0.707107007504,0.382683604956,0.000000023850,-0.382683575153,-0.707107007504,-0.923879683018,-1.000000000000,-0.923879623413,-0.707106769085,-0.382683306932,-0.000000174846,0.382683426142,0.707106888294,0.923879444599,1.000000000000,0.923879444599,0.707106709480,0.382683426142,0.000000087423,-0.382683485746,-0.707106769085,-0.923879563808,-1.000000000000,-0.923879504204,-0.707106828690,-0.382683455944,0.000000000000,0.382683455944,0.707106828690,0.923879504204,1.000000000000,0.923879563808,0.707106769085,0.382683485746,-0.000000087423,-0.382683426142,-0.707106709480,-0.923879444599,-1.000000000000,-0.923879444599,-0.707106888294,-0.382683426142,0.000000174846,0.382683306932,0.707106769085,0.923879623413,1.000000000000,0.923879683018,0.707107007504,0.382683575153,-0.000000023850,-0.382683604956,-0.707107007504,-0.923879325390,-1.000000000000,-0.923879563808,-0.707106769085,-0.382683277130,0.000000349691,] 72 | # bhaskara_radians = [-3.047618865967,-3.005593538284,-2.961039066315,-2.913781404495,-2.863636255264,-2.810408830643,-2.753894090652,-2.693877458572,-2.630136966705,-2.562443733215,-2.490566015244,-2.414271593094,-2.333333015442,-2.247535705566,-2.156682014465,-2.060606002808,-1.959183573723,-1.852348923683,-1.740112900734,-1.622585535049,-1.500000000000,-1.372742176056,-1.241379261017,-1.106690645218,-0.969696998596,-0.831683158875,-0.694214880466,-0.559139788151,-0.428571432829,-0.304849833250,-0.190476179123,-0.088019557297,0.000000000000,0.071246817708,0.123711340129,0.155844151974,0.166666656733,0.155844166875,0.123711347580,0.071246840060,0.000000000000,-0.088019534945,-0.190476149321,-0.304849773645,-0.428571403027,-0.559139847755,-0.694214761257,-0.831683158875,-0.969696998596,-1.106690645218,-1.241379261017,-1.372742176056,-1.500000000000,-1.622585177422,-1.740112781525,-1.852348804474,-1.959183573723,-2.060606002808,-2.156682014465,-2.247535467148,-2.333333015442,-2.414271593094,-2.490566015244,-2.562443733215,-2.630136966705,] 73 | pade = [49.701240539551,42.227882385254,35.307811737061,28.972780227661,23.250602722168,18.163597106934,13.726802825928,9.946066856384,6.816237926483,4.319363117218,2.423375606537,1.081289649010,0.231323838234,-0.201873153448,-0.304691821337,-0.170606121421,0.105037495494,0.431226164103,0.727860629559,0.932004094124,1.002875804901,0.924785315990,0.707355439663,0.382741451263,0.000011251694,-0.382682055235,-0.707106769085,-0.923879683018,-1.000000000000,-0.923879504204,-0.707106828690,-0.382683426142,0.000000000000,0.382683426142,0.707106828690,0.923879504204,1.000000000000,0.923879683018,0.707106769085,0.382682055235,-0.000011251694,-0.382741451263,-0.707355439663,-0.924785315990,-1.002875804901,-0.932004094124,-0.727860629559,-0.431226164103,-0.105037495494,0.170606121421,0.304691821337,0.201873153448,-0.231323838234,-1.081289649010,-2.423375606537,-4.319363117218,-6.816237926483,-9.946066856384,-13.726802825928,-18.163597106934,-23.250602722168,-28.972780227661,-35.307811737061,-42.227882385254,-49.701240539551,] 74 | sin_approx = [-9491.151367187500,-5948.825683593750,-3662.681152343750,-2212.158447265625,-1308.597167968750,-756.874328613281,-427.246826171875,-234.958602905273,-125.702659606934,-65.402648925781,-33.163314819336,-16.494836807251,-8.144445419312,-4.040431499481,-1.990154743195,-0.876610636711,-0.175704747438,0.325832486153,0.690734624863,0.919813096523,0.999170243740,0.923751175404,0.707094013691,0.382682859898,0.000000087423,-0.382683515549,-0.707106828690,-0.923879563808,-1.000000000000,-0.923879444599,-0.707106769085,-0.382683426142,0.000000000000,0.382683426142,0.707106769085,0.923879444599,1.000000000000,0.923879563808,0.707106828690,0.382683515549,-0.000000087423,-0.382682859898,-0.707094013691,-0.923751175404,-0.999170243740,-0.919813096523,-0.690734624863,-0.325832486153,0.175704747438,0.876610636711,1.990154743195,4.040431499481,8.144445419312,16.494836807251,33.163314819336,65.402648925781,125.702659606934,234.958602905273,427.246826171875,756.874328613281,1308.597167968750,2212.158447265625,3662.681152343750,5948.825683593750,9491.151367187500,] 75 | slaru = [555.599975585938,481.344604492188,414.820159912109,355.467926025391,302.749877929688,256.149200439453,215.170257568359,179.338333129883,148.199951171875,121.322708129883,98.295272827148,78.727409362793,62.249992370605,48.514930725098,37.195297241211,27.985248565674,20.599998474121,14.775873184204,10.270307540894,6.861813545227,4.349997997284,2.555565595627,1.320312500000,0.507128417492,0.000000000000,-0.382129132748,-0.707812786102,-0.924316287041,-1.000000000000,-0.924316465855,-0.707812488079,-0.382128894329,0.000000000000,0.382128894329,0.707812488079,0.924316465855,1.000000000000,0.924316287041,0.707812786102,0.382129132748,0.000000000000,-0.507128417492,-1.320312500000,-2.555565595627,-4.349997997284,-6.861813545227,-10.270307540894,-14.775873184204,-20.599998474121,-27.985248565674,-37.195297241211,-48.514930725098,-62.249992370605,-78.727409362793,-98.295272827148,-121.322708129883,-148.199951171875,-179.338333129883,-215.170257568359,-256.149200439453,-302.749877929688,-355.467926025391,-414.820159912109,-481.344604492188,-555.599975585938,] 76 | juha = [48.000000000000,44.562500000000,41.249992370605,38.062492370605,34.999996185303,32.062496185303,29.250000000000,26.562500000000,24.000000000000,21.562496185303,19.249996185303,17.062496185303,14.999996185303,13.062500000000,11.250000000000,9.562497138977,8.000000000000,6.562498569489,5.249999046326,4.062500000000,3.000000000000,2.062499284744,1.249999284744,0.562500000000,-0.000000000000,-0.437500178814,-0.750000000000,-0.937500059605,-1.000000000000,-0.937500000000,-0.750000000000,-0.437500000000,0.000000000000,0.437500000000,0.750000000000,0.937500000000,1.000000000000,0.937500059605,0.750000000000,0.437500178814,0.000000000000,-0.562500000000,-1.249999284744,-2.062499284744,-3.000000000000,-4.062500000000,-5.249999046326,-6.562498569489,-8.000000000000,-9.562497138977,-11.250000000000,-13.062500000000,-14.999996185303,-17.062496185303,-19.249996185303,-21.562496185303,-24.000000000000,-26.562500000000,-29.250000000000,-32.062496185303,-34.999996185303,-38.062492370605,-41.249992370605,-44.562500000000,-48.000000000000,] 77 | juha_fmod = [-0.000000000000,0.437500178814,0.750000238419,0.937500178814,1.000000000000,0.937499761581,0.750000119209,0.437499880791,0.000000238419,-0.437500357628,-0.750000357628,-0.937500238419,-1.000000000000,-0.937500000000,-0.749999880791,-0.437499701977,-0.000000000000,0.437500178814,0.750000238419,0.937500000000,0.999999940395,0.937499940395,0.749999880791,0.437499880791,0.000000000000,-0.437500178814,-0.750000000000,-0.937500059605,-1.000000000000,-0.937500000000,-0.750000000000,-0.437500000000,0.000000000000,0.437500000000,0.750000000000,0.937500000000,1.000000000000,0.937500059605,0.750000000000,0.437500178814,-0.000000000000,-0.437499880791,-0.749999880791,-0.937499940395,-0.999999940395,-0.937500000000,-0.750000238419,-0.437500178814,0.000000000000,0.437499701977,0.749999880791,0.937500000000,1.000000000000,0.937500238419,0.750000357628,0.437500357628,-0.000000238419,-0.437499880791,-0.750000119209,-0.937499761581,-1.000000000000,-0.937500178814,-0.750000238419,-0.437500178814,0.000000000000,] 78 | mineiro = [39333496.000000000000,25176090.000000000000,15832175.000000000000,9767151.000000000000,5901057.500000000000,3484804.750000000000,2006961.000000000000,1124276.375000000000,610730.000000000000,320544.312500000000,161842.203125000000,78189.367187500000,35907.546875000000,15544.102539062500,6273.893066406250,2326.371826171875,776.074707031250,225.732910156250,54.493064880371,10.192822456360,1.644728183746,0.726024925709,0.637736618519,0.375405341387,0.000000374052,-0.382703781128,-0.707092881203,-0.923892557621,-0.999986410141,-0.923892736435,-0.707092881203,-0.382704019547,0.000000000000,0.382704019547,0.707092881203,0.923892736435,0.999986410141,0.923892557621,0.707092881203,0.382703781128,-0.000000374052,-0.375405341387,-0.637736618519,-0.726024925709,-1.644728183746,-10.192822456360,-54.493064880371,-225.732910156250,-776.074707031250,-2326.371826171875,-6273.893066406250,-15544.102539062500,-35907.546875000000,-78189.367187500000,-161842.203125000000,-320544.312500000000,-610730.000000000000,-1124276.375000000000,-2006961.000000000000,-3484804.750000000000,-5901057.500000000000,-9767151.000000000000,-15832175.000000000000,-25176090.000000000000,-39333496.000000000000,] 79 | mineiro_faster = [551.252075195312,477.601257324219,411.616882324219,352.744476318359,300.450805664062,254.223342895508,213.570983886719,178.022674560547,147.128952026367,120.461128234863,97.611335754395,78.192657470703,61.839088439941,48.205581665039,36.967922210693,27.822870254517,20.488098144531,14.702142715454,10.224518775940,6.835619449615,4.336756706238,2.550164222717,1.318983316422,0.507271289825,0.000000370183,-0.296944439411,-0.456762313843,-0.531738638878,-0.553245127201,-0.531738698483,-0.456762313843,-0.296944588423,0.000000000000,0.382344365120,0.707733035088,0.923880457878,0.999415159225,0.923880338669,0.707733035088,0.382344126701,-0.000000370183,-0.366100251675,-0.621842265129,-0.652198016644,-0.321224749088,0.527935028076,2.073050498962,4.512807369232,8.066810607910,12.975555419922,19.500494003296,27.923954010010,38.549186706543,51.700386047363,67.722618103027,86.981880187988,109.865089416504,136.780120849609,168.155639648438,204.441162109375,246.107696533203,293.646362304688,347.569641113281,408.410858154297,476.724395751953,] 80 | mineiro_full = [0.000000000000,0.382703542709,0.707092881203,0.923892736435,0.999986529350,0.923892378807,0.707093000412,0.382704108953,0.000000000000,-0.382704108953,-0.707093000412,-0.923892855644,-0.999986767769,-0.923892736435,-0.707092881203,-0.382703542709,0.000000000000,0.382703781128,0.707092881203,0.923892557621,0.999986529350,0.923892557621,0.707092761993,0.382703930140,0.000000000000,-0.382704108953,-0.707093000412,-0.923892736435,-0.999986410141,-0.923892557621,-0.707092881203,-0.382703542709,-0.000000374052,0.382703542709,0.707092881203,0.923892557621,0.999986410141,0.923892736435,0.707093000412,0.382704108953,0.000000000000,-0.382703930140,-0.707092761993,-0.923892557621,-0.999986529350,-0.923892557621,-0.707092881203,-0.382703781128,0.000000000000,0.382703542709,0.707092881203,0.923892736435,0.999986767769,0.923892855644,0.707093000412,0.382704108953,0.000000000000,-0.382704108953,-0.707093000412,-0.923892378807,-0.999986529350,-0.923892736435,-0.707092881203,-0.382703542709,0.000000000000,] 81 | mineiro_full_faster = [0.000000000000,0.382343888283,0.707733035088,0.923880457878,0.999415278435,0.923880100250,0.707733213902,0.382344454527,0.000000000000,-0.382344454527,-0.707733213902,-0.923880636692,-0.999415516853,-0.923880457878,-0.707733035088,-0.382343888283,0.000000000000,0.382344126701,0.707733035088,0.923880338669,0.999415278435,0.923880338669,0.707732915878,0.382344275713,0.000000000000,-0.382344454527,-0.707733213902,-0.923880457878,-0.999415159225,-0.923880338669,-0.707733035088,-0.382343888283,-0.000000370183,0.382343888283,0.707733035088,0.923880338669,0.999415159225,0.923880457878,0.707733213902,0.382344454527,0.000000000000,-0.382344275713,-0.707732915878,-0.923880338669,-0.999415278435,-0.923880338669,-0.707733035088,-0.382344126701,0.000000000000,0.382343888283,0.707733035088,0.923880457878,0.999415516853,0.923880636692,0.707733213902,0.382344454527,0.000000000000,-0.382344454527,-0.707733213902,-0.923880100250,-0.999415278435,-0.923880457878,-0.707733035088,-0.382343888283,0.000000000000,] 82 | 83 | njuffa = [0.000000000021,0.382683575153,0.707107245922,0.923879802227,1.000000000000,0.923879086971,0.707106530666,0.382683575153,-0.000000000015,-0.382683575153,-0.707107245922,-0.923879802227,-1.000000000000,-0.923879444599,-0.707106530666,-0.382683128119,0.000000000010,0.382683575153,0.707106888294,0.923879444599,1.000000000000,0.923879444599,0.707106649876,0.382683366537,-0.000000000005,-0.382683575153,-0.707106828690,-0.923879563808,-1.000000000000,-0.923879504204,-0.707106709480,-0.382683455944,0.000000000000,0.382683455944,0.707106709480,0.923879504204,1.000000000000,0.923879563808,0.707106828690,0.382683575153,0.000000000005,-0.382683366537,-0.707106649876,-0.923879444599,-1.000000000000,-0.923879444599,-0.707106888294,-0.382683575153,-0.000000000010,0.382683128119,0.707106530666,0.923879444599,1.000000000000,0.923879802227,0.707107245922,0.382683575153,0.000000000015,-0.382683575153,-0.707106530666,-0.923879086971,-1.000000000000,-0.923879802227,-0.707107245922,-0.382683575153,-0.000000000021,] 84 | 85 | wildmagic0 = [-2067.758056640625,-1747.263671875000,-1467.265136718750,-1223.856079101562,-1013.384094238281,-832.445068359375,-677.873840332031,-546.734375000000,-436.313568115234,-344.111114501953,-267.831420898438,-205.375015258789,-154.830047607422,-114.463699340820,-82.713821411133,-58.180229187012,-39.616367340088,-25.920513153076,-16.127502441406,-9.400059700012,-5.020290374756,-2.381196260452,-0.978110074997,-0.400172024965,-0.321810156107,-0.494206398726,-0.736769616604,-0.928607463837,-0.999997675419,-0.923859357834,-0.707225620747,-0.382714301348,0.000000000000,0.382714301348,0.707225620747,0.923859357834,0.999997675419,0.928607463837,0.736769616604,0.494206398726,0.321810156107,0.400172024965,0.978110074997,2.381196260452,5.020290374756,9.400059700012,16.127502441406,25.920513153076,39.616367340088,58.180229187012,82.713821411133,114.463699340820,154.830047607422,205.375015258789,267.831420898438,344.111114501953,436.313568115234,546.734375000000,677.873840332031,832.445068359375,1013.384094238281,1223.856079101562,1467.265136718750,1747.263671875000,2067.758056640625,] 86 | wildmagic1 = [15507.542968750000,10557.169921875000,7086.625488281250,4685.791503906250,3048.538574218750,1949.030029296875,1222.754638671875,751.491271972656,451.545806884766,264.608795166016,150.761459350586,83.189079284668,44.245231628418,22.570520401001,11.022744178772,5.221198558807,2.547279357910,1.476758241653,1.147341966629,1.088062047958,1.055972695351,0.941009759903,0.711697220802,0.383723884821,0.000189126062,-0.382658183575,-0.707104682922,-0.923879444599,-0.999999880791,-0.923879563808,-0.707106769085,-0.382683426142,0.000000000000,0.382683426142,0.707106769085,0.923879563808,0.999999880791,0.923879444599,0.707104682922,0.382658183575,-0.000189126062,-0.383723884821,-0.711697220802,-0.941009759903,-1.055972695351,-1.088062047958,-1.147341966629,-1.476758241653,-2.547279357910,-5.221198558807,-11.022744178772,-22.570520401001,-44.245231628418,-83.189079284668,-150.761459350586,-264.608795166016,-451.545806884766,-751.491271972656,-1222.754638671875,-1949.030029296875,-3048.538574218750,-4685.791503906250,-7086.625488281250,-10557.169921875000,-15507.542968750000,] 87 | 88 | bluemangoo = [48.000000000000,44.562500000000,41.249992370605,38.062492370605,34.999996185303,32.062496185303,29.250000000000,26.562500000000,24.000000000000,21.562496185303,19.249996185303,17.062496185303,14.999996185303,13.062500000000,11.250000000000,9.562497138977,8.000000000000,6.562498569489,5.249999046326,4.062500000000,3.000000000000,2.062499284744,1.249999284744,0.562500000000,0.000000000000,-0.437500178814,-0.750000000000,-0.937500059605,-1.000000000000,-0.937500000000,-0.750000000000,-0.437500000000,0.000000000000,0.437500000000,0.750000000000,0.937500000000,1.000000000000,0.937500059605,0.750000000000,0.437500178814,0.000000000000,-0.562500000000,-1.249999284744,-2.062499284744,-3.000000000000,-4.062500000000,-5.249999046326,-6.562498569489,-8.000000000000,-9.562497138977,-11.250000000000,-13.062500000000,-14.999996185303,-17.062496185303,-19.249996185303,-21.562496185303,-24.000000000000,-26.562500000000,-29.250000000000,-32.062496185303,-34.999996185303,-38.062492370605,-41.249992370605,-44.562500000000,-48.000000000000,] 89 | lanceputnam_gamma = [-481.199981689453,-412.272735595703,-350.882690429688,-296.471069335938,-248.499938964844,-206.452392578125,-169.832794189453,-138.166503906250,-111.000000000000,-87.900840759277,-68.457778930664,-52.280540466309,-38.999977111816,-28.268066406250,-19.757810592651,-13.163369178772,-8.199999809265,-4.604000568390,-2.132811069489,-0.564941406250,0.299999982119,0.641308665276,0.617187321186,0.364746093750,-0.000000000000,-0.382129073143,-0.707812488079,-0.924316465855,-1.000000000000,-0.924316406250,-0.707812488079,-0.382128894329,0.000000000000,0.382128894329,0.707812488079,0.924316406250,1.000000000000,0.924316465855,0.707812488079,0.382129073143,0.000000000000,-0.364746093750,-0.617187321186,-0.641308665276,-0.299999982119,0.564941406250,2.132811069489,4.604000568390,8.199999809265,13.163369178772,19.757810592651,28.268066406250,38.999977111816,52.280540466309,68.457778930664,87.900840759277,111.000000000000,138.166503906250,169.832794189453,206.452392578125,248.499938964844,296.471069335938,350.882690429688,412.272735595703,481.199981689453,] 90 | 91 | x_labels = [ 92 | '-4', '', '-3 3/4', '', '-3 1/2', '', '-3 1/4', '', 93 | '-3', '', '-2 3/4', '', '-2 1/2', '', '-2 1/4', '', 94 | '-2', '', '-1 3/4', '', '-1 1/2', '', '-1 1/4', '', 95 | '-π', '', '-3/4', '', '-π/2', '', '-π/4', '', 96 | '0', '', 'π/4', '', 'π/2', '', '3/4', '', 97 | 'π', '', '1 1/4', '', '1 1/2', '', '1 3/4', '', 98 | '2', '', '2 1/4', '', '2 1/2', '', '2 3/4', '', 99 | '3', '', '3 1/4', '', '3 1/2', '', '3 3/4', '', 100 | '4', 101 | ] 102 | 103 | class Styles: 104 | idx = 0 105 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 106 | 107 | def get(self): 108 | s = self.types[self.idx] 109 | self.idx = (self.idx + 1) & 3 110 | return s 111 | 112 | linestyles = Styles() 113 | 114 | fig, ax = plt.subplots() 115 | 116 | x_ticks = [i for i in range(len(x_labels))] 117 | x = [i for i in range(len(stl))] 118 | 119 | # plt.xlabel('phase 0-1') 120 | plt.xticks(ticks=x_ticks, labels=x_labels) 121 | plt.ylabel('mag') 122 | plt.ylim(-1, 1) 123 | plt.xlim(left=(-1.5 * math.pi), right=(1.5 * math.pi)) 124 | 125 | ax.plot(stl, label='stl', linestyle=linestyles.get()) 126 | # ax.plot(bhaskara_radians, label='bhaskara_radians', linestyle=linestyles.get()) 127 | 128 | ax.plot(pade, label='pade', linestyle=linestyles.get()) 129 | # ax.plot(sin_approx, label='sin_approx', linestyle=linestyles.get()) 130 | ax.plot(mineiro, label='mineiro', linestyle=linestyles.get()) 131 | # ax.plot(wildmagic0, label='wildmagic0', linestyle=linestyles.get()) 132 | 133 | # bad after π 134 | # ax.plot(slaru, label='slaru', linestyle=linestyles.get()) 135 | # ax.plot(juha, label='juha', linestyle=linestyles.get()) 136 | # ax.plot(mineiro_faster, label='mineiro_faster', linestyle=linestyles.get()) 137 | # ax.plot(wildmagic1, label='wildmagic1', linestyle=linestyles.get()) 138 | 139 | # cycles well 140 | # ax.plot(mineiro_full, label='mineiro_full', linestyle=linestyles.get()) 141 | # ax.plot(mineiro_full_faster, label='mineiro_full_faster', linestyle=linestyles.get()) 142 | # ax.plot(njuffa, label='njuffa', linestyle=linestyles.get()) 143 | # ax.plot(juha_fmod, label='juha_fmod', linestyle=linestyles.get()) 144 | 145 | ax.plot(bluemangoo, label='bluemangoo', linestyle=linestyles.get()) 146 | ax.plot(lanceputnam_gamma, label='lanceputnam_gamma', linestyle=linestyles.get()) 147 | 148 | ax.legend() 149 | plt.show() 150 | -------------------------------------------------------------------------------- /graphs/sqrt.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import math 4 | 5 | """ 6 | stl is very fast. It's not worth it to use anything else. 7 | 8 | The following table compares the speed and error margin of 9 | different sqrt approxiamtions used in the following formula: 10 | sqrt(x) 11 | 12 | SEC xSPEED ERROR NAME 13 | 0.055580 pass 14 | 0.060113 0 stl 15 | 0.059068 0.075 bigtailwolf 16 | 0.102217 0.0000000 nimig18 17 | 18 | - pass = no processing 19 | - stl = sqrt(x) 20 | - xSpeed of the sqrt function calculated: (stl - pass) / (other_sec - pass) 21 | - Error is is taken at the worst point within +/- π, excexpt for the full sine 22 | function, where is error is taken anywhere that looks bad 23 | """ 24 | 25 | 26 | 27 | stl = [0.000000000000,0.316227763891,0.447213590145,0.547722578049,0.632455527782,0.707106769085,0.774596691132,0.836660027504,0.894427180290,0.948683261871,1.000000000000,1.048808813095,1.095445156097,1.140175461769,1.183215975761,1.224744915962,1.264911055565,1.303840517998,1.341640710831,1.378404855728,1.414213538170,1.449137687683,1.483239769936,1.516575098038,1.549193382263,1.581138849258,1.612451553345,1.643167734146,1.673320055008,1.702938675880,1.732050776482,1.760681629181,1.788854360580,1.816590189934,1.843908905983,1.870828747749,1.897366523743,1.923538446426,1.949358820915,1.974841833115,2.000000000000,] 28 | bigtailwolf = [0.000000000000,0.324999988079,0.449999988079,0.550000011921,0.649999976158,0.750000000000,0.800000011921,0.849999964237,0.899999976158,0.949999988079,1.000000000000,1.049999952316,1.100000023842,1.149999976158,1.199999928474,1.250000000000,1.299999952316,1.350000023842,1.399999976158,1.449999928474,1.500000000000,1.524999976158,1.549999952316,1.574999928474,1.600000023842,1.625000000000,1.649999976158,1.674999952316,1.699999928474,1.725000023842,1.750000000000,1.774999976158,1.799999952316,1.824999928474,1.850000023842,1.875000000000,1.899999976158,1.924999952316,1.949999928474,1.975000023842,2.000000000000,] 29 | nimig18 = [0.000000000000,0.316227734089,0.447213560343,0.547722518444,0.632455468178,0.707106769085,0.774596631527,0.836659967899,0.894427120686,0.948683202267,1.000000000000,1.048808813095,1.095445036888,1.140175342560,1.183215856552,1.224744796753,1.264910936356,1.303840398788,1.341640591621,1.378404736519,1.414213538170,1.449137568474,1.483239650726,1.516574978828,1.549193263054,1.581138730049,1.612451314926,1.643167495728,1.673319935799,1.702938556671,1.732050657272,1.760681509972,1.788854241371,1.816589951515,1.843908667564,1.870828509331,1.897366404533,1.923538208008,1.949358582497,1.974841475487,2.000000000000,] 30 | 31 | x_labels = [ 32 | 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 33 | 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 34 | 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 35 | 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 36 | 4.0, 37 | ] 38 | 39 | class Styles: 40 | idx = 0 41 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 42 | 43 | def get(self): 44 | s = self.types[self.idx] 45 | self.idx = (self.idx + 1) & 3 46 | return s 47 | 48 | linestyles = Styles() 49 | 50 | fig, ax = plt.subplots() 51 | 52 | x_ticks = [i for i in range(len(x_labels))] 53 | x = [i for i in range(len(stl))] 54 | 55 | # plt.xlabel('phase 0-1') 56 | plt.xticks(ticks=x_ticks, labels=x_labels) 57 | plt.ylabel('mag') 58 | 59 | ax.plot(stl, label='stl', linestyle=linestyles.get()) 60 | ax.plot(bigtailwolf, label='bigtailwolf', linestyle=linestyles.get()) 61 | ax.plot(nimig18, label='nimig18', linestyle=linestyles.get()) 62 | 63 | ax.legend() 64 | plt.show() 65 | -------------------------------------------------------------------------------- /graphs/tan.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import math 4 | 5 | """ 6 | tan is popular in calculating filter coefficients. 7 | 8 | In generating filter coefficients, high accuracy is needed 9 | else the cutoff could be too far from it's desired position. 10 | Generally tan in used like this: 11 | π * fc / fs 12 | If fs (sample rate) is 44100 and the cutoff is 20kHz, the 13 | maximum value ever to go into the function will be 1.424758 14 | It should be noted that at higher sample rates min & max 15 | inputs into the function will be lower. 16 | 17 | Most approximations here have tiny errors, so the fastest 18 | functions kay & kay_precise can be used with confidence. 19 | 20 | A special mention should be made for the jrus algorithms, 21 | they expect inputs between 0-1 rather than 0-π/2 (1.57). 22 | The denormalising (* 0.636) operation has been counted in 23 | the bench, and when removed, the jrus_alt function 24 | performs at the same speed as the kay function. The 25 | normalising in jrus_alt becomes a feature, because when 26 | using tan for an algorithm like tan(π * fc / 44100), it 27 | can be optimised to be jrus_alt(fc * inv_nyquist) where 28 | inv_nyquist = 1 / (44100 / 2) 29 | 30 | The following table compares the speed and error margin of 31 | different tan approxiamtions used in the following formula: 32 | (calc g) 33 | x = value representing Hz 34 | g = tan(π * x / 44100) 35 | 36 | SEC xSPEED ERROR NAME 37 | 0.055474 pass 38 | 0.116913 1 +0.00139471496 stl -- still has rounding errors when using inverse g function 39 | 0.096169 1.51 +0..00068600408 jrus_full_denorm 40 | 0.085327 2.05 bad wildmagic1 -- bad after 17k 41 | 0.076044 2.98 +0.00196168308 jrus_denorm 42 | 0.075524 3.06 +0.000969488377 pade -- cycles well. accurate 43 | 0.073580 3.39 +0.156165502 jrus_alt_denorm 44 | 0.068136 4.85 -1.0091539572531474 kay -- 45 | 0.068053 4.88 -1.0091539572531474 kay_precise -- uses 1 extra unique constant for no gain within our range 46 | 0.067788 4.98 bad wildmagic0 -- bad after 13k 47 | 48 | - pass = no processing 49 | - stl = tan(x) 50 | - xSpeed of the tan function calculated: (stl - pass) / (other_sec - pass) 51 | - Error is in Hz, taking the value at 20kHz using the formula 52 | atan(y) / π * 41'000 - 20'000 53 | """ 54 | 55 | stl = [0.000712379406,0.001424759510,0.002137141069,0.002849524841,0.003561911639,0.004274301697,0.004986696877,0.005699096248,0.006411501672,0.007123913616,0.014248549938,0.021374633536,0.028502887115,0.035634037107,0.042768806219,0.049907930195,0.057052124292,0.064202129841,0.071358680725,0.143447801471,0.217028051615,0.292923182249,0.372058898211,0.455511212349,0.544570982456,0.640832304955,0.746319413185,0.863674342632,0.996444404125,1.149541258812,1.329999446869,1.548302888870,1.820836424828,2.174767971039,2.658732414246,3.369331836700,4.529793262482,6.798800468445,] 56 | pade = [0.000712379348,0.001424759510,0.002137140837,0.002849524608,0.003561911639,0.004274301697,0.004986696411,0.005699096248,0.006411501206,0.007123914082,0.014248549938,0.021374633536,0.028502888978,0.035634037107,0.042768806219,0.049907930195,0.057052120566,0.064202137291,0.071358688176,0.143447816372,0.217028066516,0.292923182249,0.372058928013,0.455511212349,0.544570982456,0.640832364559,0.746319353580,0.863674283028,0.996444463730,1.149541258812,1.329999327660,1.548303008080,1.820836424828,2.174767971039,2.658732175827,3.369331359863,4.529793262482,6.798799037933,] 57 | wildmagic0 = [0.000712379348,0.001424759394,0.002137140837,0.002849524608,0.003561910940,0.004274300765,0.004986694548,0.005699093454,0.006411497947,0.007123907562,0.014248505235,0.021374480799,0.028502522036,0.035633325577,0.042767584324,0.049905996770,0.057049244642,0.064198054373,0.071353100240,0.143406197429,0.216904059052,0.292680919170,0.371705383062,0.455124944448,0.544311106205,0.640903651714,0.746855795383,0.864479124546,0.996487438679,1.146042585373,1.316798567772,1.512946605682,1.739259839058,2.001137256622,2.304651260376,2.656587123871,3.064494132996,3.536726713181,] 58 | wildmagic1 = [0.000712379348,0.001424759626,0.002137141069,0.002849525074,0.003561911406,0.004274301697,0.004986696877,0.005699096248,0.006411501672,0.007123913616,0.014248550870,0.021374633536,0.028502887115,0.035634033382,0.042768806219,0.049907926470,0.057052128017,0.064202129841,0.071358680725,0.143447816372,0.217028051615,0.292923182249,0.372058868408,0.455511242151,0.544570982456,0.640832304955,0.746319413185,0.863674342632,0.996444463730,1.149538159370,1.329957604408,1.547996878624,1.819203615189,2.167570352554,2.630675554276,3.267831563950,4.172825813293,5.493455410004,] 59 | jrus_alt_denorm = [0.000712373003,0.001424746704,0.002137121977,0.002849499229,0.003561879508,0.004274263047,0.004986651707,0.005699045025,0.006411443464,0.007123849820,0.014248422347,0.021374441683,0.028502633795,0.035633720458,0.042768433690,0.049907494336,0.057051632553,0.064201585948,0.071358084679,0.143446847796,0.217027187347,0.292922943830,0.372059971094,0.455514162779,0.544576048851,0.640839517117,0.746327996254,0.863682925701,0.996450662613,1.149542212486,1.329990625381,1.548280000687,1.820796370506,2.174710750580,2.658667802811,3.369294166565,4.529881477356,6.799321174622,] 60 | jrus_denorm = [0.000712379406,0.001424759626,0.002137141302,0.002849524841,0.003561911639,0.004274301697,0.004986696877,0.005699096248,0.006411501672,0.007123913616,0.014248550870,0.021374635398,0.028502887115,0.035634037107,0.042768806219,0.049907930195,0.057052124292,0.064202129841,0.071358680725,0.143447831273,0.217028066516,0.292923182249,0.372058898211,0.455511242151,0.544571042061,0.640832364559,0.746319353580,0.863674342632,0.996444404125,1.149541258812,1.329999327660,1.548302888870,1.820836186409,2.174768209457,2.658732175827,3.369330883026,4.529793262482,6.798802375793,] 61 | jrus_full_denorm = [0.000712379348,0.001424759510,0.002137141069,0.002849524608,0.003561911406,0.004274301231,0.004986696411,0.005699095782,0.006411501206,0.007123913616,0.014248549938,0.021374633536,0.028502887115,0.035634033382,0.042768802494,0.049907930195,0.057052124292,0.064202122390,0.071358680725,0.143447801471,0.217028051615,0.292923182249,0.372058868408,0.455511212349,0.544570982456,0.640832304955,0.746319413185,0.863674283028,0.996444344521,1.149541258812,1.329999327660,1.548302531242,1.820836186409,2.174767971039,2.658732175827,3.369331121445,4.529791831970,6.798798084259,] 62 | kay = [0.000712379406,0.001424759510,0.002137140837,0.002849524841,0.003561911173,0.004274301231,0.004986695945,0.005699094851,0.006411499809,0.007123912219,0.014248536900,0.021374586970,0.028502775356,0.035633817315,0.042768429965,0.049907326698,0.057051230222,0.064200863242,0.071356937289,0.143433868885,0.216980904341,0.292811244726,0.371839851141,0.455131947994,0.543967068195,0.639928102493,0.745027303696,0.861894965172,0.994065701962,1.146438121796,1.326033115387,1.543320894241,1.814670801163,2.167235136032,2.649631977081,3.358446121216,4.516886234283,6.783615112305,] 63 | kay_precise = [0.000713617250,0.001427235315,0.002140854485,0.002854476450,0.003568100743,0.004281728528,0.004995360970,0.005708998069,0.006422641221,0.007136291359,0.014273293316,0.021411728114,0.028552304953,0.035695735365,0.042842749506,0.049994055182,0.057150367647,0.064312413335,0.071480929852,0.143683105707,0.217357933521,0.293320029974,0.372485995293,0.455922782421,0.544912278652,0.641040086746,0.746321976185,0.863392651081,0.995792984962,1.148430347443,1.328337430954,1.546002626419,1.817824125290,2.171000719070,2.654236316681,3.364281654358,4.524734973907,6.795402526855,] 64 | 65 | 66 | x_labels = [ 67 | 10, 20, 30, 40, 50, 60, 70, 80, 90, 68 | 100, 200, 300, 400, 500, 600, 700, 800, 900, 69 | '1k', '2k', '3k', '4k', '5k', '6k', '7k', '8k', '9k', 70 | '10k', '11k', '12k', '13k', '14k', '15k', '16k', '17k', '18k', '19k', 71 | '20k' 72 | ] 73 | 74 | class Styles: 75 | idx = 0 76 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 77 | 78 | def get(self): 79 | s = self.types[self.idx] 80 | self.idx = (self.idx + 1) & 3 81 | return s 82 | 83 | linestyles = Styles() 84 | 85 | fig, ax = plt.subplots() 86 | 87 | x_ticks = [i for i in range(len(x_labels))] 88 | x = [i for i in range(len(stl))] 89 | 90 | plt.xlabel('Frequency in Hz') 91 | plt.xticks(ticks=x_ticks, labels=x_labels) 92 | 93 | 94 | ax.plot(stl, label='stl', linestyle=linestyles.get()) 95 | ax.plot(pade, label='pade', linestyle=linestyles.get()) 96 | ax.plot(wildmagic0, label='wildmagic0', linestyle=linestyles.get()) 97 | ax.plot(wildmagic1, label='wildmagic1', linestyle=linestyles.get()) 98 | ax.plot(jrus_alt_denorm, label='jrus_alt_denorm', linestyle=linestyles.get()) 99 | ax.plot(jrus_denorm, label='jrus_denorm', linestyle=linestyles.get()) 100 | ax.plot(jrus_full_denorm, label='jrus_full_denorm', linestyle=linestyles.get()) 101 | ax.plot(kay, label='kay', linestyle=linestyles.get()) 102 | ax.plot(kay_precise, label='kay_precise', linestyle=linestyles.get()) 103 | 104 | ax.legend() 105 | plt.show() 106 | -------------------------------------------------------------------------------- /graphs/tanh.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import math 4 | 5 | """ 6 | tanh is popular in bounded saturation algorithms (also AI). 7 | 8 | In sturation, destroying signals is often a good thing, and 9 | the signal is often boosten to the nth degree. Each of the 10 | functions gain precision the greater the input signal. This 11 | makes the super fast and generally accurate exp_schraudolph 12 | a great choice. exp_ekmett_ub may be preferable however 13 | because it is more accurate at 0 14 | 15 | The following table compares the speed and error margin of 16 | different tanh approxiamtions used in the following formula: 17 | tanh(x) 18 | 19 | SEC xSPEED ERROR NAME 20 | 0.055509 pass 21 | 0.157988 0 stl 22 | 0.096117 2.52 0.000025 exp_mineiro 23 | 0.087596 3.19 0.0000007 c3 24 | 0.080004 4.18 0 pade 25 | 0.079603 4.25 0.008 exp_mineiro_faster 26 | 0.078102 4.53 0.025 exp_ekmett_ub -- only super fast algo to accurately produce 0 27 | 0.077790 4.59 0.02 exp_ekmett_lb 28 | 0.077662 4.62 0.008 exp_schraudolph 29 | 30 | - pass = no processing 31 | - stl = tanh(x) 32 | - xSpeed of the tanh function calculated: (stl - pass) / (other_sec - pass) 33 | - Error is is taken at the worst point. Often around 0 - 0.3 34 | """ 35 | 36 | stl = [-0.999329328537,-0.999180853367,-0.998999595642,-0.998778223991,-0.998507916927,-0.998177886009,-0.997774899006,-0.997282981873,-0.996682405472,-0.995949387550,-0.995054781437,-0.993963181973,-0.992631494999,-0.991007447243,-0.989027380943,-0.986614286900,-0.983674883842,-0.980096399784,-0.975743114948,-0.970451951027,-0.964027583599,-0.956237435341,-0.946806013584,-0.935409069061,-0.921668589115,-0.905148267746,-0.885351657867,-0.861723124981,-0.833654642105,-0.800499022007,-0.761594176292,-0.716297864914,-0.664036750793,-0.604367792606,-0.537049591541,-0.462117165327,-0.379948973656,-0.291312634945,-0.197375327349,-0.099667996168,0.000000000000,0.099667996168,0.197375327349,0.291312634945,0.379948973656,0.462117165327,0.537049591541,0.604367792606,0.664036750793,0.716297864914,0.761594176292,0.800499022007,0.833654642105,0.861723124981,0.885351657867,0.905148267746,0.921668589115,0.935409069061,0.946806013584,0.956237435341,0.964027583599,0.970451951027,0.975743114948,0.980096399784,0.983674883842,0.986614286900,0.989027380943,0.991007447243,0.992631494999,0.993963181973,0.995054781437,0.995949387550,0.996682405472,0.997282981873,0.997774899006,0.998177886009,0.998507916927,0.998778223991,0.998999595642,0.999180853367,0.999329328537,] 37 | pade = [-0.999344229698,-0.999192714691,-0.999009013176,-0.998785495758,-0.998513579369,-0.998182237148,-0.997778236866,-0.997285306454,-0.996684134007,-0.995950579643,-0.995055675507,-0.993963778019,-0.992631971836,-0.991007685661,-0.989027678967,-0.986614465714,-0.983674943447,-0.980096399784,-0.975743174553,-0.970451951027,-0.964027583599,-0.956237435341,-0.946805953979,-0.935409128666,-0.921668589115,-0.905148267746,-0.885351657867,-0.861723184586,-0.833654642105,-0.800499022007,-0.761594176292,-0.716297805309,-0.664036810398,-0.604367792606,-0.537049591541,-0.462117165327,-0.379949003458,-0.291312634945,-0.197375327349,-0.099667988718,0.000000000000,0.099667988718,0.197375327349,0.291312634945,0.379949003458,0.462117165327,0.537049591541,0.604367792606,0.664036810398,0.716297805309,0.761594176292,0.800499022007,0.833654642105,0.861723184586,0.885351657867,0.905148267746,0.921668589115,0.935409128666,0.946805953979,0.956237435341,0.964027583599,0.970451951027,0.975743174553,0.980096399784,0.983674943447,0.986614465714,0.989027678967,0.991007685661,0.992631971836,0.993963778019,0.995055675507,0.995950579643,0.996684134007,0.997285306454,0.997778236866,0.998182237148,0.998513579369,0.998785495758,0.999009013176,0.999192714691,0.999344229698,] 38 | c3 = [-0.999329209328,-0.999180793762,-0.998999536037,-0.998778283596,-0.998507916927,-0.998177886009,-0.997774958611,-0.997282922268,-0.996682405472,-0.995949327946,-0.995054721832,-0.993963241577,-0.992631614208,-0.991007447243,-0.989027500153,-0.986614406109,-0.983674943447,-0.980096399784,-0.975743055344,-0.970451951027,-0.964027464390,-0.956237375736,-0.946806073189,-0.935409247875,-0.921668648720,-0.905148208141,-0.885351717472,-0.861722886562,-0.833654642105,-0.800499498844,-0.761594653130,-0.716298043728,-0.664036810398,-0.604367733002,-0.537048816681,-0.462117373943,-0.379950076342,-0.291313588619,-0.197375774384,-0.099668070674,0.000000000000,0.099668070674,0.197375774384,0.291313588619,0.379950076342,0.462117373943,0.537048816681,0.604367733002,0.664036810398,0.716298043728,0.761594653130,0.800499498844,0.833654642105,0.861722886562,0.885351717472,0.905148208141,0.921668648720,0.935409247875,0.946806073189,0.956237375736,0.964027464390,0.970451951027,0.975743055344,0.980096399784,0.983674943447,0.986614406109,0.989027500153,0.991007447243,0.992631614208,0.993963241577,0.995054721832,0.995949327946,0.996682405472,0.997282922268,0.997774958611,0.998177886009,0.998507916927,0.998778283596,0.998999536037,0.999180793762,0.999329209328,] 39 | exp_ekmett_ub = [-0.999366700649,-0.999220907688,-0.999006271362,-0.998835265636,-0.998593211174,-0.998224198818,-0.997844576836,-0.997436404228,-0.996837556362,-0.995990753174,-0.995293915272,-0.994303822517,-0.992786169052,-0.991311550140,-0.989651143551,-0.987206101418,-0.983896434307,-0.981083810329,-0.977080702782,-0.970928907394,-0.965316951275,-0.958704710007,-0.948977291584,-0.936473011971,-0.925556361675,-0.910109400749,-0.886575102806,-0.866738259792,-0.842516064644,-0.807534635067,-0.765850901604,-0.729268431664,-0.679141461849,-0.606229543686,-0.551817059517,-0.485249280930,-0.395463407040,-0.302069723606,-0.223927795887,-0.126078903675,0.000000000000,0.077741861343,0.168592810631,0.276167750359,0.368494391441,0.439546823502,0.518381476402,0.603170275688,0.650899052620,0.701557040215,0.755423665047,0.795123338699,0.824658393860,0.855180740356,0.884544730186,0.900693893433,0.917121767998,0.933836579323,0.945102572441,0.953668713570,0.962310791016,0.970129847527,0.974514126778,0.978918313980,0.983341932297,0.986139416695,0.988365054131,0.990595698357,0.992524504662,0.993643760681,0.994764447212,0.995886206627,0.996555328369,0.997116923332,0.997679114342,0.998145103455,0.998426437378,0.998707890511,0.998989343643,0.999147295952,0.999288082123,] 40 | exp_ekmett_lb = [-0.999329268932,-0.999163508415,-0.998960733414,-0.998772263527,-0.998500227928,-0.998073399067,-0.997737109661,-0.997282922268,-0.996600687504,-0.995805442333,-0.995036542416,-0.993922412395,-0.992190718651,-0.990874826908,-0.989025473595,-0.986235976219,-0.983149051666,-0.980044066906,-0.975536346436,-0.968820154667,-0.963577210903,-0.956214547157,-0.945121049881,-0.933566868305,-0.921534061432,-0.904178142548,-0.879719555378,-0.860329926014,-0.833487510681,-0.793875634670,-0.756016194820,-0.716033756733,-0.660382449627,-0.589103102684,-0.533833622932,-0.461384832859,-0.362279355526,-0.280456721783,-0.197111189365,-0.091925024986,0.021991968155,0.103329896927,0.198737025261,0.312202811241,0.388945460320,0.462194204330,0.543598890305,0.617117166519,0.665692687035,0.717276692390,0.772159218788,0.803833365440,0.833658099174,0.864484786987,0.889333367348,0.905565023422,0.922077655792,0.938879370689,0.947650074959,0.956238746643,0.964903712273,0.971435546875,0.975825905800,0.980235934258,0.984580874443,0.986802935600,0.989029884338,0.991261959076,0.992858290672,0.993978142738,0.995098948479,0.996161222458,0.996722817421,0.997284770012,0.997846722603,0.998229146004,0.998510241508,0.998791694641,0.999048709869,0.999189257622,0.999330043793,] 41 | exp_schraudolph = [-0.999341964722,-0.999183177948,-0.998976051807,-0.998793601990,-0.998531937599,-0.998125314713,-0.997773349285,-0.997335016727,-0.996681809425,-0.995867788792,-0.995123565197,-0.994052410126,-0.992378115654,-0.991022109985,-0.989237844944,-0.986568391323,-0.983400464058,-0.980395734310,-0.976062715054,-0.969271421432,-0.964163839817,-0.957059562206,-0.946442127228,-0.934544086456,-0.922893762589,-0.906198143959,-0.881323516369,-0.862488031387,-0.836545765400,-0.798541665077,-0.759315431118,-0.720493018627,-0.666741251945,-0.593791842461,-0.539859294891,-0.469412863255,-0.373502731323,-0.287656068802,-0.206064522266,-0.103361248970,0.014709115028,0.094846367836,0.188729643822,0.300220727921,0.382204174995,0.454725027084,0.535277366638,0.612538933754,0.660835504532,0.712114572525,0.766662478447,0.800981521606,0.830711245537,0.861438035965,0.887767910957,0.903972506523,0.920457482338,0.937230706215,0.946817994118,0.955399274826,0.964056730270,0.971009373665,0.975397586823,0.979805707932,0.984233260155,0.986586332321,0.988812923431,0.991044521332,0.992749333382,0.993868827820,0.994989871979,0.996106624603,0.996668219566,0.997230052948,0.997792005539,0.998201608658,0.998482942581,0.998764276505,0.999034881592,0.999175667763,0.999316453934,] 42 | exp_mineiro = [-0.999329328537,-0.999180853367,-0.998999595642,-0.998778223991,-0.998507916927,-0.998177826405,-0.997774839401,-0.997282981873,-0.996682286263,-0.995949268341,-0.995054662228,-0.993963122368,-0.992631196976,-0.991007149220,-0.989027500153,-0.986613869667,-0.983674407005,-0.980096220970,-0.975742936134,-0.970450758934,-0.964026629925,-0.956237912178,-0.946803808212,-0.935407042503,-0.921667635441,-0.905146777630,-0.885348021984,-0.861719727516,-0.833656549454,-0.800491929054,-0.761584997177,-0.716296792030,-0.664031624794,-0.604361116886,-0.537041068077,-0.462118685246,-0.379934132099,-0.291293919086,-0.197374224663,-0.099653482437,0.000000000000,0.099678039551,0.197376370430,0.291337013245,0.379966735840,0.462116718292,0.537059783936,0.604368567467,0.664041876793,0.716298460960,0.761605024338,0.800505280495,0.833654880524,0.861728072166,0.885352849960,0.905150055885,0.921669006348,0.935412049294,0.946807861328,0.956237316132,0.964029073715,0.970452427864,0.975743532181,0.980096578598,0.983675360680,0.986614823341,0.989027500153,0.991007924080,0.992631793022,0.993963122368,0.995054841042,0.995949387550,0.996682405472,0.997282862663,0.997774958611,0.998178005219,0.998507857323,0.998778343201,0.998999595642,0.999180912971,0.999329328537,] 43 | exp_mineiro_faster = [-0.999342262745,-0.999183595181,-0.998976409435,-0.998794078827,-0.998532652855,-0.998126566410,-0.997774183750,-0.997336208820,-0.996683716774,-0.995869278908,-0.995125591755,-0.994055509567,-0.992383241653,-0.991025567055,-0.989242792130,-0.986576318741,-0.983406364918,-0.980403959751,-0.976075351238,-0.969291687012,-0.964177668095,-0.957079827785,-0.946473598480,-0.934567093849,-0.922926366329,-0.906246423721,-0.881361365318,-0.862538814545,-0.836619079113,-0.798650622368,-0.759393215179,-0.720600247383,-0.666890323162,-0.593902587891,-0.540004611015,-0.469606101513,-0.373766124249,-0.287828266621,-0.206278443336,-0.103634119034,0.014534354210,0.094642996788,0.188489794731,0.299933791161,0.382042050362,0.454545497894,0.535077333450,0.612428545952,0.660718441010,0.711990118027,0.766530036926,0.800912618637,0.830640077591,0.861364603043,0.887730002403,0.903934121132,0.920418262482,0.937190890312,0.946797847748,0.955379009247,0.964036226273,0.970999002457,0.975387334824,0.979795217514,0.984222888947,0.986581087112,0.988807678223,0.991039037704,0.992746710777,0.993866205215,0.994987249374,0.996105194092,0.996666789055,0.997228622437,0.997790813446,0.998201131821,0.998482465744,0.998763561249,0.999034643173,0.999175429344,0.999315977097,] 44 | 45 | 46 | x_labels = [ 47 | -4.0, -3.9, -3.8, -3.7, -3.6, -3.5, -3.4, -3.3, -3.2, -3.1, 48 | -3.0, -2.9, -2.8, -2.7, -2.6, -2.5, -2.4, -2.3, -2.2, -2.1, 49 | -2.0, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, 50 | -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 51 | 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 52 | 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 53 | 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 54 | 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 55 | 4.0, 56 | ] 57 | 58 | class Styles: 59 | idx = 0 60 | types = ['solid', 'dotted', 'dashed', 'dashdot'] 61 | 62 | def get(self): 63 | s = self.types[self.idx] 64 | self.idx = (self.idx + 1) & 3 65 | return s 66 | 67 | linestyles = Styles() 68 | 69 | fig, ax = plt.subplots() 70 | 71 | x_ticks = [i for i in range(len(x_labels))] 72 | x = [i for i in range(len(stl))] 73 | 74 | # plt.xlabel('phase 0-1') 75 | plt.xticks(ticks=x_ticks, labels=x_labels) 76 | # plt.ylabel('mag') 77 | 78 | ax.plot(stl, label='stl', linestyle=linestyles.get()) 79 | # ax.plot(pade, label='pade', linestyle=linestyles.get()) 80 | # ax.plot(c3, label='c3', linestyle=linestyles.get()) 81 | ax.plot(exp_ekmett_ub, label='exp_ekmett_ub', linestyle=linestyles.get()) 82 | ax.plot(exp_ekmett_lb, label='exp_ekmett_lb', linestyle=linestyles.get()) 83 | ax.plot(exp_schraudolph, label='exp_schraudolph', linestyle=linestyles.get()) 84 | # ax.plot(exp_mineiro, label='exp_mineiro', linestyle=linestyles.get()) 85 | ax.plot(exp_mineiro_faster, label='exp_mineiro_faster', linestyle=linestyles.get()) 86 | 87 | 88 | ax.legend() 89 | plt.show() 90 | -------------------------------------------------------------------------------- /log.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "common.hpp" 4 | 5 | namespace fast { 6 | namespace log { 7 | 8 | static inline float stl(float x) noexcept { return std::logf(x); } 9 | 10 | // JUCE 11 | /** Provides a fast approximation of the function log(x+1) using a Pade approximant 12 | continued fraction, calculated sample by sample. 13 | Note: This is an approximation which works on a limited range. You are 14 | advised to use input values only between -0.8 and +5 for limiting the error. 15 | */ 16 | template 17 | static FloatType logNPlusOne (FloatType x) noexcept 18 | { 19 | auto numerator = x * (7560 + x * (15120 + x * (9870 + x * (2310 + x * 137)))); 20 | auto denominator = 7560 + x * (18900 + x * (16800 + x * (6300 + x * (900 + 30 * x)))); 21 | return numerator / denominator; 22 | } 23 | 24 | // https://stackoverflow.com/a/39822314 25 | /* compute natural logarithm, maximum error 0.85089 ulps */ 26 | static float njuffa (float a) noexcept { 27 | float i, m, r, s, t; 28 | uint32_t e; 29 | 30 | #if PORTABLE 31 | m = frexpf (a, &e); 32 | if (m < 0.666666667f) { 33 | m = m + m; 34 | e = e - 1; 35 | } 36 | i = (float)e; 37 | #else // PORTABLE 38 | i = 0.0f; 39 | if (a < 1.175494351e-38f){ // 0x1.0p-126 40 | a = a * 8388608.0f; // 0x1.0p+23 41 | i = -23.0f; 42 | } 43 | e = (convert_type (a) - convert_type (0.666666667f)) & 0xff800000; 44 | m = convert_type (convert_type (a) - e); 45 | i = fmaf ((float)e, 1.19209290e-7f, i); // 0x1.0p-23 46 | #endif // PORTABLE 47 | /* m in [2/3, 4/3] */ 48 | m = m - 1.0f; 49 | s = m * m; 50 | /* Compute log1p(m) for m in [-1/3, 1/3] */ 51 | r = -0.130310059f; // -0x1.0ae000p-3 52 | t = 0.140869141f; // 0x1.208000p-3 53 | r = fmaf (r, s, -0.121483512f); // -0x1.f198b2p-4 54 | t = fmaf (t, s, 0.139814854f); // 0x1.1e5740p-3 55 | r = fmaf (r, s, -0.166846126f); // -0x1.55b36cp-3 56 | t = fmaf (t, s, 0.200120345f); // 0x1.99d8b2p-3 57 | r = fmaf (r, s, -0.249996200f); // -0x1.fffe02p-3 58 | r = fmaf (t, m, r); 59 | r = fmaf (r, m, 0.333331972f); // 0x1.5554fap-2 60 | r = fmaf (r, m, -0.500000000f); // -0x1.000000p-1 61 | r = fmaf (r, s, m); 62 | r = fmaf (i, 0.693147182f, r); // 0x1.62e430p-1 // log(2) 63 | if (!((a > 0.0f) && (a < INFINITY))) { 64 | r = a + a; // silence NaNs if necessary 65 | if (a < 0.0f) r = INFINITY - INFINITY; // NaN 66 | if (a == 0.0f) r = -INFINITY; 67 | } 68 | return r; 69 | } 70 | 71 | // https://stackoverflow.com/a/39822314 72 | /* natural log on [0x1.f7a5ecp-127, 0x1.fffffep127]. Maximum relative error 9.4529e-5 */ 73 | float njuffa_faster (float a) noexcept { 74 | float m, r, s, t, i, f; 75 | uint32_t e; 76 | 77 | e = (convert_type (a) - 0x3f2aaaab) & 0xff800000; 78 | m = convert_type (convert_type (a) - e); 79 | i = (float)e * 1.19209290e-7f; // 0x1.0p-23 80 | /* m in [2/3, 4/3] */ 81 | f = m - 1.0f; 82 | s = f * f; 83 | /* Compute log1p(f) for f in [-1/3, 1/3] */ 84 | r = fmaf (0.230836749f, f, -0.279208571f); // 0x1.d8c0f0p-3, -0x1.1de8dap-2 85 | t = fmaf (0.331826031f, f, -0.498910338f); // 0x1.53ca34p-2, -0x1.fee25ap-2 86 | r = fmaf (r, s, t); 87 | r = fmaf (r, s, f); 88 | r = fmaf (i, 0.693147182f, r); // 0x1.62e430p-1 // log(2) 89 | return r; 90 | } 91 | 92 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 93 | /* Ankerl's inversion of Schraudolph's published algorithm, converted to explicit multiplication */ 94 | static inline double ankerl64(double a) noexcept { 95 | union { double d; int x[2]; } u = { a }; 96 | return (u.x[1] - 1072632447) * 6.610368362777016e-7; /* 1 / 1512775.0; */ 97 | } 98 | 99 | // https://martin.ankerl.com/2007/10/04/optimized-pow-approximation-for-java-and-c-c/ 100 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 101 | /* 1065353216 - 486411 = 1064866805 */ 102 | static inline float ankerl32(float a) noexcept { 103 | union { float f; int x; } u = { a }; 104 | return (u.x - 1064866805) * 8.262958405176314e-8f; /* 1 / 12102203.0; */ 105 | } 106 | 107 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 108 | /* 1065353216 - 722019 */ 109 | static inline float ekmett_ub(float a) { 110 | union { float f; int x; } u = { a }; 111 | return (u.x - 1064631197) * 8.262958405176314e-8f; /* 1 / 12102203.0; */ 112 | } 113 | 114 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 115 | /* 1065353216 + 1 */ 116 | static inline float ekmett_lb(float a) noexcept { 117 | union { float f; int x; } u = { a }; 118 | return (u.x - 1065353217) * 8.262958405176314e-8f; /* 1 / 12102203.0 */ 119 | } 120 | 121 | // https://stackoverflow.com/a/74585982 122 | // assumes x > 0 and that it's not a subnormal. 123 | // Results for 0 or negative x won't be -Infinity or NaN 124 | inline float jenkas(float x) 125 | { 126 | //fast_log abs(rel) : avgError = 2.85911e-06(3.32628e-08), MSE = 4.67298e-06(5.31012e-08), maxError = 1.52588e-05(1.7611e-07) 127 | const float s_log_C0 = -19.645704f; 128 | const float s_log_C1 = 0.767002f; 129 | const float s_log_C2 = 0.3717479f; 130 | const float s_log_C3 = 5.2653985f; 131 | const float s_log_C4 = -(1.0f + s_log_C0) * (1.0f + s_log_C1) / ((1.0f + s_log_C2) * (1.0f + s_log_C3)); //ensures that log(1) == 0 132 | const float s_log_2 = 0.6931472f; 133 | 134 | // uint32_t ux = std::bit_cast(x); 135 | union { float f; uint32_t i; } ux = { x }; 136 | int e = static_cast(ux.i - 0x3f800000) >> 23; //e = exponent part can be negative 137 | ux.i |= 0x3f800000; 138 | ux.i &= 0x3fffffff; // 1 <= x < 2 after replacing the exponent field 139 | // x = std::bit_cast(ux); 140 | x = ux.f; 141 | float a = (x + s_log_C0) * (x + s_log_C1); 142 | float b = (x + s_log_C2) * (x + s_log_C3); 143 | float c = (float(e) + s_log_C4); 144 | float d = a / b; 145 | return (c + d) * s_log_2; 146 | } 147 | 148 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fastlog.h 149 | constexpr float mineiro (float x) noexcept { 150 | union { float f; uint32_t i; } vx = { x }; 151 | union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 }; 152 | float y = vx.i; 153 | y *= 1.1920928955078125e-7f; 154 | 155 | float log2_x = y - 124.22551499f 156 | - 1.498030302f * mx.f 157 | - 1.72587999f / (0.3520887068f + mx.f); 158 | 159 | return 0.69314718f * log2_x; 160 | } 161 | 162 | constexpr float mineiro_faster (float x) noexcept { 163 | // return 0.69314718f * mineiro (x); 164 | union { float f; uint32_t i; } vx = { x }; 165 | float y = vx.i; 166 | y *= 8.2629582881927490e-8f; 167 | return y - 87.989971088f; 168 | } 169 | 170 | } // namespace log 171 | } // namespace fast 172 | -------------------------------------------------------------------------------- /log10.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "log.hpp" 4 | 5 | namespace fast { 6 | namespace log10 { 7 | 8 | static inline float stl(float x) noexcept { return std::log10f(x); } 9 | 10 | // https://www.johndcook.com/blog/2021/03/24/log10-trick/ 11 | constexpr float jcook(float x) noexcept { return (x - 1) / (x + 1); } 12 | 13 | // https://stackoverflow.com/a/41416894 14 | constexpr float __newton_next(float r, float x) noexcept { 15 | // static float one_over_ln2 = 1.4426950408889634f; 16 | return r - static_cast(M_LOG2E) * (1 - x / (1 << static_cast(r))); 17 | } 18 | 19 | constexpr float __newton_log2(float x) noexcept { 20 | // const float epsilon = 0.00001f; // change this to change accuracy 21 | float r = x / 2; // better first guesses converge faster 22 | float r2 = __newton_next(r, x); 23 | // float delta = r - r2; 24 | // while (delta * delta > epsilon) { 25 | // r = r2; 26 | // r2 = __newton_next(r, x); 27 | // delta = r - r2; 28 | // } 29 | return r2; 30 | } 31 | 32 | static inline float newton(float x) noexcept { 33 | static float log2_10 = __newton_log2(10); 34 | return __newton_log2(x) / log2_10; 35 | } 36 | 37 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fastlog.h 38 | // adapted from pmineiro's log2 39 | 40 | // 1 / log10(e) 41 | static constexpr float log10e = 0.434294481903251827651f; 42 | 43 | static inline float log1_njuffa(float x) noexcept { return log::njuffa(x) * log10e; } 44 | static inline float log1_njuffa_faster(float x) noexcept { return log::njuffa_faster(x) * log10e; } 45 | // static inline float log1_ankerl32(float x) noexcept { return log::ankerl32(x) * log10e; } 46 | static inline float log1_ankerl32(float a) noexcept { 47 | union { float f; int x; } u = { a }; 48 | // return (u.x - 1064866805) * 8.262958405176314e-8f * log10e; /* 1 / 12102203.0; */ 49 | return (u.x - 1064866805) * 3.5885572395641675e-8f; /* 1 / 12102203.0; */ 50 | } 51 | static inline float log1_ekmett_ub(float x) noexcept { return log::ekmett_ub(x) * log10e; } 52 | static inline float log1_ekmett_lb(float x) noexcept { return log::ekmett_lb(x) * log10e; } 53 | static inline float log1_jenkas(float x) noexcept { return log::jenkas(x) * log10e; } 54 | 55 | // adapted from log2::mineiro 56 | constexpr float log2_mineiro (float x) noexcept { 57 | union { float f; uint32_t i; } vx = { x }; 58 | union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 }; 59 | float y = vx.i; 60 | // log21_10 = 0.3010299956639812 61 | // y *= log21_10 * 1.1920928955078125e-7f; 62 | y *= 3.588557191657796e-8f; 63 | 64 | // return log21_10 * (y - 124.22551499f 65 | // - 1.498030302f * mx.f 66 | // - 1.72587999f / (0.3520887068f + mx.f)); 67 | return y - 37.39560623879553f 68 | - 0.4509520553155725f * mx.f 69 | - 0.5195416459062518f / (0.3520887068f + mx.f); 70 | } 71 | 72 | // adapted from log2::mineiro_faster 73 | static inline float log2_mineiro_faster(float x) noexcept { 74 | union { float f; uint32_t i; } vx = { x }; 75 | float y = vx.i; 76 | // log21_10 = 0.3010299956639812 77 | // y *= log21_10 * 1.1920928955078125e-7f; 78 | y *= 3.588557191657796e-8f; 79 | // return y - log21_10 * 126.94269504f; 80 | // return y - 38.21355893746529f; 81 | return y - 38.21355894f; 82 | } 83 | 84 | 85 | } // namespace log10 86 | } // namespace fast 87 | -------------------------------------------------------------------------------- /log2.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "log.hpp" 5 | 6 | namespace fast { 7 | namespace log2 { 8 | 9 | static inline float stl(float x) noexcept { return std::log2f(x); } 10 | 11 | // https://stackoverflow.com/questions/9411823/fast-log2float-x-implementation-c/28730362#28730362 12 | static inline float lgeoffroy(float val) { 13 | union { float val; int32_t x; } u = { val }; 14 | float log_2 = (float)(((u.x >> 23) & 255) - 128); 15 | u.x &= ~(255 << 23); 16 | u.x += 127 << 23; 17 | log_2 += ((-0.3358287811f) * u.val + 2.0f) * u.val -0.65871759316667f; 18 | return (log_2); 19 | } 20 | 21 | static inline float lgeoffroy_accurate(float val) { 22 | union { float val; int32_t x; } u = { val }; 23 | float log_2 = (float)(((u.x >> 23) & 255) - 128); 24 | u.x &= ~(255 << 23); 25 | u.x += 127 << 23; 26 | log_2 += ((-0.34484843f) * u.val + 2.02466578f) * u.val - 0.67487759f; 27 | return (log_2); 28 | } 29 | 30 | // https://www.johndcook.com/blog/2021/03/24/log10-trick/ 31 | static inline float jcook(float x) noexcept { 32 | return 2.9142f * (x - 1)/(x + 1); 33 | } 34 | 35 | // https://stackoverflow.com/a/41416894 36 | constexpr float __newton_next(float r, float x) noexcept { 37 | // static float one_over_ln2 = 1.4426950408889634f; 38 | return r - static_cast(M_LOG2E) * (1 - x / (1 << static_cast(r))); 39 | } 40 | 41 | static inline float newton(float x) noexcept { 42 | // static float epsilon = 0.000001f; // change this to change accuracy 43 | float r = x / 2; // better first guesses converge faster 44 | float r2 = __newton_next(r, x); 45 | 46 | // NOTE: sometimes gets stuck in infinite loops 47 | // float delta = r - r2; 48 | // while (delta * delta > epsilon) { 49 | // r = r2; 50 | // r2 = next(r, x); 51 | // delta = r - r2 52 | // } 53 | return r2; 54 | } 55 | 56 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fastlog.h 57 | static inline float mineiro(float x) { 58 | union { float f; uint32_t i; } vx = { x }; 59 | union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 }; 60 | float y = vx.i; 61 | y *= 1.1920928955078125e-7f; 62 | 63 | return y - 124.22551499f 64 | - 1.498030302f * mx.f 65 | - 1.72587999f / (0.3520887068f + mx.f); 66 | } 67 | 68 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fastlog.h 69 | static inline float mineiro_faster (float x) noexcept { 70 | union { float f; uint32_t i; } vx = { x }; 71 | float y = vx.i; 72 | y *= 1.1920928955078125e-7f; 73 | return y - 126.94269504f; 74 | } 75 | 76 | // https://www.musicdsp.org/en/latest/Other/63-fast-log2.html 77 | static inline float desoras (float val) noexcept { 78 | // assert (val > 0); 79 | 80 | int * const exp_ptr = reinterpret_cast (&val); 81 | int x = *exp_ptr; 82 | const int log_2 = ((x >> 23) & 255) - 128; 83 | x &= ~(255 << 23); 84 | x += 127 << 23; 85 | *exp_ptr = x; 86 | 87 | return (val + log_2); 88 | } 89 | 90 | static constexpr float log2e = 1.4426950408888495f; 91 | 92 | static inline float log1_njuffa(float x) noexcept { return log::njuffa(x) * log2e; } 93 | static inline float log1_njuffa_faster(float x) noexcept { return log::njuffa_faster(x) * log2e; } 94 | static inline float log1_ankerl32(float x) noexcept { return log::ankerl32(x) * log2e; } 95 | static inline float log1_ekmett_lb(float x) noexcept { return log::ekmett_lb(x) * log2e; } 96 | static inline float log1_jenkas(float x) noexcept { return log::jenkas(x) * log2e; } 97 | static inline float log1_mineiro_faster(float x) noexcept { return log::mineiro_faster(x) * log2e; } 98 | 99 | 100 | } // namespace log2 101 | } // namespace fast 102 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "common.hpp" 8 | 9 | #include "cos.hpp" 10 | #include "exp.hpp" 11 | #include "exp2.hpp" 12 | #include "exp10.hpp" 13 | #include "log.hpp" 14 | #include "log2.hpp" 15 | #include "log10.hpp" 16 | #include "pow.hpp" 17 | #include "sin.hpp" 18 | #include "sqrt.hpp" 19 | #include "tan.hpp" 20 | #include "tanh.hpp" 21 | 22 | 23 | template 24 | void log_hz_to_midi (F log2_func, S name) { 25 | constexpr float frequencies[] = { 26 | 1.0f, 2.0f, 5.0f, 27 | 10.0f, 20.0f, 50.0f, 28 | 100.0f, 200.0f, 500.0f, 29 | 1000, 2000.0f, 5000.0f, 30 | 10000.0f, 20000.0f 31 | }; 32 | std::cout << name << " = ["; 33 | 34 | auto hz_to_midi = [=](float Hz) { return 69 + log2_func(Hz / 440) * 12; }; 35 | 36 | for (const float Hz : frequencies) { 37 | std::cout << std::setprecision(12) << hz_to_midi(Hz) << ","; 38 | } 39 | std::cout << "]" << std::endl; 40 | } 41 | 42 | template 43 | void log_ratio_to_midi_offset (F log2_func, S name) { 44 | constexpr float ratios[] = { 45 | 0.125f, 0.25f, 0.5f, 46 | 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 47 | 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 48 | 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 49 | 31.0f, 32.0f, 33.0f, 34.0f, 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 50 | 41.0f, 42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f, 48.0f 51 | }; 52 | std::cout << name << " = ["; 53 | 54 | auto ratio_to_midi_offset = [=](float r) { return log2_func(r) * 12; }; 55 | 56 | for (const float r : ratios) { 57 | std::cout << std::setprecision(12) << ratio_to_midi_offset(r) << ","; 58 | } 59 | std::cout << "]" << std::endl; 60 | } 61 | 62 | template 63 | void log_midi_to_hz (F pow2_func, S name) { 64 | constexpr float midi_notes[] = { 65 | -36.376312f, // 1Hz 66 | -24.376312f, // 2Hz 67 | -8.513184f, // 5Hz 68 | 3.486816f, // 10Hz 69 | 15.486820f, // 20Hz 70 | 31.349960f, // 50Hz 71 | 43.349960f, // 100Hz 72 | 55.349960f, // 200Hz 73 | 71.213097f, // 500Hz 74 | 83.213097f, // 1kHz 75 | 95.213097f, // 2kHz 76 | 111.076233f, // 5kHz 77 | 123.076233f, // 10kHz 78 | 135.076233f, // 20kHz 79 | }; 80 | std::cout << name << " = ["; 81 | 82 | for (const float midi : midi_notes) { 83 | const float hz = 440.0f * pow2_func((midi - 69.0f) * 0.083333f); 84 | std::cout << std::setprecision(12) << hz << ","; 85 | } 86 | std::cout << "]" << std::endl; 87 | } 88 | 89 | template 90 | void log_normalised_freq(F log_func, S name) noexcept { 91 | constexpr float frequencies[] = { 92 | 20.0f, 50.0f, 93 | 100.0f, 200.0f, 500.0f, 94 | 1000, 2000.0f, 5000.0f, 95 | 10000.0f, 20000.0f 96 | }; 97 | std::cout << name << " = ["; 98 | 99 | for (const float Hz : frequencies) { 100 | float normalised = log_func(Hz * 0.05f) * 0.14426950408889633f; 101 | std::cout << std::setprecision(12) << normalised << ","; 102 | } 103 | std::cout << "]" << std::endl; 104 | } 105 | 106 | template 107 | void log_denormalised_freq(F exp_func, S name) noexcept { 108 | constexpr float values[] = { 109 | 0.0f, 0.025f, 0.05f, 0.075f, 110 | 0.1f, 0.125f, 0.15f, 0.175f, 111 | 0.2f, 0.225f, 0.25f, 0.275f, 112 | 0.3f, 0.325f, 0.35f, 0.375f, 113 | 0.4f, 0.425f, 0.45f, 0.475f, 114 | 0.5f, 0.525f, 0.55f, 0.575f, 115 | 0.6f, 0.625f, 0.65f, 0.675f, 116 | 0.7f, 0.725f, 0.75f, 0.775f, 117 | 0.8f, 0.825f, 0.85f, 0.875f, 118 | 0.9f, 0.925f, 0.95f, 0.975f, 119 | 1.0f}; 120 | std::cout << name << " = ["; 121 | 122 | for (const float v : values) { 123 | float denormalised = 20 * exp_func(v * 10); 124 | std::cout << std::setprecision(12) << denormalised << ","; 125 | } 126 | std::cout << "]" << std::endl; 127 | } 128 | 129 | template 130 | void log_db_to_gain(F exp_func, S name) noexcept { 131 | constexpr float decibels[] = { 132 | -84.0f, -81.0f, -78.0f, -75.0f, 133 | -72.0f, -69.0f, -66.0f, -63.0f, 134 | -60.0f, -57.0f, -54.0f, -51.0f, 135 | -48.0f, -45.0f, -42.0f, -39.0f, 136 | -36.0f, -33.0f, -30.0f, -27.0f, 137 | -24.0f, -21.0f, -18.0f, -15.0f, 138 | -12.0f, -9.0f, -6.0f, -3.0f, 139 | 0.0f, 3.0f, 6.0f, 9.0f, 140 | 12.0f}; 141 | std::cout << name << " = ["; 142 | 143 | for (const float dB : decibels) { 144 | // pow (10, dB / 20) 145 | // exp10 (dB * 0.05) 146 | float gain = exp_func(dB * 0.05f); 147 | std::cout << std::setprecision(12) << gain << ","; 148 | } 149 | std::cout << "]" << std::endl; 150 | } 151 | 152 | template 153 | void log_gain_to_db(F log_func, S name) noexcept { 154 | constexpr float gains[] = { 155 | 6.309573444801929e-05f, // -84 156 | 8.912509381337459e-05f, // -81 157 | 0.00012589254117941674f, // -78 158 | 0.00017782794100389227f, // -75 159 | 0.00025118864315095795f, // -72 160 | 0.0003548133892335753f, // -69 161 | 0.0005011872336272725f, // -66 162 | 0.000707945784384138f, // -63 163 | 0.001f, // -60 164 | 0.001412537544622754f, // -57 165 | 0.001995262314968879f, // -54 166 | 0.002818382931264455f, // -51 167 | 0.003981071705534973f, // -48 168 | 0.005623413251903491f, // -45 169 | 0.007943282347242814f, // -42 170 | 0.011220184543019636f, // -39 171 | 0.015848931924611134f, // -36 172 | 0.0223872113856834f, // -33 173 | 0.03162277660168379f, // -30 174 | 0.0446683592150963f, // -27 175 | 0.06309573444801933f, // -24 176 | 0.08912509381337455f, // -21 177 | 0.12589254117941673f, // -18 178 | 0.1778279410038923f, // -15 179 | 0.251188643150958f, // -12 180 | 0.35481338923357547f, // -9 181 | 0.5011872336272722f, // -6 182 | 0.7079457843841379f, // -3 183 | 1.0f, // 0 184 | 1.4125375446227544f, // 3 185 | 1.9952623149688795f, // 6 186 | 2.8183829312644537f, // 9 187 | 3.9810717055349722f, // 12 188 | }; 189 | std::cout << name << " = ["; 190 | 191 | for (const float g : gains) { 192 | // log10(gain) * 20 193 | float gain = log_func(g) * 20; 194 | std::cout << std::setprecision(12) << gain << ","; 195 | } 196 | std::cout << "]" << std::endl; 197 | } 198 | 199 | template 200 | void log_sin(F sin_func, S name) noexcept { 201 | constexpr float radians[] = { 202 | -12.566370614359172f, -12.173671532660448f, -11.780972450961723f, -11.388273369263f, -10.995574287564276f, -10.602875205865551f, -10.210176124166829f, -9.817477042468104f, 203 | -9.42477796076938f, -9.032078879070655f, -8.63937979737193f, -8.246680715673207f, -7.853981633974483f, -7.461282552275758f, -7.0685834705770345f, -6.675884388878311f, 204 | -6.283185307179586f, -5.890486225480862f, -5.497787143782138f, -5.105088062083414f, -4.71238898038469f, -4.319689898685965f, -3.9269908169872414f, -3.5342917352885173f, 205 | -3.141592653589793f, -2.748893571891069f, -2.356194490192345f, -1.9634954084936207f, -1.5707963267948966f, -1.1780972450961724f, -0.7853981633974483f, -0.39269908169872414f, 206 | 0.0f, 0.39269908169872414f, 0.7853981633974483f, 1.1780972450961724f, 1.5707963267948966f, 1.9634954084936207f, 2.356194490192345f, 2.748893571891069f, 207 | 3.141592653589793f, 3.5342917352885173f, 3.9269908169872414f, 4.319689898685965f, 4.71238898038469f, 5.105088062083414f, 5.497787143782138f, 5.890486225480862f, 208 | 6.283185307179586f, 6.675884388878311f, 7.0685834705770345f, 7.461282552275758f, 7.853981633974483f, 8.246680715673207f, 8.63937979737193f, 9.032078879070655f, 209 | 9.42477796076938f, 9.817477042468104f, 10.210176124166829f, 10.602875205865551f, 10.995574287564276f, 11.388273369263f, 11.780972450961723f, 12.173671532660448f, 210 | 12.566370614359172f 211 | }; 212 | 213 | std::cout << name << " = ["; 214 | 215 | for (const float r : radians) { 216 | float s = sin_func(r); 217 | std::cout << std::setprecision(12) << s << ","; 218 | } 219 | std::cout << "]" << std::endl; 220 | } 221 | 222 | template 223 | void log_tanh(F tanh_func, S name) noexcept { 224 | constexpr float values[] = { 225 | -4.0f, -3.9f, -3.8f, -3.7f, -3.6f, -3.5f, -3.4f, -3.3f, -3.2f, -3.1f, 226 | -3.0f, -2.9f, -2.8f, -2.7f, -2.6f, -2.5f, -2.4f, -2.3f, -2.2f, -2.1f, 227 | -2.0f, -1.9f, -1.8f, -1.7f, -1.6f, -1.5f, -1.4f, -1.3f, -1.2f, -1.1f, 228 | -1.0f, -0.9f, -0.8f, -0.7f, -0.6f, -0.5f, -0.4f, -0.3f, -0.2f, -0.1f, 229 | 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 230 | 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 231 | 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 232 | 3.0f, 3.1f, 3.2f, 3.3f, 3.4f, 3.5f, 3.6f, 3.7f, 3.8f, 3.9f, 233 | 4.0f, 234 | }; 235 | 236 | std::cout << name << " = ["; 237 | 238 | for (const float v : values) { 239 | float s = tanh_func(v); 240 | std::cout << std::setprecision(12) << s << ","; 241 | } 242 | std::cout << "]" << std::endl; 243 | } 244 | 245 | template 246 | void log_tan(F tan_func, S name) noexcept { 247 | constexpr float frequencies[] = { 248 | 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 249 | 100.0f, 200.0f, 300.0f, 400.0f, 500.0f, 600.0f, 700.0f, 800.0f, 900.0f, 250 | 1000.0f, 2000.0f, 3000.0f, 4000.0f, 5000.0f, 6000.0f, 7000.0f, 8000.0f, 9000.0f, 251 | 10'000.0f, 11'000.0f, 12'000.0f, 13'000.0f, 14'000.0f, 15'000.0f, 16'000.0f, 17'000.0f, 18'000.0f, 19'000.0f, 252 | 20'000.0f, 253 | }; 254 | 255 | std::cout << name << " = ["; 256 | 257 | const float sampleRate = 44100.0f; 258 | for (const float fc : frequencies) { 259 | // wc = pi * fc / fs 260 | float wc = static_cast(M_PI) * fc / sampleRate; 261 | float g = tan_func(wc); 262 | std::cout << std::setprecision(12) << g << ","; 263 | } 264 | std::cout << "]" << std::endl; 265 | } 266 | 267 | 268 | template 269 | void log_sqrt(F sqrt_func, S name) noexcept { 270 | constexpr float values[] = { 271 | 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 272 | 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 273 | 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 274 | 3.0f, 3.1f, 3.2f, 3.3f, 3.4f, 3.5f, 3.6f, 3.7f, 3.8f, 3.9f, 275 | 4.0f, 276 | }; 277 | 278 | std::cout << name << " = ["; 279 | 280 | for (const float v : values) { 281 | float s = sqrt_func(v); 282 | std::cout << std::setprecision(12) << s << ","; 283 | } 284 | std::cout << "]" << std::endl; 285 | } 286 | 287 | float gen_random() noexcept { 288 | static std::random_device rd; 289 | static std::mt19937 gen(rd()); 290 | static std::uniform_real_distribution dis(-1.0, 1.0); 291 | return dis(gen); 292 | } 293 | 294 | volatile float sink{}; // ensures a side effect 295 | 296 | int main() { 297 | auto benchmark = [](auto fun, auto rem) { 298 | const auto start = std::chrono::high_resolution_clock::now(); 299 | for (auto size{1ULL}; size != 10'000'000ULL; ++size) { 300 | sink = fun(gen_random()); 301 | } 302 | const std::chrono::duration diff = 303 | std::chrono::high_resolution_clock::now() - start; 304 | std::cout << "Time: " << std::fixed << std::setprecision(6) << diff.count() 305 | << " sec " << rem << std::endl; 306 | }; 307 | 308 | benchmark([](float x) { return x; }, "pass"); 309 | benchmark([](float x) { return x * x; }, "x^2"); 310 | 311 | /** SINE */ 312 | benchmark(fast::sin::stl, "stl"); 313 | // benchmark(fast::sin::taylor, "taylor 5"); 314 | // benchmark(fast::sin::taylor, "taylor 9"); 315 | // benchmark(fast::sin::taylor, "taylor 13"); 316 | // benchmark(fast::sin::taylor, "taylor 13"); 317 | // benchmark(fast::sin::taylorN, "taylorN 1"); 318 | // benchmark(fast::sin::taylorN, "taylorN 2"); 319 | // benchmark(fast::sin::taylorN, "taylorN 3"); 320 | // benchmark(fast::sin::taylorN, "taylorN 3"); 321 | benchmark(fast::sin::bhaskara_radians, "bhaskara_radians"); 322 | benchmark(fast::sin::pade, "pade"); 323 | benchmark(fast::sin::sin_approx, "sin_approx"); 324 | benchmark(fast::sin::slaru, "slaru"); 325 | benchmark(fast::sin::juha, "juha"); 326 | benchmark(fast::sin::juha_fmod, "juha_fmod"); 327 | benchmark(fast::sin::mineiro, "mineiro"); 328 | benchmark(fast::sin::mineiro_faster, "mineiro_faster"); 329 | benchmark(fast::sin::mineiro_full, "mineiro_full"); 330 | benchmark(fast::sin::mineiro_full_faster, "mineiro_full_faster"); 331 | benchmark(fast::sin::njuffa, "njuffa"); 332 | benchmark(fast::sin::wildmagic0, "wildmagic0"); 333 | benchmark(fast::sin::wildmagic1, "wildmagic1"); 334 | benchmark(fast::sin::bluemangoo, "bluemangoo"); 335 | benchmark(fast::sin::lanceputnam_gamma, "lanceputnam_gamma"); 336 | 337 | log_sin(fast::sin::stl, "stl"); 338 | log_sin(fast::sin::bhaskara_radians, "bhaskara_radians"); 339 | log_sin(fast::sin::pade, "pade"); 340 | log_sin(fast::sin::sin_approx, "sin_approx"); 341 | log_sin(fast::sin::slaru, "slaru"); 342 | log_sin(fast::sin::juha, "juha"); 343 | log_sin(fast::sin::juha_fmod, "juha_fmod"); 344 | log_sin(fast::sin::mineiro, "mineiro"); 345 | log_sin(fast::sin::mineiro_faster, "mineiro_faster"); 346 | log_sin(fast::sin::mineiro_full, "mineiro_full"); 347 | log_sin(fast::sin::mineiro_full_faster, "mineiro_full_faster"); 348 | log_sin(fast::sin::njuffa, "njuffa"); 349 | log_sin(fast::sin::wildmagic0, "wildmagic0"); 350 | log_sin(fast::sin::wildmagic1, "wildmagic1"); 351 | log_sin(fast::sin::bluemangoo, "bluemangoo"); 352 | log_sin(fast::sin::lanceputnam_gamma, "lanceputnam_gamma"); 353 | 354 | /** COS */ 355 | /** 356 | benchmark(fast::cos::stl, "stl"); 357 | benchmark(fast::cos::pade, "pade"); 358 | benchmark(fast::cos::milianw, "milianw"); 359 | benchmark(fast::cos::milianw_precise, "milianw_precise"); 360 | benchmark(fast::cos::juha, "juha"); 361 | benchmark(fast::cos::mineiro, "mineiro"); 362 | benchmark(fast::cos::mineiro_faster, "mineiro_faster"); 363 | benchmark(fast::cos::wildmagic0, "wildmagic0"); 364 | benchmark(fast::cos::wildmagic1, "wildmagic1"); 365 | 366 | log_sin(fast::cos::stl, "stl"); 367 | log_sin(fast::cos::pade, "pade"); 368 | log_sin(fast::cos::milianw, "milianw"); 369 | log_sin(fast::cos::milianw_precise, "milianw_precise"); 370 | log_sin(fast::cos::juha, "juha"); 371 | log_sin(fast::cos::mineiro, "mineiro"); 372 | log_sin(fast::cos::mineiro_faster, "mineiro_faster"); 373 | log_sin(fast::cos::wildmagic0, "wildmagic0"); 374 | log_sin(fast::cos::wildmagic1, "wildmagic1"); 375 | */ 376 | 377 | /** TAN */ 378 | /** 379 | benchmark(fast::tan::stl, "stl"); 380 | benchmark(fast::tan::pade, "pade"); 381 | benchmark(fast::tan::wildmagic0, "wildmagic0"); 382 | benchmark(fast::tan::wildmagic1, "wildmagic1"); 383 | benchmark(fast::tan::jrus_alt, "jrus_alt"); 384 | benchmark(fast::tan::jrus_alt_denorm, "jrus_alt_denorm"); 385 | benchmark(fast::tan::jrus_denorm, "jrus_denorm"); 386 | benchmark(fast::tan::jrus_full_denorm, "jrus_full_denorm"); 387 | benchmark(fast::tan::kay, "kay"); 388 | benchmark(fast::tan::kay_precise, "kay_precise"); 389 | 390 | log_tan(fast::tan::stl, "stl"); 391 | log_tan(fast::tan::pade, "pade"); 392 | log_tan(fast::tan::wildmagic0, "wildmagic0"); 393 | log_tan(fast::tan::wildmagic1, "wildmagic1"); 394 | log_tan(fast::tan::jrus_alt_denorm, "jrus_alt_denorm"); 395 | log_tan(fast::tan::jrus_denorm, "jrus_denorm"); 396 | log_tan(fast::tan::jrus_full_denorm, "jrus_full_denorm"); 397 | log_tan(fast::tan::kay, "kay"); 398 | log_tan(fast::tan::kay_precise, "kay_precise"); 399 | */ 400 | 401 | /** TANH */ 402 | /** 403 | benchmark(fast::tanh::stl, "stl"); 404 | benchmark(fast::tanh::pade, "pade"); 405 | benchmark(fast::tanh::c3, "c3"); 406 | benchmark(fast::tanh::exp_ekmett_ub, "exp_ekmett_ub"); 407 | benchmark(fast::tanh::exp_ekmett_lb, "exp_ekmett_lb"); 408 | benchmark(fast::tanh::exp_schraudolph, "exp_schraudolph"); 409 | benchmark(fast::tanh::exp_mineiro, "exp_mineiro"); 410 | benchmark(fast::tanh::exp_mineiro_faster, "exp_mineiro_faster"); 411 | 412 | log_tanh(fast::tanh::stl, "stl"); 413 | log_tanh(fast::tanh::pade, "pade"); 414 | log_tanh(fast::tanh::c3, "c3"); 415 | log_tanh(fast::tanh::exp_ekmett_ub, "exp_ekmett_ub"); 416 | log_tanh(fast::tanh::exp_ekmett_lb, "exp_ekmett_lb"); 417 | log_tanh(fast::tanh::exp_schraudolph, "exp_schraudolph"); 418 | log_tanh(fast::tanh::exp_mineiro, "exp_mineiro"); 419 | log_tanh(fast::tanh::exp_mineiro_faster, "exp_mineiro_faster"); 420 | */ 421 | 422 | /** LOG */ 423 | /** 424 | benchmark(fast::log::stl, "stl"); 425 | benchmark(fast::log::logNPlusOne, "logNPlusOne"); 426 | benchmark(fast::log::njuffa, "njuffa"); 427 | benchmark(fast::log::njuffa_faster, "njuffa_faster"); 428 | benchmark(fast::log::ankerl32, "ankerl32"); 429 | benchmark(fast::log::ekmett_lb, "ekmett_lb"); 430 | benchmark(fast::log::mineiro, "mineiro"); 431 | benchmark(fast::log::mineiro_faster, "mineiro_faster"); 432 | log_normalised_freq(fast::log::stl, "stl"); 433 | log_normalised_freq(fast::log::logNPlusOne, "logNPlusOne"); 434 | log_normalised_freq(fast::log::njuffa, "njuffa"); 435 | log_normalised_freq(fast::log::njuffa_faster, "njuffa_faster"); 436 | log_normalised_freq(fast::log::ankerl32, "ankerl32"); 437 | log_normalised_freq(fast::log::ekmett_lb, "ekmett_lb"); 438 | log_normalised_freq(fast::log::mineiro, "mineiro"); 439 | log_normalised_freq(fast::log::mineiro_faster, "mineiro_faster"); 440 | */ 441 | 442 | /** LOG2 */ 443 | /** 444 | benchmark(fast::log2::stl, "stl"); 445 | benchmark(fast::log2::lgeoffroy, "lgeoffroy"); 446 | benchmark(fast::log2::lgeoffroy_accurate, "lgeoffroy_accurate"); 447 | benchmark(fast::log2::jcook, "jcook"); 448 | benchmark(fast::log2::mineiro, "mineiro"); 449 | benchmark(fast::log2::mineiro_faster, "mineiro_faster"); 450 | benchmark(fast::log2::newton, "newton"); 451 | benchmark(fast::log2::desoras, "desoras"); 452 | benchmark(fast::log2::log1_njuffa, "log1_njuffa"); 453 | benchmark(fast::log2::log1_njuffa_faster, "log1_njuffa_faster"); 454 | benchmark(fast::log2::log1_ankerl32, "log1_ankerl32"); 455 | benchmark(fast::log2::log1_ekmett_lb, "log1_ekmett_lb"); 456 | 457 | log_hz_to_midi(fast::log2::stl, "stl"); 458 | log_hz_to_midi(fast::log2::lgeoffroy, "lgeoffroy"); 459 | log_hz_to_midi(fast::log2::lgeoffroy_accurate, "lgeoffroy_accurate"); 460 | log_hz_to_midi(fast::log2::jcook, "jcook"); 461 | log_hz_to_midi(fast::log2::mineiro, "mineiro"); 462 | log_hz_to_midi(fast::log2::mineiro_faster, "mineiro_faster"); 463 | log_hz_to_midi(fast::log2::newton, "newton"); 464 | log_hz_to_midi(fast::log2::desoras, "desoras"); 465 | log_hz_to_midi(fast::log2::log1_njuffa, "log1_njuffa"); 466 | log_hz_to_midi(fast::log2::log1_njuffa_faster, "log1_njuffa_faster"); 467 | log_hz_to_midi(fast::log2::log1_ankerl32, "log1_ankerl32"); 468 | log_hz_to_midi(fast::log2::log1_ekmett_lb, "log1_ekmett_lb"); 469 | */ 470 | 471 | /* 472 | log_ratio_to_midi_offset(fast::log2::stl, "stl"); 473 | log_ratio_to_midi_offset(fast::log2::lgeoffroy, "lgeoffroy"); 474 | log_ratio_to_midi_offset(fast::log2::lgeoffroy_accurate, "lgeoffroy_accurate"); 475 | log_ratio_to_midi_offset(fast::log2::jcook, "jcook"); 476 | log_ratio_to_midi_offset(fast::log2::mineiro, "mineiro"); 477 | log_ratio_to_midi_offset(fast::log2::mineiro_faster, "mineiro_faster"); 478 | log_ratio_to_midi_offset(fast::log2::newton, "newton"); 479 | log_ratio_to_midi_offset(fast::log2::desoras, "desoras"); 480 | log_ratio_to_midi_offset(fast::log2::log1_njuffa, "log1_njuffa"); 481 | log_ratio_to_midi_offset(fast::log2::log1_njuffa_faster, "log1_njuffa_faster"); 482 | log_ratio_to_midi_offset(fast::log2::log1_ankerl32, "log1_ankerl32"); 483 | log_ratio_to_midi_offset(fast::log2::log1_ekmett_lb, "log1_ekmett_lb"); 484 | log_ratio_to_midi_offset(fast::log2::log1_mineiro_faster, "log1_mineiro_faster"); 485 | */ 486 | 487 | /** LOG10 */ 488 | /* 489 | benchmark(fast::log10::stl, "stl"); 490 | benchmark(fast::log10::jcook, "jcook"); 491 | benchmark(fast::log10::newton, "newton"); 492 | benchmark(fast::log10::log1_njuffa, "log1_njuffa"); 493 | benchmark(fast::log10::log1_njuffa_faster, "log1_njuffa_faster"); 494 | benchmark(fast::log10::log1_ankerl32, "log1_ankerl32"); 495 | benchmark(fast::log10::log1_ekmett_ub, "log1_ekmett_ub"); 496 | benchmark(fast::log10::log1_ekmett_lb, "log1_ekmett_lb"); 497 | benchmark(fast::log10::log2_mineiro, "log2_mineiro"); 498 | benchmark(fast::log10::log2_mineiro_faster, "log2_mineiro_faster"); 499 | 500 | log_gain_to_db(fast::log10::stl, "stl"); 501 | log_gain_to_db(fast::log10::jcook, "jcook"); 502 | log_gain_to_db(fast::log10::newton, "newton"); 503 | log_gain_to_db(fast::log10::log1_njuffa, "log1_njuffa"); 504 | log_gain_to_db(fast::log10::log1_njuffa_faster, "log1_njuffa_faster"); 505 | log_gain_to_db(fast::log10::log1_ankerl32, "log1_ankerl32"); 506 | log_gain_to_db(fast::log10::log1_ekmett_ub, "log1_ekmett_ub"); 507 | log_gain_to_db(fast::log10::log1_ekmett_lb, "log1_ekmett_lb"); 508 | log_gain_to_db(fast::log10::log2_mineiro, "log2_mineiro"); 509 | log_gain_to_db(fast::log10::log2_mineiro_faster, "log2_mineiro_faster"); 510 | */ 511 | 512 | /** EXP2 */ 513 | /** 514 | benchmark([](float x) { return fast::exp2::stl(x); }, "exp2"); 515 | benchmark([](float x) { return fast::exp2::mineiro(x); }, "mineiro"); 516 | benchmark([](float x) { return fast::exp2::mineiro_faster(x); }, "mineiro_faster"); 517 | benchmark([](float x) { return fast::exp2::schraudolph(x); }, "schraudolph"); 518 | benchmark([](float x) { return (float)fast::exp2::desoras(x); }, "desoras"); 519 | benchmark([](float x) { return (float)fast::exp2::desoras_pos(x); }, "desoras_pos"); 520 | benchmark([](float x) { return fast::exp2::powx_stl(x); }, "powx_stl"); 521 | benchmark([](float x) { return fast::exp2::powx_ekmett_fast(x); }, "powx_ekmett_fast"); 522 | benchmark([](float x) { return fast::exp2::powx_ekmett_fast_lb(x); }, "powx_ekmett_fast_lb"); 523 | benchmark([](float x) { return fast::exp2::powx_ekmett_fast_ub(x); }, "powx_ekmett_fast_ub"); 524 | benchmark([](float x) { return fast::exp2::powx_ekmett_fast_precise(x); }, "powx_ekmett_fast_precise"); 525 | benchmark([](float x) { return fast::exp2::powx_ekmett_fast_better_precise(x); }, "powx_ekmett_fast_better_precise"); 526 | benchmark([](float x) { return fast::exp2::exp_stl(x); }, "exp_stl"); 527 | benchmark([](float x) { return fast::exp2::exp_ekmett_ub(x); }, "exp_ekmett_ub"); 528 | benchmark([](float x) { return fast::exp2::exp_schraudolph(x); }, "exp_schraudolph"); 529 | benchmark([](float x) { return fast::exp2::exp_mineiro(x); }, "exp_mineiro"); 530 | benchmark([](float x) { return fast::exp2::exp_mineiro_faster(x); }, "exp_mineiro_faster"); 531 | 532 | log_midi_to_hz([](float x) { return fast::exp2::stl(x); }, "exp2"); 533 | log_midi_to_hz([](float x) { return fast::exp2::mineiro(x); }, "mineiro"); 534 | log_midi_to_hz([](float x) { return fast::exp2::mineiro_faster(x); }, "mineiro_faster"); 535 | log_midi_to_hz([](float x) { return fast::exp2::schraudolph(x); }, "schraudolph"); 536 | log_midi_to_hz([](float x) { return (float)fast::exp2::desoras(x); }, "desoras"); 537 | log_midi_to_hz([](float x) { return fast::exp2::powx_stl(x); }, "powx_stl"); 538 | log_midi_to_hz([](float x) { return fast::exp2::powx_ekmett_fast(x); }, "powx_ekmett_fast"); 539 | log_midi_to_hz([](float x) { return fast::exp2::powx_ekmett_fast_lb(x); }, "powx_ekmett_fast_lb"); 540 | log_midi_to_hz([](float x) { return fast::exp2::powx_ekmett_fast_ub(x); }, "powx_ekmett_fast_ub"); 541 | log_midi_to_hz([](float x) { return fast::exp2::powx_ekmett_fast_precise(x); }, "powx_ekmett_fast_precise"); 542 | log_midi_to_hz([](float x) { return fast::exp2::powx_ekmett_fast_better_precise(x); }, "powx_ekmett_fast_better_precise"); 543 | log_midi_to_hz([](float x) { return fast::exp2::exp_stl(x); }, "exp_stl"); 544 | log_midi_to_hz([](float x) { return fast::exp2::exp_ekmett_ub(x); }, "exp_ekmett_ub"); 545 | log_midi_to_hz([](float x) { return fast::exp2::exp_schraudolph(x); }, "exp_schraudolph"); 546 | log_midi_to_hz([](float x) { return fast::exp2::exp_mineiro(x); }, "exp_mineiro"); 547 | log_midi_to_hz([](float x) { return fast::exp2::exp_mineiro_faster(x); }, "exp_mineiro_faster"); 548 | 549 | log_denormalised_freq([](float x) { return fast::exp2::stl(x); }, "exp2"); 550 | log_denormalised_freq([](float x) { return fast::exp2::mineiro(x); }, "mineiro"); 551 | log_denormalised_freq([](float x) { return fast::exp2::mineiro_faster(x); }, "mineiro_faster"); 552 | log_denormalised_freq([](float x) { return fast::exp2::schraudolph(x); }, "schraudolph"); 553 | log_denormalised_freq([](float x) { return (float)fast::exp2::desoras(x); }, "desoras"); 554 | log_denormalised_freq([](float x) { return fast::exp2::powx_stl(x); }, "powx_stl"); 555 | log_denormalised_freq([](float x) { return fast::exp2::powx_ekmett_fast(x); }, "powx_ekmett_fast"); 556 | log_denormalised_freq([](float x) { return fast::exp2::powx_ekmett_fast_lb(x); }, "powx_ekmett_fast_lb"); 557 | log_denormalised_freq([](float x) { return fast::exp2::powx_ekmett_fast_ub(x); }, "powx_ekmett_fast_ub"); 558 | log_denormalised_freq([](float x) { return fast::exp2::powx_ekmett_fast_precise(x); }, "powx_ekmett_fast_precise"); 559 | log_denormalised_freq([](float x) { return fast::exp2::powx_ekmett_fast_better_precise(x); }, "powx_ekmett_fast_better_precise"); 560 | log_denormalised_freq([](float x) { return fast::exp2::exp_stl(x); }, "exp_stl"); 561 | log_denormalised_freq([](float x) { return fast::exp2::exp_ekmett_ub(x); }, "exp_ekmett_ub"); 562 | log_denormalised_freq([](float x) { return fast::exp2::exp_schraudolph(x); }, "exp_schraudolph"); 563 | log_denormalised_freq([](float x) { return fast::exp2::exp_mineiro(x); }, "exp_mineiro"); 564 | log_denormalised_freq([](float x) { return fast::exp2::exp_mineiro_faster(x); }, "exp_mineiro_faster"); 565 | */ 566 | 567 | /** EXP */ 568 | // benchmark(fast::exp::stl, "stl"); 569 | // benchmark(fast::exp::ekmett_ub, "ekmett_ub"); 570 | // benchmark(fast::exp::schraudolph, "schraudolph"); 571 | // benchmark(fast::exp::mineiro, "mineiro"); 572 | // benchmark(fast::exp::mineiro_faster, "mineiro_faster"); 573 | 574 | /** EXP10 */ 575 | /** 576 | benchmark([](float x) { return fast::exp10::powx_stl(x); }, "powx_stl"); 577 | benchmark([](float x) { return fast::exp10::powx_ekmett_fast(x); }, "powx_ekmett_fast"); 578 | benchmark([](float x) { return fast::exp10::powx_ekmett_fast_lb(x); }, "powx_ekmett_fast_lb"); 579 | benchmark([](float x) { return fast::exp10::powx_ekmett_fast_ub(x); }, "powx_ekmett_fast_ub"); 580 | benchmark([](float x) { return fast::exp10::powx_ekmett_fast_precise(x); }, "powx_ekmett_fast_precise"); 581 | benchmark([](float x) { return fast::exp10::powx_ekmett_fast_better_precise(x); }, "powx_ekmett_fast_better_precise"); 582 | benchmark([](float x) { return fast::exp10::exp_stl(x); }, "exp_stl"); 583 | benchmark([](float x) { return fast::exp10::exp_ekmett_lb(x); }, "exp_ekmett_lb"); 584 | benchmark([](float x) { return fast::exp10::exp_ekmett_ub(x); }, "exp_ekmett_ub"); 585 | benchmark([](float x) { return fast::exp10::exp_schraudolph(x); }, "exp_schraudolph"); 586 | benchmark([](float x) { return fast::exp10::exp_mineiro(x); }, "exp_mineiro"); 587 | benchmark([](float x) { return fast::exp10::exp_mineiro_faster(x); }, "exp_mineiro_faster"); 588 | 589 | log_db_to_gain([](float x) { return fast::exp10::powx_stl(x); }, "powx_stl"); 590 | log_db_to_gain([](float x) { return fast::exp10::powx_ekmett_fast(x); }, "powx_ekmett_fast"); 591 | log_db_to_gain([](float x) { return fast::exp10::powx_ekmett_fast_lb(x); }, "powx_ekmett_fast_lb"); 592 | log_db_to_gain([](float x) { return fast::exp10::powx_ekmett_fast_ub(x); }, "powx_ekmett_fast_ub"); 593 | log_db_to_gain([](float x) { return fast::exp10::powx_ekmett_fast_precise(x); }, "powx_ekmett_fast_precise"); 594 | log_db_to_gain([](float x) { return fast::exp10::powx_ekmett_fast_better_precise(x); }, "powx_ekmett_fast_better_precise"); 595 | log_db_to_gain([](float x) { return fast::exp10::exp_stl(x); }, "exp_stl"); 596 | log_db_to_gain([](float x) { return fast::exp10::exp_ekmett_lb(x); }, "exp_ekmett_lb"); 597 | log_db_to_gain([](float x) { return fast::exp10::exp_ekmett_ub(x); }, "exp_ekmett_ub"); 598 | log_db_to_gain([](float x) { return fast::exp10::exp_schraudolph(x); }, "exp_schraudolph"); 599 | log_db_to_gain([](float x) { return fast::exp10::exp_mineiro(x); }, "exp_mineiro"); 600 | log_db_to_gain([](float x) { return fast::exp10::exp_mineiro_faster(x); }, "exp_mineiro_faster"); 601 | */ 602 | 603 | /** SQRT */ 604 | /** 605 | benchmark(fast::sqrt::stl, "stl"); 606 | benchmark(fast::sqrt::bigtailwolf, "bigtailwolf"); 607 | benchmark(fast::sqrt::nimig18, "nimig18"); // awful 608 | 609 | log_sqrt(fast::sqrt::stl, "stl"); 610 | log_sqrt(fast::sqrt::bigtailwolf, "bigtailwolf"); 611 | log_sqrt(fast::sqrt::nimig18, "nimig18"); 612 | */ 613 | } 614 | -------------------------------------------------------------------------------- /pow.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fast { 4 | namespace pow { 5 | 6 | static inline float stl(float a, float b) noexcept { return std::powf(a, b); } 7 | 8 | // https://martin.ankerl.com/2007/10/04/optimized-pow-approximation-for-java-and-c-c/ 9 | // meant for doubles 10 | static inline double ankerl64(double a, double b) { 11 | union { double d; int x[2]; } u = { a }; 12 | u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447); 13 | u.x[0] = 0; 14 | return u.d; 15 | } 16 | 17 | // NOTE: while loop can cause infinite loops. Not recommended! 18 | // https://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/ 19 | // should be much more precise with large b 20 | static inline double ankerl_precise64(double a, double b) { 21 | // calculate approximation with fraction of the exponent 22 | int e = (int) b; 23 | union { double d; int x[2]; } u = { a }; 24 | u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447); 25 | u.x[0] = 0; 26 | 27 | // exponentiation by squaring with the exponent's integer part 28 | // double r = u.d makes everything much slower, not sure why 29 | double r = 1.0; 30 | while (e) { 31 | if (e & 1) { 32 | r *= a; 33 | } 34 | a *= a; 35 | e >>= 1; 36 | } 37 | 38 | return r * u.d; 39 | } 40 | 41 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 42 | /* 1065353216 + 1 = 1065353217 ub */ 43 | /* 1065353216 - 486411 = 1064866805 min RMSE */ 44 | /* 1065353216 - 722019 = 1064631197 lb */ 45 | static inline float ekmett_fast(float a, float b) noexcept { 46 | union { float d; int x; } u = { a }; 47 | u.x = (int)(b * (u.x - 1064866805) + 1064866805); 48 | return u.d; 49 | } 50 | 51 | static inline float ekmett_fast_lb(float a, float b) noexcept { 52 | union { float d; int x; } u = { a }; 53 | u.x = (int)(b * (u.x - 1065353217) + 1064631197); 54 | return u.d; 55 | } 56 | 57 | static inline float ekmett_fast_ub(float a, float b) noexcept { 58 | union { float d; int x; } u = { a }; 59 | u.x = (int)(b * (u.x - 1064631197) + 1065353217); 60 | return u.d; 61 | } 62 | 63 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 64 | /* should be much more precise with large b */ 65 | // slower than stl 66 | static inline float ekmett_fast_precise(float a, float b) { 67 | int flipped = 0; 68 | if (b < 0) { 69 | flipped = 1; 70 | b = -b; 71 | } 72 | 73 | /* calculate approximation with fraction of the exponent */ 74 | int e = (int) b; 75 | union { float f; int x; } u = { a }; 76 | u.x = (int)((b - e) * (u.x - 1065353216) + 1065353216); 77 | 78 | float r = 1.0f; 79 | while (e) { 80 | if (e & 1) { 81 | r *= a; 82 | } 83 | a *= a; 84 | e >>= 1; 85 | } 86 | 87 | r *= u.f; 88 | return flipped ? (1.0f / r) : r; 89 | } 90 | 91 | // https://github.com/ekmett/approximate/blob/master/cbits/fast.c 92 | /* should be much more precise with large b */ 93 | // slower than stl 94 | static inline float __better_expf_fast(float a) { 95 | union { float f; int x; } u, v; 96 | u.x = (int)(6051102 * a + 1056478197); 97 | v.x = (int)(1056478197 - 6051102 * a); 98 | return u.f / v.f; 99 | } 100 | static inline float ekmett_fast_better_precise(float a, float b) { 101 | int flipped = 0; 102 | if (b < 0) { 103 | flipped = 1; 104 | b = -b; 105 | } 106 | 107 | /* calculate approximation with fraction of the exponent */ 108 | int e = (int) b; 109 | float f = __better_expf_fast(b - e); 110 | 111 | float r = 1.0f; 112 | while (e) { 113 | if (e & 1) { 114 | r *= a; 115 | } 116 | a *= a; 117 | e >>= 1; 118 | } 119 | 120 | r *= f; 121 | return flipped ? 1.0f/r : r; 122 | } 123 | 124 | 125 | } // namespace pow 126 | } // namespace fast 127 | -------------------------------------------------------------------------------- /sin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "./common.hpp" 4 | 5 | namespace fast { 6 | namespace sin { 7 | 8 | static inline float stl(float x) noexcept { return std::sinf(x); } 9 | 10 | // based on https://stackoverflow.com/questions/18662261/fastest-implementation-of-sine-cosine-and-square-root-in-c-doesnt-need-to-b 11 | template 12 | constexpr T taylor(T x) noexcept { 13 | T sum = 0; 14 | T power = x; 15 | T sign = 1; 16 | const T x2 = x * x; 17 | T Fact = 1.0; 18 | for (unsigned int i=1; i(-1); 24 | } 25 | return sum; 26 | } 27 | 28 | // own implementation 29 | // slower than above method when N is low, faster when N is >= 3 30 | template 31 | constexpr T taylorN(T x) noexcept { 32 | // sin(x) = x - x^3 / 3! + x^5 / 5! 33 | T x2 = x * x; 34 | T x3 = x * x2; 35 | T x5 = x3 * x2; 36 | T y = x; 37 | for (int i = 0; i < N; i++) { 38 | auto d3 = i * 4 + 3; 39 | auto d5 = i * 4 + 5; 40 | y -= x3 / d3 + x5 / d5; 41 | x3 = x5; 42 | x5 = x5 * x2; 43 | } 44 | return y; 45 | } 46 | 47 | // https://www.musicdsp.org/en/latest/Other/93-hermite-interpollation.html 48 | constexpr float __hermiteInterpolate(float v0, float v1, float v2, float v3, float offset) { 49 | float slope0 = (v2 - v0) * 0.5f; 50 | float slope1 = (v3 - v1) * 0.5f; 51 | 52 | float v = v1 - v2; 53 | float w = slope0 + v; 54 | float a = w + v + slope1; 55 | float b_neg = w + a; 56 | float stage1 = a * offset - b_neg; 57 | float stage2 = stage1 * offset + slope0; 58 | float result = stage2 * offset + v1; 59 | return result; 60 | } 61 | 62 | // fairly accurate in values between -pi & pi, but not beyond that 63 | // ~ 32% faster than std::sin 64 | // JUCE uses this 65 | // https://github.com/juce-framework/JUCE/blob/master/modules/juce_dsp/maths/juce_FastMathApproximations.h 66 | template 67 | constexpr T pade (T x) noexcept { 68 | T x2 = x * x; 69 | T numerator = -x * (-11511339840 + x2 * (1640635920 + x2 * (-52785432 + x2 * 479249))); 70 | T denominator = 11511339840 + x2 * (277920720 + x2 * (3177720 + x2 * 18361)); 71 | return numerator / denominator; 72 | } 73 | 74 | // not sure where i found this 75 | // fairly accurate in values between -pi & pi, but not beyond that 76 | // ~28% faster than std::sin 77 | template 78 | constexpr T sin_approx(T x) noexcept { 79 | T pi_major = static_cast(3.1415927); 80 | T pi_minor = static_cast(-0.00000008742278); 81 | T x2 = x*x; 82 | T p11 = static_cast(0.00000000013291342); 83 | T p9 = p11*x2 + static_cast(-0.000000023317787); 84 | T p7 = p9*x2 + static_cast(0.0000025222919); 85 | T p5 = p7*x2 + static_cast(-0.00017350505); 86 | T p3 = p5*x2 + static_cast(0.0066208798); 87 | T p1 = p3*x2 + static_cast(-0.10132118); 88 | return (x - pi_major - pi_minor) * 89 | (x + pi_major + pi_minor) * p1 * x; 90 | } 91 | 92 | // https://en.wikipedia.org/wiki/Bhaskara_I's_sine_approximation_formula 93 | template 94 | constexpr T bhaskara_degrees(T x) noexcept { 95 | return 4 * x * (180 - x) / (40500 - x * (180 - x)); 96 | } 97 | // very very fast 98 | // ~43% faster than stl 99 | template 100 | constexpr T bhaskara_radians(T x) noexcept { 101 | return 16 * x * (static_cast(M_PI) - x) / 102 | (25 * static_cast(M_PI) * static_cast(M_PI) - 4 * x * (static_cast(M_PI) - x)); 103 | } 104 | 105 | // https://web.archive.org/web/20141220225551/http://forum.devmaster.net/t/fast-and-accurate-sine-cosine/9648 106 | template 107 | constexpr T slaru(T x) noexcept { 108 | const T B = 4/static_cast(M_PI); 109 | const T C = -4/(static_cast(M_PI)*static_cast(M_PI)); 110 | 111 | T y = B * x 112 | + C * x * abs(x); 113 | 114 | // const float Q = 0.775; 115 | const T P = static_cast(0.225); 116 | 117 | y = P * (y * abs(y) - y) + y; // Q * y + P * y * abs(y) 118 | return y; 119 | } 120 | 121 | // very very fast 122 | // ~46% faster than stl 123 | // https://stackoverflow.com/a/71674578 124 | template 125 | constexpr T juha(float x) noexcept { 126 | return 4 * static_cast(0.31830988618) * x * (1 - static_cast(0.31830988618) * std::abs(x)); 127 | } 128 | 129 | // I edited juha to cycle well over +/- pi 130 | static inline float juha_fmod(float x) noexcept { 131 | int times = (int)(x / static_cast(M_PI)); 132 | 133 | // correct sign 134 | union { float f; int i; } y = { juha(std::fmodf(x, static_cast(M_PI))) }; 135 | y.i ^= times << 31; 136 | return y.f; 137 | } 138 | 139 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fasttrig.h 140 | static inline float mineiro (float x) noexcept { 141 | static const float fouroverpi = 1.2732395447351627f; 142 | static const float fouroverpisq = 0.40528473456935109f; 143 | static const float q = 0.78444488374548933f; 144 | union { float f; uint32_t i; } p = { 0.20363937680730309f }; 145 | union { float f; uint32_t i; } r = { 0.015124940802184233f }; 146 | union { float f; uint32_t i; } s = { -0.0032225901625579573f }; 147 | 148 | union { float f; uint32_t i; } vx = { x }; 149 | uint32_t sign = vx.i & 0x80000000; 150 | vx.i = vx.i & 0x7FFFFFFF; 151 | 152 | float qpprox = fouroverpi * x - fouroverpisq * x * vx.f; 153 | float qpproxsq = qpprox * qpprox; 154 | 155 | p.i |= sign; 156 | r.i |= sign; 157 | s.i ^= sign; 158 | 159 | return q * qpprox + qpproxsq * (p.f + qpproxsq * (r.f + qpproxsq * s.f)); 160 | } 161 | 162 | static inline float mineiro_faster (float x) noexcept { 163 | static const float fouroverpi = 1.2732395447351627f; 164 | static const float fouroverpisq = 0.40528473456935109f; 165 | static const float q = 0.77633023248007499f; 166 | union { float f; uint32_t i; } p = { 0.22308510060189463f }; 167 | 168 | union { float f; uint32_t i; } vx = { x }; 169 | uint32_t sign = vx.i & 0x80000000; 170 | vx.i &= 0x7FFFFFFF; 171 | 172 | float qpprox = fouroverpi * x 173 | - fouroverpisq * x * vx.f; 174 | 175 | p.i |= sign; 176 | 177 | return qpprox * (q + p.f * qpprox); 178 | } 179 | 180 | static inline float mineiro_full (float x) noexcept { 181 | static const float twopi = 6.2831853071795865f; 182 | static const float invtwopi = 0.15915494309189534f; 183 | 184 | int k = (int)(x * invtwopi); 185 | float half = (x < 0) ? -0.5f : 0.5f; 186 | return mineiro ((half + k) * twopi - x); 187 | } 188 | 189 | static inline float mineiro_full_faster (float x) noexcept { 190 | static const float twopi = 6.2831853071795865f; 191 | static const float invtwopi = 0.15915494309189534f; 192 | 193 | int k = (int)(x * invtwopi); 194 | float half = (x < 0) ? -0.5f : 0.5f; 195 | return mineiro_faster ((half + k) * twopi - x); 196 | } 197 | 198 | // This is slower than stl for 32/64/128 floats 199 | // https://stackoverflow.com/a/11575574 200 | template 201 | constexpr T __rint (T x) noexcept { 202 | T t = floor(std::fabs(x) + static_cast(0.5)); 203 | return (x < 0) ? -t : t; 204 | } 205 | template 206 | constexpr T __cos_core (T x) noexcept { 207 | T x8, x4, x2; 208 | x2 = x * x; 209 | x4 = x2 * x2; 210 | x8 = x4 * x4; 211 | /* evaluate polynomial using Estrin's scheme */ 212 | return (static_cast(-2.7236370439787708e-7) * x2 + static_cast(2.4799852696610628e-5)) * x8 + 213 | (static_cast(-1.3888885054799695e-3) * x2 + static_cast(4.1666666636943683e-2)) * x4 + 214 | (static_cast(-4.9999999999963024e-1) * x2 + static_cast(1.0000000000000000e+0)); 215 | } 216 | /* minimax approximation to sin on [-pi/4, pi/4] with rel. err. ~= 5.5e-12 */ 217 | template 218 | constexpr T __sin_core (T x) noexcept { 219 | T x4, x2; 220 | x2 = x * x; 221 | x4 = x2 * x2; 222 | /* evaluate polynomial using a mix of Estrin's and Horner's scheme */ 223 | return ((static_cast(2.7181216275479732e-6) * x2 - static_cast(1.9839312269456257e-4)) * x4 + 224 | (static_cast(8.3333293048425631e-3) * x2 - static_cast(1.6666666640797048e-1))) * x2 * x + x; 225 | } 226 | 227 | /* relative error < 7e-12 on [-50000, 50000] */ 228 | template 229 | constexpr T njuffa (T x) noexcept { 230 | T q, t; 231 | int quadrant; 232 | /* Cody-Waite style argument reduction */ 233 | q = __rint (x * static_cast(6.3661977236758138e-1)); 234 | quadrant = (int)q; 235 | t = x - q * static_cast(1.5707963267923333e+00); 236 | t = t - q * static_cast(2.5633441515945189e-12); 237 | if (quadrant & 1) { 238 | t = __cos_core(t); 239 | } else { 240 | t = __sin_core(t); 241 | } 242 | return (quadrant & 2) ? -t : t; 243 | } 244 | 245 | // https://www.musicdsp.org/en/latest/Other/115-sin-cos-tan-approximation.html 246 | static inline float wildmagic0 (float fAngle) noexcept { 247 | float fASqr = fAngle*fAngle; 248 | float fResult = 7.61e-03f; 249 | fResult *= fASqr; 250 | fResult -= 1.6605e-01f; 251 | fResult *= fASqr; 252 | fResult += 1.0f; 253 | fResult *= fAngle; 254 | return fResult; 255 | } 256 | //---------------------------------------------------------------------- 257 | static inline float wildmagic1 (float fAngle) noexcept { 258 | float fASqr = fAngle*fAngle; 259 | float fResult = -2.39e-08f; 260 | fResult *= fASqr; 261 | fResult += 2.7526e-06f; 262 | fResult *= fASqr; 263 | fResult -= 1.98409e-04f; 264 | fResult *= fASqr; 265 | fResult += 8.3333315e-03f; 266 | fResult *= fASqr; 267 | fResult -= 1.666666664e-01f; 268 | fResult *= fASqr; 269 | fResult += 1.0f; 270 | fResult *= fAngle; 271 | return fResult; 272 | } 273 | 274 | // in [-1,1], out [-0.25, 0.25] 275 | // https://bmtechjournal.wordpress.com/2020/05/27/super-fast-quadratic-sinusoid-approximation/ 276 | static inline float bluemangoo_original(float x) 277 | { 278 | return -x * fabsf(x) + x; 279 | } 280 | // in [-pi,pi], out [-1,1] 281 | static inline float bluemangoo(float x) 282 | { 283 | float x2 = x * float(M_1_PI); 284 | float y = -x2 * fabsf(x2) + x2; 285 | return 4 * y; 286 | } 287 | 288 | // [0, 2] corresponding to [0, pi] 289 | // https://github.com/LancePutnam/Gamma/blob/0ab245147c8bbebe1e96eb301e52ebb47c8c1c60/Gamma/scl.h#L963 290 | static float lanceputnam_gamma_original(float x) 291 | { 292 | float y = x * (2.0f - x); 293 | return y * (0.775f + 0.225f * y); 294 | } 295 | // More forgiving inputs 296 | // [-pi, pi] 297 | static float lanceputnam_gamma(float x) 298 | { 299 | float ax = fabsf(x * float(M_2_PI)); 300 | float y = ax * (2.0f - ax); 301 | y = y * (0.775f + 0.225f * y); 302 | return x < 0 ? -y : y; 303 | } 304 | 305 | } // namespace sin 306 | } // namespace fast 307 | -------------------------------------------------------------------------------- /sqrt.hpp: -------------------------------------------------------------------------------- 1 | namespace fast { 2 | namespace sqrt { 3 | 4 | static inline float stl(float x) noexcept { return std::sqrt(x); } 5 | 6 | // https://stackoverflow.com/a/18662665 7 | static inline float bigtailwolf(float x) noexcept { 8 | unsigned int i = *(unsigned int*) &x; 9 | 10 | // adjust bias 11 | i += 127 << 23; 12 | // approximation of square root 13 | i >>= 1; 14 | 15 | return *(float*) &i; 16 | } 17 | 18 | // much slower than stl 19 | // https://stackoverflow.com/a/43176496 20 | static inline float nimig18(float x) noexcept { 21 | union {float f; uint32_t i; } X, Y; 22 | float ScOff; 23 | uint32_t e; 24 | 25 | X.f = x; 26 | e = X.i >> 23; // f.SFPbits.e; 27 | 28 | // if(x <= 0) return(0.0f); 29 | 30 | ScOff = ((e & 1) != 0) ? 1.0f : 0x1.6a09e6p0; // NOTE: If exp=EVEN, b/c (exp-127) a (EVEN - ODD) := ODD; but a (ODD - ODD) := EVEN!! 31 | 32 | e = ((e + 127) >> 1); // NOTE: If exp=ODD, b/c (exp-127) then flr((exp-127)/2) 33 | X.i = (X.i & ((1uL << 23) - 1)) | (0x7F << 23); // Mask mantissa, force exponent to zero. 34 | Y.i = (((uint32_t) e) << 23); 35 | 36 | // Error grows with square root of the exponent. Unfortunately no work around like inverse square root... :( 37 | // Y.f *= ScOff * (0x9.5f61ap-4 + X.f*(0x6.a09e68p-4)); // Error = +-1.78e-2 * 2^(flr(log2(x)/2)) 38 | // Y.f *= ScOff * (0x7.2181d8p-4 + X.f*(0xa.05406p-4 + X.f*(-0x1.23a14cp-4))); // Error = +-7.64e-5 * 2^(flr(log2(x)/2)) 39 | // Y.f *= ScOff * (0x5.f10e7p-4 + X.f*(0xc.8f2p-4 +X.f*(-0x2.e41a4cp-4 + X.f*(0x6.441e6p-8)))); // Error = 8.21e-5 * 2^(flr(log2(x)/2)) 40 | // Y.f *= ScOff * (0x5.32eb88p-4 + X.f*(0xe.abbf5p-4 + X.f*(-0x5.18ee2p-4 + X.f*(0x1.655efp-4 + X.f*(-0x2.b11518p-8))))); // Error = +-9.92e-6 * 2^(flr(log2(x)/2)) 41 | // Y.f *= ScOff * (0x4.adde5p-4 + X.f*(0x1.08448cp0 + X.f*(-0x7.ae1248p-4 + X.f*(0x3.2cf7a8p-4 + X.f*(-0xc.5c1e2p-8 + X.f*(0x1.4b6dp-8)))))); // Error = +-1.38e-6 * 2^(flr(log2(x)/2)) 42 | // Y.f *= ScOff * (0x4.4a17fp-4 + X.f*(0x1.22d44p0 + X.f*(-0xa.972e8p-4 + X.f*(0x5.dd53fp-4 + X.f*(-0x2.273c08p-4 + X.f*(0x7.466cb8p-8 + X.f*(-0xa.ac00ep-12))))))); // Error = +-2.9e-7 * 2^(flr(log2(x)/2)) 43 | Y.f *= ScOff * (0x3.fbb3e8p-4 + X.f*(0x1.3b2a3cp0 + X.f*(-0xd.cbb39p-4 + X.f*(0x9.9444ep-4 + X.f*(-0x4.b5ea38p-4 + X.f*(0x1.802f9ep-4 + X.f*(-0x4.6f0adp-8 + X.f*(0x5.c24a28p-12 )))))))); // Error = +-2.7e-6 * 2^(flr(log2(x)/2)) 44 | 45 | return Y.f; 46 | } 47 | 48 | } // namespace sqrt 49 | } // namespace fast 50 | -------------------------------------------------------------------------------- /tan.hpp: -------------------------------------------------------------------------------- 1 | namespace fast { 2 | namespace tan { 3 | 4 | static inline float stl(float x) noexcept { return std::tanf(x); } 5 | 6 | // https://github.com/juce-framework/JUCE/blob/master/modules/juce_dsp/maths/juce_FastMathApproximations.h 7 | static inline float pade (float x) noexcept { 8 | auto x2 = x * x; 9 | auto numerator = x * (-135135 + x2 * (17325 + x2 * (-378 + x2))); 10 | auto denominator = -135135 + x2 * (62370 + x2 * (-3150 + 28 * x2)); 11 | return numerator / denominator; 12 | } 13 | 14 | // https://www.musicdsp.org/en/latest/Other/115-sin-cos-tan-approximation.html 15 | static inline float wildmagic0 (float fAngle) noexcept { 16 | float fASqr = fAngle * fAngle; 17 | float fResult = 2.033e-01f; 18 | fResult *= fASqr; 19 | fResult += 3.1755e-01f; 20 | fResult *= fASqr; 21 | fResult += 1.0f; 22 | fResult *= fAngle; 23 | return fResult; 24 | } 25 | static inline float wildmagic1 (float fAngle) noexcept { 26 | float fASqr = fAngle * fAngle; 27 | float fResult = 9.5168091e-03f; 28 | fResult *= fASqr; 29 | fResult += 2.900525e-03f; 30 | fResult *= fASqr; 31 | fResult += 2.45650893e-02f; 32 | fResult *= fASqr; 33 | fResult += 5.33740603e-02f; 34 | fResult *= fASqr; 35 | fResult += 1.333923995e-01f; 36 | fResult *= fASqr; 37 | fResult += 3.333314036e-01f; 38 | fResult *= fASqr; 39 | fResult += 1.0f; 40 | fResult *= fAngle; 41 | return fResult; 42 | } 43 | 44 | // https://observablehq.com/@jrus/fasttan 45 | // NOTE: this function is normalised to take normalised halfpi values 46 | // Regular tan functions will cycle after halfpi (1.57), this cycles 47 | // after 1.0 48 | // This is ideal for calculating tan(πfc/fs) 49 | static inline float jrus_alt(float x) noexcept { 50 | // 3 add, 3 mult, 1 div 51 | float y = 1 - x * x; 52 | return x * (-0.0187108f * y + 0.31583526f + 1.27365776f / y); 53 | } 54 | 55 | static inline float jrus_alt_denorm(float x) noexcept { 56 | x *= 0.6366197723675814f; 57 | float y = 1 - x * x; 58 | return x * (-0.0187108f * y + 0.31583526f + 1.27365776f / y); 59 | } 60 | 61 | 62 | static inline float jrus_denorm(float x) noexcept { 63 | x *= 0.6366197723675814; 64 | float y = (1 - x*x); 65 | return x * (((-0.000221184f * y + 0.0024971104f) * y - 0.02301937096f) * y + 0.3182994604f + 1.2732402998f / y); 66 | } 67 | 68 | static inline float jrus_full_denorm(float x) noexcept { 69 | x *= 0.6366197723675814f; 70 | 71 | // 2**54 = 18014398509481984 72 | float S = 18014398509481984.0 * ((x > 0) - (x < 0)); 73 | x -= (x - S) + S; // reduce range to -1...1 74 | float y = (1 - x * x); 75 | return x * (((-0.00023552f * y + 0.002530368f) * y - 0.023045536f) * y 76 | + 0.3183073636f + 1.2732395912f / y); 77 | } 78 | 79 | // license = Public domain 80 | // https://andrewkay.name/blog/post/efficiently-approximating-tan-x/ 81 | static inline float kay (float x) noexcept { 82 | // 3 mult, 2 sub, 1 div 83 | static const float pisqby4 = 2.4674011002723397f; 84 | static const float oneminus8bypisq = 0.1894305308612978f; 85 | float xsq = x*x; 86 | return x * (pisqby4 - oneminus8bypisq * xsq) / (pisqby4 - xsq); 87 | } 88 | 89 | // approximation of tan with lower relative error 90 | // https://andrewkay.name/blog/post/efficiently-approximating-tan-x/ 91 | static inline float kay_precise (float x) noexcept { 92 | // 3 mult, 2 sub, 1 div 93 | static const float pisqby4 = 2.4674011002723397f; 94 | static const float adjpisqby4 = 2.471688400562703f; 95 | static const float adj1minus8bypisq = 0.189759681063053f; 96 | float xsq = x * x; 97 | return x * (adjpisqby4 - adj1minus8bypisq * xsq) / (pisqby4 - xsq); 98 | } 99 | 100 | } // namespace tan 101 | } // namespace fast 102 | -------------------------------------------------------------------------------- /tanh.hpp: -------------------------------------------------------------------------------- 1 | #include "exp.hpp" 2 | 3 | namespace fast { 4 | namespace tanh { 5 | 6 | template 7 | constexpr T stl(T x) noexcept { return std::tanh(x); } 8 | 9 | // https://github.com/juce-framework/JUCE/blob/master/modules/juce_dsp/maths/juce_FastMathApproximations.h 10 | template 11 | constexpr T pade (T x) noexcept { 12 | auto x2 = x * x; 13 | auto numerator = x * (135135 + x2 * (17325 + x2 * (378 + x2))); 14 | auto denominator = 135135 + x2 * (62370 + x2 * (3150 + 28 * x2)); 15 | return numerator / denominator; 16 | } 17 | 18 | // https://math.stackexchange.com/a/3485944 19 | static float c3(float v) noexcept { 20 | const float c1 = 0.03138777F; 21 | const float c2 = 0.276281267F; 22 | const float c_log2f = 1.442695022F; 23 | v *= c_log2f; 24 | int intPart = (int)v; 25 | float x = (v - intPart); 26 | float xx = x * x; 27 | float v1 = c_log2f + c2 * xx; 28 | float v2 = x + xx * c1 * x; 29 | float v3 = (v2 + v1); 30 | *((int*)&v3) += intPart << 24; 31 | float v4 = v2 - v1; 32 | return (v3 + v4) / (v3 - v4); 33 | } 34 | 35 | // these are slower 36 | // https://stackoverflow.com/q/29239343 37 | // static float big_bang(float x) noexcept { 38 | // return 2 / (1 + std::exp(-2 * x)) - 1; 39 | // } 40 | // // https://stackoverflow.com/a/60505422 41 | // static float spagnum_moss(float x) noexcept { 42 | // return 1 - (2 * (1 / (1 + std::exp(x * 2)))); 43 | // } 44 | 45 | static inline float exp_ekmett_ub (float p) noexcept { return -1 + 2 / (1 + exp::ekmett_ub(-2 * p)); } 46 | static inline float exp_ekmett_lb (float p) noexcept { return -1 + 2 / (1 + exp::ekmett_lb(-2 * p)); } 47 | static inline float exp_schraudolph (float p) noexcept { return -1 + 2 / (1 + exp::schraudolph(-2 * p)); } 48 | 49 | // https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fasthyperbolic.h 50 | static inline float exp_mineiro (float p) noexcept { return -1 + 2 / (1 + exp::mineiro (-2 * p)); } 51 | static inline float exp_mineiro_faster (float p) noexcept { return -1 + 2 / (1 + exp::mineiro_faster(-2 * p)); } 52 | 53 | 54 | 55 | } // namespace tanh 56 | } // namespace fast 57 | --------------------------------------------------------------------------------