LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
binvert.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/impl/mparam.h"
17#include "../../../include/lammp/impl/tmp_alloc.h"
18#include "../../../include/lammp/impl/inlines.h"
19#include "../../../include/lammp/lmmpn.h"
20#include "../../../include/lammp/numth.h"
21
22/**
23 * @brief 计算 [dst,n] = [xp,n]*[ap,n] div B^n
24 * @param dst 结果指针
25 * @param tp scratch space, need 2*n limbs
26 * @warning [xp,n] * [ap,n] mod B^n == 1
27 */
30 lmmp_mul_n_(tp, xp, ap, n);
31 lmmp_copy(dst, tp + n, n);
32 } else {
33 mp_size_t m = lmmp_fft_next_size_((n * 2 + 1) >> 1);
34 lmmp_debug_assert(n * 2 > m && m >= n);
36 lmmp_dec(tp);
37 mp_size_t fn = m - n; // 从 tp+n 开始的长度
38 mp_size_t sn = n - fn; // 从 tp 开始的长度
39 lmmp_copy(dst, tp + n, fn);
40 lmmp_copy(dst + fn, tp, sn);
41 }
42}
43
44static inline void lmmp_sqrlo_n_(
49) {
50 if (n < MULLO_DC_THRESHOLD) {
52 } else {
54 }
55}
56
57static inline void lmmp_mullo_n_(
63) {
64 if (n < MULLO_DC_THRESHOLD) {
66 } else {
68 }
69}
70
71/*
72balanced:
73 a := [numa,2*n]
74 we neead to find x such that x * a == 1 mod B^2n
75 we know that a == a_lo + a_hi * B^n
76 and x_lo == a_lo ^ -1 mod B^n
77 means x_lo * a_lo == 1 + k * B^n and k < B^n
78
79 x = x_lo * (2 - a * x_lo) mod B^2n
80 = x_lo * (2 - a_lo * x_lo - a_hi * x_lo * B^n) mod B^2n
81 = x_lo * (1 - k * B^n - a_hi * x_lo * B^n) mod B^2n
82 = x_lo - (k * x_lo + a_hi * x_lo^2) * B^n mod B^2n
83-----------------------------------------------------------------------------
84unbalanced:
85 a := [numa,na]
86 我们需要求x,使得x * a == 1 mod B^n ,同时n远远大于na
87 我们可以求出 x0 = a ^ -1 mod B^na,这是一个平衡的逆元
88 接下来,我们使用线性递推法来求,我们以na个limb为基本处理单元
89 假定现在已经求出 t 个,即 Xt = X0 + X1*B^na + X2*B^2na +... + X{t-1}*B^(t-1)*na
90 且满足 a*Xt == 1 mod B^t*na
91 可以写成 a*Xt = 1 + k * B^t*na, k < B^na
92 我们需要求出下一个 p,使得X{t+1} = X{t} + p*B^na
93 我们代入 a*X{t+1} = 1 mod B^(t+1)*na
94 可以得到
95 1 + k * B^t*na + a*p*B^t*na = 1 mod B^(t+1)*na
96 k + a*p = 0 mod B^na
97 p = -k * a^-1 mod B^na
98 此时,我们已经有了新的X{t+1},我们需要更新 k 为 k'
99 我们需要 k' 满足
100 a*X{t+1} = 1 + k' * B^(t+1)*na, k' < B^na
101 k' * B^na = k + a*p
102 k' = (k + a*p) / B^na
103*/
104
105
107 lmmp_param_assert(dst != NULL && tp != NULL);
108 lmmp_param_assert(numa != NULL && n > 0);
109 lmmp_param_assert(numa[0] % 2 == 1);
110 if (n == 1) {
112 } else if (n == 2) {
114 } else if (n == 3) {
116 } else if (n == 4) {
118 } else if (n % 2 == 0) {
119 mp_size_t halfn = n / 2;
120
121#define k (tp) // [tp, halfn]
122#define alo (numa) // [numa, halfn]
123#define ahi (numa + halfn) // [numa+halfn, halfn]
124#define xlo (dst) // [dst, halfn]
125#define xhi (dst + halfn) // [dst+halfn, halfn]
126#define xlo_sqr (tp + halfn) // [tp+halfn, halfn]
127#define xlo_sqr_mul_ahi (tp + 2 * halfn) // [tp+2*halfn, halfn]
128#define scratch (tp + 3 * halfn) // [tp+3*halfn,2*halfn]
129// ________________________________________________________________
130// tp : |_________________________5*(n+1)/2____________________________|
131// | k | xlo_sqr | xlo_sqr_mul_ahi | scratch | remaining |
132// |_halfn_|__halfn__|______halfn______|___2*halfn___| |
133
141 lmmp_inc(xhi);
142 } else {
143 mp_size_t halfn = n / 2 + 1;
144 mp_size_t ahin = n - halfn;
145
146#define k (tp) // [tp, halfn]
147#define alo (numa) // [numa, halfn]
148#define ahi (numa + halfn) // [numa+halfn, ahin]
149#define xlo (dst) // [dst, halfn]
150#define xhi (dst + halfn) // [dst+halfn, ahin]
151#define xlo_sqr (tp + halfn) // [tp+halfn, ahin]
152#define xlo_sqr_mul_ahi (tp + 2 * halfn) // [tp+2*halfn, ahin]
153#define scratch (tp + 3 * halfn) // [tp+3*halfn, 2*ahin]
154// ________________________________________________________________
155// tp : |_________________________5*(n+1)/2____________________________|
156// | k | xlo_sqr | xlo_sqr_mul_ahi | scratch | remaining |
157// |__halfn__|__halfn__|______halfn______|___2*ahin___| |
158
166 lmmp_inc(xhi);
167 }
168#undef k
169#undef alo
170#undef ahi
171#undef xlo
172#undef xhi
173#undef xlo_sqr
174#undef xlo_sqr_mul_ahi
175#undef scratch
176}
177
179 lmmp_param_assert(dst != NULL && numa != NULL && tp != NULL);
180 lmmp_param_assert(numa[0] % 2 == 1);
181 lmmp_param_assert(n > na && na > 0);
182
183#define a_binvert (tp) // [tp, na]
184#define k (tp + 1 * na) // [tp+na, na]
185#define scratch (tp + 2 * na) // [tp+2*na, 5*(na+1)/2]
186
190
191 // a_binvert 低位不可能为0,故加一不会进位
194 a_binvert[0] += 1;
195
196 mp_size_t i = na;
197 for (; i < n - na; i += na) {
199 /*
200 FIXME: 这里的循环中,第二个乘数numa,始终保持不变
201 在拥有可以惰性初始化的FFT算法的情况下,可以节省numa的正变换
202 在循环的情况下,这将会有可观的性能提升
203 */
205 // now [scratch,2*na] = a * p
206 if (lmmp_add_n_(scratch, scratch, k, na)) {
208 }
209 lmmp_copy(k, scratch + na, na);
210 }
211
213#undef a_binvert
214#undef k
215#undef scratch
216}
217
220 lmmp_param_assert(na > 0 && n > 0);
221 lmmp_param_assert(numa[0] % 2 == 1);
222 TEMP_DECL;
223 if (n == na) {
224 mp_ptr restrict tp = ALLOC_TYPE(5 * (n + 1) / 2, mp_limb_t);
226 } else if (na == 1) {
228 } else if (na == 2) {
230 } else if (4 * n >= 5 * na) {
231 // n/na >= 5/4 这是一个比较简单的调优结果
232 mp_ptr restrict tp = ALLOC_TYPE((9 * n + 5) / 2, mp_limb_t);
234 } else {
236 mp_ptr restrict tp = ALLOC_TYPE((5 * n + 5) / 2, mp_limb_t);
237 lmmp_copy(ap, numa, n);
238 lmmp_zero(ap + na, n - na);
240 }
241 TEMP_FREE;
242}
#define k
#define ahi
void lmmp_binvert_unbalanced_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t na, mp_size_t n, mp_ptr restrict tp)
Definition binvert.c:178
void lmmp_binvert_n_dc_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t n, mp_ptr restrict tp)
Definition binvert.c:106
#define xlo_sqr_mul_ahi
#define xlo_sqr
static void binvert_mulhi_(mp_ptr dst, mp_srcptr xp, mp_srcptr ap, mp_size_t n, mp_ptr tp)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition binvert.c:28
#define xhi
#define scratch
#define a_binvert
#define alo
void lmmp_binvert_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t na, mp_size_t n)
Definition binvert.c:218
static void lmmp_sqrlo_n_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t n, mp_ptr restrict tp)
Definition binvert.c:44
#define xlo
static void lmmp_mullo_n_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_srcptr restrict numb, mp_size_t n, mp_ptr restrict tp)
Definition binvert.c:57
#define lmmp_mul_n_
Definition inlines.h:167
mp_limb_t * mp_ptr
Definition lmmp.h:80
#define lmmp_copy(dst, src, n)
Definition lmmp.h:367
#define lmmp_zero(dst, n)
Definition lmmp.h:369
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
void lmmp_mul_mersenne_(mp_ptr dst, mp_size_t rn, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
梅森数模乘法 [dst,rn] = [numa,na]*[numb,nb] mod B^rn-1
Definition mul_fft.c:761
#define lmmp_dec(p)
大数减1宏(预期无借位)
Definition lmmpn.h:965
void lmmp_mullo_dc_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_ptr tp, mp_size_t n)
低位乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
#define lmmp_inc(p)
大数加1宏(预期无进位)
Definition lmmpn.h:938
mp_size_t lmmp_fft_next_size_(mp_size_t n)
计算满足 >=n 的最小费马/梅森乘法可行尺寸
Definition mul_fft.c:95
void lmmp_sqrlo_dc_(mp_ptr dst, mp_srcptr numa, mp_ptr tp, mp_size_t n)
低位平方 [dst,n] = [numa,n]^2 mod B^n
void lmmp_mullo_fft_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_ptr scratch)
低位FFT乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
Definition mullo.c:22
void lmmp_not_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
大数按位取反操作 [dst,na] = ~[numa,na] (对每个limb执行按位非操作)
mp_limb_t lmmp_add_n_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
无进位的n位加法 [dst,n] = [numa,n] + [numb,n]
Definition add_n.c:81
#define MULHI_MERSENNE_THRESHOLD
Definition mparam.h:121
#define MULLO_DC_THRESHOLD
Definition mparam.h:59
#define numb
#define tp
#define n
ulong lmmp_binvert_ulong_(ulong a)
计算 a 在2^64下的逆元
Definition binvert_1.c:42
void lmmp_binvert_2_(mp_ptr dst, mp_srcptr numa)
计算 [numa,2] 在 B^2 下的逆元
Definition binvert_1.c:56
void lmmp_binvert_3_(mp_ptr dst, mp_srcptr numa)
计算 [numa,3] 在 B^3 下的逆元
void lmmp_binvert_unbalanced_1_(mp_ptr dst, mp_limb_t a, mp_size_t n)
计算 a 在 B^n 下的逆元
void lmmp_binvert_4_(mp_ptr dst, mp_srcptr numa)
计算 [numa,4] 在 B^4 下的逆元
void lmmp_binvert_unbalanced_2_(mp_ptr dst, mp_srcptr numa, mp_size_t n)
计算 [numa,2] 在 B^n 下的逆元
#define TEMP_DECL
Definition tmp_alloc.h:131
#define ALLOC_TYPE(n, type)
Definition tmp_alloc.h:173
#define TEMP_FREE
Definition tmp_alloc.h:150