48 using Field =
typename FieldExt::BaseField;
50 using CElt =
typename FieldExt::Elt;
55 static void validate_root(
const CElt& omega,
const FieldExt& C) {
56 check(C.mulf(omega, C.conjf(omega)) == C.one(),
57 "root of unity not on the unit circle");
60 static void r2hcI(RElt* A,
size_t s,
const Field& R) {
66 static void r2hcII(RElt* A,
size_t s,
const CElt& tw,
const Field& R) {
67 R.mul(A[s], R.negf(tw.im));
70 static void hc2hcf(RElt* Ar, RElt* Ai,
size_t s,
const CElt& tw,
73 cmulj(&xr, &xi, Ar[s], Ai[s], tw.re, tw.im, R);
76 Ar[0] = R.addf(ar0, xr);
77 Ai[0] = R.subf(ar0, xr);
78 Ar[s] = R.subf(xi, ai0);
79 Ai[s] = R.addf(xi, ai0);
82 static void hc2rI(RElt* A,
size_t s,
const Field& R) {
89 static void hc2rIII(RElt* A,
size_t s,
const CElt& tw,
const Field& R) {
92 R.mul(A[s], R.negf(tw.im));
95 static void hc2hcb(RElt* Ar, RElt* Ai,
size_t s,
const CElt& tw,
101 Ar[0] = R.addf(ar0, ai0);
102 Ai[0] = R.subf(ai1, ar1);
103 RElt xr = R.subf(ar0, ai0);
104 RElt xi = R.addf(ai1, ar1);
105 cmul(&Ar[s], &Ai[s], xr, xi, tw.re, tw.im, R);
111 static void r2hc(RElt A[],
size_t n,
const CElt& omega,
112 uint64_t omega_order,
const FieldExt& C) {
113 validate_root(omega, C);
119 const Field& R = C.base_field();
120 CElt omega_n = Twiddle<FieldExt>::reroot(omega, omega_order, n, C);
123 Permutations<RElt>::bitrev(A, n);
126 for (
size_t k = 0; k < n; k += 2) {
131 for (
size_t m = 2; m < n; m = 2 * m) {
132 size_t ws = n / (2 * m);
133 for (
size_t k = 0; k < n; k += 2 * m) {
137 for (j = 1; j + j < m; ++j) {
138 hc2hcf(&A[k + j], &A[k + m - j], m, roots.w_[j * ws], R);
141 r2hcII(&A[k + j], m, roots.w_[j * ws], R);
147 static void hc2r(RElt A[],
size_t n,
const CElt& omega,
148 uint64_t omega_order,
const FieldExt& C) {
149 validate_root(omega, C);
155 const Field& R = C.base_field();
156 CElt omega_n = Twiddle<FieldExt>::reroot(omega, omega_order, n, C);
160 for (
size_t m = n; (m /= 2) >= 2;) {
161 size_t ws = n / (2 * m);
162 for (
size_t k = 0; k < n; k += 2 * m) {
166 for (j = 1; j + j < m; ++j) {
167 hc2hcb(&A[k + j], &A[k + m - j], m, roots.w_[j * ws], R);
170 hc2rIII(&A[k + j], m, roots.w_[j * ws], R);
175 for (
size_t k = 0; k < n; k += 2) {
179 Permutations<RElt>::bitrev(A, n);
183 static void cmul(RElt* xr, RElt* xi,
const RElt& ar,
const RElt& ai,
184 const RElt& br,
const RElt& bi,
const Field& R) {
186 auto p0 = R.mulf(ar, br);
187 auto p1 = R.mulf(ai, bi);
188 auto a01 = R.addf(ar, ai);
189 auto b01 = R.addf(br, bi);
190 *xr = R.subf(p0, p1);
198 static void cmulj(RElt* xr, RElt* xi,
const RElt& ar,
const RElt& ai,
199 const RElt& br,
const RElt& bi,
const Field& R) {
201 auto p0 = R.mulf(ar, br);
202 auto p1 = R.mulf(ai, bi);
203 auto a01 = R.addf(ar, ai);
204 auto b01 = R.subf(br, bi);
205 *xr = R.addf(p0, p1);