poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/arithmetic/vec_rnx_approxdecomp_ref.c
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/arithmetic/vec_rnx_approxdecomp_ref.cRaw
1#include <memory.h>
2
3#include "vec_rnx_arithmetic_private.h"
4
5typedef union di {
6 double dv;
7 uint64_t uv;
8} di_t;
9
10/** @brief new gadget: delete with delete_tnxdbl_approxdecomp_gadget */
11EXPORT TNXDBL_APPROXDECOMP_GADGET* new_tnxdbl_approxdecomp_gadget( //
12 const MOD_RNX* module, // N
13 uint64_t k, uint64_t ell // base 2^K and size
14) {
15 if (k * ell > 50) return spqlios_error("gadget requires a too large fp precision");
16 TNXDBL_APPROXDECOMP_GADGET* res = spqlios_alloc(sizeof(TNXDBL_APPROXDECOMP_GADGET));
17 res->k = k;
18 res->ell = ell;
19 // double add_cst; // double(3.2^(51-ell.K) + 1/2.(sum 2^(-iK)) for i=[0,ell[)
20 union di add_cst;
21 add_cst.dv = UINT64_C(3) << (51 - ell * k);
22 for (uint64_t i = 0; i < ell; ++i) {
23 add_cst.uv |= UINT64_C(1) << ((i + 1) * k - 1);
24 }
25 res->add_cst = add_cst.dv;
26 // uint64_t and_mask; // uint64(2^(K)-1)
27 res->and_mask = (UINT64_C(1) << k) - 1;
28 // uint64_t or_mask; // double(2^52)
29 union di or_mask;
30 or_mask.dv = (UINT64_C(1) << 52);
31 res->or_mask = or_mask.uv;
32 // double sub_cst; // double(2^52 + 2^(K-1))
33 res->sub_cst = ((UINT64_C(1) << 52) + (UINT64_C(1) << (k - 1)));
34 return res;
35}
36
37EXPORT void delete_tnxdbl_approxdecomp_gadget(TNXDBL_APPROXDECOMP_GADGET* gadget) { spqlios_free(gadget); }
38
39/** @brief sets res = gadget_decompose(a) */
40EXPORT void rnx_approxdecomp_from_tnxdbl_ref( //
41 const MOD_RNX* module, // N
42 const TNXDBL_APPROXDECOMP_GADGET* gadget, // output base 2^K
43 double* res, uint64_t res_size, uint64_t res_sl, // res
44 const double* a // a
45) {
46 const uint64_t nn = module->n;
47 const uint64_t k = gadget->k;
48 const uint64_t ell = gadget->ell;
49 const double add_cst = gadget->add_cst;
50 const uint64_t and_mask = gadget->and_mask;
51 const uint64_t or_mask = gadget->or_mask;
52 const double sub_cst = gadget->sub_cst;
53 const uint64_t msize = res_size <= ell ? res_size : ell;
54 const uint64_t first_rsh = (ell - msize) * k;
55 // gadget decompose column by column
56 if (msize > 0) {
57 double* const last_r = res + (msize - 1) * res_sl;
58 for (uint64_t j = 0; j < nn; ++j) {
59 double* rr = last_r + j;
60 di_t t = {.dv = a[j] + add_cst};
61 if (msize < ell) t.uv >>= first_rsh;
62 do {
63 di_t u;
64 u.uv = (t.uv & and_mask) | or_mask;
65 *rr = u.dv - sub_cst;
66 t.uv >>= k;
67 rr -= res_sl;
68 } while (rr >= res);
69 }
70 }
71 // zero-out the last slices (if any)
72 for (uint64_t i = msize; i < res_size; ++i) {
73 memset(res + i * res_sl, 0, nn * sizeof(double));
74 }
75}