LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
bninv.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
22/*
23funtion: bninv
24output:
25 dstq := B^(2*(na+ni)) // ([numa,na] * B^ni)
26
27 numa
28 |
29 |---ni---|------na-------|
30 +--------+---------------+
31 | 000000 | aaaaaaaaaaaaa |
32 +--------+---------------+
33 <---remn---->|<--a_hatn->|
34 |
35 a_hat
36
37 N = na + ni
38 a_hatn = N / 2 + 1
39 remn = N - a_hatn
40 a_hat = numa + na - a_hatn
41
42 if remn > ni:
43 ni_hat = 0
44 else
45 ni_hat = ni - remn
46 q_hat = bninv(a_hat, a_hatn, ni_hat)
47
48 q_hatn = a_hatn + ni_hat + 1
49 = N_half + 1
50
51 qrn = N + 1 - q_hatn
52 = N + 1 - (N_half + 1)
53 = N - N_half
54
55 q_hat
56 |
57 |---qrn----|--q_hatn--|
58 +----------+----------+
59 | 00000000 | qqqqqqqq |
60 +----------+----------+
61 <---------N+1--------->
62
63
64 2*q_hatn + 2*qrn + an + ni = 2*(N+1) + N = 3*N + 2
65
66 q_hat_sqr_a
67 |
68 |---qrn---|---qrn---|-----ni-----|------2 * q_hatn + an-------|
69 +---------+---------+------------+----------------------------+
70 | 0000000 | 0000000 | 0000000000 | ssssssssssssssssssss | 0 |
71 +---------+---------+----------+-+---------+------------+-----+
72 | delete | 000000000 | qqqqqqqqqq | ca |
73 +-------------- 2*N -----------+----qrn----+-- q_hatn --+-----+
74 | 2*N_half |<------- N+1 ---------->|<-1->|
75 |
76 dstq
77 and assert(ca == 0)
78*/
79
80/**
81 * @brief 牛顿法求精确逆元(至多产生1的误差)
82 * @note dstq := B^(2*(na+ni)) // ([numa,na] * B^ni) + [0|1]
83 * @warning eqsep(dstq,numa), dstq!=NULL, numa!=NULL, na>=3, MSB(numa)=1
84 */
91 mp_ptr restrict bnp = TALLOC_TYPE(2 * na + ni + 1, mp_limb_t);
92 lmmp_zero(bnp, 2 * na + ni + 1);
93 bnp[2 * na + ni] = 1;
95 lmmp_div_basecase_(dstq, bnp, 2 * na + ni + 1, numa, na, inv21);
96 } else {
98
99 mp_size_t N = na + ni;
100 mp_size_t a_hatn = N / 2 + 1;
103 if (remn > ni) {
104 ni_hat = 0;
105 a_hat = numa + na - a_hatn;
106 } else {
107 ni_hat = ni - remn;
108 a_hat = numa;
109 a_hatn = na;
110 }
112 mp_size_t qrn = N + 1 - q_hatn;
114
117
121 // we can assert q_hat_sqr_a[2*q_hatn+na-1] == 0
123 if (2 * qrn + ni > 2 * N) {
124 mp_size_t start = 2 * qrn + ni - 2 * N;
125 lmmp_shl_(q_hat, q_hat, q_hatn, 1); // assert no carry
127 } else {
128 mp_size_t start = 2 * N - 2 * qrn - ni;
129 lmmp_shl_(q_hat, q_hat, q_hatn, 1); // assert no carry
131 }
132 }
133 TEMP_FREE;
134}
135
139 lmmp_param_assert(numa[na - 1] > 0);
140 TEMP_DECL;
141 if (na == 1) {
143 lmmp_zero(bnp, 2 + ni);
144 bnp[2 + ni] = 1;
145 lmmp_div_1_(dstq, bnp, 3 + ni, numa[0]);
146 } else if (na == 2) {
147 mp_size_t bn = 2 * 2 + ni + 1;
149 lmmp_zero(bnp, bn - 1);
150 bnp[bn - 1] = 1;
151 mp_limb_t d[2] = {numa[0], numa[1]};
152 lmmp_div_2_(dstq, bnp, bn, d);
153 } else if (ni > na) {
154 mp_ptr restrict B = TALLOC_TYPE(2 * na + ni + 1, mp_limb_t);
155 lmmp_zero(B, 2 * na + ni);
156 B[2 * na + ni] = 1;
157 lmmp_div_(dstq, NULL, B, 2 * na + ni + 1, numa, na);
158 } else {
159 int shift = lmmp_leading_zeros_(numa[na - 1]);
160 if (shift > 0) {
164 lmmp_shr_(dstq, dstq, na + ni + 2, LIMB_BITS - shift);
165 } else {
167 lmmp_copy(dstq, dstq + 1, na + ni + 1);
168 dstq[na + ni + 1] = 0;
169 }
170 }
171 TEMP_FREE;
172 return;
173}
void lmmp_bninv_(mp_ptr restrict dstq, mp_srcptr restrict numa, mp_size_t na, mp_size_t ni)
Definition bninv.c:136
static void lmmp_bninv_appr_newton_(mp_ptr restrict dstq, mp_srcptr restrict numa, mp_size_t na, mp_size_t ni)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition bninv.c:85
#define bn
#define B
#define lmmp_leading_zeros_
Definition inlines.h:160
#define lmmp_sqr_
Definition inlines.h:166
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
uint64_t mp_limb_t
Definition lmmp.h:76
#define LIMB_BITS
Definition lmmp.h:86
#define lmmp_param_assert(x)
Definition lmmp.h:401
mp_limb_t lmmp_div_1_(mp_ptr dstq, mp_srcptr numa, mp_size_t na, mp_limb_t x)
单精度数除法
Definition div.c:77
void lmmp_div_2_(mp_ptr dstq, mp_srcptr numa, mp_size_t na, mp_ptr numb)
双精度数除法 (除数为2个limb)
Definition div.c:234
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:19
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_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
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:74
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_2_1_(mp_limb_t xh, mp_limb_t xl)
2-1阶逆元计算 (inv21)
Definition inv.c:20
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:157
#define BNINV_NEWTON_THRESHOLD
Definition mparam.h:62
#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