File indexing completed on 2026-11-07 10:15:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef FFT_SMALL_H
0013 #define FFT_SMALL_H
0014
0015 #include "longlong.h"
0016 #include "machine_vectors.h"
0017
0018 #if FLINT_USES_PTHREAD
0019 # include <pthread.h>
0020 # include <stdatomic.h>
0021 #endif
0022
0023 #define LG_BLK_SZ 8
0024 #define BLK_SZ 256
0025
0026 #ifdef __cplusplus
0027 extern "C" {
0028 #endif
0029
0030
0031
0032 int fft_small_mulmod_satisfies_bounds(ulong n);
0033
0034 FLINT_FORCE_INLINE ulong n_pow2(int k)
0035 {
0036 return UWORD(1) << k;
0037 }
0038
0039 FLINT_FORCE_INLINE ulong n_min(ulong a, ulong b)
0040 {
0041 return FLINT_MIN(a, b);
0042 }
0043
0044 FLINT_FORCE_INLINE ulong n_max(ulong a, ulong b)
0045 {
0046 return FLINT_MAX(a, b);
0047 }
0048
0049 FLINT_FORCE_INLINE ulong n_cdiv(ulong a, ulong b)
0050 {
0051
0052 return (a + b - 1)/b;
0053 }
0054
0055 FLINT_FORCE_INLINE ulong n_round_up(ulong a, ulong b)
0056 {
0057 return n_cdiv(a, b)*b;
0058 }
0059
0060 FLINT_FORCE_INLINE ulong n_round_down(ulong a, ulong b)
0061 {
0062 return a/b*b;
0063 }
0064
0065
0066 FLINT_FORCE_INLINE ulong n_next_pow2m1(ulong a)
0067 {
0068 a |= a >> 1;
0069 a |= a >> 2;
0070 a |= a >> 4;
0071 a |= a >> 8;
0072 a |= a >> 16;
0073 #if FLINT64
0074 a |= a >> 32;
0075 #endif
0076 return a;
0077 }
0078
0079 FLINT_FORCE_INLINE ulong n_leading_zeros(ulong x) {
0080 return x == 0 ? FLINT_BITS : flint_clz(x);
0081 }
0082
0083 FLINT_FORCE_INLINE ulong n_trailing_zeros(ulong x) {
0084 return x == 0 ? FLINT_BITS : flint_ctz(x);
0085 }
0086
0087 FLINT_FORCE_INLINE ulong n_nbits(ulong x) {
0088 return FLINT_BIT_COUNT(x);
0089 }
0090
0091 FLINT_FORCE_INLINE ulong n_nbits_nz(ulong x) {
0092 FLINT_ASSERT(x != 0);
0093 return (flint_clz(x)^(FLINT_BITS-1)) + 1;
0094 }
0095
0096 FLINT_FORCE_INLINE ulong n_clog2(ulong x) {
0097 return (x <= 2) ? (x == 2) : FLINT_BITS - flint_clz(x - 1);
0098 }
0099
0100 FLINT_FORCE_INLINE ulong n_flog2(ulong x) {
0101 return (x <= 2) ? (x == 2) : FLINT_BITS - flint_clz(x);
0102 }
0103
0104 FLINT_FORCE_INLINE slong z_min(slong a, slong b) {return FLINT_MIN(a, b);}
0105
0106 FLINT_FORCE_INLINE slong z_max(slong a, slong b) {return FLINT_MAX(a, b);}
0107
0108 int fft_small_mulmod_satisfies_bounds(ulong n);
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154 #define SET_J_BITS_AND_J_R(j_bits, j_r, j) \
0155 do { \
0156 if (j == 0) \
0157 { \
0158 j_bits = 0; \
0159 j_r = 0; \
0160 } \
0161 else \
0162 { \
0163 j_bits = n_nbits_nz(j); \
0164 j_r = j - n_pow2(j_bits - 1); \
0165 } \
0166 } while (0)
0167
0168
0169 #define SET_J_BITS_AND_J_MR(j_bits, j_mr, j) \
0170 do { \
0171 if (j == 0) \
0172 { \
0173 j_bits = 0; \
0174 j_mr = 0; \
0175 } \
0176 else \
0177 { \
0178 j_bits = n_nbits_nz(j); \
0179 j_mr = n_pow2(j_bits) - 1 - j; \
0180 } \
0181 } while (0)
0182
0183
0184 #define SD_FFT_CTX_W2TAB_INIT 12
0185 #define SD_FFT_CTX_W2TAB_SIZE 40
0186
0187
0188
0189
0190
0191
0192 typedef struct {
0193 double p;
0194 double pinv;
0195 nmod_t mod;
0196 ulong primitive_2power_root;
0197 #if FLINT_USES_PTHREAD
0198 _Atomic(unsigned int) w2tab_depth;
0199 #else
0200 unsigned int w2tab_depth;
0201 #endif
0202 double* w2tab[SD_FFT_CTX_W2TAB_SIZE];
0203
0204
0205 #if FLINT_USES_PTHREAD
0206 pthread_mutex_t mutex;
0207 #endif
0208 } sd_fft_ctx_struct;
0209
0210 typedef sd_fft_ctx_struct sd_fft_ctx_t[1];
0211
0212 FLINT_FORCE_INLINE ulong sd_fft_ctx_blk_offset(ulong I)
0213 {
0214 return I << LG_BLK_SZ;
0215 }
0216
0217 FLINT_FORCE_INLINE ulong sd_fft_ctx_data_size(ulong L)
0218 {
0219 return n_pow2(L);
0220 }
0221
0222
0223 FLINT_FORCE_INLINE double* sd_fft_ctx_blk_index(double* d, ulong I)
0224 {
0225 return d + sd_fft_ctx_blk_offset(I);
0226 }
0227
0228
0229
0230
0231
0232
0233 FLINT_FORCE_INLINE ulong sd_fft_ctx_trunc_index(ulong L, ulong i)
0234 {
0235
0236 if (L >= 4)
0237 i = (i&(-16)) | ((i>>2)&3) | ((i&3)<<2);
0238 return i;
0239 }
0240
0241
0242 void sd_fft_trunc(sd_fft_ctx_t Q, double* d, ulong L, ulong itrunc, ulong otrunc);
0243
0244
0245 void sd_ifft_trunc(sd_fft_ctx_t Q, double* d, ulong L, ulong trunc);
0246
0247
0248 void sd_fft_ctx_clear(sd_fft_ctx_t Q);
0249 void sd_fft_ctx_init_prime(sd_fft_ctx_t Q, ulong pp);
0250 void sd_fft_ctx_fit_depth_with_lock(sd_fft_ctx_t Q, ulong k);
0251
0252 FLINT_FORCE_INLINE void sd_fft_ctx_fit_depth(sd_fft_ctx_t Q, ulong depth)
0253 {
0254 #if FLINT_USES_PTHREAD
0255 ulong tdepth = (ulong)atomic_load_explicit(&Q->w2tab_depth, memory_order_relaxed);
0256 #else
0257 ulong tdepth = (ulong)Q->w2tab_depth;
0258 #endif
0259 if (FLINT_UNLIKELY(tdepth < depth))
0260 sd_fft_ctx_fit_depth_with_lock(Q, depth);
0261 }
0262
0263 void sd_fft_ctx_point_mul(const sd_fft_ctx_t Q,
0264 double* a, const double* b, ulong m_, ulong depth);
0265 void sd_fft_ctx_point_sqr(const sd_fft_ctx_t Q,
0266 double* a, ulong m_, ulong depth);
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278 FLINT_FORCE_INLINE double sd_fft_ctx_w2(const sd_fft_ctx_t Q, ulong j)
0279 {
0280 ulong j_bits, j_r;
0281 SET_J_BITS_AND_J_R(j_bits, j_r, j);
0282 return Q->w2tab[j_bits][j_r];
0283 }
0284
0285
0286 FLINT_FORCE_INLINE double sd_fft_ctx_w2inv(const sd_fft_ctx_t Q, ulong j)
0287 {
0288 ulong j_bits, j_mr;
0289 SET_J_BITS_AND_J_MR(j_bits, j_mr, j);
0290 return (j == 0) ? -1.0 : Q->w2tab[j_bits][j_mr];
0291 }
0292
0293
0294 FLINT_FORCE_INLINE double sd_fft_ctx_w(const sd_fft_ctx_t Q, ulong j)
0295 {
0296 double r = sd_fft_ctx_w2(Q, j/2);
0297 return (j&1) ? -r : r;
0298 }
0299
0300 typedef struct {
0301 ulong prime;
0302 ulong coeff_len;
0303 ulong nprimes;
0304 ulong* data;
0305 } crt_data_struct;
0306
0307 typedef crt_data_struct crt_data_t[1];
0308
0309 void crt_data_init(crt_data_t C, ulong prime, ulong coeff_len, ulong nprimes);
0310
0311 void crt_data_clear(crt_data_t C);
0312
0313
0314 FLINT_FORCE_INLINE ulong* crt_data_co_prime(const crt_data_t C, ulong i)
0315 {
0316 FLINT_ASSERT(i < C->nprimes);
0317 return C->data + i*C->coeff_len;
0318 }
0319
0320 FLINT_FORCE_INLINE ulong* _crt_data_co_prime(const crt_data_t C, ulong i, ulong n)
0321 {
0322 FLINT_ASSERT(i < C->nprimes);
0323 FLINT_ASSERT(n == C->coeff_len);
0324 return C->data + i*n;
0325 }
0326
0327
0328 FLINT_FORCE_INLINE ulong* crt_data_prod_primes(const crt_data_t C)
0329 {
0330 return C->data + C->nprimes*C->coeff_len;
0331 }
0332
0333
0334 FLINT_FORCE_INLINE ulong* crt_data_co_prime_red(const crt_data_t C, ulong i)
0335 {
0336 FLINT_ASSERT(i < C->nprimes);
0337 return C->data + C->nprimes*C->coeff_len + C->coeff_len + i;
0338 }
0339
0340
0341 typedef void (*to_ffts_func)(
0342 sd_fft_ctx_struct* Qffts, double* d, ulong dstride,
0343 const ulong* a_, ulong an_, ulong atrunc,
0344 const vec4d* two_pow,
0345 ulong start_easy, ulong stop_easy,
0346 ulong start_hard, ulong stop_hard);
0347
0348 typedef struct {
0349 ulong np;
0350 ulong bits;
0351 ulong bn_bound;
0352 to_ffts_func to_ffts;
0353 } profile_entry_struct;
0354
0355 typedef profile_entry_struct profile_entry_t[1];
0356
0357 #define MPN_CTX_NCRTS 8
0358 #define MAX_NPROFILES 20
0359 #define VEC_SZ 4
0360
0361
0362
0363
0364
0365
0366 #define MPN_CTX_TWO_POWER_TAB_SIZE 256
0367
0368 typedef struct {
0369 sd_fft_ctx_struct ffts[MPN_CTX_NCRTS];
0370 crt_data_struct crts[MPN_CTX_NCRTS];
0371
0372
0373
0374
0375
0376 vec4d* vec_two_pow_tab[(MPN_CTX_NCRTS + VEC_SZ - 1)/VEC_SZ];
0377 vec4d* vec_two_pow_buffer;
0378 double* slow_two_pow_tab[MPN_CTX_NCRTS];
0379 double* slow_two_pow_buffer;
0380
0381 profile_entry_struct profiles[MAX_NPROFILES];
0382 ulong profiles_size;
0383 void* buffer;
0384 ulong buffer_alloc;
0385 } mpn_ctx_struct;
0386
0387 typedef mpn_ctx_struct mpn_ctx_t[1];
0388
0389 void _convert_block(ulong* Xs, sd_fft_ctx_struct* Rffts, double* d, ulong dstride, ulong np, ulong Iv);
0390 void _convert_block_1_mod(ulong* Xs, sd_fft_ctx_struct* Rffts, double* d, ulong dstride, ulong I, double p2, double p2inv);
0391 ulong flint_mpn_nbits(const ulong* a, ulong an);
0392 int flint_mpn_cmp_ui_2exp(const ulong* a, ulong an, ulong b, ulong e);
0393 unsigned char flint_mpn_add_inplace_c(ulong* z, ulong zn, ulong* a, ulong an, unsigned char cf);
0394
0395
0396 void mpn_ctx_init(mpn_ctx_t R, ulong p);
0397 void mpn_ctx_clear(mpn_ctx_t R);
0398 void* mpn_ctx_fit_buffer(mpn_ctx_t R, ulong n);
0399 void mpn_ctx_mpn_mul(mpn_ctx_t R, ulong* z, const ulong* a, ulong an, const ulong* b, ulong bn);
0400
0401 void _nmod_poly_mul_mid_mpn_ctx(
0402 ulong* z, ulong zl, ulong zh,
0403 const ulong* a, ulong an,
0404 const ulong* b, ulong bn,
0405 nmod_t mod,
0406 mpn_ctx_t R);
0407
0408 void _nmod_poly_divrem_mpn_ctx(
0409 ulong* q,
0410 ulong* r,
0411 const ulong* a, ulong an,
0412 const ulong* b, ulong bn,
0413 nmod_t mod,
0414 mpn_ctx_t R);
0415
0416 void _nmod_poly_mul_mid_classical(
0417 ulong* z, slong zl, slong zh,
0418 const ulong* a, slong an,
0419 const ulong* b, slong bn,
0420 nmod_t mod);
0421
0422 void _nmod_poly_mul_mid(
0423 ulong* z, slong zl, slong zh,
0424 const ulong* a, slong an,
0425 const ulong* b, slong bn,
0426 nmod_t mod);
0427
0428 typedef struct {
0429 ulong depth;
0430 ulong N;
0431 ulong offset;
0432 ulong np;
0433 ulong stride;
0434 ulong bn;
0435 ulong btrunc;
0436 double* bbuf;
0437 } mul_precomp_struct;
0438
0439 void _mul_precomp_init(
0440 mul_precomp_struct* M,
0441 const ulong * b, ulong bn, ulong btrunc,
0442 ulong depth,
0443 nmod_t mod,
0444 mpn_ctx_t R);
0445
0446 FLINT_FORCE_INLINE void _mul_precomp_clear(mul_precomp_struct* M)
0447 {
0448 flint_aligned_free(M->bbuf);
0449 }
0450
0451 int _nmod_poly_mul_mid_precomp(
0452 ulong* z, ulong zl, ulong zh,
0453 const ulong* a, ulong an,
0454 mul_precomp_struct* M,
0455 nmod_t mod,
0456 mpn_ctx_t R);
0457
0458 typedef struct {
0459 mul_precomp_struct quo_maker[1];
0460 mul_precomp_struct rem_maker[1];
0461 } nmod_poly_divrem_precomp_struct;
0462
0463 FLINT_FORCE_INLINE void _nmod_poly_divrem_precomp_clear(nmod_poly_divrem_precomp_struct* M)
0464 {
0465 _mul_precomp_clear(M->quo_maker);
0466 _mul_precomp_clear(M->rem_maker);
0467 }
0468
0469 void _nmod_poly_divrem_precomp_init(
0470 nmod_poly_divrem_precomp_struct* M,
0471 const ulong* b, ulong bn,
0472 ulong Bn,
0473 nmod_t mod,
0474 mpn_ctx_t R);
0475
0476
0477 int _nmod_poly_divrem_precomp(
0478 ulong* q,
0479 ulong* r,
0480 const ulong* a, ulong an,
0481 nmod_poly_divrem_precomp_struct* M,
0482 nmod_t mod,
0483 mpn_ctx_t R);
0484
0485 mpn_ctx_struct * get_default_mpn_ctx(void);
0486
0487 void mpn_mul_default_mpn_ctx(nn_ptr r1, nn_srcptr i1, slong n1, nn_srcptr i2, slong n2);
0488 void _nmod_poly_mul_mid_default_mpn_ctx(nn_ptr res, slong zl, slong zh, nn_srcptr a, slong an, nn_srcptr b, slong bn, nmod_t mod);
0489
0490
0491 int _fmpz_poly_mul_mid_mpn_ctx(
0492 fmpz * z, ulong zl, ulong zh,
0493 const fmpz * a, ulong an,
0494 const fmpz * b, ulong bn,
0495 mpn_ctx_t R);
0496
0497 int _fmpz_poly_mul_mid_default_mpn_ctx(
0498 fmpz * z, slong zl, slong zh,
0499 const fmpz * a, slong an,
0500 const fmpz * b, slong bn);
0501
0502 #ifdef __cplusplus
0503 }
0504 #endif
0505
0506 #endif