poulpy/spqlios/lib/spqlios/reim/reim_to_tnx_ref.c
spqlios/lib/spqlios/reim/reim_to_tnx_ref.cRaw
1#include <errno.h>
2#include <string.h>
3
4#include "../commons_private.h"
5#include "reim_fft_internal.h"
6#include "reim_fft_private.h"
7
8EXPORT void reim_to_tnx_basic_ref(const REIM_TO_TNX_PRECOMP* tables, double* r, const double* x) {
9 const uint64_t n = tables->m << 1;
10 double divisor = tables->divisor;
11 for (uint64_t i=0; i<n; ++i) {
12 double ri = x[i]/divisor;
13 r[i] = ri - rint(ri);
14 }
15}
16
17typedef union {double d; uint64_t u;} dblui64_t;
18
19EXPORT void reim_to_tnx_ref(const REIM_TO_TNX_PRECOMP* tables, double* r, const double* x) {
20 const uint64_t n = tables->m << 1;
21 double add_cst = tables->add_cst;
22 uint64_t mask_and = tables->mask_and;
23 uint64_t mask_or = tables->mask_or;
24 double sub_cst = tables->sub_cst;
25 dblui64_t cur;
26 for (uint64_t i=0; i<n; ++i) {
27 cur.d = x[i] + add_cst;
28 cur.u &= mask_and;
29 cur.u |= mask_or;
30 r[i] = cur.d - sub_cst;
31 }
32}
33
34void* init_reim_to_tnx_precomp(REIM_TO_TNX_PRECOMP* const res, uint32_t m, double divisor, uint32_t log2overhead) {
35 if (m & (m - 1)) return spqlios_error("m must be a power of 2");
36 if (is_not_pow2_double(&divisor)) return spqlios_error("divisor must be a power of 2");
37 if (log2overhead > 52) return spqlios_error("log2overhead is too large");
38 res->m = m;
39 res->divisor = divisor;
40 res->log2overhead = log2overhead;
41 // 52 + 11 + 1
42 // ......1.......01(1)|expo|sign
43 // .......=========(1)|expo|sign msbbits = log2ovh + 2 + 11 + 1
44 uint64_t nbits = 50 - log2overhead;
45 dblui64_t ovh_cst;
46 ovh_cst.d = 0.5 + (6<<log2overhead);
47 res->add_cst = ovh_cst.d * divisor;
48 res->mask_and = ((UINT64_C(1) << nbits) - 1);
49 res->mask_or = ovh_cst.u & ((UINT64_C(-1)) << nbits);
50 res->sub_cst = ovh_cst.d;
51 // TODO: check selection logic
52 if (CPU_SUPPORTS("avx2")) {
53 if (m >= 8) {
54 res->function = reim_to_tnx_avx;
55 } else {
56 res->function = reim_to_tnx_ref;
57 }
58 } else {
59 res->function = reim_to_tnx_ref;
60 }
61 return res;
62}
63
64EXPORT REIM_TO_TNX_PRECOMP* new_reim_to_tnx_precomp(uint32_t m, double divisor, uint32_t log2overhead) {
65 REIM_TO_TNX_PRECOMP* res = malloc(sizeof(*res));
66 if (!res) return spqlios_error(strerror(errno));
67 return spqlios_keep_or_free(res, init_reim_to_tnx_precomp(res, m, divisor, log2overhead));
68}
69
70EXPORT void reim_to_tnx(const REIM_TO_TNX_PRECOMP* tables, double* r, const double* x) {
71 tables->function(tables, r, x);
72}