LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
inv.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/inlines.h"
17#include "../../../include/lammp/impl/mparam.h"
18#include "../../../include/lammp/impl/tmp_alloc.h"
19#include "../../../include/lammp/lmmpn.h"
20
21
25 if (na == 1)
26 *dst = lmmp_inv_1_(*numa);
27 else {
30 mp_size_t i = na;
31 do {
32 xp[--i] = LIMB_MAX;
33 } while (i);
34 lmmp_not_(xp + na, numa, na);
35 //[xp,2*na] = B^(2*na)-1 - [numa,na]*B^na
36
37 if (na == 2) {
39 } else {
43 } else {
45 }
46 }
48 }
49}
50
54
56 mp_size_t nr = na, mn;
58
59 do {
60 *sizp = nr;
61 nr = (nr >> 1) + 1;
62 ++sizp;
63 } while (nr >= INV_NEWTON_THRESHOLD);
64
65 numa += na;
66 dst += na;
67
69
71 mp_ptr restrict xp = TALLOC_TYPE(3 * (na >> 1) + 3, mp_limb_t);
72 do {
73 na = *--sizp;
74
75 // ar = 0:[numa-nr,nr]
76 // an = 0:[numa-na,na]
77 // ir = 1:[dst-nr,nr] = (B^(2*nr)-1)/ar - [0|1]
78 // rem = ir*an-B^(na+nr)
79 //-2*B^na < rem < 2*B^na
80
81 //[xp] = rem
82 if (na < INV_MODM_THRESHOLD || (mn = lmmp_fft_next_size_(na + 1)) >= na + nr) {
83 lmmp_mul_(xp, numa - na, na, dst - nr, nr);
84 lmmp_add_n_(xp + nr, xp + nr, numa - na, na + 1 - nr);
85 cy = 1; // for mod B^(na+1)
86 } else { // nr < na < mn < na+nr
87
88 //[xp,mn] = [dst,nr] * [numa,na] mod (B^mn-1)
89 lmmp_mul_mersenne_(xp, mn, numa - na, na, dst - nr, nr);
90
91 //[xp,mn] += [numa,na]*B^nr mod (B^mn-1)
92 cy = lmmp_add_n_(xp + nr, xp + nr, numa - na, mn - nr);
93 cy = lmmp_add_nc_(xp, xp, numa - (na - (mn - nr)), na - (mn - nr), cy);
94
95 //[xp,mn] -= B^(na+nr) mod (B^mn-1)
96 xp[mn] = 1;
97 lmmp_dec_1(xp + na + nr - mn, 1 - cy);
98 lmmp_dec_1(xp, 1 - xp[mn]);
99
100 cy = 0; // for mod (B^mn-1)
101 }
102
103 // adjust ir,rem s.t.
104 // -B^na < rem = ir*an - B^(na+nr) < 0
105 // use this we can prove B^nr <= ir < 2*B^nr
106 // so inc/dec ir won't overflow
107 if (xp[na] < 2) { // rem>=0
108
109 // rem-=cy*an s.t. rem[na]=0
110 if ((cy = xp[na])) {
111 if (!lmmp_sub_n_(xp, xp, numa - na, na)) {
112 ++cy;
113 lmmp_sub_n_(xp, xp, numa - na, na);
114 }
115 }
116
117 // rem-=cy*an s.t. 0<=rem<an
118 if (lmmp_cmp_(xp, numa - na, na) >= 0) {
119 lmmp_sub_n_(xp, xp, numa - na, na);
120 ++cy;
121 }
122
123 // 0 < an-rem <= an < B^na , trunc to nr limbs
124 lmmp_sub_nc_(xp + 2 * nr, numa - nr, xp + na - nr, nr, lmmp_cmp_(xp, numa - na, na - nr) > 0);
125 ++cy;
126
127 lmmp_dec_1(dst - nr, cy);
128 } else { // rem<0
129 if (cy)
130 lmmp_dec(xp); // for neg to not
131 // else (neg to not) compensate (mod transfer)
132
133 if (xp[na] != LIMB_MAX) {
136 lmmp_inc(dst - nr);
137 }
138
139 //-rem
140 lmmp_not_(xp + 2 * nr, xp + na - nr, nr);
141 }
142
143 // in = 1:[dst-na,na]
144 // in = ir*B^(na-nr) + ir*(-rem/B^(na-nr))/B^(3*nr-na)
145 // use inequality an*ir!=B^(na+nr),
146 //(otherwise obviously contradictory),
147 // we can prove
148 // an*in <= an*ir * ( 2*B^(na+nr) - an*ir ) * B^(-2*nr) < B^(2*na)
149 // so in < B^(2*na)/an <= 2*B^(na),
150 // inc below won't overflow
151
152 // and via inequality -B^na < an*ir - B^(na+nr) < 0
153 // we can prove in = (B^(2*na)-1)/an - [0|1]
154 lmmp_mul_n_(xp, xp + 2 * nr, dst - nr, nr);
155 cy = lmmp_add_n_(xp + nr, xp + nr, xp + 2 * nr, 2 * nr - na);
156 if (lmmp_add_nc_(dst - na, xp + 3 * nr - na, xp + 4 * nr - na, na - nr, cy))
157 lmmp_inc(dst - nr);
158
159 nr = na;
160 } while (sizp != sizes);
161 TEMP_FREE;
162}
163
166 lmmp_param_assert(numa[na - 1] != 0);
167 mp_limb_t high = numa[na - 1];
169 TEMP_DECL;
170 if (dst == numa || nsh || nf) {
171 nf += nsh != 0;
174 if (nsh)
175 lmmp_shl_(numa2 + nf, numa, na, nsh);
176 else
177 lmmp_copy(numa2 + nf, numa, na);
178 numa = numa2;
179 }
181 if (nsh)
183 else
184 dst[na + nf] = 1;
185 TEMP_FREE;
186}
187
mp_limb_t lmmp_inv_2_1_(mp_limb_t xh, mp_limb_t xl)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition inv.c:20
#define lmmp_leading_zeros_
Definition inlines.h:160
#define lmmp_mul_n_
Definition inlines.h:167
void lmmp_inv_basecase_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t na)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition inv.c:22
void lmmp_invappr_newton_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t na)
Definition inv.c:51
void lmmp_inv_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t nf)
求逆操作 [dst,na+nf+1] = (B^(2*(na+nf)) - 1) / ([numa,na]*B^nf) + [0|-1]
Definition inv.c:164
void lmmp_invappr_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t na)
Definition inv.c:188
mp_limb_t * mp_ptr
Definition lmmp.h:117
#define lmmp_copy(dst, src, n)
Definition lmmp.h:461
#define lmmp_zero(dst, n)
Definition lmmp.h:463
uint64_t mp_size_t
Definition lmmp.h:114
const mp_limb_t * mp_srcptr
Definition lmmp.h:118
#define LIMB_MAX
Definition lmmp.h:126
uint64_t mp_limb_t
Definition lmmp.h:113
#define lmmp_assert(x)
Definition lmmp.h:468
#define LIMB_BITS
Definition lmmp.h:123
#define lmmp_param_assert(x)
Definition lmmp.h:496
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
mp_limb_t lmmp_shr_c_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t shr, mp_limb_t c)
带进位的右移操作 [dst,na] = [numa,na]>>shr,dst的高shr位填充c的高shr位
Definition shr.c:40
static int lmmp_cmp_(mp_srcptr numa, mp_srcptr numb, mp_size_t n)
比较函数(内联)
Definition lmmpn.h:959
#define lmmp_dec(p)
减1宏(预期无借位)
Definition lmmpn.h:928
#define lmmp_inc(p)
加1宏(预期无进位)
Definition lmmpn.h:901
void lmmp_mul_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
不等长乘法操作 [dst,na+nb] = [numa,na] * [numb,nb]
mp_limb_t lmmp_add_nc_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_limb_t c)
带进位的n位加法 [dst,n] = [numa,n] + [numb,n] + c
Definition add_n.c:19
mp_size_t lmmp_fft_next_size_(mp_size_t n)
计算满足 >=n 的最小费马/梅森乘法可行尺寸
Definition mul_fft.c:95
mp_limb_t lmmp_shl_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t shl)
左移操作 [dst,na] = [numa,na]<<shl,dst的低shl位填充0
Definition shl.c:19
#define lmmp_dec_1(p, dec)
减指定值宏(预期无借位)
Definition lmmpn.h:940
mp_limb_t lmmp_div_2_s_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb)
双精度数除法(除数为2个limb)
void lmmp_not_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
按位取反操作 [dst,na] = ~[numa,na] (对每个limb执行按位非操作)
mp_limb_t lmmp_sub_n_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
无借位的n位减法 [dst,n] = [numa,n] - [numb,n]
Definition sub_n.c:80
mp_limb_t lmmp_inv_1_(mp_limb_t x)
1阶逆元计算 (inv1)
Definition inv.c:117
mp_limb_t lmmp_div_basecase_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb, mp_limb_t inv21)
基础除法运算
mp_limb_t lmmp_sub_nc_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_limb_t c)
带借位的n位减法 [dst,n] = [numa,n] - [numb,n] - c
Definition sub_n.c:19
mp_limb_t lmmp_div_divide_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb, mp_limb_t inv21)
分治除法运算
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 DIV_DIVIDE_THRESHOLD
Definition mparam.h:26
#define LIMB_B_2
Definition mparam.h:157
#define INV_NEWTON_THRESHOLD
Definition mparam.h:33
#define INV_MODM_THRESHOLD
Definition mparam.h:35
#define n
#define TEMP_DECL
Definition tmp_alloc.h:131
#define TEMP_FREE
Definition tmp_alloc.h:158
#define TALLOC_TYPE(n, type)
Definition tmp_alloc.h:156