KpqC-0.1.0: cbits/third_party/HAETAE/src/fft.c
// SPDX-License-Identifier: MIT
#include "fft.h"
/**************************************************************************
* Roots of unity. This table is used to initialize the FFT data.
* The even entries are reused as twiddle factors in the FFT.
* To generate values in Python using numpy:
* rootsf = np.exp(-1j * np.pi * np.arange(256) / 256)
* roots = [(int(r.real), int(r.imag)) for r in np.round(65536 * rootsf)]
**************************************************************************/
static const complex_fp32_16 roots[] = {
{.real = +65536, .imag = +0}, {.real = +65531, .imag = -804},
{.real = +65516, .imag = -1608}, {.real = +65492, .imag = -2412},
{.real = +65457, .imag = -3216}, {.real = +65413, .imag = -4019},
{.real = +65358, .imag = -4821}, {.real = +65294, .imag = -5623},
{.real = +65220, .imag = -6424}, {.real = +65137, .imag = -7224},
{.real = +65043, .imag = -8022}, {.real = +64940, .imag = -8820},
{.real = +64827, .imag = -9616}, {.real = +64704, .imag = -10411},
{.real = +64571, .imag = -11204}, {.real = +64429, .imag = -11996},
{.real = +64277, .imag = -12785}, {.real = +64115, .imag = -13573},
{.real = +63944, .imag = -14359}, {.real = +63763, .imag = -15143},
{.real = +63572, .imag = -15924}, {.real = +63372, .imag = -16703},
{.real = +63162, .imag = -17479}, {.real = +62943, .imag = -18253},
{.real = +62714, .imag = -19024}, {.real = +62476, .imag = -19792},
{.real = +62228, .imag = -20557}, {.real = +61971, .imag = -21320},
{.real = +61705, .imag = -22078}, {.real = +61429, .imag = -22834},
{.real = +61145, .imag = -23586}, {.real = +60851, .imag = -24335},
{.real = +60547, .imag = -25080}, {.real = +60235, .imag = -25821},
{.real = +59914, .imag = -26558}, {.real = +59583, .imag = -27291},
{.real = +59244, .imag = -28020}, {.real = +58896, .imag = -28745},
{.real = +58538, .imag = -29466}, {.real = +58172, .imag = -30182},
{.real = +57798, .imag = -30893}, {.real = +57414, .imag = -31600},
{.real = +57022, .imag = -32303}, {.real = +56621, .imag = -33000},
{.real = +56212, .imag = -33692}, {.real = +55794, .imag = -34380},
{.real = +55368, .imag = -35062}, {.real = +54934, .imag = -35738},
{.real = +54491, .imag = -36410}, {.real = +54040, .imag = -37076},
{.real = +53581, .imag = -37736}, {.real = +53114, .imag = -38391},
{.real = +52639, .imag = -39040}, {.real = +52156, .imag = -39683},
{.real = +51665, .imag = -40320}, {.real = +51166, .imag = -40951},
{.real = +50660, .imag = -41576}, {.real = +50146, .imag = -42194},
{.real = +49624, .imag = -42806}, {.real = +49095, .imag = -43412},
{.real = +48559, .imag = -44011}, {.real = +48015, .imag = -44604},
{.real = +47464, .imag = -45190}, {.real = +46906, .imag = -45769},
{.real = +46341, .imag = -46341}, {.real = +45769, .imag = -46906},
{.real = +45190, .imag = -47464}, {.real = +44604, .imag = -48015},
{.real = +44011, .imag = -48559}, {.real = +43412, .imag = -49095},
{.real = +42806, .imag = -49624}, {.real = +42194, .imag = -50146},
{.real = +41576, .imag = -50660}, {.real = +40951, .imag = -51166},
{.real = +40320, .imag = -51665}, {.real = +39683, .imag = -52156},
{.real = +39040, .imag = -52639}, {.real = +38391, .imag = -53114},
{.real = +37736, .imag = -53581}, {.real = +37076, .imag = -54040},
{.real = +36410, .imag = -54491}, {.real = +35738, .imag = -54934},
{.real = +35062, .imag = -55368}, {.real = +34380, .imag = -55794},
{.real = +33692, .imag = -56212}, {.real = +33000, .imag = -56621},
{.real = +32303, .imag = -57022}, {.real = +31600, .imag = -57414},
{.real = +30893, .imag = -57798}, {.real = +30182, .imag = -58172},
{.real = +29466, .imag = -58538}, {.real = +28745, .imag = -58896},
{.real = +28020, .imag = -59244}, {.real = +27291, .imag = -59583},
{.real = +26558, .imag = -59914}, {.real = +25821, .imag = -60235},
{.real = +25080, .imag = -60547}, {.real = +24335, .imag = -60851},
{.real = +23586, .imag = -61145}, {.real = +22834, .imag = -61429},
{.real = +22078, .imag = -61705}, {.real = +21320, .imag = -61971},
{.real = +20557, .imag = -62228}, {.real = +19792, .imag = -62476},
{.real = +19024, .imag = -62714}, {.real = +18253, .imag = -62943},
{.real = +17479, .imag = -63162}, {.real = +16703, .imag = -63372},
{.real = +15924, .imag = -63572}, {.real = +15143, .imag = -63763},
{.real = +14359, .imag = -63944}, {.real = +13573, .imag = -64115},
{.real = +12785, .imag = -64277}, {.real = +11996, .imag = -64429},
{.real = +11204, .imag = -64571}, {.real = +10411, .imag = -64704},
{.real = +9616, .imag = -64827}, {.real = +8820, .imag = -64940},
{.real = +8022, .imag = -65043}, {.real = +7224, .imag = -65137},
{.real = +6424, .imag = -65220}, {.real = +5623, .imag = -65294},
{.real = +4821, .imag = -65358}, {.real = +4019, .imag = -65413},
{.real = +3216, .imag = -65457}, {.real = +2412, .imag = -65492},
{.real = +1608, .imag = -65516}, {.real = +804, .imag = -65531},
{.real = +0, .imag = -65536}, {.real = -804, .imag = -65531},
{.real = -1608, .imag = -65516}, {.real = -2412, .imag = -65492},
{.real = -3216, .imag = -65457}, {.real = -4019, .imag = -65413},
{.real = -4821, .imag = -65358}, {.real = -5623, .imag = -65294},
{.real = -6424, .imag = -65220}, {.real = -7224, .imag = -65137},
{.real = -8022, .imag = -65043}, {.real = -8820, .imag = -64940},
{.real = -9616, .imag = -64827}, {.real = -10411, .imag = -64704},
{.real = -11204, .imag = -64571}, {.real = -11996, .imag = -64429},
{.real = -12785, .imag = -64277}, {.real = -13573, .imag = -64115},
{.real = -14359, .imag = -63944}, {.real = -15143, .imag = -63763},
{.real = -15924, .imag = -63572}, {.real = -16703, .imag = -63372},
{.real = -17479, .imag = -63162}, {.real = -18253, .imag = -62943},
{.real = -19024, .imag = -62714}, {.real = -19792, .imag = -62476},
{.real = -20557, .imag = -62228}, {.real = -21320, .imag = -61971},
{.real = -22078, .imag = -61705}, {.real = -22834, .imag = -61429},
{.real = -23586, .imag = -61145}, {.real = -24335, .imag = -60851},
{.real = -25080, .imag = -60547}, {.real = -25821, .imag = -60235},
{.real = -26558, .imag = -59914}, {.real = -27291, .imag = -59583},
{.real = -28020, .imag = -59244}, {.real = -28745, .imag = -58896},
{.real = -29466, .imag = -58538}, {.real = -30182, .imag = -58172},
{.real = -30893, .imag = -57798}, {.real = -31600, .imag = -57414},
{.real = -32303, .imag = -57022}, {.real = -33000, .imag = -56621},
{.real = -33692, .imag = -56212}, {.real = -34380, .imag = -55794},
{.real = -35062, .imag = -55368}, {.real = -35738, .imag = -54934},
{.real = -36410, .imag = -54491}, {.real = -37076, .imag = -54040},
{.real = -37736, .imag = -53581}, {.real = -38391, .imag = -53114},
{.real = -39040, .imag = -52639}, {.real = -39683, .imag = -52156},
{.real = -40320, .imag = -51665}, {.real = -40951, .imag = -51166},
{.real = -41576, .imag = -50660}, {.real = -42194, .imag = -50146},
{.real = -42806, .imag = -49624}, {.real = -43412, .imag = -49095},
{.real = -44011, .imag = -48559}, {.real = -44604, .imag = -48015},
{.real = -45190, .imag = -47464}, {.real = -45769, .imag = -46906},
{.real = -46341, .imag = -46341}, {.real = -46906, .imag = -45769},
{.real = -47464, .imag = -45190}, {.real = -48015, .imag = -44604},
{.real = -48559, .imag = -44011}, {.real = -49095, .imag = -43412},
{.real = -49624, .imag = -42806}, {.real = -50146, .imag = -42194},
{.real = -50660, .imag = -41576}, {.real = -51166, .imag = -40951},
{.real = -51665, .imag = -40320}, {.real = -52156, .imag = -39683},
{.real = -52639, .imag = -39040}, {.real = -53114, .imag = -38391},
{.real = -53581, .imag = -37736}, {.real = -54040, .imag = -37076},
{.real = -54491, .imag = -36410}, {.real = -54934, .imag = -35738},
{.real = -55368, .imag = -35062}, {.real = -55794, .imag = -34380},
{.real = -56212, .imag = -33692}, {.real = -56621, .imag = -33000},
{.real = -57022, .imag = -32303}, {.real = -57414, .imag = -31600},
{.real = -57798, .imag = -30893}, {.real = -58172, .imag = -30182},
{.real = -58538, .imag = -29466}, {.real = -58896, .imag = -28745},
{.real = -59244, .imag = -28020}, {.real = -59583, .imag = -27291},
{.real = -59914, .imag = -26558}, {.real = -60235, .imag = -25821},
{.real = -60547, .imag = -25080}, {.real = -60851, .imag = -24335},
{.real = -61145, .imag = -23586}, {.real = -61429, .imag = -22834},
{.real = -61705, .imag = -22078}, {.real = -61971, .imag = -21320},
{.real = -62228, .imag = -20557}, {.real = -62476, .imag = -19792},
{.real = -62714, .imag = -19024}, {.real = -62943, .imag = -18253},
{.real = -63162, .imag = -17479}, {.real = -63372, .imag = -16703},
{.real = -63572, .imag = -15924}, {.real = -63763, .imag = -15143},
{.real = -63944, .imag = -14359}, {.real = -64115, .imag = -13573},
{.real = -64277, .imag = -12785}, {.real = -64429, .imag = -11996},
{.real = -64571, .imag = -11204}, {.real = -64704, .imag = -10411},
{.real = -64827, .imag = -9616}, {.real = -64940, .imag = -8820},
{.real = -65043, .imag = -8022}, {.real = -65137, .imag = -7224},
{.real = -65220, .imag = -6424}, {.real = -65294, .imag = -5623},
{.real = -65358, .imag = -4821}, {.real = -65413, .imag = -4019},
{.real = -65457, .imag = -3216}, {.real = -65492, .imag = -2412},
{.real = -65516, .imag = -1608}, {.real = -65531, .imag = -804}};
static inline int32_t _mulrnd16(const int32_t x, const int32_t y) {
int64_t r = ((int64_t)x * (int64_t)y) + (1 << 15);
return r >> 16;
}
static inline int32_t _complex_mul_real(const complex_fp32_16 x,
const complex_fp32_16 y) {
return _mulrnd16(x.real, y.real) - _mulrnd16(x.imag, y.imag);
}
static inline int32_t _complex_mul_imag(const complex_fp32_16 x,
const complex_fp32_16 y) {
return _mulrnd16(x.real, y.imag) + _mulrnd16(x.imag, y.real);
}
static void _complex_mul(complex_fp32_16 *r, const complex_fp32_16 x,
const complex_fp32_16 y) {
r->real = _complex_mul_real(x, y);
r->imag = _complex_mul_imag(x, y);
}
/****************************************************************************
* To generate values in Phython:
* brv8 = [int(f"{t:08b}"[::-1],2) for t in range(2**8)]
****************************************************************************/
const uint16_t brv8[] = {
0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255};
/****************************************************************************
* Initialize the FFT array with coeffs[i] * root[i] and
* store the values in bit-reversed order.
****************************************************************************/
void fft_init_and_bitrev(complex_fp32_16 r[FFT_N], const poly *x) {
int i, inv_i;
int c;
for (i = 0; i < FFT_N; i++) {
inv_i = brv8[i];
c = x->coeffs[i];
r[inv_i].real = c * roots[i].real;
r[inv_i].imag = c * roots[i].imag;
}
}
int32_t complex_fp_sqabs(complex_fp32_16 x) {
return _mulrnd16(x.real, x.real) + _mulrnd16(x.imag, x.imag);
}
/*************************************************
* Name: fft
*
* Description:
*
* Arguments: - complex_fp32_16 data[FFT_N]
*
* Specification: Implements @[Algorithm 49, FFT]
**************************************************/
void fft(complex_fp32_16 data[FFT_N]) {
unsigned int r, m, md2, n, k, even, odd, twid;
complex_fp32_16 u, t;
for (r = 1; r <= FFT_LOGN; r++) {
m = 1 << r;
md2 = m >> 1;
for (n = 0; n < FFT_N; n += m) {
for (k = 0; k < md2; k++) {
even = n + k;
odd = even + md2;
twid = k << (FFT_LOGN - r + 1);
u = data[even];
_complex_mul(&t, roots[twid], data[odd]);
data[even].real = u.real + t.real;
data[even].imag = u.imag + t.imag;
data[odd].real = u.real - t.real;
data[odd].imag = u.imag - t.imag;
}
}
}
}