提交记录 115767


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_cc_v41_260924 1004e8. 【模板题】高精度乘法×100 Accepted 100 994.53 ms 1253356 KB C++17 84.86 KB
提交时间 评测时间
2026-09-30 14:44:29 2026-09-30 14:44:38
#pragma GCC optimize("O3")
#define E8_BSS 1
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <cmath>
#include <immintrin.h>
#define TGT __attribute__((target("avx2,fma,prfchw")))
#define E8NG 64
#define RSB (R4+8)
/* ---- CH1: THE ROW-STRIDE PAD, and its FLAT -> PADDED index map.
   The plane is R4 rows of C4 doubles with row stride C4P = C4 + CH1_PAD.  A logical
   plane element q (= row*C4 + col) lives at offset PIDX(q).  CH1_PAD = 0 makes PIDX
   the identity, so a `-DCH1_PAD=0` build IS the unpadded engine -- that build is this
   edit's own congruent control.  CH1_PAD must be a multiple of 8 doubles (64 B) or the
   row starts stop being 64-B-line aligned and the L2 set step stops being integral. */
#ifndef CH1_PAD
#define CH1_PAD 0
#endif
#define C4P ((C4)+CH1_PAD)
#define PIDX(q) ((size_t)(q) + (((size_t)(q)) >> 13) * (size_t)CH1_PAD)
typedef uint64_t u64;
typedef uint32_t u32;
#if defined(E8_NT)
#define E8DIFW dif4nt
#define E8DITW dit4nt
#else
#define E8DIFW dif4
#define E8DITW dit4
#endif
TGT static void dif4nt(double*,double*,int,int,const double*,const double*);
TGT static void dit4nt(double*,double*,int,int,const double*,const double*);
#ifndef E8N
#define E8N (1 << 25)
#endif
#if defined(E8_BSS)
static double G_P1[E8N/3 + 64] __attribute__((aligned(4096)));
static double G_P2[E8N/3 + 128] __attribute__((aligned(4096)));
#endif
struct FT {
int n, nlev;
double *c1[40], *s1[40];
double *p1, *p2;
};
TGT static void ft_build(FT &T, int n) {
T.n = n;
int nlev = 0;
for (int L = n; L >= 4; L >>= 2) nlev++;
T.nlev = nlev;
size_t tot = 0;
for (int k = 0; k < nlev; k++) tot += (size_t)(n >> (2 * k + 2));
#if defined(E8_BSS)
T.p1 = G_P1; T.p2 = G_P2 + 48;
#else
T.p1 = (double *)_mm_malloc(tot * 8 + 8192, 64);
T.p2 = (double *)_mm_malloc(tot * 8 + 8192, 64) + 48;
#endif
const double pi = 3.14159265358979323846;
size_t o = 0;
for (int k = 0; k < nlev; k++) { T.c1[k] = T.p1 + o; T.s1[k] = T.p2 + o; o += (size_t)(n >> (2 * k + 2)); }
int h0 = n >> 2;
int R = 1; while ((long long)R * R < (long long)h0) R <<= 1;
double *ca = (double *)malloc(sizeof(double) * R * 2), *cb = (double *)malloc(sizeof(double) * R * 2);
double *sa = ca + R, *sb = cb + R;
for (int j = 0; j < R; j++) {
double a = -2.0 * pi * (double)j * (double)R / (double)n;
ca[j] = cos(a); sa[j] = sin(a);
double b = -2.0 * pi * (double)j / (double)n;
cb[j] = cos(b); sb[j] = sin(b);
}
double *C0 = T.c1[0], *S0 = T.s1[0];
for (int a = 0; a < R; a++) {
double ac = ca[a], as = sa[a];
double *cp = C0 + (size_t)a * R, *sp = S0 + (size_t)a * R;
for (int b = 0; b < R; b++) {
cp[b] = ac * cb[b] - as * sb[b];
sp[b] = ac * sb[b] + as * cb[b];
}
}
free(ca); free(cb);
for (int k = 1; k < nlev; k++) {          // decimation: w_k[j] = w_0[j * 4^k]
int h = n >> (2 * k + 2), st = 1 << (2 * k);
const double *pc = T.c1[k - 1], *ps = T.s1[k - 1];
double *c = T.c1[k], *ss = T.s1[k];
for (int j = 0; j < h; j++) c[j] = pc[(size_t)j * 4];
for (int j = 0; j < h; j++) ss[j] = ps[(size_t)j * 4];
(void)st;
}
}
#if defined(E8_NT)
TGT static void dif4nt(double*,double*,int,int,const double*,const double*);
TGT static void dit4nt(double*,double*,int,int,const double*,const double*);
#endif
TGT static void dif4(double *__restrict RE, double *__restrict IM, int n, int L,
const double *__restrict c1, const double *__restrict s1) {
int h = L >> 2;
if (__builtin_expect(h < 4, 0)) {
for (int p = 0; p < n; p += L)
for (int j = 0; j < h; j++) {
double x0r = RE[p+j], x0i = IM[p+j], x1r = RE[p+j+h], x1i = IM[p+j+h];
double x2r = RE[p+j+2*h], x2i = IM[p+j+2*h], x3r = RE[p+j+3*h], x3i = IM[p+j+3*h];
double a1 = c1[j], b1 = s1[j];
double a2 = a1*a1 - b1*b1, b2 = 2.0*a1*b1;
double a3 = a2*a1 - b2*b1, b3 = a2*b1 + b2*a1;
double T0r = x0r+x2r, T0i = x0i+x2i, T1r = x0r-x2r, T1i = x0i-x2i;
double T2r = x1r+x3r, T2i = x1i+x3i, T3r = x1r-x3r, T3i = x1i-x3i;
double u0r = T0r+T2r, u0i = T0i+T2i, u2r = T0r-T2r, u2i = T0i-T2i;
double u1r = T1r+T3i, u1i = T1i-T3r, u3r = T1r-T3i, u3i = T1i+T3r;
RE[p+j] = u0r; IM[p+j] = u0i;
RE[p+j+h]   = u1r*a1 - u1i*b1; IM[p+j+h]   = u1r*b1 + u1i*a1;
RE[p+j+2*h] = u2r*a2 - u2i*b2; IM[p+j+2*h] = u2r*b2 + u2i*a2;
RE[p+j+3*h] = u3r*a3 - u3i*b3; IM[p+j+3*h] = u3r*b3 + u3i*a3;
}
return;
}
for (int p = 0; p < n; p += L) {
double *r0 = RE + p, *i0 = IM + p;
for (int j = 0; j < h; j += 4) {
__m256d x0r = _mm256_load_pd(r0 + j),       x0i = _mm256_load_pd(i0 + j); __asm__("" : "+x"(x0r),"+x"(x0i));
__m256d x1r = _mm256_load_pd(r0 + j + h),   x1i = _mm256_load_pd(i0 + j + h); __asm__("" : "+x"(x1r),"+x"(x1i));
__m256d x2r = _mm256_load_pd(r0 + j + 2*h), x2i = _mm256_load_pd(i0 + j + 2*h); __asm__("" : "+x"(x2r),"+x"(x2i));
__m256d x3r = _mm256_load_pd(r0 + j + 3*h), x3i = _mm256_load_pd(i0 + j + 3*h); __asm__("" : "+x"(x3r),"+x"(x3i));
__m256d T0r = _mm256_add_pd(x0r, x2r), T0i = _mm256_add_pd(x0i, x2i);
__m256d T1r = _mm256_sub_pd(x0r, x2r), T1i = _mm256_sub_pd(x0i, x2i);
__m256d T2r = _mm256_add_pd(x1r, x3r), T2i = _mm256_add_pd(x1i, x3i);
__m256d T3r = _mm256_sub_pd(x1r, x3r), T3i = _mm256_sub_pd(x1i, x3i);
__m256d u0r = _mm256_add_pd(T0r, T2r), u0i = _mm256_add_pd(T0i, T2i);
__m256d u2r = _mm256_sub_pd(T0r, T2r), u2i = _mm256_sub_pd(T0i, T2i);
__m256d u1r = _mm256_add_pd(T1r, T3i), u1i = _mm256_sub_pd(T1i, T3r);
__m256d u3r = _mm256_sub_pd(T1r, T3i), u3i = _mm256_add_pd(T1i, T3r);
__m256d a1 = _mm256_load_pd(c1 + j), b1 = _mm256_load_pd(s1 + j); __asm__("" : "+x"(a1),"+x"(b1));
__m256d a2 = _mm256_fnmadd_pd(b1, b1, _mm256_mul_pd(a1, a1));
__m256d b2 = _mm256_add_pd(_mm256_mul_pd(a1, b1), _mm256_mul_pd(a1, b1));
__m256d a3 = _mm256_fnmadd_pd(b2, b1, _mm256_mul_pd(a2, a1));
__m256d b3 = _mm256_fmadd_pd (a2, b1, _mm256_mul_pd(b2, a1));
_mm256_store_pd(r0 + j, u0r); _mm256_store_pd(i0 + j, u0i);
_mm256_store_pd(r0 + j + h,   _mm256_fnmadd_pd(u1i, b1, _mm256_mul_pd(u1r, a1)));
_mm256_store_pd(i0 + j + h,   _mm256_fmadd_pd (u1r, b1, _mm256_mul_pd(u1i, a1)));
_mm256_store_pd(r0 + j + 2*h, _mm256_fnmadd_pd(u2i, b2, _mm256_mul_pd(u2r, a2)));
_mm256_store_pd(i0 + j + 2*h, _mm256_fmadd_pd (u2r, b2, _mm256_mul_pd(u2i, a2)));
_mm256_store_pd(r0 + j + 3*h, _mm256_fnmadd_pd(u3i, b3, _mm256_mul_pd(u3r, a3)));
_mm256_store_pd(i0 + j + 3*h, _mm256_fmadd_pd (u3r, b3, _mm256_mul_pd(u3i, a3)));
}
}
}
TGT static void dit4(double *__restrict RE, double *__restrict IM, int n, int L,
const double *__restrict c1, const double *__restrict s1) {
int h = L >> 2;
if (__builtin_expect(h < 4, 0)) {
for (int p = 0; p < n; p += L)
for (int j = 0; j < h; j++) {
double x0r = RE[p+j], x0i = IM[p+j], x1r = RE[p+j+h], x1i = IM[p+j+h];
double x2r = RE[p+j+2*h], x2i = IM[p+j+2*h], x3r = RE[p+j+3*h], x3i = IM[p+j+3*h];
double a1 = c1[j], b1 = s1[j];
double a2 = a1*a1 - b1*b1, b2 = 2.0*a1*b1;
double a3 = a2*a1 - b2*b1, b3 = a2*b1 + b2*a1;
double n1r = x1r*a1 + x1i*b1, n1i = x1i*a1 - x1r*b1;
double n2r = x2r*a2 + x2i*b2, n2i = x2i*a2 - x2r*b2;
double n3r = x3r*a3 + x3i*b3, n3i = x3i*a3 - x3r*b3;
double T0r = x0r+n2r, T0i = x0i+n2i, T1r = x0r-n2r, T1i = x0i-n2i;
double T2r = n1r+n3r, T2i = n1i+n3i, T3r = n1r-n3r, T3i = n1i-n3i;
double Er = -T3i, Ei = T3r;
RE[p+j] = T0r+T2r; IM[p+j] = T0i+T2i;
RE[p+j+h]   = T1r+Er; IM[p+j+h]   = T1i+Ei;
RE[p+j+2*h] = T0r-T2r; IM[p+j+2*h] = T0i-T2i;
RE[p+j+3*h] = T1r-Er; IM[p+j+3*h] = T1i-Ei;
}
return;
}
for (int p = 0; p < n; p += L) {
double *r0 = RE + p, *i0 = IM + p;
__m256d a1 = _mm256_load_pd(c1), b1 = _mm256_load_pd(s1); __asm__("" : "+x"(a1),"+x"(b1));
for (int j = 0; j < h; j += 4) {
__m256d na1, nb1;
if (j + 4 < h) { na1 = _mm256_load_pd(c1 + j + 4); nb1 = _mm256_load_pd(s1 + j + 4); __asm__("" : "+x"(na1),"+x"(nb1)); }
__m256d x0r = _mm256_load_pd(r0 + j),       x0i = _mm256_load_pd(i0 + j); __asm__("" : "+x"(x0r),"+x"(x0i));
__m256d x1r = _mm256_load_pd(r0 + j + h),   x1i = _mm256_load_pd(i0 + j + h); __asm__("" : "+x"(x1r),"+x"(x1i));
__m256d x2r = _mm256_load_pd(r0 + j + 2*h), x2i = _mm256_load_pd(i0 + j + 2*h); __asm__("" : "+x"(x2r),"+x"(x2i));
__m256d x3r = _mm256_load_pd(r0 + j + 3*h), x3i = _mm256_load_pd(i0 + j + 3*h); __asm__("" : "+x"(x3r),"+x"(x3i));
__m256d a2 = _mm256_fnmadd_pd(b1, b1, _mm256_mul_pd(a1, a1));
__m256d b2 = _mm256_add_pd(_mm256_mul_pd(a1, b1), _mm256_mul_pd(a1, b1));
__m256d a3 = _mm256_fnmadd_pd(b2, b1, _mm256_mul_pd(a2, a1));
__m256d b3 = _mm256_fmadd_pd (a2, b1, _mm256_mul_pd(b2, a1));
__m256d n1r = _mm256_fmadd_pd (x1i, b1, _mm256_mul_pd(x1r, a1));
__m256d n1i = _mm256_fnmadd_pd(x1r, b1, _mm256_mul_pd(x1i, a1));
__m256d n2r = _mm256_fmadd_pd (x2i, b2, _mm256_mul_pd(x2r, a2));
__m256d n2i = _mm256_fnmadd_pd(x2r, b2, _mm256_mul_pd(x2i, a2));
__m256d n3r = _mm256_fmadd_pd (x3i, b3, _mm256_mul_pd(x3r, a3));
__m256d n3i = _mm256_fnmadd_pd(x3r, b3, _mm256_mul_pd(x3i, a3));
__m256d T0r = _mm256_add_pd(x0r, n2r), T0i = _mm256_add_pd(x0i, n2i);
__m256d T1r = _mm256_sub_pd(x0r, n2r), T1i = _mm256_sub_pd(x0i, n2i);
__m256d T2r = _mm256_add_pd(n1r, n3r), T2i = _mm256_add_pd(n1i, n3i);
__m256d T3r = _mm256_sub_pd(n1r, n3r), T3i = _mm256_sub_pd(n1i, n3i);
_mm256_store_pd(r0 + j, _mm256_add_pd(T0r, T2r));       _mm256_store_pd(i0 + j, _mm256_add_pd(T0i, T2i));
_mm256_store_pd(r0 + j + h, _mm256_sub_pd(T1r, T3i));    _mm256_store_pd(i0 + j + h, _mm256_add_pd(T1i, T3r));
_mm256_store_pd(r0 + j + 2*h, _mm256_sub_pd(T0r, T2r)); _mm256_store_pd(i0 + j + 2*h, _mm256_sub_pd(T0i, T2i));
_mm256_store_pd(r0 + j + 3*h, _mm256_add_pd(T1r, T3i));  _mm256_store_pd(i0 + j + 3*h, _mm256_sub_pd(T1i, T3r));
if (j + 4 < h) { a1 = na1; b1 = nb1; }
}
}
}
TGT static void fft_fwd(double *RE, double *IM, FT &T, int B) {
int SUB = B;
int n = T.n;
if (B > n) B = n;
int k = 0;
for (; k < T.nlev; k++) { int L = n >> (2 * k); if (L <= B) break;
E8DIFW(RE, IM, n, L, T.c1[k], T.s1[k]); }
_mm_sfence();
for (int b = 0; b < n; b += B) {
double *r = RE + b, *i = IM + b;
for (int kk = k; kk < T.nlev; kk++) { int L = n >> (2 * kk);
dif4(r, i, B, L, T.c1[kk], T.s1[kk]); }
}
}
#if defined(E8_NT)
#define E8DIFW dif4nt
#define E8DITW dit4nt
#else
#define E8DIFW dif4
#define E8DITW dit4
#endif
/* removed dif4nt */

/* removed dit4nt */

