LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
binvert_1.c
浏览该文件的文档.
1/**
2 * Copyright (C) 2026 HJimmyK(Jericho Knox)
3 *
4 * This file is part of LAMMP.
5 *
6 * LAMMP is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License (LGPL) as published
8 * by the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed WITHOUT ANY WARRANTY.
12 *
13 * See <https://www.gnu.org/licenses/>.
14 */
15
16#include "../../../include/lammp/numth.h"
17#include "../../../include/lammp/lmmpn.h"
18#include "../../../include/lammp/impl/longlong.h"
19
20/* from https://arxiv.org/abs/2204.04342 */
21
22static const uchar binv_tab[128] = {
23 1, 171, 205, 183, 57, 163, 197, 239, 241, 27, 61, 167, 41, 19, 53, 223, 225, 139, 173, 151, 25, 131,
24 165, 207, 209, 251, 29, 135, 9, 243, 21, 191, 193, 107, 141, 119, 249, 99, 133, 175, 177, 219, 253, 103,
25 233, 211, 245, 159, 161, 75, 109, 87, 217, 67, 101, 143, 145, 187, 221, 71, 201, 179, 213, 127, 129, 43,
26 77, 55, 185, 35, 69, 111, 113, 155, 189, 39, 169, 147, 181, 95, 97, 11, 45, 23, 153, 3, 37, 79,
27 81, 123, 157, 7, 137, 115, 149, 63, 65, 235, 13, 247, 121, 227, 5, 47, 49, 91, 125, 231, 105, 83,
28 117, 31, 33, 203, 237, 215, 89, 195, 229, 15, 17, 59, 93, 199, 73, 51, 85, 255};
29
31 lmmp_param_assert(a % 2 == 1);
32 uint r, y;
33
34 r = binv_tab[(a / 2) & 0x7F]; /* 8 bits */
35 y = 1 - a * r;
36 r = r * (1 + y); /* 16 bits */
37 y *= y;
38 r = r * (1 + y); /* 32 bits */
39 return r;
40}
41
43 lmmp_param_assert(a % 2 == 1);
44 ulong r, y;
45
46 r = binv_tab[(a / 2) & 0x7F]; /* 8 bits */
47 y = 1 - a * r;
48 r = r * (1 + y); /* 16 bits */
49 y *= y;
50 r = r * (1 + y); /* 32 bits */
51 y *= y;
52 r = r * (1 + y); /* 64 bits */
53 return r;
54}
55
57 lmmp_param_assert(numa[0] % 2 == 1);
58 mp_limb_t k, t;
59 mp_limb_t a1 = numa[1];
60 mp_limb_t a0 = numa[0];
63 /*
64 xn * a0 == 1 + k * B
65 yn := xn * (2 - a * xn) mod B^2
66 := xn * (2 - a0 * xn - a1 * xn * B) mod B^2
67 := xn * (2 - 1 - k*B - a1 * xn * B) mod B^2
68 := xn * (1 - k*B - a1 * xn * B) mod B^2
69 := (xn - xn*k * B - a1 * xn^2 * B) mod B^2
70 */
71 _umul64to128_(a0, xn, &t, &k);
72 z = xn * k;
73 z += a1 * xn * xn;
74 dst[0] = xn;
75 dst[1] = -z;
76}
77
78static inline void _umul128to192_(uint64_t a_high, uint64_t a_low, uint64_t b_high, uint64_t b_low, uint64_t rr[3]) {
79 uint64_t p1_low, p1_high; // p1 = a_low × b_high
80 uint64_t p2_low, p2_high; // p2 = a_high × b_low
84 /*
85 | res0 | res1 | res2 |
86 | p0l | p0h | |
87 | p1l | p1h |
88 | p2l | p2h |
89 | | p3l |
90 */
91 rr[1] += p1_low;
92 uint64_t carry = (rr[1] < p1_low) ? 1 : 0;
93 rr[1] += p2_low;
94 carry += (rr[1] < p2_low) ? 1 : 0;
95
96 rr[2] = a_high * b_high;
97 rr[2] += carry;
98 rr[2] += p1_high;
99 rr[2] += p2_high;
100}
101
103 /*
104 a == a0 + a1 * B^2
105 xn * a0 == 1 + k * B^2
106 yn := xn * (2 - a * xn) mod B^4
107 := xn * (2 - a0 * xn - a1 * xn * B^2) mod B^4
108 := xn * (2 - 1 - k*B^2 - a1 * xn * B^2) mod B^4
109 := xn * (1 - k*B^2 - a1 * xn * B^2) mod B^4
110 := (xn - xn*k * B^2 - a1 * xn^2 * B^2) mod B^4
111 */
113 mp_limb_t k[3];
114 mp_limb_t z;
115 mp_limb_t a2 = numa[2];
116 _umul128to192_(dst[1], dst[0], numa[1], numa[0], k);
117 lmmp_debug_assert(k[1] == 0 && k[0] == 1);
118#define xn (dst[0])
119#define k (k[2])
120 z = xn * k;
121 z += a2 * xn * xn;
122 dst[2] = -z;
123#undef xn
124#undef k
125}
126
128 /*
129 a == a0 + a1 * B^2
130 xn * a0 == 1 + k * B^2
131 yn := xn * (2 - a * xn) mod B^4
132 := xn * (2 - a0 * xn - a1 * xn * B^2) mod B^4
133 := xn * (2 - 1 - k*B^2 - a1 * xn * B^2) mod B^4
134 := xn * (1 - k*B^2 - a1 * xn * B^2) mod B^4
135 := (xn - xn*k * B^2 - a1 * xn^2 * B^2) mod B^4
136 */
138 mp_limb_t k[4];
139 mp_limb_t z[2];
140 mp_limb_t t[2];
141 _umul128to256_(dst[1], dst[0], numa[1], numa[0], k);
142 lmmp_debug_assert(k[1] == 0 && k[0] == 1);
143
144#define xn (dst)
145#define k (k + 2)
146 _umul128to128_(k[1], k[0], xn[1], xn[0], z);
147
148 _umul64to128_(xn[0], xn[0], t, t + 1);
149 t[1] += (xn[1] * xn[0]) << 1;
150 _umul128to128_(t[1], t[0], numa[3], numa[2], t);
151
152 _u128add(z, z, t);
153 dst[2] = 0;
154 dst[3] = 0;
155 _u128sub(dst + 2, dst + 2, z);
156
157#undef xn
158#undef k
159}
160
161/*
162unbalanced:
163 a := [numa,na]
164 a^-1 = a^-1 mod B^na
165
166 p = -k * a^-1 mod B^na
167 k = (k + a*p) / B^na
168*/
169
172 lmmp_param_assert(a % 2 == 1);
173 lmmp_param_assert(n > 1);
175 dst[0] = a_binvert;
176 mp_size_t i = 0;
177 ulong k, p, lo, hi, carry;
180 for (; i < n - 2; i++) {
181 p = a_binvert * k;
182 dst[i + 1] = p;
183 _umul64to128_(p, a, &lo, &hi);
184 carry = (k + lo) < lo ? 1 : 0;
185 k = hi + carry;
186 }
187 p = a_binvert * k;
188 dst[n - 1] = p;
189}
190
193 lmmp_param_assert(numa[0] % 2 == 1);
194 lmmp_param_assert(n > 2);
197 dst[0] = a_binvert[0];
198 dst[1] = a_binvert[1];
199
201 mp_limb_t k[4];
202 mp_limb_t t[4];
203 mp_limb_t p[2];
204 _umul128to256_(a_binvert[1], a_binvert[0], numa[1], numa[0], k);
205
206 // 此处本应按位取反再加一,得到相反数,但是a_binvert[0]不可能为0,所以进位必定为0
208 a_binvert[0] = ~a_binvert[0];
209 a_binvert[1] = ~a_binvert[1];
210 a_binvert[0]++;
211
212 mp_size_t i = 0;
213 if (n % 2 == 0) {
214 for (; i < n - 4; i += 2) {
215 _umul128to128_(a_binvert[1], a_binvert[0], k[3], k[2], p);
216 dst[i + 2] = p[0];
217 dst[i + 3] = p[1];
218 _umul128to256_(p[1], p[0], numa[1], numa[0], t);
219 // t = a*p
220 // k的结果在 k[2] 和 k[3] 中
221 t[0] += k[2];
222 carry = (t[0] < k[2]) ? 1 : 0;
223 t[1] += carry;
224 carry = (t[1] < carry) ? 1 : 0;
225 t[1] += k[3];
226 carry += (t[1] < k[3]) ? 1 : 0;
227
228 k[2] = t[2] + carry;
229 carry = (k[2] < carry) ? 1 : 0;
230 k[3] = t[3] + carry;
231 }
232 _umul128to128_(a_binvert[1], a_binvert[0], k[3], k[2], p);
233 dst[i + 2] = p[0];
234 dst[i + 3] = p[1];
235 } else {
236 for (; i < n - 3; i += 2) {
237 _umul128to128_(a_binvert[1], a_binvert[0], k[3], k[2], p);
238 dst[i + 2] = p[0];
239 dst[i + 3] = p[1];
240 _umul128to256_(p[1], p[0], numa[1], numa[0], t);
241 // t = a*p
242 // k的结果在 k[2] 和 k[3] 中
243 t[0] += k[2];
244 carry = (t[0] < k[2]) ? 1 : 0;
245 t[1] += carry;
246 carry = (t[1] < carry) ? 1 : 0;
247 t[1] += k[3];
248 carry += (t[1] < k[3]) ? 1 : 0;
249
250 k[2] = t[2] + carry;
251 carry = (k[2] < carry) ? 1 : 0;
252 k[3] = t[3] + carry;
253 }
254 _umul128to128_(a_binvert[1], a_binvert[0], k[3], k[2], p);
255 dst[i + 2] = p[0];
256 }
257}
#define a_binvert
#define k
ulong lmmp_binvert_ulong_(ulong a)
计算 a 在2^64下的逆元
Definition binvert_1.c:42
uint lmmp_binvert_uint_(uint a)
计算 a 在2^32下的逆元
Definition binvert_1.c:30
void lmmp_binvert_unbalanced_1_(mp_ptr restrict dst, mp_limb_t a, mp_size_t n)
Definition binvert_1.c:170
void lmmp_binvert_unbalanced_2_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t n)
Definition binvert_1.c:191
void lmmp_binvert_2_(mp_ptr dst, mp_srcptr numa)
计算 [numa,2] 在 B^2 下的逆元
Definition binvert_1.c:56
static const uchar binv_tab[128]
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition binvert_1.c:22
void lmmp_binvert_3_(mp_ptr restrict dst, mp_srcptr restrict numa)
Definition binvert_1.c:102
#define xn
static void _umul128to192_(uint64_t a_high, uint64_t a_low, uint64_t b_high, uint64_t b_low, uint64_t rr[3])
Definition binvert_1.c:78
void lmmp_binvert_4_(mp_ptr restrict dst, mp_srcptr restrict numa)
Definition binvert_1.c:127
mp_limb_t * mp_ptr
Definition lmmp.h:80
uint64_t mp_size_t
Definition lmmp.h:77
#define lmmp_debug_assert(x)
Definition lmmp.h:390
const mp_limb_t * mp_srcptr
Definition lmmp.h:81
uint64_t mp_limb_t
Definition lmmp.h:76
#define lmmp_param_assert(x)
Definition lmmp.h:401
#define _u128add(r, x, y)
Definition longlong.h:346
static void _umul64to128_(uint64_t a, uint64_t b, uint64_t *low, uint64_t *high)
Definition longlong.h:174
static void _umul128to256_(uint64_t a_high, uint64_t a_low, uint64_t b_high, uint64_t b_low, uint64_t rr[4])
Definition longlong.h:212
#define _u128sub(r, x, y)
Definition longlong.h:368
static void _umul128to128_(uint64_t a_high, uint64_t a_low, uint64_t b_high, uint64_t b_low, uint64_t rr[2])
Definition longlong.h:241
#define a0
#define a1
#define a2
#define t
#define n
#define lo
uint8_t uchar
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition numth.h:27
uint32_t uint
Definition numth.h:31
uint64_t ulong
Definition numth.h:32