arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/reim/reim_to_tnx_ref.c
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/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 {
18  double d;
19  uint64_t u;
20} dblui64_t;
21
22EXPORT void reim_to_tnx_ref(const REIM_TO_TNX_PRECOMP* tables, double* r, const double* x) {
23  const uint64_t n = tables->m << 1;
24  double add_cst = tables->add_cst;
25  uint64_t mask_and = tables->mask_and;
26  uint64_t mask_or = tables->mask_or;
27  double sub_cst = tables->sub_cst;
28  dblui64_t cur;
29  for (uint64_t i = 0; i < n; ++i) {
30    cur.d = x[i] + add_cst;
31    cur.u &= mask_and;
32    cur.u |= mask_or;
33    r[i] = cur.d - sub_cst;
34  }
35}
36
37void* init_reim_to_tnx_precomp(REIM_TO_TNX_PRECOMP* const res, uint32_t m, double divisor, uint32_t log2overhead) {
38  if (m & (m - 1)) return spqlios_error("m must be a power of 2");
39  if (is_not_pow2_double(&divisor)) return spqlios_error("divisor must be a power of 2");
40  if (log2overhead > 52) return spqlios_error("log2overhead is too large");
41  res->m = m;
42  res->divisor = divisor;
43  res->log2overhead = log2overhead;
44  //                 52 + 11 + 1
45  // ......1.......01(1)|expo|sign
46  // .......=========(1)|expo|sign  msbbits = log2ovh + 2 + 11 + 1
47  uint64_t nbits = 50 - log2overhead;
48  dblui64_t ovh_cst;
49  ovh_cst.d = 0.5 + (6 << log2overhead);
50  res->add_cst = ovh_cst.d * divisor;
51  res->mask_and = ((UINT64_C(1) << nbits) - 1);
52  res->mask_or = ovh_cst.u & ((UINT64_C(-1)) << nbits);
53  res->sub_cst = ovh_cst.d;
54  // TODO: check selection logic
55  if (CPU_SUPPORTS("avx2")) {
56    if (m >= 8) {
57      res->function = reim_to_tnx_avx;
58    } else {
59      res->function = reim_to_tnx_ref;
60    }
61  } else {
62    res->function = reim_to_tnx_ref;
63  }
64  return res;
65}
66
67EXPORT REIM_TO_TNX_PRECOMP* new_reim_to_tnx_precomp(uint32_t m, double divisor, uint32_t log2overhead) {
68  REIM_TO_TNX_PRECOMP* res = malloc(sizeof(*res));
69  if (!res) return spqlios_error(strerror(errno));
70  return spqlios_keep_or_free(res, init_reim_to_tnx_precomp(res, m, divisor, log2overhead));
71}
72
73EXPORT void reim_to_tnx(const REIM_TO_TNX_PRECOMP* tables, double* r, const double* x) {
74  tables->function(tables, r, x);
75}