TGT static void fft_fwd_sq(double *RE, double *IM, FT &T, int B, int SUB, double sc) {
int n = T.n;
if (B > n) B = n;
int k = 0;
for (; k < T.nlev; k++) { int L = n >> (2 * k); if (L <= B) break;
E8DIFW(RE, IM, n, L, T.c1[k], T.s1[k]); }
_mm_sfence();
__m256d sv = _mm256_set1_pd(sc), two = _mm256_set1_pd(2.0);
int last = T.nlev - 1;
int ksub = k; while (ksub < T.nlev && (n >> (2 * ksub)) > SUB) ksub++;
for (int b = 0; b < n; b += B) {
double *r = RE + b, *i = IM + b;
for (int kk = k; kk < ksub; kk++) { int L = n >> (2 * kk);
dif4(r, i, B, L, T.c1[kk], T.s1[kk]); }
for (int sb = 0; sb < B; sb += SUB) {
double *rr = r + sb, *ii = i + sb;
for (int kk = ksub; kk <= last; kk++) { int L = n >> (2 * kk);
dif4(rr, ii, SUB, L, T.c1[kk], T.s1[kk]); }
}
for (int j = 0; j < B; j += 4) {
__m256d pr = _mm256_loadu_pd(r + j), mi = _mm256_loadu_pd(i + j);
__m256d rr = _mm256_mul_pd(_mm256_fnmadd_pd(mi, mi, _mm256_mul_pd(pr, pr)), sv);
__m256d ii = _mm256_mul_pd(_mm256_mul_pd(two, _mm256_mul_pd(pr, mi)), sv);
_mm256_storeu_pd(r + j, rr); _mm256_storeu_pd(i + j, ii);
}
}
}
TGT static void fft_inv(double *RE, double *IM, FT &T, int B, int SUB) {
int n = T.n;
if (B > n) B = n;
int kstop = T.nlev;
for (int k = 0; k < T.nlev; k++) { if ((n >> (2 * k)) <= B) { kstop = k; break; } }
int ksub = kstop; while (ksub < T.nlev && (n >> (2 * ksub)) > SUB) ksub++;
for (int b = 0; b < n; b += B) {
double *r = RE + b, *i = IM + b;
for (int sb = 0; sb < B; sb += SUB) {
double *rr = r + sb, *ii = i + sb;
for (int kk = T.nlev - 1; kk >= ksub; kk--) { int L = n >> (2 * kk);
dit4(rr, ii, SUB, L, T.c1[kk], T.s1[kk]); }
}
for (int kk = ksub - 1; kk >= kstop; kk--) { int L = n >> (2 * kk);
dit4(r, i, B, L, T.c1[kk], T.s1[kk]); }
}
for (int k = kstop - 1; k >= 0; k--) { int L = n >> (2 * k);
E8DITW(RE, IM, n, L, T.c1[k], T.s1[k]); }
_mm_sfence();
}
static double *fft_place(size_t ndoubles, int offb) {
char *p = (char *)malloc(ndoubles * 8 + 16384);
uintptr_t a = (uintptr_t)p;
uintptr_t base = (a + 4095) & ~(uintptr_t)4095;
return (double *)(base + offb);
}
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <cmath>
static const int N = E8N;
#ifndef E8B
#define E8B (1 << 16)
#ifndef E8S
#define E8S (1 << 12)
#endif
#endif
static const int NB = E8B;
static const int NS = E8S;
#define RLOGX 6
#define CLOGX 7
#include <cmath>
static const int R4 = 1 << 12, C4 = 1 << 13, N4 = R4*C4;
static const int NLEVR4 = 6, NLEVC4 = 6;
static double *cR4[16], *sR4[16], *cC4[16], *sC4[16];
static double *TWR4, *TWI4, *TWR4B, *TWI4B, *BFR4, *BFI4;
static int *REV4;
static double *W4T[8];
/* removed mkpow4tab */

TGT static void dif4t(double *__restrict RE, double *__restrict IM, int n, int L,
const double *__restrict W) {
int h = L >> 2;
for (int p = 0; p < n; p += L) {
double *r0 = RE + p, *i0 = IM + p;
const double *w = W;
for (int j = 0; j < h; j += 4, w += 24) {
__m256d a1 = _mm256_load_pd(w),      b1 = _mm256_load_pd(w + 4); __asm__("" : "+x"(a1),"+x"(b1));
__m256d a2 = _mm256_load_pd(w + 8),  b2 = _mm256_load_pd(w + 12);
__m256d a3 = _mm256_load_pd(w + 16), b3 = _mm256_load_pd(w + 20); __asm__("" : "+x"(a3),"+x"(b3));
__m256d x0r = _mm256_load_pd(r0 + j),       x0i = _mm256_load_pd(i0 + j); __asm__("" : "+x"(x0r),"+x"(x0i));
__m256d x1r = _mm256_load_pd(r0 + j + h),   x1i = _mm256_load_pd(i0 + j + h); __asm__("" : "+x"(x1r),"+x"(x1i));
__m256d x2r = _mm256_load_pd(r0 + j + 2*h), x2i = _mm256_load_pd(i0 + j + 2*h); __asm__("" : "+x"(x2r),"+x"(x2i));
__m256d x3r = _mm256_load_pd(r0 + j + 3*h), x3i = _mm256_load_pd(i0 + j + 3*h); __asm__("" : "+x"(x3r),"+x"(x3i));
__m256d T0r = _mm256_add_pd(x0r, x2r), T0i = _mm256_add_pd(x0i, x2i);
__m256d T1r = _mm256_sub_pd(x0r, x2r), T1i = _mm256_sub_pd(x0i, x2i);
__m256d T2r = _mm256_add_pd(x1r, x3r), T2i = _mm256_add_pd(x1i, x3i);
__m256d T3r = _mm256_sub_pd(x1r, x3r), T3i = _mm256_sub_pd(x1i, x3i);
__m256d u0r = _mm256_add_pd(T0r, T2r), u0i = _mm256_add_pd(T0i, T2i);
__m256d u2r = _mm256_sub_pd(T0r, T2r), u2i = _mm256_sub_pd(T0i, T2i);
__m256d u1r = _mm256_add_pd(T1r, T3i), u1i = _mm256_sub_pd(T1i, T3r);
__m256d u3r = _mm256_sub_pd(T1r, T3i), u3i = _mm256_add_pd(T1i, T3r);
_mm256_store_pd(r0 + j, u0r); _mm256_store_pd(i0 + j, u0i);
_mm256_store_pd(r0 + j + h,   _mm256_fnmadd_pd(u1i, b1, _mm256_mul_pd(u1r, a1)));
_mm256_store_pd(i0 + j + h,   _mm256_fmadd_pd (u1r, b1, _mm256_mul_pd(u1i, a1)));
_mm256_store_pd(r0 + j + 2*h, _mm256_fnmadd_pd(u2i, b2, _mm256_mul_pd(u2r, a2)));
_mm256_store_pd(i0 + j + 2*h, _mm256_fmadd_pd (u2r, b2, _mm256_mul_pd(u2i, a2)));
_mm256_store_pd(r0 + j + 3*h, _mm256_fnmadd_pd(u3i, b3, _mm256_mul_pd(u3r, a3)));
_mm256_store_pd(i0 + j + 3*h, _mm256_fmadd_pd (u3r, b3, _mm256_mul_pd(u3i, a3)));
}
}
}
TGT static void dit4t(double *__restrict RE, double *__restrict IM, int n, int L,
const double *__restrict W) {
int h = L >> 2;
for (int p = 0; p < n; p += L) {
double *r0 = RE + p, *i0 = IM + p;
const double *w = W;
for (int j = 0; j < h; j += 4, w += 24) {
__m256d a1 = _mm256_load_pd(w),      b1 = _mm256_load_pd(w + 4); __asm__("" : "+x"(a1),"+x"(b1));
__m256d a2 = _mm256_load_pd(w + 8),  b2 = _mm256_load_pd(w + 12); __asm__("" : "+x"(a2),"+x"(b2));
__m256d a3 = _mm256_load_pd(w + 16), b3 = _mm256_load_pd(w + 20); __asm__("" : "+x"(a3),"+x"(b3));
__m256d x0r = _mm256_load_pd(r0 + j),       x0i = _mm256_load_pd(i0 + j); __asm__("" : "+x"(x0r),"+x"(x0i));
__m256d x1r = _mm256_load_pd(r0 + j + h),   x1i = _mm256_load_pd(i0 + j + h); __asm__("" : "+x"(x1r),"+x"(x1i));
__m256d x2r = _mm256_load_pd(r0 + j + 2*h), x2i = _mm256_load_pd(i0 + j + 2*h); __asm__("" : "+x"(x2r),"+x"(x2i));
__m256d x3r = _mm256_load_pd(r0 + j + 3*h), x3i = _mm256_load_pd(i0 + j + 3*h); __asm__("" : "+x"(x3r),"+x"(x3i));
__m256d n1r = _mm256_fmadd_pd (x1i, b1, _mm256_mul_pd(x1r, a1));
__m256d n1i = _mm256_fnmadd_pd(x1r, b1, _mm256_mul_pd(x1i, a1));
__m256d n2r = _mm256_fmadd_pd (x2i, b2, _mm256_mul_pd(x2r, a2));
__m256d n2i = _mm256_fnmadd_pd(x2r, b2, _mm256_mul_pd(x2i, a2));
__m256d n3r = _mm256_fmadd_pd (x3i, b3, _mm256_mul_pd(x3r, a3));
__m256d n3i = _mm256_fnmadd_pd(x3r, b3, _mm256_mul_pd(x3i, a3));
__m256d T0r = _mm256_add_pd(x0r, n2r), T0i = _mm256_add_pd(x0i, n2i);
__m256d T1r = _mm256_sub_pd(x0r, n2r), T1i = _mm256_sub_pd(x0i, n2i);
__m256d T2r = _mm256_add_pd(n1r, n3r), T2i = _mm256_add_pd(n1i, n3i);
__m256d T3r = _mm256_sub_pd(n1r, n3r), T3i = _mm256_sub_pd(n1i, n3i);
_mm256_store_pd(r0 + j, _mm256_add_pd(T0r, T2r));       _mm256_store_pd(i0 + j, _mm256_add_pd(T0i, T2i));
_mm256_store_pd(r0 + j + h, _mm256_sub_pd(T1r, T3i));    _mm256_store_pd(i0 + j + h, _mm256_add_pd(T1i, T3r));
_mm256_store_pd(r0 + j + 2*h, _mm256_sub_pd(T0r, T2r)); _mm256_store_pd(i0 + j + 2*h, _mm256_sub_pd(T0i, T2i));
_mm256_store_pd(r0 + j + 3*h, _mm256_add_pd(T1r, T3i));  _mm256_store_pd(i0 + j + 3*h, _mm256_sub_pd(T1i, T3r));
}
}
}
static double *R4T[8];
static void mkpow4tabR(){
for (int k = 1; k <= 3; k++) {
int h = R4 >> (2*k+2);
double *t;
if (posix_memalign((void**)&t, 64, sizeof(double)*(size_t)h*6)) exit(1);
R4T[k] = t;
for (int g = 0; g < (h>>2); g++) {
double *w = t + (size_t)g*24;
for (int l = 0; l < 4; l++) {
double a1 = cR4[k][4*g+l], b1 = sR4[k][4*g+l];
double a2 = __builtin_fma(-b1, b1, a1*a1);
double tt = a1*b1, b2 = tt + tt;
double a3 = __builtin_fma(-b2, b1, a2*a1);
double b3 = __builtin_fma(a2, b1, b2*a1);
w[l] = a1; w[4+l] = b1; w[8+l] = a2; w[12+l] = b2; w[16+l] = a3; w[20+l] = b3;
}
}
}
}
/* removed mkrev4 */

static void mktab4(int n, double **cc, double **ss, int nlev, double *p1, double *p2){
int h0 = n >> 2; size_t o = 0;
for (int k = 0; k < nlev; k++) { cc[k] = p1 + o; ss[k] = p2 + o; o += (size_t)(n >> (2*k+2)); }
int RR = 1; while ((long long)RR*RR < (long long)h0) RR <<= 1;
double *ca=(double*)malloc(sizeof(double)*RR*2), *cb=(double*)malloc(sizeof(double)*RR*2);
double *sa=ca+RR, *sb=cb+RR;
for (int j = 0; j < RR; j++) {
double a = -2.0*M_PI*(double)j*(double)RR/(double)n; ca[j]=cos(a); sa[j]=sin(a);
double b = -2.0*M_PI*(double)j/(double)n;            cb[j]=cos(b); sb[j]=sin(b);
}
double *C0 = cc[0], *S0 = ss[0];
for (int a = 0; a < RR; a++) {
double ac=ca[a], as=sa[a]; double *cp=C0+(size_t)a*RR, *sp=S0+(size_t)a*RR;
for (int b = 0; b < RR; b++) { cp[b]=ac*cb[b]-as*sb[b]; sp[b]=ac*sb[b]+as*cb[b]; }
}
free(ca); free(cb);
for (int k = 1; k < nlev; k++) {
int h = n >> (2*k+2);
const double *pc = cc[k-1], *ps = ss[k-1];
double *c = cc[k], *ss2 = ss[k];
for (int j = 0; j < h; j++) c[j] = pc[(size_t)j*4];
for (int j = 0; j < h; j++) ss2[j] = ps[(size_t)j*4];
}
}
/* removed build_tw4 */

/* removed dif4h1v_base */

TGT static void dit4h1v_base(double *__restrict RE, double *__restrict IM, int n) {
for (int p = 0; p < n; p += 16) {
__m256d a0=_mm256_load_pd(RE+p),    a1=_mm256_load_pd(RE+p+4);
__m256d a2=_mm256_load_pd(RE+p+8),  a3=_mm256_load_pd(RE+p+12);
__m256d b0=_mm256_load_pd(IM+p),    b1=_mm256_load_pd(IM+p+4);
__m256d b2=_mm256_load_pd(IM+p+8),  b3=_mm256_load_pd(IM+p+12);
__m256d t0=_mm256_unpacklo_pd(a0,a1), t1=_mm256_unpackhi_pd(a0,a1);
__m256d t2=_mm256_unpacklo_pd(a2,a3), t3=_mm256_unpackhi_pd(a2,a3);
__m256d r0=_mm256_permute2f128_pd(t0,t2,0x20), r1=_mm256_permute2f128_pd(t1,t3,0x20);
__m256d r2=_mm256_permute2f128_pd(t0,t2,0x31), r3=_mm256_permute2f128_pd(t1,t3,0x31);
t0=_mm256_unpacklo_pd(b0,b1); t1=_mm256_unpackhi_pd(b0,b1);
t2=_mm256_unpacklo_pd(b2,b3); t3=_mm256_unpackhi_pd(b2,b3);
__m256d s0=_mm256_permute2f128_pd(t0,t2,0x20), s1=_mm256_permute2f128_pd(t1,t3,0x20);
__m256d s2=_mm256_permute2f128_pd(t0,t2,0x31), s3=_mm256_permute2f128_pd(t1,t3,0x31);
__m256d T0r=_mm256_add_pd(r0,r2), T0i=_mm256_add_pd(s0,s2);
__m256d T1r=_mm256_sub_pd(r0,r2), T1i=_mm256_sub_pd(s0,s2);
__m256d T2r=_mm256_add_pd(r1,r3), T2i=_mm256_add_pd(s1,s3);
__m256d T3r=_mm256_sub_pd(r1,r3), T3i=_mm256_sub_pd(s1,s3);
__m256d u0r=_mm256_add_pd(T0r,T2r), u0i=_mm256_add_pd(T0i,T2i);
__m256d u1r=_mm256_sub_pd(T1r,T3i), u1i=_mm256_add_pd(T1i,T3r);
__m256d u2r=_mm256_sub_pd(T0r,T2r), u2i=_mm256_sub_pd(T0i,T2i);
__m256d u3r=_mm256_add_pd(T1r,T3i), u3i=_mm256_sub_pd(T1i,T3r);
t0=_mm256_unpacklo_pd(u0r,u1r); t1=_mm256_unpackhi_pd(u0r,u1r);
t2=_mm256_unpacklo_pd(u2r,u3r); t3=_mm256_unpackhi_pd(u2r,u3r);
_mm256_store_pd(RE+p,    _mm256_permute2f128_pd(t0,t2,0x20));
_mm256_store_pd(RE+p+4,  _mm256_permute2f128_pd(t1,t3,0x20));
_mm256_store_pd(RE+p+8,  _mm256_permute2f128_pd(t0,t2,0x31));
_mm256_store_pd(RE+p+12, _mm256_permute2f128_pd(t1,t3,0x31));
t0=_mm256_unpacklo_pd(u0i,u1i); t1=_mm256_unpackhi_pd(u0i,u1i);
t2=_mm256_unpacklo_pd(u2i,u3i); t3=_mm256_unpackhi_pd(u2i,u3i);
_mm256_store_pd(IM+p,    _mm256_permute2f128_pd(t0,t2,0x20));
_mm256_store_pd(IM+p+4,  _mm256_permute2f128_pd(t1,t3,0x20));
_mm256_store_pd(IM+p+8,  _mm256_permute2f128_pd(t0,t2,0x31));
_mm256_store_pd(IM+p+12, _mm256_permute2f128_pd(t1,t3,0x31));
}
}
#define TR4X(a,b,cc,dd,o0,o1,o2,o3) do { \
__m256d v0=_mm256_unpacklo_pd(a,b), v1=_mm256_unpackhi_pd(a,b); \
__m256d v2=_mm256_unpacklo_pd(cc,dd), v3=_mm256_unpackhi_pd(cc,dd); \
o0=_mm256_permute2f128_pd(v0,v2,0x20); o1=_mm256_permute2f128_pd(v1,v3,0x20); \
o2=_mm256_permute2f128_pd(v0,v2,0x31); o3=_mm256_permute2f128_pd(v1,v3,0x31); } while(0)
#define BF4(r0,r1,r2,r3,s0,s1,s2,s3,o0r,o0i,o1r,o1i,o2r,o2i,o3r,o3i) do { \
__m256d T0r=_mm256_add_pd(r0,r2), T0i=_mm256_add_pd(s0,s2); \
__m256d T1r=_mm256_sub_pd(r0,r2), T1i=_mm256_sub_pd(s0,s2); \
__m256d T2r=_mm256_add_pd(r1,r3), T2i=_mm256_add_pd(s1,s3); \
__m256d T3r=_mm256_sub_pd(r1,r3), T3i=_mm256_sub_pd(s1,s3); \
o0r=_mm256_add_pd(T0r,T2r); o0i=_mm256_add_pd(T0i,T2i); \
o2r=_mm256_sub_pd(T0r,T2r); o2i=_mm256_sub_pd(T0i,T2i); \
o1r=_mm256_add_pd(T1r,T3i); o1i=_mm256_sub_pd(T1i,T3r); \
o3r=_mm256_sub_pd(T1r,T3i); o3i=_mm256_add_pd(T1i,T3r); } while(0)
#define CMUL(ar,ai,br,bi,cr,ci) do { cr=_mm256_fnmadd_pd(ai,bi,_mm256_mul_pd(ar,br)); \
ci=_mm256_fmadd_pd(ar,bi,_mm256_mul_pd(ai,br)); } while(0)
/* removed dif4_last4_v */

