LAMMP 4.1.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
bninv.c
浏览该文件的文档.
1/*
2 * LAMMP - Copyright (C) 2025-2026 HJimmyK(Jericho Knox)
3 * This file is part of lammp, under the GNU LGPL v2 license.
4 * See LICENSE in the project root for the full license text.
5 */
6
7#include "../../include/lammp/impl/mparam.h"
8#include "../../include/lammp/impl/tmp_alloc.h"
9#include "../../include/lammp/lmmpn.h"
10
11/*
12funtion: bninv
13output:
14 dstq := B^(2*(na+ni)) // ([numa,na] * B^ni)
15
16 numa
17 |
18 |---ni---|------na-------|
19 +--------+---------------+
20 | 000000 | aaaaaaaaaaaaa |
21 +--------+---------------+
22 <---remn---->|<--a_hatn->|
23 |
24 a_hat
25
26 N = na + ni
27 a_hatn = N / 2 + 1
28 remn = N - a_hatn
29 a_hat = numa + na - a_hatn
30
31 if remn > ni:
32 ni_hat = 0
33 else
34 ni_hat = ni - remn
35 q_hat = bninv(a_hat, a_hatn, ni_hat)
36
37 q_hatn = a_hatn + ni_hat + 1
38 = N_half + 1
39
40 qrn = N + 1 - q_hatn
41 = N + 1 - (N_half + 1)
42 = N - N_half
43
44 q_hat
45 |
46 |---qrn----|--q_hatn--|
47 +----------+----------+
48 | 00000000 | qqqqqqqq |
49 +----------+----------+
50 <---------N+1--------->
51
52
53 2*q_hatn + 2*qrn + an + ni = 2*(N+1) + N = 3*N + 2
54
55 q_hat_sqr_a
56 |
57 |---qrn---|---qrn---|-----ni-----|------2 * q_hatn + an-------|
58 +---------+---------+------------+----------------------------+
59 | 0000000 | 0000000 | 0000000000 | ssssssssssssssssssss | 0 |
60 +---------+---------+----------+-+---------+------------+-----+
61 | delete | 000000000 | qqqqqqqqqq | ca |
62 +-------------- 2*N -----------+----qrn----+-- q_hatn --+-----+
63 | 2*N_half |<------- N+1 ---------->|<-1->|
64 |
65 dstq
66 and assert(ca == 0)
67*/
68
69/**
70 * @brief 牛顿法求精确逆元(至多产生1的误差)
71 * @note dstq := B^(2*(na+ni)) // ([numa,na] * B^ni) + [0|1]
72 * @warning eqsep(dstq,numa), dstq!=NULL, numa!=NULL, na>=3, MSB(numa)=1
73 */
74static void lmmp_bninv_appr_newton_(mp_ptr restrict dstq, mp_srcptr restrict numa, mp_size_t na, mp_size_t ni) {
75 lmmp_param_assert(na >= 3);
76 lmmp_param_assert(dstq != NULL && numa != NULL);
77 lmmp_param_assert(numa[na - 1] > LIMB_B_2);
79 if (na < BNINV_NEWTON_THRESHOLD) {
80 mp_ptr restrict bnp = TALLOC_TYPE(2 * na + ni + 1, mp_limb_t);
81 lmmp_zero(bnp, 2 * na + ni + 1);
82 bnp[2 * na + ni] = 1;
83 mp_limb_t inv21 = lmmp_inv_2_1_(numa[na - 1], numa[na - 2]);
84 lmmp_div_basecase_(dstq, bnp, 2 * na + ni + 1, numa, na, inv21);
85 } else {
86 mp_srcptr restrict a_hat;
87
88 mp_size_t N = na + ni;
89 mp_size_t a_hatn = N / 2 + 1;
90 mp_size_t remn = N - a_hatn;
91 mp_size_t ni_hat;
92 if (remn > ni) {
93 ni_hat = 0;
94 a_hat = numa + na - a_hatn;
95 } else {
96 ni_hat = ni - remn;
97 a_hat = numa;
98 a_hatn = na;
99 }
100 mp_size_t q_hatn = a_hatn + ni_hat + 1;
101 mp_size_t qrn = N + 1 - q_hatn;
102 mp_ptr restrict q_hat = dstq + qrn;
103
104 mp_ptr restrict q_hat_sqr = TALLOC_TYPE(2 * q_hatn, mp_limb_t);
105 mp_ptr restrict q_hat_sqr_a = TALLOC_TYPE(2 * q_hatn + na, mp_limb_t);
106
107 lmmp_bninv_appr_newton_(q_hat, a_hat, a_hatn, ni_hat);
108 lmmp_sqr_(q_hat_sqr, q_hat, q_hatn);
109 lmmp_mul_(q_hat_sqr_a, q_hat_sqr, 2 * q_hatn, numa, na);
110 // we can assert q_hat_sqr_a[2*q_hatn+na-1] == 0
111 lmmp_zero(dstq, qrn);
112 if (2 * qrn + ni > 2 * N) {
113 mp_size_t start = 2 * qrn + ni - 2 * N;
114 lmmp_shl_(q_hat, q_hat, q_hatn, 1); // assert no carry
115 lmmp_sub_n_(dstq + start, dstq + start, q_hat_sqr_a, N + 1 - start);
116 } else {
117 mp_size_t start = 2 * N - 2 * qrn - ni;
118 lmmp_shl_(q_hat, q_hat, q_hatn, 1); // assert no carry
119 lmmp_sub_n_(dstq, dstq, q_hat_sqr_a + start, N + 1);
120 }
121 }
122 TEMP_FREE;
123}
124
125void lmmp_bninv_(mp_ptr restrict dstq, mp_srcptr restrict numa, mp_size_t na, mp_size_t ni) {
126 lmmp_param_assert(na > 0);
127 lmmp_param_assert(dstq != NULL && numa != NULL);
128 lmmp_param_assert(numa[na - 1] > 0);
129 TEMP_DECL;
130 if (na == 1) {
131 mp_ptr restrict bnp = TALLOC_TYPE(3 + ni, mp_limb_t);
132 lmmp_zero(bnp, 2 + ni);
133 bnp[2 + ni] = 1;
134 lmmp_div_1_(dstq, bnp, 3 + ni, numa[0]);
135 } else if (na == 2) {
136 mp_size_t bn = 2 * 2 + ni + 1;
137 mp_ptr restrict bnp = TALLOC_TYPE(bn, mp_limb_t);
138 lmmp_zero(bnp, bn - 1);
139 bnp[bn - 1] = 1;
140 mp_limb_t d[2] = {numa[0], numa[1]};
141 lmmp_div_2_(dstq, bnp, bn, d);
142 } else if (ni > na) {
143 mp_ptr restrict B = TALLOC_TYPE(2 * na + ni + 1, mp_limb_t);
144 lmmp_zero(B, 2 * na + ni);
145 B[2 * na + ni] = 1;
146 lmmp_div_(dstq, NULL, B, 2 * na + ni + 1, numa, na);
147 } else {
148 int shift = lmmp_leading_zeros_(numa[na - 1]);
149 if (shift > 0) {
150 mp_ptr restrict numa_shift = TALLOC_TYPE(na, mp_limb_t);
151 lmmp_shl_(numa_shift, numa, na, shift);
152 lmmp_bninv_appr_newton_(dstq, numa_shift, na, ni + 1);
153 lmmp_shr_(dstq, dstq, na + ni + 2, LIMB_BITS - shift);
154 } else {
155 lmmp_bninv_appr_newton_(dstq, numa, na, ni + 1);
156 lmmp_copy(dstq, dstq + 1, na + ni + 1);
157 dstq[na + ni + 1] = 0;
158 }
159 }
160 TEMP_FREE;
161 return;
162}
void lmmp_bninv_(mp_ptr restrict dstq, mp_srcptr restrict numa, mp_size_t na, mp_size_t ni)
Definition bninv.c:125
static void lmmp_bninv_appr_newton_(mp_ptr restrict dstq, mp_srcptr restrict numa, mp_size_t na, mp_size_t ni)
牛顿法求精确逆元(至多产生1的误差)
Definition bninv.c:74
#define bn
#define B
mp_limb_t * mp_ptr
Definition lmmp.h:215
#define lmmp_copy(dst, src, n)
Definition lmmp.h:364
#define lmmp_zero(dst, n)
Definition lmmp.h:366
uint64_t mp_size_t
Definition lmmp.h:212
const mp_limb_t * mp_srcptr
Definition lmmp.h:216
uint64_t mp_limb_t
Definition lmmp.h:211
#define LIMB_BITS
Definition lmmp.h:221
#define lmmp_param_assert(x)
Definition lmmp.h:398
mp_limb_t lmmp_div_1_(mp_ptr dstq, mp_srcptr numa, mp_size_t na, mp_limb_t x)
单精度数除法
Definition div.c:66
int lmmp_leading_zeros_(mp_limb_t x)
计算一个单精度数(limb)中前导零的个数
Definition tiny.c:35
void lmmp_div_2_(mp_ptr dstq, mp_srcptr numa, mp_size_t na, mp_ptr numb)
双精度数除法 (除数为2个limb)
Definition div.c:223
mp_limb_t lmmp_shr_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t shr)
大数右移操作 [dst,na] = [numa,na] >> shr,dst的高shr位填充0
Definition shr.c:9
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]
void lmmp_sqr_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
大数平方操作 [dst,2*na] = [numa,na]^2
Definition sqr.c:10
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:9
void lmmp_div_(mp_ptr dstq, mp_ptr dstr, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
大数除法和取模操作
Definition div.c:57
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:70
mp_limb_t lmmp_inv_2_1_(mp_limb_t xh, mp_limb_t xl)
2-1阶逆元计算 (inv21)
Definition inv.c:10
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)
基础除法运算
#define LIMB_B_2
Definition mparam.h:160
#define BNINV_NEWTON_THRESHOLD
Definition mparam.h:62
#define TEMP_DECL
Definition tmp_alloc.h:72
#define TEMP_FREE
Definition tmp_alloc.h:93
#define TALLOC_TYPE(n, type)
Definition tmp_alloc.h:91