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) {
135 lmmp_inc(dst - nr);
136 }
137
138 //-rem
139 lmmp_not_(xp + 2 * nr, xp + na - nr, nr);
140 }
141
142 // in = 1:[dst-na,na]
143 // in = ir*B^(na-nr) + ir*(-rem/B^(na-nr))/B^(3*nr-na)
144 // use inequality an*ir!=B^(na+nr),
145 //(otherwise obviously contradictory),
146 // we can prove
147 // an*in <= an*ir * ( 2*B^(na+nr) - an*ir ) * B^(-2*nr) < B^(2*na)
148 // so in < B^(2*na)/an <= 2*B^(na),
149 // inc below won't overflow
150
151 // and via inequality -B^na < an*ir - B^(na+nr) < 0
152 // we can prove in = (B^(2*na)-1)/an - [0|1]
153 lmmp_mul_n_(xp, xp + 2 * nr, dst - nr, nr);
154 cy = lmmp_add_n_(xp + nr, xp + nr, xp + 2 * nr, 2 * nr - na);
155 if (lmmp_add_nc_(dst - na, xp + 3 * nr - na, xp + 4 * nr - na, na - nr, cy))
156 lmmp_inc(dst - nr);
157
158 nr = na;
159 } while (sizp != sizes);
160 TEMP_FREE;
161}
162
165 lmmp_param_assert(numa[na - 1] != 0);
166 mp_limb_t high = numa[na - 1];
168 TEMP_DECL;
169 if (dst == numa || nsh || nf) {
170 nf += nsh != 0;
173 if (nsh)
174 lmmp_shl_(numa2 + nf, numa, na, nsh);
175 else
176 lmmp_copy(numa2 + nf, numa, na);
177 numa = numa2;
178 }
180 if (nsh)
182 else
183 dst[na + nf] = 1;
184 TEMP_FREE;
185}
186
mp_limb_t lmmp_inv_1_(mp_limb_t x)
1阶逆元计算 (inv1)
Definition inv.c:117
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:163
void lmmp_invappr_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t na)
Definition inv.c:187
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
const mp_limb_t * mp_srcptr
Definition lmmp.h:81
#define LIMB_MAX
Definition lmmp.h:89
uint64_t mp_limb_t
Definition lmmp.h:76
#define lmmp_assert(x)
Definition lmmp.h:373
#define LIMB_BITS
Definition lmmp.h:86
#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
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:996
#define lmmp_dec(p)
大数减1宏(预期无借位)
Definition lmmpn.h:965
#define lmmp_inc(p)
大数加1宏(预期无进位)
Definition lmmpn.h:938
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:977
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_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:150
#define TALLOC_TYPE(n, type)
Definition tmp_alloc.h:148