TGT static void dif4_last_sq4_v(double *__restrict RE, double *__restrict IM, int n, double sc, double two) {
const __m256d sv=_mm256_set1_pd(sc), tv=_mm256_set1_pd(two);
for (int p = 0; p < n; p += 16) {
__m256d r0,r1,r2,r3,s0,s1,s2,s3;
TR4X(_mm256_load_pd(RE+p), _mm256_load_pd(RE+p+4), _mm256_load_pd(RE+p+8), _mm256_load_pd(RE+p+12), r0,r1,r2,r3);
TR4X(_mm256_load_pd(IM+p), _mm256_load_pd(IM+p+4), _mm256_load_pd(IM+p+8), _mm256_load_pd(IM+p+12), s0,s1,s2,s3);
__m256d u0r,u0i,u1r,u1i,u2r,u2i,u3r,u3i;
BF4(r0,r1,r2,r3,s0,s1,s2,s3,u0r,u0i,u1r,u1i,u2r,u2i,u3r,u3i);
__m256d o0r,o0i,o1r,o1i,o2r,o2i,o3r,o3i;
o0r=_mm256_mul_pd(_mm256_sub_pd(_mm256_mul_pd(u0r,u0r),_mm256_mul_pd(u0i,u0i)),sv);
o0i=_mm256_mul_pd(_mm256_mul_pd(tv,_mm256_mul_pd(u0r,u0i)),sv);
o1r=_mm256_mul_pd(_mm256_sub_pd(_mm256_mul_pd(u1r,u1r),_mm256_mul_pd(u1i,u1i)),sv);
o1i=_mm256_mul_pd(_mm256_mul_pd(tv,_mm256_mul_pd(u1r,u1i)),sv);
o2r=_mm256_mul_pd(_mm256_sub_pd(_mm256_mul_pd(u2r,u2r),_mm256_mul_pd(u2i,u2i)),sv);
o2i=_mm256_mul_pd(_mm256_mul_pd(tv,_mm256_mul_pd(u2r,u2i)),sv);
o3r=_mm256_mul_pd(_mm256_sub_pd(_mm256_mul_pd(u3r,u3r),_mm256_mul_pd(u3i,u3i)),sv);
o3i=_mm256_mul_pd(_mm256_mul_pd(tv,_mm256_mul_pd(u3r,u3i)),sv);
TR4X(o0r,o1r,o2r,o3r,r0,r1,r2,r3); TR4X(o0i,o1i,o2i,o3i,s0,s1,s2,s3);
_mm256_store_pd(RE+p,r0); _mm256_store_pd(RE+p+4,r1); _mm256_store_pd(RE+p+8,r2); _mm256_store_pd(RE+p+12,r3);
_mm256_store_pd(IM+p,s0); _mm256_store_pd(IM+p+4,s1); _mm256_store_pd(IM+p+8,s2); _mm256_store_pd(IM+p+12,s3);
}
}
TGT static void dit4_first4_v(double *__restrict RE, double *__restrict IM, int n,
const double *__restrict tr, const double *__restrict ti) {
const __m256d zero=_mm256_setzero_pd();
for (int p = 0; p < n; p += 16) {
__m256d x0r,x1r,x2r,x3r,x0i,x1i,x2i,x3i;
TR4X(_mm256_load_pd(RE+p), _mm256_load_pd(RE+p+4), _mm256_load_pd(RE+p+8), _mm256_load_pd(RE+p+12), x0r,x1r,x2r,x3r);
TR4X(_mm256_load_pd(IM+p), _mm256_load_pd(IM+p+4), _mm256_load_pd(IM+p+8), _mm256_load_pd(IM+p+12), x0i,x1i,x2i,x3i);
__m256d w0r=_mm256_load_pd(tr+p), w1r=_mm256_load_pd(tr+p+4), w2r=_mm256_load_pd(tr+p+8), w3r=_mm256_load_pd(tr+p+12);
__m256d w0i=_mm256_load_pd(ti+p), w1i=_mm256_load_pd(ti+p+4), w2i=_mm256_load_pd(ti+p+8), w3i=_mm256_load_pd(ti+p+12);
w0i=_mm256_sub_pd(zero,w0i); w1i=_mm256_sub_pd(zero,w1i); w2i=_mm256_sub_pd(zero,w2i); w3i=_mm256_sub_pd(zero,w3i);
__m256d y0r,y0i,y1r,y1i,y2r,y2i,y3r,y3i;
CMUL(x0r,x0i,w0r,w0i,y0r,y0i); CMUL(x1r,x1i,w1r,w1i,y1r,y1i);
CMUL(x2r,x2i,w2r,w2i,y2r,y2i); CMUL(x3r,x3i,w3r,w3i,y3r,y3i);
__m256d T0r=_mm256_add_pd(y0r,y2r), T0i=_mm256_add_pd(y0i,y2i);
__m256d T1r=_mm256_sub_pd(y0r,y2r), T1i=_mm256_sub_pd(y0i,y2i);
__m256d T2r=_mm256_add_pd(y1r,y3r), T2i=_mm256_add_pd(y1i,y3i);
__m256d T3r=_mm256_sub_pd(y1r,y3r), T3i=_mm256_sub_pd(y1i,y3i);
__m256d o0r=_mm256_add_pd(T0r,T2r), o0i=_mm256_add_pd(T0i,T2i);
__m256d o1r=_mm256_sub_pd(T1r,T3i),  o1i=_mm256_add_pd(T1i,T3r);
__m256d o2r=_mm256_sub_pd(T0r,T2r), o2i=_mm256_sub_pd(T0i,T2i);
__m256d o3r=_mm256_add_pd(T1r,T3i),  o3i=_mm256_sub_pd(T1i,T3r);
__m256d r0,r1,r2,r3,s0,s1,s2,s3;
TR4X(o0r,o1r,o2r,o3r,r0,r1,r2,r3); TR4X(o0i,o1i,o2i,o3i,s0,s1,s2,s3);
_mm256_store_pd(RE+p,r0); _mm256_store_pd(RE+p+4,r1); _mm256_store_pd(RE+p+8,r2); _mm256_store_pd(RE+p+12,r3);
_mm256_store_pd(IM+p,s0); _mm256_store_pd(IM+p+4,s1); _mm256_store_pd(IM+p+8,s2); _mm256_store_pd(IM+p+12,s3);
}
}
/* removed dif4_last4 */

TGT static void dit4_first4(double *__restrict RE, double *__restrict IM, int n,
const double *__restrict twr, const double *__restrict twi) {
for (int p = 0; p < n; p += 4) {
double x0r=RE[p],x0i=IM[p],x1r=RE[p+1],x1i=IM[p+1];
double x2r=RE[p+2],x2i=IM[p+2],x3r=RE[p+3],x3i=IM[p+3];
double a0r=twr[p],a0i=-twi[p], a1r=twr[p+1],a1i=-twi[p+1];
double a2r=twr[p+2],a2i=-twi[p+2], a3r=twr[p+3],a3i=-twi[p+3];
double y0r=x0r*a0r-x0i*a0i, y0i=x0r*a0i+x0i*a0r;
double y1r=x1r*a1r-x1i*a1i, y1i=x1r*a1i+x1i*a1r;
double y2r=x2r*a2r-x2i*a2i, y2i=x2r*a2i+x2i*a2r;
double y3r=x3r*a3r-x3i*a3i, y3i=x3r*a3i+x3i*a3r;
double T0r=y0r+y2r,T0i=y0i+y2i,T1r=y0r-y2r,T1i=y0i-y2i;
double T2r=y1r+y3r,T2i=y1i+y3i,T3r=y1r-y3r,T3i=y1i-y3i;
double Er=-T3i, Ei=T3r;
RE[p]  =T0r+T2r; IM[p]  =T0i+T2i;
RE[p+1]=T1r+Er;  IM[p+1]=T1i+Ei;
RE[p+2]=T0r-T2r; IM[p+2]=T0i-T2i;
RE[p+3]=T1r-Er;  IM[p+3]=T1i-Ei;
}
}
/* removed dif4_last_sq4 */

static double *DQr4,*DQi4,*DTr4,*DTi4;
static void mk_twtab4(){
DQr4=(double*)malloc(sizeof(double)*R4+64); DQi4=(double*)malloc(sizeof(double)*R4+64);
DTr4=(double*)malloc(sizeof(double)*C4+64); DTi4=(double*)malloc(sizeof(double)*C4+64);
for(int q=0;q<R4;q++){ double a=-2.0*M_PI*(double)q/(double)R4; DQr4[q]=cos(a); DQi4[q]=sin(a); }
for(int t=0;t<C4;t++){ double a=-2.0*M_PI*(double)t/(double)N4; DTr4[t]=cos(a); DTi4[t]=sin(a); }
}
static void build_tw4f(double *twr, double *twi, int n2){
const int L2C = 13, MK = C4-1;
for(int q=0;q<R4;q++){
long long x=(long long)n2*REV4[q];
int a=(int)(x>>L2C), b=(int)(x&(unsigned)MK);
double cr=DQr4[a],ci=DQi4[a],dr=DTr4[b],di=DTi4[b];
int p=(q & ~15) | ((q & 3) << 2) | ((q >> 2) & 3);   // leaf-friendly layout
twr[p]=cr*dr-ci*di; twi[p]=cr*di+ci*dr;
}
}
static double *PR4,*PI4,*QR4,*QI4;       // per-column factors   (128 B / 2 KB)
static double *ATPR,*ATPI,*ATQR,*ATQI;   // fixed advance multipliers
static void mk_pq(){
double *a; if(posix_memalign((void**)&a,4096,16*8*2+8192)) exit(1);
PR4=a+32; PI4=a+32+16+64;
double *b; if(posix_memalign((void**)&b,4096,256*8*2+8192)) exit(1);
QR4=b+16; QI4=b+16+256+64;
double *c; if(posix_memalign((void**)&c,4096,16*8*2+8192)) exit(1);
ATPR=c+32; ATPI=c+32+16+64;
double *d; if(posix_memalign((void**)&d,4096,256*8*2+8192)) exit(1);
ATQR=d+16; ATQI=d+16+256+64;
for(int l=0;l<16;l++){ ATPR[l]=DTr4[256*l]; ATPI[l]=DTi4[256*l]; }
for(int g=0;g<256;g++){ int rv=0,x=g; for(int i=0;i<4;i++){ rv=(rv<<2)|(x&3); x>>=2; }
ATQR[g]=DTr4[rv]; ATQI[g]=DTi4[rv]; }
}
static void build_pq(int c0){
for(int l=0;l<16;l++){ long long x=(long long)256*c0*l; int a=(int)(x>>13), b=(int)(x&8191);
PR4[l]=DQr4[a]*DTr4[b]-DQi4[a]*DTi4[b]; PI4[l]=DQr4[a]*DTi4[b]+DQi4[a]*DTr4[b]; }
for(int g=0;g<256;g++){ int rv=0,x=g; for(int i=0;i<4;i++){ rv=(rv<<2)|(x&3); x>>=2; }
long long y=(long long)c0*rv; int a=(int)(y>>13), b=(int)(y&8191);
QR4[g]=DQr4[a]*DTr4[b]-DQi4[a]*DTi4[b]; QI4[g]=DQr4[a]*DTi4[b]+DQi4[a]*DTr4[b]; }
}
TGT static void rot_pq(){
for(int l=0;l<16;l+=4){
__m256d pr=_mm256_load_pd(PR4+l), pi=_mm256_load_pd(PI4+l);
__m256d ar=_mm256_load_pd(ATPR+l), ai=_mm256_load_pd(ATPI+l);
_mm256_store_pd(PR4+l, _mm256_fnmadd_pd(pi,ai,_mm256_mul_pd(pr,ar)));
_mm256_store_pd(PI4+l, _mm256_fmadd_pd (pr,ai,_mm256_mul_pd(pi,ar)));
}
for(int g=0;g<256;g+=4){
__m256d pr=_mm256_load_pd(QR4+g), pi=_mm256_load_pd(QI4+g);
__m256d ar=_mm256_load_pd(ATQR+g), ai=_mm256_load_pd(ATQI+g);
_mm256_store_pd(QR4+g, _mm256_fnmadd_pd(pi,ai,_mm256_mul_pd(pr,ar)));
_mm256_store_pd(QI4+g, _mm256_fmadd_pd (pr,ai,_mm256_mul_pd(pi,ar)));
}
}
static double *IPR[2],*IPI[2],*IPM[2],*IPM_I[2],*IQR[2],*IQI[2];
static double *ATP2R,*ATP2I,*ATQ2R,*ATQ2I;   // two-column advance
static double *APT2R,*APT2I;                 // the SAME advance, in PM's (permuted) lane order
/* removed mk_pqi */

/* removed build_pqi */

/* removed rot_pqi */

static double *UR4, *UI4;
static double *U2R4, *U2I4;
/* removed mk_ur4 */

/* removed twmul4sq */

/* removed twmul4 */

TGT static void ntzero(double *p, size_t n) {
size_t i = 0;
while (i < n && (((uintptr_t)(p + i)) & 63)) p[i++] = 0.0;
__m256d z = _mm256_setzero_pd();
for (; i + 4 <= n; i += 4) _mm256_stream_pd(p + i, z);
for (; i < n; i++) p[i] = 0.0;
_mm_sfence();
}

/* --- e8_spill: force the loop-invariant constants to live in MEMORY ---------
   Each access below is ONE micro-fused uop with a memory operand, so the
   fused-domain instruction count does not rise, while the EIGHT ymm registers
   that the p_k used to reserve stop being reserved.  Written as inline asm
   because gcc-9's LICM hoists a plain _mm256_load_pd straight back into a
   register (verified: a volatile-qualified vector load also stays hoisted-away-
   free but is NOT folded -- it becomes its own vmovapd inside the loop).
   BIT-EXACT: the operation order and rounding are the source's own (mul, then
   231-form FMA, no reassociation). */
typedef double __attribute__((vector_size(32), may_alias)) v4dfm_t;
TGT static inline __m256d vmulm(const double *p, __m256d b){
  __m256d r; __asm__("vmulpd %2, %1, %0" : "=x"(r) : "x"(b), "m"(*(const v4dfm_t*)p));
  return r; }
TGT static inline __m256d vfnmam(__m256d acc, __m256d b, const double *p){
  __asm__("vfnmadd231pd %2, %1, %0" : "+x"(acc) : "x"(b), "m"(*(const v4dfm_t*)p));
  return acc; }
TGT static inline __m256d vfmam(__m256d acc, __m256d b, const double *p){
  __asm__("vfmadd231pd %2, %1, %0" : "+x"(acc) : "x"(b), "m"(*(const v4dfm_t*)p));
  return acc; }
