| 
							- #pragma once
 - #include <dsp/common.hpp>
 - 
 - 
 - namespace rack {
 - namespace dsp {
 - 
 - 
 - /*
 - Glossary:
 - https://en.wikipedia.org/wiki/Taylor_series
 - https://en.wikipedia.org/wiki/Chebyshev_polynomials
 - https://en.wikipedia.org/wiki/Pad%C3%A9_approximant
 - https://en.wikipedia.org/wiki/Horner%27s_method
 - https://en.wikipedia.org/wiki/Estrin%27s_scheme
 - https://en.wikipedia.org/wiki/CORDIC
 - */
 - 
 - 
 - /** Evaluates a polynomial with coefficients `a[n]` at `x`.
 - Uses naive direct evaluation.
 - */
 - template <typename T, size_t N>
 - T polyDirect(const T (&a)[N], T x) {
 - 	T y = 0;
 - 	T xn = 1;
 - 	for (size_t n = 0; n < N; n++) {
 - 		y += a[n] * xn;
 - 		xn *= x;
 - 	}
 - 	return y;
 - }
 - 
 - /** Evaluates a polynomial with coefficients `a[n]` at `x`.
 - Uses Horner's method.
 - https://en.wikipedia.org/wiki/Horner%27s_method
 - */
 - template <typename T, size_t N>
 - T polyHorner(const T (&a)[N], T x) {
 - 	if (N == 0)
 - 		return 0;
 - 
 - 	T y = a[N - 1];
 - 	for (size_t n = 1; n < N; n++) {
 - 		y = a[N - 1 - n] + y * x;
 - 	}
 - 	return y;
 - }
 - 
 - /** Evaluates a polynomial with coefficients `a[n]` at `x`.
 - Uses Estrin's method.
 - https://en.wikipedia.org/wiki/Estrin%27s_scheme
 - */
 - template <typename T, size_t N>
 - T polyEstrin(const T (&a)[N], T x) {
 - 	if (N == 0)
 - 		return 0;
 - 	if (N == 1)
 - 		return a[0];
 - 
 - 	const size_t M = (N + 1) / 2;
 - 	T b[M];
 - 	for (size_t i = 0; i < M; i++) {
 - 		b[i] = a[2 * i];
 - 		if (2 * i + 1 < N)
 - 			b[i] += a[2 * i + 1] * x;
 - 	}
 - 	return polyEstrin(b, x * x);
 - }
 - 
 - 
 - /** Returns `2^floor(x)`.
 - If xf is given, sets it to the fractional part of x.
 - This is useful in the computation `2^x = 2^floor(x) * 2^frac(x)`.
 - */
 - template <typename T>
 - T exp2Floor(T x, T* xf);
 - 
 - template <>
 - inline float exp2Floor(float x, float* xf) {
 - 	x += 127;
 - 	// x should be positive now, so this always truncates towards -inf.
 - 	int32_t xi = x;
 - 	if (xf)
 - 		*xf = x - xi;
 - 	// Set mantissa of float
 - 	union {
 - 		float yi;
 - 		int32_t yii;
 - 	};
 - 	yii = xi << 23;
 - 	return yi;
 - }
 - 
 - template <>
 - inline simd::float_4 exp2Floor(simd::float_4 x, simd::float_4* xf) {
 - 	x += 127;
 - 	simd::int32_4 xi = x;
 - 	if (xf)
 - 		*xf = x - simd::float_4(xi);
 - 	simd::int32_4 yii = xi << 23;
 - 	return simd::float_4::cast(yii);
 - }
 - 
 - /** Deprecated alias of exp2Floor() */
 - template <typename T>
 - T approxExp2Floor(T x, T* xf) {
 - 	return exp2Floor(x, xf);
 - }
 - 
 - 
 - /** Returns 2^x with at most 6e-06 relative error.
 - 
 - Polynomial coefficients are chosen to minimize relative error while maintaining continuity and giving exact values at integer values of `x`.
 - Thanks to Andy Simper for coefficients.
 - */
 - template <typename T>
 - T exp2_taylor5(T x) {
 - 	T xf;
 - 	T yi = exp2Floor(x, &xf);
 - 
 - 	const T a[] = {
 - 		1.0,
 - 		0.69315169353961,
 - 		0.2401595990753,
 - 		0.055817908652,
 - 		0.008991698010,
 - 		0.001879100722,
 - 	};
 - 	T yf = polyHorner(a, xf);
 - 	return yi * yf;
 - }
 - 
 - /** Deprecated alias of exp2_taylor5() */
 - template <typename T>
 - T approxExp2_taylor5(T x) {
 - 	return exp2_taylor5(x);
 - }
 - 
 - 
 - } // namespace dsp
 - } // namespace rack
 
 
  |