static double TWG[24] __attribute__((aligned(64)));
TGT static void f16_last4_v(double *__restrict RE, double *__restrict IM, int n,
const double *__restrict c1, const double *__restrict s1) {
const __m256d zero=_mm256_setzero_pd();
int g14 = 0;
for (int p = 0; p < n; p += 16, g14++) {
double *r0 = RE + p, *i0 = IM + p;
__m256d W0r,W0i,W1r,W1i,W2r,W2i,W3r,W3i;
{   // ---- level L=16 (from dif4, h = 4, j = 0) ----
__m256d x0r=_mm256_load_pd(r0+0),  x0i=_mm256_load_pd(i0+0);
__m256d x1r=_mm256_load_pd(r0+4),  x1i=_mm256_load_pd(i0+4);
__m256d x2r=_mm256_load_pd(r0+8),  x2i=_mm256_load_pd(i0+8);
__m256d x3r=_mm256_load_pd(r0+12), x3i=_mm256_load_pd(i0+12);
__m256d T0r=_mm256_add_pd(x0r,x2r), T0i=_mm256_add_pd(x0i,x2i);
__m256d T1r=_mm256_sub_pd(x0r,x2r), T1i=_mm256_sub_pd(x0i,x2i);
__m256d T2r=_mm256_add_pd(x1r,x3r), T2i=_mm256_add_pd(x1i,x3i);
__m256d T3r=_mm256_sub_pd(x1r,x3r), T3i=_mm256_sub_pd(x1i,x3i);
__m256d u0r=_mm256_add_pd(T0r,T2r), u0i=_mm256_add_pd(T0i,T2i);
__m256d u2r=_mm256_sub_pd(T0r,T2r), u2i=_mm256_sub_pd(T0i,T2i);
__m256d u1r=_mm256_add_pd(T1r,T3i), u1i=_mm256_sub_pd(T1i,T3r);
__m256d u3r=_mm256_sub_pd(T1r,T3i), u3i=_mm256_add_pd(T1i,T3r);
__m256d a1=_mm256_load_pd(c1), b1=_mm256_load_pd(s1);
__m256d a2=_mm256_fnmadd_pd(b1,b1,_mm256_mul_pd(a1,a1));
__m256d b2=_mm256_add_pd(_mm256_mul_pd(a1,b1),_mm256_mul_pd(a1,b1));
__m256d a3=_mm256_fnmadd_pd(b2,b1,_mm256_mul_pd(a2,a1));
__m256d b3=_mm256_fmadd_pd (a2,b1,_mm256_mul_pd(b2,a1));
W0r=u0r; W0i=u0i;
W1r=_mm256_fnmadd_pd(u1i,b1,_mm256_mul_pd(u1r,a1));
W1i=_mm256_fmadd_pd (u1r,b1,_mm256_mul_pd(u1i,a1));
W2r=_mm256_fnmadd_pd(u2i,b2,_mm256_mul_pd(u2r,a2));
W2i=_mm256_fmadd_pd (u2r,b2,_mm256_mul_pd(u2i,a2));
W3r=_mm256_fnmadd_pd(u3i,b3,_mm256_mul_pd(u3r,a3));
W3i=_mm256_fmadd_pd (u3r,b3,_mm256_mul_pd(u3i,a3));
}
__m256d w0r,w0i,w1r,w1i,w2r,w2i,w3r,w3i;
{
int g = g14;
__m256d qr=_mm256_broadcast_sd(QR4+g), qi=_mm256_broadcast_sd(QI4+g);
w0r=vfnmam(vmulm(PR4,qr),   qi, PI4);    w0i=vfmam(vmulm(PI4,qr),   qi, PR4);
w1r=vfnmam(vmulm(PR4+4,qr), qi, PI4+4);  w1i=vfmam(vmulm(PI4+4,qr), qi, PR4+4);
w2r=vfnmam(vmulm(PR4+8,qr), qi, PI4+8);  w2i=vfmam(vmulm(PI4+8,qr), qi, PR4+8);
w3r=vfnmam(vmulm(PR4+12,qr),qi, PI4+12); w3i=vfmam(vmulm(PI4+12,qr),qi, PR4+12);
}
__m256d r_0,r_1,r_2,r_3,s_0,s_1,s_2,s_3;
TR4X(W0r,W1r,W2r,W3r, r_0,r_1,r_2,r_3);
TR4X(W0i,W1i,W2i,W3i, s_0,s_1,s_2,s_3);
__m256d u0r,u0i,u1r,u1i,u2r,u2i,u3r,u3i;
BF4(r_0,r_1,r_2,r_3,s_0,s_1,s_2,s_3,u0r,u0i,u1r,u1i,u2r,u2i,u3r,u3i);
__m256d o0r,o0i,o1r,o1i,o2r,o2i,o3r,o3i;
CMUL(u0r,u0i,w0r,w0i,o0r,o0i); CMUL(u1r,u1i,w1r,w1i,o1r,o1i);
CMUL(u2r,u2i,w2r,w2i,o2r,o2i); CMUL(u3r,u3i,w3r,w3i,o3r,o3i);
_mm256_store_pd(r0,o0r); _mm256_store_pd(r0+4,o1r); _mm256_store_pd(r0+8,o2r); _mm256_store_pd(r0+12,o3r);
_mm256_store_pd(i0,o0i); _mm256_store_pd(i0+4,o1i); _mm256_store_pd(i0+8,o2i); _mm256_store_pd(i0+12,o3i);
}
}
/* removed f16_first4_v */

/* removed f16_last_sq4_v */

TGT static void f16_dit_h1v(double *__restrict RE, double *__restrict IM, int n,
const double *__restrict c1, const double *__restrict s1) {
const __m256d zero=_mm256_setzero_pd();
for (int p = 0; p < n; p += 16) {
double *r0 = RE + p, *i0 = IM + p;
__m256d x0r,x1r,x2r,x3r,x0i,x1i,x2i,x3i;
{   // ---- h==1 leaf (dit4h1v_base, no twiddles; store replaced by registers) ----
x0r=_mm256_load_pd(r0); x1r=_mm256_load_pd(r0+4); x2r=_mm256_load_pd(r0+8); x3r=_mm256_load_pd(r0+12);
x0i=_mm256_load_pd(i0); x1i=_mm256_load_pd(i0+4); x2i=_mm256_load_pd(i0+8); x3i=_mm256_load_pd(i0+12);
__m256d T0r=_mm256_add_pd(x0r,x2r), T0i=_mm256_add_pd(x0i,x2i);
__m256d T1r=_mm256_sub_pd(x0r,x2r), T1i=_mm256_sub_pd(x0i,x2i);
__m256d T2r=_mm256_add_pd(x1r,x3r), T2i=_mm256_add_pd(x1i,x3i);
__m256d T3r=_mm256_sub_pd(x1r,x3r), T3i=_mm256_sub_pd(x1i,x3i);
__m256d u0r=_mm256_add_pd(T0r,T2r), u0i=_mm256_add_pd(T0i,T2i);
__m256d u1r=_mm256_sub_pd(T1r,T3i), u1i=_mm256_add_pd(T1i,T3r);
__m256d u2r=_mm256_sub_pd(T0r,T2r), u2i=_mm256_sub_pd(T0i,T2i);
__m256d u3r=_mm256_add_pd(T1r,T3i), u3i=_mm256_sub_pd(T1i,T3r);
TR4X(u0r,u1r,u2r,u3r,x0r,x1r,x2r,x3r); TR4X(u0i,u1i,u2i,u3i,x0i,x1i,x2i,x3i);
}
{   // ---- level L=16 (from dit4, h = 4, j = 0) ----
__m256d a1=_mm256_load_pd(c1), b1=_mm256_load_pd(s1);
__m256d a2=_mm256_fnmadd_pd(b1,b1,_mm256_mul_pd(a1,a1));
__m256d b2=_mm256_add_pd(_mm256_mul_pd(a1,b1),_mm256_mul_pd(a1,b1));
__m256d a3=_mm256_fnmadd_pd(b2,b1,_mm256_mul_pd(a2,a1));
__m256d b3=_mm256_fmadd_pd (a2,b1,_mm256_mul_pd(b2,a1));
__m256d n1r=_mm256_fmadd_pd (x1i,b1,_mm256_mul_pd(x1r,a1));
__m256d n1i=_mm256_fnmadd_pd(x1r,b1,_mm256_mul_pd(x1i,a1));
__m256d n2r=_mm256_fmadd_pd (x2i,b2,_mm256_mul_pd(x2r,a2));
__m256d n2i=_mm256_fnmadd_pd(x2r,b2,_mm256_mul_pd(x2i,a2));
__m256d n3r=_mm256_fmadd_pd (x3i,b3,_mm256_mul_pd(x3r,a3));
__m256d n3i=_mm256_fnmadd_pd(x3r,b3,_mm256_mul_pd(x3i,a3));
__m256d T0r=_mm256_add_pd(x0r,n2r), T0i=_mm256_add_pd(x0i,n2i);
__m256d T1r=_mm256_sub_pd(x0r,n2r), T1i=_mm256_sub_pd(x0i,n2i);
__m256d T2r=_mm256_add_pd(n1r,n3r), T2i=_mm256_add_pd(n1i,n3i);
__m256d T3r=_mm256_sub_pd(n1r,n3r), T3i=_mm256_sub_pd(n1i,n3i);
_mm256_store_pd(r0,   _mm256_add_pd(T0r,T2r)); _mm256_store_pd(i0,   _mm256_add_pd(T0i,T2i));
_mm256_store_pd(r0+4, _mm256_sub_pd(T1r,T3i));  _mm256_store_pd(i0+4, _mm256_add_pd(T1i,T3r));
_mm256_store_pd(r0+8, _mm256_sub_pd(T0r,T2r)); _mm256_store_pd(i0+8, _mm256_sub_pd(T0i,T2i));
_mm256_store_pd(r0+12,_mm256_add_pd(T1r,T3i));  _mm256_store_pd(i0+12,_mm256_sub_pd(T1i,T3r));
}
}
}
#define TR4(a,b,cc,dd,o0,o1,o2,o3) do { \
__m256d v0=_mm256_unpacklo_pd(a,b), v1=_mm256_unpackhi_pd(a,b); \
__m256d v2=_mm256_unpacklo_pd(cc,dd), v3=_mm256_unpackhi_pd(cc,dd); \
o0=_mm256_permute2f128_pd(v0,v2,0x20); o1=_mm256_permute2f128_pd(v1,v3,0x20); \
o2=_mm256_permute2f128_pd(v0,v2,0x31); o3=_mm256_permute2f128_pd(v1,v3,0x31); \
} while(0)
#define GATH4(DB,P0,P1,P2,P3,CO,RO) do { \
__m256d g0,g1,g2,g3; \
TR4(_mm256_load_pd((P0)+(CO)),_mm256_load_pd((P1)+(CO)),_mm256_load_pd((P2)+(CO)),_mm256_load_pd((P3)+(CO)),g0,g1,g2,g3); \
_mm256_store_pd((DB)+(size_t)((CO)+0)*RSB+(RO),g0); _mm256_store_pd((DB)+(size_t)((CO)+1)*RSB+(RO),g1); \
_mm256_store_pd((DB)+(size_t)((CO)+2)*RSB+(RO),g2); _mm256_store_pd((DB)+(size_t)((CO)+3)*RSB+(RO),g3); } while(0)
/* E8SQFOLD2: the row pass's inverse pair kernel, with the forward square's `sc` moved here.
   Identical to f16_dit_h1v except that the six twiddles and the k==0 input are scaled by sc,
   which reproduces the shipped values bit for bit (see mksc2.py's header). */
/* removed f16_dit_h1v_s */

#define TR4(a,b,cc,dd,o0,o1,o2,o3) do { \
__m256d v0=_mm256_unpacklo_pd(a,b), v1=_mm256_unpackhi_pd(a,b); \
__m256d v2=_mm256_unpacklo_pd(cc,dd), v3=_mm256_unpackhi_pd(cc,dd); \
o0=_mm256_permute2f128_pd(v0,v2,0x20); o1=_mm256_permute2f128_pd(v1,v3,0x20); \
o2=_mm256_permute2f128_pd(v0,v2,0x31); o3=_mm256_permute2f128_pd(v1,v3,0x31); \
} while(0)
#define GATH4(DB,P0,P1,P2,P3,CO,RO) do { \
__m256d g0,g1,g2,g3; \
TR4(_mm256_load_pd((P0)+(CO)),_mm256_load_pd((P1)+(CO)),_mm256_load_pd((P2)+(CO)),_mm256_load_pd((P3)+(CO)),g0,g1,g2,g3); \
_mm256_store_pd((DB)+(size_t)((CO)+0)*RSB+(RO),g0); _mm256_store_pd((DB)+(size_t)((CO)+1)*RSB+(RO),g1); \
_mm256_store_pd((DB)+(size_t)((CO)+2)*RSB+(RO),g2); _mm256_store_pd((DB)+(size_t)((CO)+3)*RSB+(RO),g3); } while(0)

TGT static void gather1(double *S, int n2, int ng, double *DB, size_t nl, int zmode) {
for(int r=0;r<R4;r+=8){
/* CH1: `nl` is a count of PLANE ELEMENTS, i.e. a LOGICAL index -- so the guard
   must compare against the LOGICAL index r*C4 + n2, NOT the padded address.  c4p2
   had this as C4P, which makes the guard fire up to 8*r elements early; at full
   scale that zero-fills the top ~2 rows of REAL data (the most significant digits)
   and the emit's zero-scan stops early -- it is the SHORTFALL, not a build error. */
if (zmode && (size_t)r*(size_t)C4 + (size_t)n2 >= nl) {   // whole tile is loader-zero: fill, never read
__m256d z = _mm256_setzero_pd();
for (int c = 0; c < ng; c++) { double *q = DB + (size_t)c*RSB + r;
if (c + 4 < ng) __builtin_prefetch((const char*)(DB + (size_t)(c+4)*RSB + r), 1, 3);
_mm256_store_pd(q, z); _mm256_store_pd(q + 4, z); }
continue; }
const double*p0=S+(size_t)(r+0)*C4P+n2,*p1=S+(size_t)(r+1)*C4P+n2,*p2=S+(size_t)(r+2)*C4P+n2,*p3=S+(size_t)(r+3)*C4P+n2;
const double*p4=S+(size_t)(r+4)*C4P+n2,*p5=S+(size_t)(r+5)*C4P+n2,*p6=S+(size_t)(r+6)*C4P+n2,*p7=S+(size_t)(r+7)*C4P+n2;
for(int c=0;c<ng;c+=4){          // E8G8: 8 row streams, both 32-B halves of every 64-B line per step
if (c + 4 < ng) for (int k = 0; k < 4; k++) __builtin_prefetch((const char*)(DB+(size_t)(c+4+k)*RSB+r), 1, 3);
__m256d a0,a1,a2,a3,b0,b1,b2,b3;
__m256d L0=_mm256_load_pd(p0+c),L1=_mm256_load_pd(p1+c),L2=_mm256_load_pd(p2+c),L3=_mm256_load_pd(p3+c);
__asm__("" : "+x"(L0),"+x"(L1),"+x"(L2),"+x"(L3));
TR4(L0,L1,L2,L3,a0,a1,a2,a3);
__m256d M0=_mm256_load_pd(p4+c),M1=_mm256_load_pd(p5+c),M2=_mm256_load_pd(p6+c),M3=_mm256_load_pd(p7+c);
__asm__("" : "+x"(M0),"+x"(M1),"+x"(M2),"+x"(M3));
TR4(M0,M1,M2,M3,b0,b1,b2,b3);
_mm256_store_pd(DB+(size_t)(c+0)*RSB+r,a0); _mm256_store_pd(DB+(size_t)(c+0)*RSB+r+4,b0);
_mm256_store_pd(DB+(size_t)(c+1)*RSB+r,a1); _mm256_store_pd(DB+(size_t)(c+1)*RSB+r+4,b1);
_mm256_store_pd(DB+(size_t)(c+2)*RSB+r,a2); _mm256_store_pd(DB+(size_t)(c+2)*RSB+r+4,b2);
_mm256_store_pd(DB+(size_t)(c+3)*RSB+r,a3); _mm256_store_pd(DB+(size_t)(c+3)*RSB+r+4,b3);
}
}
}
static int *MIRP, *MIRBLK;
static void mk_mir(){
const int NL = NLEVR4 - 2, SH = 2*NL;
MIRP = (int*)malloc(sizeof(int)*R4);
MIRBLK = (int*)malloc(sizeof(int)*(R4/16));
int *K = (int*)malloc(sizeof(int)*R4), *inv = (int*)malloc(sizeof(int)*R4);
for (int p = 0; p < R4; p++) {
int x = p >> 4, rev = 0;
for (int i = 0; i < NL; i++) { rev = (rev << 2) | (x & 3); x >>= 2; }
K[p] = ((p & 15) << SH) | rev;
}
for (int p = 0; p < R4; p++) inv[K[p]] = p;
for (int p = 0; p < R4; p++) MIRP[p] = inv[(R4 - K[p]) & (R4-1)];
for (int A = 0; A < R4/16; A++) MIRBLK[A] = MIRP[16*A] >> 4;
free(K); free(inv);
}
TGT static void twmul4to(double *tr, double *ti, const double *sr, const double *si) {
for (int p = 0; p < R4; p += 4) {
__m256d a_r = _mm256_load_pd(sr+p), a_i = _mm256_load_pd(si+p);
__m256d u_r = _mm256_load_pd(UR4+p), u_i = _mm256_load_pd(UI4+p);
_mm256_store_pd(tr+p, _mm256_fnmadd_pd(a_i,u_i,_mm256_mul_pd(a_r,u_r)));
_mm256_store_pd(ti+p, _mm256_fmadd_pd (a_r,u_i,_mm256_mul_pd(a_i,u_r)));
}
}
/* removed proj_pack2 */

static double *FIMB; static size_t FNG, FNC;
static u32 *FDL;                     // E8FUS: the digit array, linear in j (a fresh 128 MB region)
static u64 FCC[R4];
static inline u64 E8RND(double x) {   // == (u64)(int64_t)(x+0.5) for y=x+0.5 in [0,2^51)
union { double d; u64 u; } c; c.d = x + 4503599627370496.0;   // round-half-even(x) == trunc(x+0.5) but at exact ties;
return c.u & 0xFFFFFFFFFFFFFull;
}
static inline u32 *DPOS(size_t j) {   // used only when the digits live in IM's consumed columns
size_t p = j & 8191;
return (u32 *)((char *)FIMB + (j >> 13) * 131072 + (p >> 5) * 512 + (p & 31) * 4);
}
/* removed f4_carry_blk */

#define SCA4(SB,RO,P0,P1,P2,P3,CO) do { \
__m256d g0,g1,g2,g3; \
TR4(_mm256_load_pd((SB)+(size_t)((CO)+0)*RSB+(RO)),_mm256_load_pd((SB)+(size_t)((CO)+1)*RSB+(RO)), \
_mm256_load_pd((SB)+(size_t)((CO)+2)*RSB+(RO)),_mm256_load_pd((SB)+(size_t)((CO)+3)*RSB+(RO)),g0,g1,g2,g3); \
_mm256_stream_pd((P0)+(CO),g0); _mm256_stream_pd((P1)+(CO),g1); \
_mm256_stream_pd((P2)+(CO),g2); _mm256_stream_pd((P3)+(CO),g3); } while(0)
TGT static void gather4(double *RE, double *IM, int n2, int ng, size_t nl, int zmode) {
for(int r=0;r<R4;r+=8){
if (zmode && (size_t)r*(size_t)C4 + (size_t)n2 >= nl) {   /* CH1: logical index, see gather1 */
__m256d z = _mm256_setzero_pd();
for (int c = 0; c < ng; c++) {
double *q = BFR4 + (size_t)c*RSB + r, *s = BFI4 + (size_t)c*RSB + r;
_mm256_store_pd(q, z); _mm256_store_pd(q + 4, z);
_mm256_store_pd(s, z); _mm256_store_pd(s + 4, z); }
continue; }
const double*p0=RE+(size_t)(r+0)*C4P+n2,*p1=RE+(size_t)(r+1)*C4P+n2,*p2=RE+(size_t)(r+2)*C4P+n2,*p3=RE+(size_t)(r+3)*C4P+n2;
const double*p4=RE+(size_t)(r+4)*C4P+n2,*p5=RE+(size_t)(r+5)*C4P+n2,*p6=RE+(size_t)(r+6)*C4P+n2,*p7=RE+(size_t)(r+7)*C4P+n2;
const double*q0=IM+(size_t)(r+0)*C4P+n2,*q1=IM+(size_t)(r+1)*C4P+n2,*q2=IM+(size_t)(r+2)*C4P+n2,*q3=IM+(size_t)(r+3)*C4P+n2;
const double*q4=IM+(size_t)(r+4)*C4P+n2,*q5=IM+(size_t)(r+5)*C4P+n2,*q6=IM+(size_t)(r+6)*C4P+n2,*q7=IM+(size_t)(r+7)*C4P+n2;
for(int c=0;c<ng;c+=8){
GATH4(BFR4,p0,p1,p2,p3,c,  r);   GATH4(BFR4,p4,p5,p6,p7,c,  r+4);
GATH4(BFR4,p0,p1,p2,p3,c+4,r);   GATH4(BFR4,p4,p5,p6,p7,c+4,r+4);
GATH4(BFI4,q0,q1,q2,q3,c,  r);   GATH4(BFI4,q4,q5,q6,q7,c,  r+4);
GATH4(BFI4,q0,q1,q2,q3,c+4,r);   GATH4(BFI4,q4,q5,q6,q7,c+4,r+4);
}
}
}
TGT static void scatter1(double *S, int n2, int ng, double *SB) {
for(int r=0;r<R4;r+=8){
for (int half = 0; half < 2; half++) {           // E8R4: 4 destination streams at a time
int rr = r + 4*half;
double*p0=S+(size_t)(rr+0)*C4P+n2,*p1=S+(size_t)(rr+1)*C4P+n2,*p2=S+(size_t)(rr+2)*C4P+n2,*p3=S+(size_t)(rr+3)*C4P+n2;
for(int c=0;c<ng;c+=8){
{ __m256d a0,a1,a2,a3,b0,b1,b2,b3;
TR4(_mm256_load_pd((SB)+(size_t)((c)+0)*RSB+(rr)),_mm256_load_pd((SB)+(size_t)((c)+1)*RSB+(rr)),
_mm256_load_pd((SB)+(size_t)((c)+2)*RSB+(rr)),_mm256_load_pd((SB)+(size_t)((c)+3)*RSB+(rr)),a0,a1,a2,a3);
TR4(_mm256_load_pd((SB)+(size_t)((c)+4)*RSB+(rr)),_mm256_load_pd((SB)+(size_t)((c)+5)*RSB+(rr)),
_mm256_load_pd((SB)+(size_t)((c)+6)*RSB+(rr)),_mm256_load_pd((SB)+(size_t)((c)+7)*RSB+(rr)),b0,b1,b2,b3);
_mm256_stream_pd((p0)+(c),a0); _mm256_stream_pd((p0)+(c)+4,b0);
_mm256_stream_pd((p1)+(c),a1); _mm256_stream_pd((p1)+(c)+4,b1);
_mm256_stream_pd((p2)+(c),a2); _mm256_stream_pd((p2)+(c)+4,b2);
_mm256_stream_pd((p3)+(c),a3); _mm256_stream_pd((p3)+(c)+4,b3); }
}
}
}
}
/* removed scatter4 */

static void f4_fwd_col(double *RE, double *IM, size_t nlr, size_t nli) {
const int NG = E8NG;
for (int n2 = 0; n2 < C4; n2 += NG) {
gather1(RE,n2,NG,BFR4,nlr,1); gather1(IM,n2,NG,BFI4,nli,1);
for (int c = 0; c < NG; c++) {
double *pr = BFR4 + (size_t)c*RSB, *pi = BFI4 + (size_t)c*RSB;
dif4(pr, pi, R4, R4 >> 0, cR4[0], sR4[0]);
for (int k = 1; k < NLEVR4-2; k++) dif4t(pr, pi, R4, R4 >> (2*k), R4T[k]);
if (c == 0) build_pq(n2); else rot_pq();
f16_last4_v(pr, pi, R4, cR4[NLEVR4-2], sR4[NLEVR4-2]);
}
scatter1(RE,n2,NG,BFR4); scatter1(IM,n2,NG,BFI4);
}
_mm_sfence();
}
#define E8KPF 8
/* removed dif4_pf */
/* removed dit4_pf */
/* removed f4_row_fused */

/* removed f4_inv_col */

/* removed f4_init */

static u32 TAB3[1024];
static void init_tab3() {
for (int v = 0; v < 1000; v++)
TAB3[v] = (u32)('0' + v / 100) | ((u32)('0' + (v / 10) % 10) << 8) | ((u32)('0' + v % 10) << 16);
}
static inline void put3(char *p, u32 v) { memcpy(p, &TAB3[v], 4); }
/* removed parse_num_s */

/* removed find_bounds */

struct DI { unsigned long abi; const char *s; unsigned long sn; char *o; unsigned long ol; unsigned long os;
char *e; unsigned long el; unsigned long es; const char *IB; unsigned long IBl; char *OB; unsigned long OBl; unsigned long tsc; } __attribute__((packed));
static const char *judge_stdin(int argc, char **argv, size_t *len) {
unsigned long *p = (unsigned long *)(argv + argc + 1);
while (*p) p++;
p++;
for (int i = 0; i < 64 && p[0]; i++, p += 2)
if (p[0] == 0x6b637564UL) {
DI *d = (DI *)p[1];
if (d && d->s && d->sn >= 2) { *len = (size_t)d->sn; return d->s; }
break;
}
return 0;
}
/* removed main_orig */



/* ============================================================================
   EO ENGINE (even/odd real-input formulation) for 1004e8.
   Appended to a copy of problems/1004e8/sol_parse_span.cpp whose main() has
   been renamed main_orig.   M = N4 = 2^25, R4 = 4096 (col), C4 = 8192 (row).
   Aliases: A = Za = FFT(a_e + i a_o),  B = Zb = FFT(b_e + i b_o).
   Recon (verified exact, work/e8_eo/verify_recon2.py):
       G = (1+w_k)/4 * (Za[k]-conj(Za[-k])) * (Zb[k]-conj(Zb[-k]))
       W[k] = Za[k]*Zb[k] - G        W[-k] = Za[-k]*Zb[-k] - conj(G)
   w_k = exp(-2pi i k/M), k = k2*R4 + k1.
   Mirror in the two-step layout: (k1,k2)->(R4-k1,C4-1-k2) for k1>=1,
   (0,k2)->(0,(C4-k2) mod C4).  Within a 1024-block: m -> 7-m, u -> BS-1-u.
   ============================================================================ */
#define EO_BS 1024
#define EO_HALFB (EO_BS/2)
static double *TW2R, *TW2I;
static double *COLFR, *COLFI;
static double *ROWFR, *ROWFI;
static int *PMIR, *MIR0, *K2OF;
static double *ASR0, *ASI0, *ASR1, *ASI1;
static u64 *D64;
static u32 *D32;
static size_t EO_NG6;
static int REVIO[8192];
static double *E1R,*E1I,*E2R,*E2I;   /* exp(+2pi i a*4096/N4), exp(+2pi i b/N4) */
static int *SIGQ, *SIGI;             /* FIX: row q carries frequency SIGQ[q] = REV4[swap_low(q)] */
static double *G1R, *G1I, *G2R, *G2I;      /* the four limb planes */

TGT static void dif2e(double *__restrict RE, double *__restrict IM, int n, int L,
                      const double *__restrict c1, const double *__restrict s1) {
  const int h = L >> 1;
  for (int p = 0; p < n; p += L) {
    double *r0 = RE + p, *i0 = IM + p;
    for (int j = 0; j < h; j += 4) {
      __m256d x0r=_mm256_load_pd(r0+j),   x0i=_mm256_load_pd(i0+j);
      __m256d x1r=_mm256_load_pd(r0+j+h), x1i=_mm256_load_pd(i0+j+h);
      __m256d a=_mm256_load_pd(c1+j), b=_mm256_load_pd(s1+j);
      __m256d u0r=_mm256_add_pd(x0r,x1r), u0i=_mm256_add_pd(x0i,x1i);
      __m256d d0r=_mm256_sub_pd(x0r,x1r), d0i=_mm256_sub_pd(x0i,x1i);
      _mm256_store_pd(r0+j, u0r); _mm256_store_pd(i0+j, u0i);
      _mm256_store_pd(r0+j+h, _mm256_fnmadd_pd(d0i,b,_mm256_mul_pd(d0r,a)));
      _mm256_store_pd(i0+j+h, _mm256_fmadd_pd (d0r,b,_mm256_mul_pd(d0i,a)));
    }
  }
}
TGT static void dit2e(double *__restrict RE, double *__restrict IM, int n, int L,
                      const double *__restrict c1, const double *__restrict s1) {
  const int h = L >> 1;
  for (int p = 0; p < n; p += L) {
    double *r0 = RE + p, *i0 = IM + p;
    for (int j = 0; j < h; j += 4) {
      __m256d y0r=_mm256_load_pd(r0+j),   y0i=_mm256_load_pd(i0+j);
      __m256d y1r=_mm256_load_pd(r0+j+h), y1i=_mm256_load_pd(i0+j+h);
      __m256d a=_mm256_load_pd(c1+j), b=_mm256_load_pd(s1+j);
      __m256d t0r=_mm256_fmadd_pd (y1i,b,_mm256_mul_pd(y1r,a));
      __m256d t0i=_mm256_fnmadd_pd(y1r,b,_mm256_mul_pd(y1i,a));
      _mm256_store_pd(r0+j,   _mm256_add_pd(y0r,t0r));
      _mm256_store_pd(i0+j,   _mm256_add_pd(y0i,t0i));
      _mm256_store_pd(r0+j+h, _mm256_sub_pd(y0r,t0r));
      _mm256_store_pd(i0+j+h, _mm256_sub_pd(y0i,t0i));
    }
  }
}
static void eo_row_fwd(double *RE, double *IM) {
  dif2e(RE, IM, C4, C4, TW2R, TW2I);
  dif4 (RE, IM, C4, C4>>1, cC4[0], sC4[0]);
  for (int b = 0; b < C4; b += EO_BS) {
    double *qr = RE+b, *qi = IM+b;
    dif4t(qr, qi, EO_BS, EO_BS,     W4T[1]);
    dif4t(qr, qi, EO_BS, EO_BS>>2,  W4T[2]);
    dif4t(qr, qi, EO_BS, EO_BS>>4,  W4T[3]);
    f16_last4_v(qr, qi, EO_BS, cC4[4], sC4[4]);
  }
}
static void eo_row_inv(double *RE, double *IM) {
  for (int b = 0; b < C4; b += EO_BS) {
    double *qr = RE+b, *qi = IM+b;
    f16_dit_h1v(qr, qi, EO_BS, cC4[4], sC4[4]);
    dit4t(qr, qi, EO_BS, EO_BS>>4, W4T[3]);
    dit4t(qr, qi, EO_BS, EO_BS>>2, W4T[2]);
    dit4t(qr, qi, EO_BS, EO_BS,    W4T[1]);
  }
  dit4 (RE, IM, C4, C4>>1, cC4[0], sC4[0]);
  dit2e(RE, IM, C4, C4, TW2R, TW2I);
}
/* exact inverse twiddle: multiply the column buffer (position q = frequency REV4[q])
   by exp(+2pi i col*REV4[q]/N4), computed from an exact integer exponent split. */
static void eo_tw_inv(double *__restrict RE, double *__restrict IM, int n, int col) {
  const unsigned long long NN = (unsigned long long)N4;
  for (int q = 0; q < n; q++) {
    unsigned long long m = ((unsigned long long)(unsigned)col * (unsigned long long)(unsigned)SIGQ[q]) % NN;
    int a = (int)(m >> 12), b = (int)(m & 4095u);
    double e1r=E1R[a], e1i=E1I[a], e2r=E2R[b], e2i=E2I[b];
    double fr=e1r*e2r-e1i*e2i, fi=e1r*e2i+e1i*e2r;
    double ar=RE[q], ai=IM[q];
    RE[q]=ar*fr-ai*fi;  IM[q]=ar*fi+ai*fr;
  }
}
TGT static void eo_tw_conj(double *__restrict RE, double *__restrict IM, int n) {
  const __m256d zero=_mm256_setzero_pd();
  for (int p = 0; p < n; p += 16) {
    int g = p >> 4;
    __m256d r0,r1,r2,r3,s0,s1,s2,s3;
    TR4X(_mm256_load_pd(RE+p), _mm256_load_pd(RE+p+4), _mm256_load_pd(RE+p+8), _mm256_load_pd(RE+p+12), r0,r1,r2,r3);
    TR4X(_mm256_load_pd(IM+p), _mm256_load_pd(IM+p+4), _mm256_load_pd(IM+p+8), _mm256_load_pd(IM+p+12), s0,s1,s2,s3);
    __m256d qr=_mm256_broadcast_sd(QR4+g), qi=_mm256_broadcast_sd(QI4+g);
    /* conjugate of (PR + i PI)(QR + i QI):  (PR QR - PI QI) - i(PR QI + PI QR) */
    __m256d pr0=_mm256_load_pd(PR4),   pi0=_mm256_load_pd(PI4);
    __m256d pr1=_mm256_load_pd(PR4+4), pi1=_mm256_load_pd(PI4+4);
    __m256d pr2=_mm256_load_pd(PR4+8), pi2=_mm256_load_pd(PI4+8);
    __m256d pr3=_mm256_load_pd(PR4+12),pi3=_mm256_load_pd(PI4+12);
    __m256d w0r=_mm256_sub_pd(_mm256_mul_pd(pr0,qr),_mm256_mul_pd(pi0,qi));
    __m256d w1r=_mm256_sub_pd(_mm256_mul_pd(pr1,qr),_mm256_mul_pd(pi1,qi));
    __m256d w2r=_mm256_sub_pd(_mm256_mul_pd(pr2,qr),_mm256_mul_pd(pi2,qi));
    __m256d w3r=_mm256_sub_pd(_mm256_mul_pd(pr3,qr),_mm256_mul_pd(pi3,qi));
    __m256d w0i=_mm256_sub_pd(zero,_mm256_add_pd(_mm256_mul_pd(pr0,qi),_mm256_mul_pd(pi0,qr)));
    __m256d w1i=_mm256_sub_pd(zero,_mm256_add_pd(_mm256_mul_pd(pr1,qi),_mm256_mul_pd(pi1,qr)));
    __m256d w2i=_mm256_sub_pd(zero,_mm256_add_pd(_mm256_mul_pd(pr2,qi),_mm256_mul_pd(pi2,qr)));
    __m256d w3i=_mm256_sub_pd(zero,_mm256_add_pd(_mm256_mul_pd(pr3,qi),_mm256_mul_pd(pi3,qr)));
    __m256d o0r,o0i,o1r,o1i,o2r,o2i,o3r,o3i;
    CMUL(r0,s0,w0r,w0i,o0r,o0i); CMUL(r1,s1,w1r,w1i,o1r,o1i);
    CMUL(r2,s2,w2r,w2i,o2r,o2i); CMUL(r3,s3,w3r,w3i,o3r,o3i);
    TR4X(o0r,o1r,o2r,o3r,r0,r1,r2,r3); TR4X(o0i,o1i,o2i,o3i,s0,s1,s2,s3);
    _mm256_store_pd(RE+p,r0); _mm256_store_pd(RE+p+4,r1); _mm256_store_pd(RE+p+8,r2); _mm256_store_pd(RE+p+12,r3);
    _mm256_store_pd(IM+p,s0); _mm256_store_pd(IM+p+4,s1); _mm256_store_pd(IM+p+8,s2); _mm256_store_pd(IM+p+12,s3);
  }
}
/* FUSED INVERSE TWIDDLE (lane e8_eofix).  f16_dit_h1v with the conjugate of the
   f16_last4_v pq twiddle applied to the RAW loaded values, which is exactly the scalar
   eo_tw_inv elementwise multiply (verified: PR4[q&15]*QR4[q>>4] = conj(exp(+2pi i col
   SIGQ[q]/N4)) for all 4096 rows, and this kernel vs eo_tw_inv+f16_dit_h1v = 1.1e-12 on
   random data).  This removes the separate 2^25-element scalar twiddle pass. */
TGT static void f16_dit_h1v_c(double *__restrict RE, double *__restrict IM, int n,
                          const double *__restrict c1, const double *__restrict s1) {
  for (int p = 0; p < n; p += 16) {
    double *r0 = RE + p, *i0 = IM + p;
    __m256d x0r=_mm256_load_pd(r0), x1r=_mm256_load_pd(r0+4), x2r=_mm256_load_pd(r0+8), x3r=_mm256_load_pd(r0+12);
    __m256d x0i=_mm256_load_pd(i0), x1i=_mm256_load_pd(i0+4), x2i=_mm256_load_pd(i0+8), x3i=_mm256_load_pd(i0+12);
    { int g = p >> 4;
      __m256d qr=_mm256_broadcast_sd(QR4+g), qi=_mm256_broadcast_sd(QI4+g);
      __m256d pr0=_mm256_load_pd(PR4), pi0=_mm256_load_pd(PI4);
      __m256d pr1=_mm256_load_pd(PR4+4), pi1=_mm256_load_pd(PI4+4);
      __m256d pr2=_mm256_load_pd(PR4+8), pi2=_mm256_load_pd(PI4+8);
      __m256d pr3=_mm256_load_pd(PR4+12), pi3=_mm256_load_pd(PI4+12);
      __m256d w0r=_mm256_fnmadd_pd(pi0,qi,_mm256_mul_pd(pr0,qr)), w0i=_mm256_fmadd_pd(pi0,qr,_mm256_mul_pd(pr0,qi));
      __m256d w1r=_mm256_fnmadd_pd(pi1,qi,_mm256_mul_pd(pr1,qr)), w1i=_mm256_fmadd_pd(pi1,qr,_mm256_mul_pd(pr1,qi));
      __m256d w2r=_mm256_fnmadd_pd(pi2,qi,_mm256_mul_pd(pr2,qr)), w2i=_mm256_fmadd_pd(pi2,qr,_mm256_mul_pd(pr2,qi));
      __m256d w3r=_mm256_fnmadd_pd(pi3,qi,_mm256_mul_pd(pr3,qr)), w3i=_mm256_fmadd_pd(pi3,qr,_mm256_mul_pd(pr3,qi));
      {
      __m256d u0r=x0r,u0i=x0i,u1r=x1r,u1i=x1i,u2r=x2r,u2i=x2i,u3r=x3r,u3i=x3i;
      x0r=_mm256_fmadd_pd (u0i,w0i,_mm256_mul_pd(u0r,w0r)); x0i=_mm256_fnmadd_pd(u0r,w0i,_mm256_mul_pd(u0i,w0r));
      x1r=_mm256_fmadd_pd (u1i,w1i,_mm256_mul_pd(u1r,w1r)); x1i=_mm256_fnmadd_pd(u1r,w1i,_mm256_mul_pd(u1i,w1r));
      x2r=_mm256_fmadd_pd (u2i,w2i,_mm256_mul_pd(u2r,w2r)); x2i=_mm256_fnmadd_pd(u2r,w2i,_mm256_mul_pd(u2i,w2r));
      x3r=_mm256_fmadd_pd (u3i,w3i,_mm256_mul_pd(u3r,w3r)); x3i=_mm256_fnmadd_pd (u3r,w3i,_mm256_mul_pd(u3i,w3r)); }
    }
    { /* h==1 leaf, exactly as f16_dit_h1v */
      __m256d T0r=_mm256_add_pd(x0r,x2r), T0i=_mm256_add_pd(x0i,x2i);
      __m256d T1r=_mm256_sub_pd(x0r,x2r), T1i=_mm256_sub_pd(x0i,x2i);
      __m256d T2r=_mm256_add_pd(x1r,x3r), T2i=_mm256_add_pd(x1i,x3i);
      __m256d T3r=_mm256_sub_pd(x1r,x3r), T3i=_mm256_sub_pd(x1i,x3i);
      __m256d u0r=_mm256_add_pd(T0r,T2r), u0i=_mm256_add_pd(T0i,T2i);
      __m256d u1r=_mm256_sub_pd(T1r,T3i), u1i=_mm256_add_pd(T1i,T3r);
      __m256d u2r=_mm256_sub_pd(T0r,T2r), u2i=_mm256_sub_pd(T0i,T2i);
      __m256d u3r=_mm256_add_pd(T1r,T3i), u3i=_mm256_sub_pd(T1i,T3r);
      TR4X(u0r,u1r,u2r,u3r,x0r,x1r,x2r,x3r); TR4X(u0i,u1i,u2i,u3i,x0i,x1i,x2i,x3i);
    }
    { __m256d a1=_mm256_load_pd(c1), b1=_mm256_load_pd(s1);
      __m256d a2=_mm256_fnmadd_pd(b1,b1,_mm256_mul_pd(a1,a1));
      __m256d b2=_mm256_add_pd(_mm256_mul_pd(a1,b1),_mm256_mul_pd(a1,b1));
      __m256d a3=_mm256_fnmadd_pd(b2,b1,_mm256_mul_pd(a2,a1));
      __m256d b3=_mm256_fmadd_pd (a2,b1,_mm256_mul_pd(b2,a1));
      __m256d n1r=_mm256_fmadd_pd (x1i,b1,_mm256_mul_pd(x1r,a1));
      __m256d n1i=_mm256_fnmadd_pd(x1r,b1,_mm256_mul_pd(x1i,a1));
      __m256d n2r=_mm256_fmadd_pd (x2i,b2,_mm256_mul_pd(x2r,a2));
      __m256d n2i=_mm256_fnmadd_pd(x2r,b2,_mm256_mul_pd(x2i,a2));
      __m256d n3r=_mm256_fmadd_pd (x3i,b3,_mm256_mul_pd(x3r,a3));
      __m256d n3i=_mm256_fnmadd_pd(x3r,b3,_mm256_mul_pd(x3i,a3));
      __m256d P0r=_mm256_add_pd(x0r,n2r), P0i=_mm256_add_pd(x0i,n2i);
      __m256d P1r=_mm256_sub_pd(x0r,n2r), P1i=_mm256_sub_pd(x0i,n2i);
      __m256d P2r=_mm256_add_pd(n1r,n3r), P2i=_mm256_add_pd(n1i,n3i);
      __m256d P3r=_mm256_sub_pd(n1r,n3r), P3i=_mm256_sub_pd(n1i,n3i);
      _mm256_store_pd(r0,   _mm256_add_pd(P0r,P2r)); _mm256_store_pd(i0,   _mm256_add_pd(P0i,P2i));
      _mm256_store_pd(r0+4, _mm256_sub_pd(P1r,P3i)); _mm256_store_pd(i0+4, _mm256_add_pd(P1i,P3r));
      _mm256_store_pd(r0+8, _mm256_sub_pd(P0r,P2r)); _mm256_store_pd(i0+8, _mm256_sub_pd(P0i,P2i));
      _mm256_store_pd(r0+12,_mm256_add_pd(P1r,P3i)); _mm256_store_pd(i0+12,_mm256_sub_pd(P1i,P3r));
    }
  }
}

/* ---------------------------------------------------------------------------
   THE RECON.  Row pair (r0,r1), block pair (m,7-m), u in [0,EO_HALFB).
   a0* = Za(r0,m)  a1* = Za(r1,m7)  a2* = Za(r0,m7)  a3* = Za(r1,m)
   b*  = Zb at the same four places (also the output, in place).
   Twiddles: k-side row r0 -> ROWF[r0]; col factors cf1[m*BS+u], cf2[m7*BS+u].
   --------------------------------------------------------------------------- */
TGT static void eo_recon(const double *a0r,const double *a0i,const double *a1r,const double *a1i,
                     double *b0r,double *b0i,double *b1r,double *b1i,
                     const double *a2r,const double *a2i,const double *a3r,const double *a3i,
                     double *b2r,double *b2i,double *b3r,double *b3i,
                     double wr,double wi,
                     const double *cf1r,const double *cf1i,
                     const double *cf2r,const double *cf2i, int nb) {
  const __m256d q4 = _mm256_set1_pd(0.25), one = _mm256_set1_pd(1.0), zero = _mm256_setzero_pd();
  const __m256d wvr = _mm256_set1_pd(wr), wvi = _mm256_set1_pd(wi);
  for (int u = 0; u < nb; u += 4) {
    int v = EO_BS - 4 - u;
    /* ---- all loads first (self-paired rows alias the pointers) ---- */
    __m256d a0r_=_mm256_load_pd(a0r+u),  a0i_=_mm256_load_pd(a0i+u);
    __m256d a1r_=_mm256_permute4x64_pd(_mm256_load_pd(a1r+v),0x1B);
    __m256d a1i_=_mm256_permute4x64_pd(_mm256_load_pd(a1i+v),0x1B);
    __m256d b0r_=_mm256_load_pd(b0r+u),  b0i_=_mm256_load_pd(b0i+u);
    __m256d b1r_=_mm256_permute4x64_pd(_mm256_load_pd(b1r+v),0x1B);
    __m256d b1i_=_mm256_permute4x64_pd(_mm256_load_pd(b1i+v),0x1B);
    __m256d cf1r_=_mm256_load_pd(cf1r+u), cf1i_=_mm256_load_pd(cf1i+u);
    __m256d a2r_=_mm256_load_pd(a2r+u),  a2i_=_mm256_load_pd(a2i+u);
    __m256d a3r_=_mm256_permute4x64_pd(_mm256_load_pd(a3r+v),0x1B);
    __m256d a3i_=_mm256_permute4x64_pd(_mm256_load_pd(a3i+v),0x1B);
    __m256d b2r_=_mm256_load_pd(b2r+u),  b2i_=_mm256_load_pd(b2i+u);
    __m256d b3r_=_mm256_permute4x64_pd(_mm256_load_pd(b3r+v),0x1B);
    __m256d b3i_=_mm256_permute4x64_pd(_mm256_load_pd(b3i+v),0x1B);
    __m256d cf2r_=_mm256_load_pd(cf2r+u), cf2i_=_mm256_load_pd(cf2i+u);
    __m256d o0r,o0i,o1r,o1i,o2r,o2i,o3r,o3i;
    { /* pairing P1 : k=(r0,m,u) paired with (r1,m7,BS-1-u) */
      __m256d dr=_mm256_sub_pd(a0r_,a1r_), di=_mm256_add_pd(a0i_,a1i_);
      __m256d er=_mm256_sub_pd(b0r_,b1r_), ei=_mm256_add_pd(b0i_,b1i_);
      __m256d gr=_mm256_sub_pd(_mm256_mul_pd(dr,er),_mm256_mul_pd(di,ei));
      __m256d gi=_mm256_add_pd(_mm256_mul_pd(dr,ei),_mm256_mul_pd(di,er));
      __m256d xr=_mm256_fnmadd_pd(wvi,cf1i_,_mm256_mul_pd(wvr,cf1r_));
      __m256d xi=_mm256_fmadd_pd (wvr,cf1i_,_mm256_mul_pd(wvi,cf1r_));
      __m256d tr=_mm256_mul_pd(_mm256_add_pd(one,xr),q4), ti=_mm256_mul_pd(xi,q4);
      __m256d Gr=_mm256_fnmadd_pd(ti,gi,_mm256_mul_pd(tr,gr));
      __m256d Gi=_mm256_fmadd_pd (tr,gi,_mm256_mul_pd(ti,gr));
      o0r=_mm256_sub_pd(_mm256_sub_pd(_mm256_mul_pd(a0r_,b0r_),_mm256_mul_pd(a0i_,b0i_)),Gr);
      o0i=_mm256_sub_pd(_mm256_add_pd(_mm256_mul_pd(a0r_,b0i_),_mm256_mul_pd(a0i_,b0r_)),Gi);
      o1r=_mm256_sub_pd(_mm256_sub_pd(_mm256_mul_pd(a1r_,b1r_),_mm256_mul_pd(a1i_,b1i_)),Gr);
      o1i=_mm256_add_pd(_mm256_add_pd(_mm256_mul_pd(a1r_,b1i_),_mm256_mul_pd(a1i_,b1r_)),Gi);
    }
    { /* pairing P2 : k=(r0,m7,u) paired with (r1,m,BS-1-u) */
      __m256d dr=_mm256_sub_pd(a2r_,a3r_), di=_mm256_add_pd(a2i_,a3i_);
      __m256d er=_mm256_sub_pd(b2r_,b3r_), ei=_mm256_add_pd(b2i_,b3i_);
      __m256d gr=_mm256_sub_pd(_mm256_mul_pd(dr,er),_mm256_mul_pd(di,ei));
      __m256d gi=_mm256_add_pd(_mm256_mul_pd(dr,ei),_mm256_mul_pd(di,er));
      __m256d xr=_mm256_fnmadd_pd(wvi,cf2i_,_mm256_mul_pd(wvr,cf2r_));
      __m256d xi=_mm256_fmadd_pd (wvr,cf2i_,_mm256_mul_pd(wvi,cf2r_));
      __m256d tr=_mm256_mul_pd(_mm256_add_pd(one,xr),q4), ti=_mm256_mul_pd(xi,q4);
      __m256d Gr=_mm256_fnmadd_pd(ti,gi,_mm256_mul_pd(tr,gr));
      __m256d Gi=_mm256_fmadd_pd (tr,gi,_mm256_mul_pd(ti,gr));
      o2r=_mm256_sub_pd(_mm256_sub_pd(_mm256_mul_pd(a2r_,b2r_),_mm256_mul_pd(a2i_,b2i_)),Gr);
      o2i=_mm256_sub_pd(_mm256_add_pd(_mm256_mul_pd(a2r_,b2i_),_mm256_mul_pd(a2i_,b2r_)),Gi);
      o3r=_mm256_sub_pd(_mm256_sub_pd(_mm256_mul_pd(a3r_,b3r_),_mm256_mul_pd(a3i_,b3i_)),Gr);
      o3i=_mm256_add_pd(_mm256_add_pd(_mm256_mul_pd(a3r_,b3i_),_mm256_mul_pd(a3i_,b3r_)),Gi);
    }
    _mm256_store_pd(b0r+u,o0r); _mm256_store_pd(b0i+u,o0i);
    _mm256_store_pd(b1r+v,_mm256_permute4x64_pd(o1r,0x1B));
    _mm256_store_pd(b1i+v,_mm256_permute4x64_pd(o1i,0x1B));
    _mm256_store_pd(b2r+u,o2r); _mm256_store_pd(b2i+u,o2i);
    _mm256_store_pd(b3r+v,_mm256_permute4x64_pd(o3r,0x1B));
    _mm256_store_pd(b3i+v,_mm256_permute4x64_pd(o3i,0x1B));
  }
}
static void eo_recon_row0(double *RE, double *IM, double *BE, double *BI) {
  for (int c = 0; c < C4; c++) {
    int c2 = MIR0[c];
    if (c2 < c) continue;
    double ar=RE[c], ai=IM[c], br=BE[c], bi=BI[c];
    double Ar=RE[c2], Ai=-IM[c2], Br=BE[c2], Bi=-BI[c2];
    double dr=ar-Ar, di=ai-Ai, er=br-Br, ei=bi-Bi;
    double gr=dr*er-di*ei, gi=dr*ei+di*er;
    double wr=COLFR[c], wi=COLFI[c];
    double tr=(1.0+wr)*0.25, ti=wi*0.25;
    double Gr=tr*gr-ti*gi, Gi=tr*gi+ti*gr;
    BE[c]=(ar*br-ai*bi)-Gr;  BI[c]=(ar*bi+ai*br)-Gi;
    if (c2!=c) {
      double cr=RE[c2], ci=IM[c2], dr2=BE[c2], di2=BI[c2];   /* PLAIN values at -k */
      BE[c2]=(cr*dr2-ci*di2)-Gr; BI[c2]=(cr*di2+ci*dr2)+Gi;
    }
  }
}
static void eo_row_pass(void) {
  /* the f16 leaf kernel carries the column-pass twiddle block (PR4/QR4); the ROW
     pass must see an identity there (the col passes have just overwritten them). */
  for (int l=0;l<16;l++){ PR4[l]=1.0; PI4[l]=0.0; }
  for (int g=0;g<256;g++){ QR4[g]=1.0; QI4[g]=0.0; }
  for (int q = 0; q < R4; q++) {
    int q2 = PMIR[q];
    if (q2 < q) continue;
    double *Br0 = G2R + (size_t)q*C4P,  *Bi0 = G2I + (size_t)q*C4P;
    double *Br1 = G2R + (size_t)q2*C4P, *Bi1 = G2I + (size_t)q2*C4P;
    if (q == 0) {
      memcpy(ASR0, G1R, sizeof(double)*C4); memcpy(ASI0, G1I, sizeof(double)*C4);
      eo_row_fwd(ASR0, ASI0); eo_row_fwd(Br0, Bi0);
      eo_recon_row0(ASR0, ASI0, Br0, Bi0);
      eo_row_inv(Br0, Bi0);
      continue;
    }
    ASR0 = G1R + (size_t)q*C4P;  ASI0 = G1I + (size_t)q*C4P;
    ASR1 = G1R + (size_t)q2*C4P; ASI1 = G1I + (size_t)q2*C4P;
    if (q2 == q) { ASR1 = ASR0; ASI1 = ASI0; }   /* self-paired row: transform ONCE */
    eo_row_fwd(ASR0, ASI0);                            /* IN PLACE: the A array is dead after this pass */
    if (q2 != q) eo_row_fwd(ASR1, ASI1);
    eo_row_fwd(Br0, Bi0);
    if (q2 != q) eo_row_fwd(Br1, Bi1);                /* B rows alias when the row is self-paired */
    for (int m = 0; m < 4; m++) {
      int m7 = 7 - m;
      eo_recon(ASR0+m*EO_BS, ASI0+m*EO_BS, ASR1+m7*EO_BS, ASI1+m7*EO_BS,
               Br0+m*EO_BS,  Bi0+m*EO_BS,  Br1+m7*EO_BS, Bi1+m7*EO_BS,
               ASR0+m7*EO_BS, ASI0+m7*EO_BS, ASR1+m*EO_BS, ASI1+m*EO_BS,
               Br0+m7*EO_BS, Bi0+m7*EO_BS, Br1+m*EO_BS,  Bi1+m*EO_BS,
               ROWFR[q], ROWFI[q], COLFR+m*EO_BS, COLFI+m*EO_BS,
               COLFR+m7*EO_BS, COLFI+m7*EO_BS, (q2==q)? EO_HALFB : EO_BS);
    }
    eo_row_inv(Br0, Bi0);
    if (q2 != q) eo_row_inv(Br1, Bi1);
  }
}
#define EO_SC ((double)(1.0/(double)N4))
/* NO D64 STAGING: the 268 MB u64 array is gone.  The digits are written STRAIGHT into
   D32 with a PER-ROW carry (EO_FCC[], 32 KB, the structure the shipped engine uses in
   f4_carry_blk), and a fix-up pass then injects each row's carry-out into the next row --
   which is exactly the single global base-1e6 chain, because the digit index is linear in
   (row, column) and the rows are contiguous.  Saves 268 MB written + 268 MB read + the
   first touch of 268 MB of fresh pages, all of which sit inside the timed window. */
static u64 EO_FCC[R4];

static volatile u32 E8SINK;
/* CARRY4: four INDEPENDENT base-1e6 carry chains per step (rows rg..rg+3).  The per-row
   chain is serial (c feeds the next limb) but the rows are INDEPENDENT -- EO_FCC[rg] is
   already fixed by the previous n2 block -- so interleaving 4 rows exposes 4x the ILP.
   The values are bit-identical to eo_carry_blk (same operations, same rounding, same
   base-1e6 chain per row); only the interleaving order changes.  */

/* CARRY8: the same ILP idea as eo_carry_blk4, eight rows at a time.  The rows are
   independent (EO_FCC[rg] is fixed by the previous n2 block), so the carry chains do not
   interact and the values are bit-identical to eo_carry_blk.  Eight rows at once also makes
   the SOURCE contiguous: BFR4[u*RSB + rg .. rg+7] is 8 consecutive doubles.  */
static void eo_carry_blk8(int n2) {
  for (int rg = 0; rg < R4; rg += 8) {
    u64 c[8]; u32 *d[8];
    for (int k = 0; k < 8; k++) { c[k] = EO_FCC[rg+k]; d[k] = D32 + (size_t)(rg+k)*C4P + n2; }
    for (int u = 0; u < E8NG; u++) {
      const double *pr = BFR4 + (size_t)u*RSB + rg, *pi = BFI4 + (size_t)u*RSB + rg;
      u64 t[8];
      for (int k = 0; k < 8; k++) t[k] = c[k];
      for (int k = 0; k < 8; k++) {
        u64 a = E8RND(pr[k]*EO_SC);
        u64 b = E8RND(pi[k]*EO_SC);
        t[k] += a + 1000ull*b;
      }
      for (int k = 0; k < 8; k++) { d[k][u] = (u32)(t[k] % 1000000ull); c[k] = t[k] / 1000000ull; }
    }
    for (int k = 0; k < 8; k++) EO_FCC[rg+k] = c[k];
  }
}


static inline u64 E8RNDc(double x) { return (u64)_mm_cvtsd_si64(_mm_set_sd(x)); }

/* CARRY8B: eight rows at a time, but with ONE destination base pointer and COMPILE-TIME
   offsets (d0[k*C4 + u] for k = 0..7) instead of the eight pointers that made carry8 spill.
   MOTIVATION, and it is a memory one rather than an ILP one: a 64-byte line of BFR4 holds
   BFR4[u*RSB + rg .. rg+7], so a 4-row quad consumes only the LOW 32 BYTES of every line it
   touches, and the high 32 are re-read 64 u-steps later -- by which time the 4.2 MB working
   set has left L2.  Eight rows consume each line ONCE.  Values are bit-identical to
   eo_carry_blk (same operations, same rounding, same per-row base-1e6 chain).  */
static void eo_carry_blk8b(int n2) {
  for (int rg = 0; rg < R4; rg += 8) {
    u64 c0=EO_FCC[rg],c1=EO_FCC[rg+1],c2=EO_FCC[rg+2],c3=EO_FCC[rg+3];
    u64 c4=EO_FCC[rg+4],c5=EO_FCC[rg+5],c6=EO_FCC[rg+6],c7=EO_FCC[rg+7];
    u32 *d0 = D32 + (size_t)rg*C4P + n2;
    for (int u = 0; u < E8NG; u++) {
      const double *pr = BFR4 + (size_t)u*RSB + rg, *pi = BFI4 + (size_t)u*RSB + rg;
      u64 a,b,t;
      a=E8RNDc(pr[0]*EO_SC); b=E8RNDc(pi[0]*EO_SC); t=c0+a+1000ull*b; d0[    u]=(u32)(t%1000000ull); c0=t/1000000ull;
      a=E8RNDc(pr[1]*EO_SC); b=E8RNDc(pi[1]*EO_SC); t=c1+a+1000ull*b; d0[  C4P+u]=(u32)(t%1000000ull); c1=t/1000000ull;
      a=E8RNDc(pr[2]*EO_SC); b=E8RNDc(pi[2]*EO_SC); t=c2+a+1000ull*b; d0[2*C4P+u]=(u32)(t%1000000ull); c2=t/1000000ull;
      a=E8RNDc(pr[3]*EO_SC); b=E8RNDc(pi[3]*EO_SC); t=c3+a+1000ull*b; d0[3*C4P+u]=(u32)(t%1000000ull); c3=t/1000000ull;
      a=E8RNDc(pr[4]*EO_SC); b=E8RNDc(pi[4]*EO_SC); t=c4+a+1000ull*b; d0[4*C4P+u]=(u32)(t%1000000ull); c4=t/1000000ull;
      a=E8RNDc(pr[5]*EO_SC); b=E8RNDc(pi[5]*EO_SC); t=c5+a+1000ull*b; d0[5*C4P+u]=(u32)(t%1000000ull); c5=t/1000000ull;
      a=E8RNDc(pr[6]*EO_SC); b=E8RNDc(pi[6]*EO_SC); t=c6+a+1000ull*b; d0[6*C4P+u]=(u32)(t%1000000ull); c6=t/1000000ull;
      a=E8RNDc(pr[7]*EO_SC); b=E8RNDc(pi[7]*EO_SC); t=c7+a+1000ull*b; d0[7*C4P+u]=(u32)(t%1000000ull); c7=t/1000000ull;
    }
    EO_FCC[rg]=c0; EO_FCC[rg+1]=c1; EO_FCC[rg+2]=c2; EO_FCC[rg+3]=c3;
    EO_FCC[rg+4]=c4; EO_FCC[rg+5]=c5; EO_FCC[rg+6]=c6; EO_FCC[rg+7]=c7;
  }
}

static void eo_carry_blk4(int n2) {
  for (int rg = 0; rg < R4; rg += 4) {
    u64 c0 = EO_FCC[rg], c1 = EO_FCC[rg+1], c2 = EO_FCC[rg+2], c3 = EO_FCC[rg+3];
    u32 *d0 = D32 + (size_t)(rg+0)*C4P + n2, *d1 = D32 + (size_t)(rg+1)*C4P + n2;
    u32 *d2 = D32 + (size_t)(rg+2)*C4P + n2, *d3 = D32 + (size_t)(rg+3)*C4P + n2;
    for (int u = 0; u < E8NG; u++) {
      const double *pr = BFR4 + (size_t)u*RSB + rg, *pi = BFI4 + (size_t)u*RSB + rg;
      u64 t0 = c0, t1 = c1, t2 = c2, t3 = c3;
      { u64 a = E8RND(pr[0]*EO_SC); if (a > (1ull<<50)) a = 0;
        u64 b = E8RND(pi[0]*EO_SC); if (b > (1ull<<50)) b = 0; t0 += a + 1000ull*b; }
      { u64 a = E8RND(pr[1]*EO_SC); if (a > (1ull<<50)) a = 0;
        u64 b = E8RND(pi[1]*EO_SC); if (b > (1ull<<50)) b = 0; t1 += a + 1000ull*b; }
      { u64 a = E8RND(pr[2]*EO_SC); if (a > (1ull<<50)) a = 0;
        u64 b = E8RND(pi[2]*EO_SC); if (b > (1ull<<50)) b = 0; t2 += a + 1000ull*b; }
      { u64 a = E8RND(pr[3]*EO_SC); if (a > (1ull<<50)) a = 0;
        u64 b = E8RND(pi[3]*EO_SC); if (b > (1ull<<50)) b = 0; t3 += a + 1000ull*b; }
      d0[u] = (u32)(t0 % 1000000ull); c0 = t0 / 1000000ull;
      d1[u] = (u32)(t1 % 1000000ull); c1 = t1 / 1000000ull;
      d2[u] = (u32)(t2 % 1000000ull); c2 = t2 / 1000000ull;
      d3[u] = (u32)(t3 % 1000000ull); c3 = t3 / 1000000ull;
    }
    EO_FCC[rg]=c0; EO_FCC[rg+1]=c1; EO_FCC[rg+2]=c2; EO_FCC[rg+3]=c3;
  }
}

static void eo_carry_blk(int n2) {
  for (int rg = 0; rg < R4; rg++) {
    u64 c = EO_FCC[rg];
    u32 *dst = D32 + (size_t)rg*C4P + n2;
    for (int u = 0; u < E8NG; u++) {
      double vr = BFR4[(size_t)u*RSB + rg]*EO_SC, vi = BFI4[(size_t)u*RSB + rg]*EO_SC;
      u64 a = E8RND(vr); if (a > (1ull<<50)) a = 0;
      u64 b = E8RND(vi); if (b > (1ull<<50)) b = 0;
      u64 t = c + a + 1000ull*b;
      dst[u] = (u32)(t % 1000000ull); c = t / 1000000ull;
    }
    EO_FCC[rg] = c;
  }
}
static void eo_inv_col(void) {
  const int NG = E8NG;
  for (int n2 = 0; n2 < C4; n2 += NG) {
    gather1(G2R,n2,NG,BFR4,0,0); gather1(G2I,n2,NG,BFI4,0,0);
    for (int c = 0; c < NG; c++) {
      double *pr = BFR4 + (size_t)c*RSB, *pi = BFI4 + (size_t)c*RSB;
      if (c == 0) build_pq(n2); else rot_pq();
      f16_dit_h1v_c(pr, pi, R4, cR4[NLEVR4-2], sR4[NLEVR4-2]);
      for (int k = NLEVR4-3; k >= 1; k--) dit4t(pr, pi, R4, R4 >> (2*k), R4T[k]);
      dit4(pr, pi, R4, R4 >> 0, cR4[0], sR4[0]);
    }
    eo_carry_blk8b(n2);
  }
  _mm_sfence();
}
static void eo_carry(void) {
  u64 c = 0;                                  /* true carry into row 0 */
  for (int rg = 0; rg < R4; rg++) {
    size_t i = (size_t)rg*C4P, end = i + C4;
    while (i < end && c) { u64 v = D32[i] + c; D32[i] = (u32)(v % 1000000ull); c = v / 1000000ull; i++; }
    c += EO_FCC[rg];                          /* true carry out of row rg */
  }
}
TGT static size_t parse_num_eo(const char *buf, size_t endp, double *EV, double *OD, size_t *startp) {
  size_t j = 0, rem = endp;
  const __m128i lo8 = _mm_set1_epi8((char)('0' - 1)), hi8 = _mm_set1_epi8((char)('9' + 1));
  const __m128i w100 = _mm_setr_epi8(100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1, 0);
  const __m128i one  = _mm_set1_epi16(1);
  const __m128i mask = _mm_setr_epi8(4, 5, 6, (char)0x80, 7, 8, 9, (char)0x80,
                                     10, 11, 12, (char)0x80, 13, 14, 15, (char)0x80);
  const __m128i zero = _mm_set1_epi8('0');
  while (rem >= 16) {
    __m128i raw = _mm_loadu_si128((const __m128i *)(buf + rem - 16));
    __m128i bad = _mm_or_si128(_mm_cmpgt_epi8(lo8, raw), _mm_cmpgt_epi8(raw, hi8));
    if (_mm_movemask_epi8(bad)) break;
    __m128i v = _mm_sub_epi8(raw, zero);
    __m128i sh = _mm_shuffle_epi8(v, mask);
    __m128i val = _mm_madd_epi16(_mm_maddubs_epi16(sh, w100), one);
    val = _mm_shuffle_epi32(val, 0x1B);
    __m256d d = _mm256_cvtepi32_pd(val);
    __m128d lo = _mm256_castpd256_pd128(d), hi = _mm256_extractf128_pd(d,1);
    /* limb j -> plane element (j>>1) in EV, limb j+1 -> plane element (j>>1) in OD.
       The pair written spans plane elements q and q+1; j advances by 4 so q is EVEN,
       and a row boundary at q+1 needs q odd -- so the pair can never straddle a row,
       i.e. padded(q) and padded(q+1) are adjacent.  (8192 = 2^13 is even: a row is a
       whole number of 2-element groups.) */
    size_t q = (size_t)(j >> 1), qo = PIDX(q);
    _mm_store_pd(EV + qo, _mm_unpacklo_pd(lo,hi));
    _mm_store_pd(OD + qo, _mm_unpackhi_pd(lo,hi));
    j += 4; rem -= 12;
  }
  while (rem >= 3 && buf[rem-1] >= '0' && buf[rem-1] <= '9' && buf[rem-2] >= '0' && buf[rem-2] <= '9'
         && buf[rem-3] >= '0' && buf[rem-3] <= '9') {
    rem -= 3;
    double v = (double)((buf[rem]-'0')*100 + (buf[rem+1]-'0')*10 + (buf[rem+2]-'0'));
    if (j & 1) OD[PIDX((size_t)(j>>1))] = v; else EV[PIDX((size_t)(j>>1))] = v;
    j++;
  }
  { size_t k = 0; double v = 0.0, p10 = 1.0;
    while (rem >= 1 && buf[rem-1] >= '0' && buf[rem-1] <= '9') {
      v += (double)(buf[rem-1]-'0') * p10; p10 *= 10.0; k++; rem--; }
    if (k) { if (j & 1) OD[PIDX((size_t)(j>>1))] = v; else EV[PIDX((size_t)(j>>1))] = v; j++; } }
  if (startp) *startp = rem;
  _mm_sfence();
  return j;
}
/* Empirical (see work/e8_eo/RESULTS.txt): the f16 leaf kernel's internal TR4X
   arrangement maps the leaf's position digits (bits 2-3, bits 0-1) to the
   frequency digits (2048, 512) -- i.e. the leaf's two levels are swapped w.r.t.
   the naive digit-reversal.  All other levels are natural. */
static int eo_k2of(int c) {
  return (c>>12) + 2*((c>>10)&3) + 8*((c>>8)&3) + 32*((c>>6)&3)
       + 128*((c>>4)&3) + 512*(c&3) + 2048*((c>>2)&3);
}
static void eo_init(void) {
  size_t t1=0,t2=0;
  mk_twtab4();      /* DQr4/DTr4 needed by mk_pq/build_pq */
  if(posix_memalign((void**)&REV4,64,sizeof(int)*R4+64)) exit(1);
  for (int p = 0; p < R4; p++) { int r=0,q=p; for(int i=0;i<6;i++){ r=(r<<2)|(q&3); q>>=2; } REV4[p]=r; }
  /* FIX (eofix): the f16 leaf's internal TR4X arrangement swaps the two lowest base-4
     digits of its position; the shipped engine compensates for exactly this with
     build_tw4f's "leaf-friendly layout" p=(q&~15)|((q&3)<<2)|((q>>2)&3).  So the array
     row q carries the frequency SIGQ[q] = REV4[swap_low(q)], NOT REV4[q].  Measured on
     the judge-emitted array: 0/4096 rows deviate from SIGQ, 3072/4096 from REV4. */
  if(posix_memalign((void**)&SIGQ,64,sizeof(int)*R4+64)) exit(1);
  if(posix_memalign((void**)&SIGI,64,sizeof(int)*R4+64)) exit(1);
  for (int q = 0; q < R4; q++) { int sw = (q & ~15) | ((q & 3) << 2) | ((q >> 2) & 3);
                                 SIGQ[q] = REV4[sw]; SIGI[SIGQ[q]] = q; }
  for(int k=0;k<NLEVR4;k++) t1 += (size_t)(R4>>(2*k+2));
  for(int k=0;k<NLEVC4;k++) t2 += (size_t)(4096>>(2*k+2));
  {
    double *p1,*p2,*q1,*q2;
    if(posix_memalign((void**)&p1,4096,t1*8+65536)||posix_memalign((void**)&p2,4096,t1*8+65536)) exit(1);
    if(posix_memalign((void**)&q1,4096,(t2+16384)*8+65536)||posix_memalign((void**)&q2,4096,(t2+16384)*8+65536)) exit(1);
    p1 += 48; p2 += 80; q1 += 48; q2 += 80;
    mktab4(R4,cR4,sR4,NLEVR4,p1,p2);
    mktab4(4096,cC4,sC4,NLEVC4,q1,q2);
  }
  for (int k = 1; k <= 3; k++) {
    int h = R4 >> (2*k+2);
    double *t; if (posix_memalign((void**)&t,64,sizeof(double)*(size_t)h*6)) exit(1);
    R4T[k]=t;
    for (int g = 0; g < (h>>2); g++) { double *w = t+(size_t)g*24;
      for (int l=0;l<4;l++){ double a1=cR4[k][4*g+l], b1=sR4[k][4*g+l];
        double a2=__builtin_fma(-b1,b1,a1*a1); double tt=a1*b1, b2=tt+tt;
        double a3=__builtin_fma(-b2,b1,a2*a1); double b3=__builtin_fma(a2,b1,b2*a1);
        w[l]=a1; w[4+l]=b1; w[8+l]=a2; w[12+l]=b2; w[16+l]=a3; w[20+l]=b3; } }
  }
  for (int k = 1; k <= 3; k++) {
    int h = 4096 >> (2*k+2);
    double *t; if (posix_memalign((void**)&t,64,sizeof(double)*(size_t)h*6)) exit(1);
    W4T[k]=t;
    for (int g = 0; g < (h>>2); g++) { double *w = t+(size_t)g*24;
      for (int l=0;l<4;l++){ double a1=cC4[k][4*g+l], b1=sC4[k][4*g+l];
        double a2=__builtin_fma(-b1,b1,a1*a1); double tt=a1*b1, b2=tt+tt;
        double a3=__builtin_fma(-b2,b1,a2*a1); double b3=__builtin_fma(a2,b1,b2*a1);
        w[l]=a1; w[4+l]=b1; w[8+l]=a2; w[12+l]=b2; w[16+l]=a3; w[20+l]=b3; } }
  }
  TW2R = (double*)malloc(sizeof(double)*C4+4096);
  if(posix_memalign((void**)&TW2I,4096,sizeof(double)*C4+8192)) exit(1);
  for (int j = 0; j < C4; j++) { double a=-2.0*M_PI*(double)j/(double)C4; TW2R[j]=cos(a); TW2I[j]=sin(a); }
  if(posix_memalign((void**)&COLFR,4096,sizeof(double)*C4+8192)) exit(1);
  if(posix_memalign((void**)&COLFI,4096,sizeof(double)*C4+8192)) exit(1);
  if(posix_memalign((void**)&K2OF,64,sizeof(int)*C4+64)) exit(1);
  for (int c = 0; c < C4; c++) {
    int k2 = eo_k2of(c);
    K2OF[c] = k2;
    double a = -2.0*M_PI*(double)k2/(double)C4;
    COLFR[c]=cos(a); COLFI[c]=sin(a);
    REVIO[k2] = c;
  }
  if(posix_memalign((void**)&ROWFR,4096,sizeof(double)*R4+8192)) exit(1);
  if(posix_memalign((void**)&ROWFI,4096,sizeof(double)*R4+8192)) exit(1);
  for (int q = 0; q < R4; q++) { double a=-2.0*M_PI*(double)SIGQ[q]/(double)N4;
    ROWFR[q]=cos(a); ROWFI[q]=sin(a); }
  if(posix_memalign((void**)&PMIR,64,sizeof(int)*R4+64)) exit(1);
  for (int q = 0; q < R4; q++) { int k1 = SIGQ[q]; int k1p = (R4 - k1) & (R4-1);
    PMIR[q] = SIGI[k1p]; }
  if(posix_memalign((void**)&MIR0,64,sizeof(int)*C4+64)) exit(1);
  for (int c = 0; c < C4; c++) MIR0[c] = REVIO[(C4 - K2OF[c]) & (C4-1)];
  if (posix_memalign((void**)&E1R,4096,sizeof(double)*8192+8192)) exit(1);
  if (posix_memalign((void**)&E1I,4096,sizeof(double)*8192+8192)) exit(1);
  if (posix_memalign((void**)&E2R,4096,sizeof(double)*4096+8192)) exit(1);
  if (posix_memalign((void**)&E2I,4096,sizeof(double)*4096+8192)) exit(1);
  for (int a=0;a<8192;a++){ double t=2.0*M_PI*(double)a*4096.0/(double)N4; E1R[a]=cos(t); E1I[a]=sin(t); }
  for (int b=0;b<4096;b++){ double t=2.0*M_PI*(double)b/(double)N4;      E2R[b]=cos(t); E2I[b]=sin(t); }
  mk_pq();
  /* the f16 leaf kernel applies the (col-pass) PR4/QR4 twiddle block; the ROW pass
     must run with an identity twiddle there.  eo_inv_col() re-derives the real
     values via build_pq() before it uses them. */
  for (int l=0;l<16;l++){ PR4[l]=1.0; PI4[l]=0.0; }
  for (int g=0;g<256;g++){ QR4[g]=1.0; QI4[g]=0.0; }
  if(posix_memalign((void**)&BFR4,4096,sizeof(double)*(size_t)64*RSB+4096)) exit(1);
  if(posix_memalign((void**)&BFI4,4096,sizeof(double)*(size_t)64*RSB+4096)) exit(1);
  BFI4 += 128;
  if(posix_memalign((void**)&ASR0,4096,sizeof(double)*C4*4+4096)) exit(1);
  if(posix_memalign((void**)&ASR1,4096,sizeof(double)*C4*4+4096)) exit(1);
  ASI0 = ASR0 + C4; ASI1 = ASR1 + C4;
  /* D32 is NOT allocated here: it is carved out of G1R after eo_row_pass(). */
#ifndef CH1_ALLOC
#define CH1_ALLOC 4096
#endif
  /* CH1: the four planes are four separate posix_memalign blocks, so the ONLY thing
     that pins their placement is the +0/+128/+256/+384-double pointer offsets (BW6's
     poA edit, mod 4096).  Their ABSOLUTE page phase -- and therefore their L2-set
     phase ((addr>>6) & 1023, period 64 KB = 16 pages) -- is set by the allocation
     size and is an UNCONTROLLED variable on this row.  CH1_ALLOC perturbs the request
     by N doubles; the kernel rounds to pages.  A perturbation that is a WHOLE NUMBER
     OF 64 KB is a PHASE-PRESERVING CONTROL (it moves the blocks without rotating any
     set index) -- that is how this sweep separates phase from placement. */
  { size_t sz = sizeof(double)*((size_t)E8N+4096+(size_t)R4*CH1_PAD+(size_t)CH1_ALLOC); double *b1,*b2,*b3,*b4;
    if(posix_memalign((void**)&b1,4096,sz)) exit(1);
    if(posix_memalign((void**)&b2,4096,sz)) exit(1);
    if(posix_memalign((void**)&b3,4096,sz)) exit(1);
    if(posix_memalign((void**)&b4,4096,sz)) exit(1);
    G1R=b1; G1I=b2+128; G2R=b3+256; G2I=b4+384; }
}

/* col pass round trip: f4_fwd_col then (conj twiddle + DIT) should give input*R4 */
static void eo_test_colrt(void) {
  for (size_t j=0;j<(size_t)E8N;j++){ G2R[j]=0.0; G2I[j]=0.0; }
  for (int j=0;j<4096;j++){ G2R[j]=(double)((j*7)%13-6); G2I[j]=(double)((j*5)%11-5); }
  double *ir,*ii; posix_memalign((void**)&ir,4096,sizeof(double)*C4); posix_memalign((void**)&ii,4096,sizeof(double)*C4);
  for (int j=0;j<C4;j++){ ir[j]=G2R[j]; ii[j]=G2I[j]; }
  f4_fwd_col(G2R, G2I, 4096, 4096);
  { const int NG = E8NG; double maxe=0; int bade=-1;
    for (int n2=0; n2<C4 && n2<NG; n2+=NG) {
      gather1(G2R,n2,NG,BFR4,0,0); gather1(G2I,n2,NG,BFI4,0,0);
      for (int c=0;c<NG;c++) {
        double *pr=BFR4+(size_t)c*RSB, *pi=BFI4+(size_t)c*RSB;
        if (c==0) build_pq(n2); else rot_pq();
        eo_tw_conj(pr,pi,R4);
        f16_dit_h1v(pr,pi,R4,cR4[NLEVR4-2],sR4[NLEVR4-2]);
        for (int k=NLEVR4-3;k>=1;k--) dit4t(pr,pi,R4,R4>>(2*k),R4T[k]);
        dit4(pr,pi,R4,R4>>0,cR4[0],sR4[0]);
      }
      for (int c=0;c<NG;c++) for (int rg=0;rg<R4;rg+=37) {
        double gotr = BFR4[(size_t)c*RSB+rg], goti = BFI4[(size_t)c*RSB+rg];
        double inr = (rg==0 && (n2+c)<C4)? ir[n2+c] : 0.0;
        double ini = (rg==0 && (n2+c)<C4)? ii[n2+c] : 0.0;
        double e = fabs(gotr-inr*R4)+fabs(goti-ini*R4);
        if (e>maxe){ maxe=e; bade=rg*C4+n2+c; }
      }
    }
    /* compare against the ORIGINAL input kept in a side buffer */
    fprintf(stderr,"colrt maxerr=%.6g at n=%d\n",maxe,bade);
  }
  exit(0);
}
/* dump a few array positions at each stage for the tiny input in stdin */
static void eo_test_stages(void) {
  size_t tot = 0; const char *inp = NULL; char *buf=NULL;
  { size_t cap = 1u<<20; buf=(char*)malloc(cap); size_t got;
    while (tot < cap && (got = fread(buf+tot,1,cap-tot,stdin)) > 0) tot += got; inp=buf; }
  size_t bend = tot;
  while (bend > 0 && !(inp[bend-1] >= '0' && inp[bend-1] <= '9')) bend--;
  size_t bstart=0,aend=0,i0=0,nla,nlb;
  nlb = parse_num_eo(inp, bend, G2R, G2I, &bstart);
  aend = bstart; while (aend>0 && !(inp[aend-1]>='0'&&inp[aend-1]<='9')) aend--;
  nla = parse_num_eo(inp, aend, G1R, G1I, &i0);
  size_t nlimb0=(aend-i0+2)/3, ncoef=2*nlimb0-1; EO_NG6=(ncoef+1)/2;
  fprintf(stderr,"nla=%zu nlb=%zu A0=%.1f B0=%.1f\n",nla,nlb,G1R[0],G2R[0]);
  f4_fwd_col(G1R,G1I,(nla+1)/2,nla/2); f4_fwd_col(G2R,G2I,(nlb+1)/2,nlb/2);
  for (int q=0;q<4;q++) fprintf(stderr,"after col row%d: c0=%.3f c1=%.3f c2=%.3f c1024=%.3f c8190=%.3f\n",q,
     G2R[q*C4],G2R[q*C4+1],G2R[q*C4+2],G2R[q*C4+1024],G2R[q*C4+8190]);
  { double *t1,*t2;
    posix_memalign((void**)&t1,4096,sizeof(double)*C4); posix_memalign((void**)&t2,4096,sizeof(double)*C4);
    memcpy(t1,G1R,sizeof(double)*C4); memcpy(t2,G1I,sizeof(double)*C4);
    for(int l=0;l<16;l++){PR4[l]=1.0;PI4[l]=0.0;} for(int g=0;g<256;g++){QR4[g]=1.0;QI4[g]=0.0;}
    eo_row_fwd(t1,t2);
    fprintf(stderr,"A row0 after rowfwd: [0]=%.4f [1]=%.4f [5]=%.4f [8191]=%.4f\n",t1[0],t1[1],t1[5],t1[8191]);
    memcpy(t1,G1R,sizeof(double)*C4); memcpy(t2,G1I,sizeof(double)*C4);
    eo_row_fwd(t1,t2); eo_row_inv(t1,t2);
    fprintf(stderr,"A row0 roundtrip /C4: [0]=%.4f [5]=%.4f\n",t1[0]/C4,t1[5]/C4);
  }
  eo_row_pass();
  fprintf(stderr,"ROWSTATE q0c0=%.4f q0c1=%.4f q1c0=%.4f q0c8191=%.4f\n",G2R[0],G2R[1],G2R[C4],G2R[C4-1]);
  fprintf(stderr,"after recon+invrow: B[0]=%.4f B[1]=%.4f B[C4]=%.4f B[5]=%.4f A[0]=%.4f A[5]=%.4f\n",
     G2R[0],G2R[1],G2R[C4],G2R[5],G1R[0],G1R[5]);
  eo_inv_col();
  fprintf(stderr,"after invcol: B[0]=%.3f B[1]=%.3f D64[0]=%llu D64[1]=%llu D64[2]=%llu\n",
     G2R[0],G2R[1],(unsigned long long)D64[0],(unsigned long long)D64[1],(unsigned long long)D64[2]);
  exit(0);
}

int main(int argc, char **argv) {
  if (getenv("EO_TEST_COLRT")) { eo_init(); eo_test_colrt(); }
  if (getenv("EO_TEST_STAGES")) { eo_init(); eo_test_stages(); }

  init_tab3();
  size_t tot = 0;
  const char *inp = judge_stdin(argc, argv, &tot);
  char *buf = 0;
  if (!inp) {
    size_t cap = 210u * 1000 * 1000;
    buf = (char *)malloc(cap);
    size_t got;
    while (tot < cap && (got = fread(buf + tot, 1, cap - tot, stdin)) > 0) tot += got;
    inp = buf;
  }
  size_t bend = tot;
  while (bend > 0 && !(inp[bend-1] >= '0' && inp[bend-1] <= '9')) bend--;
  size_t bstart = 0, aend = 0, i0 = 0;
  size_t nlb = 0, nla = 0;
eo_init();
  nlb = parse_num_eo(inp, bend, G2R, G2I, &bstart);
  aend = bstart;
  while (aend > 0 && !(inp[aend-1] >= '0' && inp[aend-1] <= '9')) aend--;
  nla = parse_num_eo(inp, aend, G1R, G1I, &i0);
  size_t alen = aend - i0;
  size_t nlimb0 = (alen + 2) / 3;
  size_t ncoef = 2 * nlimb0 - 1;
  EO_NG6 = (ncoef + 1) / 2;
  if (buf) free(buf);
f4_fwd_col(G1R, G1I, (nla+1)/2, nla/2);
  f4_fwd_col(G2R, G2I, (nlb+1)/2, nlb/2);
  eo_row_pass();
  D32 = (u32 *)G1R;   /* G1R's 2^25 doubles are dead now; 32768 pages saved */
  eo_inv_col();
  eo_carry();
  /* ---- emit (as the original) ---- */
  u32 *D = D32;
#define DIDX(j) ((((size_t)(j))>>13)*(size_t)C4P + (((size_t)(j))&(size_t)(C4-1)))
  size_t ng = EO_NG6;
  size_t outcap = 1u << 22;
  char *_ob = (char *)malloc(outcap + 1024); char *out = _ob + 1024;
  size_t opos = 0;
  size_t jstart = ng;
  while (jstart > 0 && D[DIDX(jstart - 1)] == 0) jstart--;
  if (jstart == 0) {
    out[opos++] = '0';
  } else {
    u32 d = D[DIDX(jstart - 1)];
    char tmp[8]; int n = 0;
    for (int t = 0; t < 6; t++) { tmp[n++] = (char)('0' + d % 10); d /= 10; }
    int s6 = 6; while (s6 > 1 && tmp[s6 - 1] == '0') s6--;
    for (int t = s6 - 1; t >= 0; t--) out[opos++] = tmp[t];
    {
      size_t _kn = jstart - 1;
      while (_kn >= 8) {
#define E8EM(I) do { u32 v = D[DIDX(I)]; put3(out+opos, v/1000); put3(out+opos+3, v%1000); opos += 6; } while(0)
        E8EM(_kn-1); E8EM(_kn-2); E8EM(_kn-3); E8EM(_kn-4);
        E8EM(_kn-5); E8EM(_kn-6); E8EM(_kn-7); E8EM(_kn-8);
#undef E8EM
        _kn -= 8;
        if (opos + 88 > outcap) { fwrite(out, 1, opos, stdout); opos = 0; }
      }
      for (size_t j = _kn; j-- > 0;) {
        u32 v = D[DIDX(j)];
        put3(out + opos, v / 1000); put3(out + opos + 3, v % 1000); opos += 6;
        if (opos + 32 > outcap) { fwrite(out, 1, opos, stdout); opos = 0; }
      }
    }
  }
  out[opos++] = '\n';
  fwrite(out, 1, opos, stdout);
  fflush(stdout);
  free(_ob);
  return 0;
}

CompilationN/AN/ACompile OKScore: N/A

Testcase #1994.53 ms1223 MB + 1004 KBAcceptedScore: 100


Judge Duck Online | 评测鸭在线
Server Time: 2026-10-17 14:54:26 | Loaded in 8 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