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/longlong.h"
17
#include "../../../../include/lammp/lmmpn.h"
18
19
20
mp_limb_t
lmmp_inv_2_1_
(
mp_limb_t
xh
,
mp_limb_t
xl
) {
21
mp_limb_t
r,
m
;
22
{
23
mp_limb_t
p,
ql
;
24
unsigned
ul
,
uh
,
qh
;
25
26
/* For notation, let b denote the half-limb base, so that B = b^2.
27
Split u1 = b uh + ul. */
28
ul
=
xh
&
LLIMB_MASK
;
29
uh
=
xh
>> (
LIMB_BITS
/ 2);
30
31
/* Approximation of the high half of quotient. Differs from the 2/1
32
inverse of the half limb uh, since we have already subtracted
33
u0. */
34
qh
= (
xh
^
LIMB_MAX
) /
uh
;
35
36
/* Adjust to get a half-limb 3/2 inverse, i.e., we want
37
38
qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u
39
= floor( (b (~u) + b-1) / u),
40
41
and the remainder
42
43
r = b (~u) + b-1 - qh (b uh + ul)
44
= b (~u - qh uh) + b-1 - qh ul
45
46
Subtraction of qh ul may underflow, which implies adjustments.
47
But by normalization, 2 u >= B > qh ul, so we need to adjust by
48
at most 2.
49
*/
50
51
r = ((
~xh
- (
mp_limb_t
)
qh
*
uh
) << (
LIMB_BITS
/ 2)) |
LLIMB_MASK
;
52
53
p = (
mp_limb_t
)
qh
*
ul
;
54
/* Adjustment steps taken from udiv_qrnnd_c */
55
if
(r < p) {
56
qh
--;
57
r +=
xh
;
58
if
(r >=
xh
)
/* i.e. we didn't get carry when adding to r */
59
if
(r < p) {
60
qh
--;
61
r +=
xh
;
62
}
63
}
64
r -= p;
65
66
/* Low half of the quotient is
67
68
ql = floor ( (b r + b-1) / u1).
69
70
This is a 3/2 division (on half-limbs), for which qh is a
71
suitable inverse. */
72
73
p = (r >> (
LIMB_BITS
/ 2)) *
qh
+ r;
74
/* Unlike full-limb 3/2, we can add 1 without overflow. For this to
75
work, it is essential that ql is a full mp_limb_t. */
76
ql
= (p >> (
LIMB_BITS
/ 2)) + 1;
77
78
/* By the 3/2 trick, we don't need the high half limb. */
79
r = (r << (
LIMB_BITS
/ 2)) +
LLIMB_MASK
-
ql
*
xh
;
80
81
if
(r >= (
LIMB_MAX
& (p << (
LIMB_BITS
/ 2)))) {
82
ql
--;
83
r +=
xh
;
84
}
85
m
= ((
mp_limb_t
)
qh
<< (
LIMB_BITS
/ 2)) +
ql
;
86
if
(r >=
xh
) {
87
m
++;
88
r -=
xh
;
89
}
90
}
91
92
/* Now m is the 2/1 inverse of u1. If u0 > 0, adjust it to become a
93
3/2 inverse. */
94
if
(
xl
> 0) {
95
mp_limb_t
th
,
tl
;
96
r =
~r
;
97
r +=
xl
;
98
if
(r <
xl
) {
99
m
--;
100
if
(r >=
xh
) {
101
m
--;
102
r -=
xh
;
103
}
104
r -=
xh
;
105
}
106
_umul64to128_
(
xl
,
m
, &
tl
, &
th
);
107
r +=
th
;
108
if
(r <
th
) {
109
m
--;
110
m
-= ((r >
xh
) | ((r ==
xh
) & (
tl
>
xl
)));
111
}
112
}
113
114
return
m
;
115
}
116
117
mp_limb_t
lmmp_inv_1_
(
mp_limb_t
x
) {
118
mp_limb_t
r,
m
;
119
{
120
mp_limb_t
p,
ql
;
121
unsigned
ul
,
uh
,
qh
;
122
123
ul
=
x
&
LLIMB_MASK
;
124
uh
=
x
>> (
LIMB_BITS
/ 2);
125
qh
= (
x
^
LIMB_MAX
) /
uh
;
126
127
r = ((
~x
- (
mp_limb_t
)
qh
*
uh
) << (
LIMB_BITS
/ 2)) |
LLIMB_MASK
;
128
p = (
mp_limb_t
)
qh
*
ul
;
129
if
(r < p) {
130
qh
--;
131
r +=
x
;
132
if
(r >=
x
)
133
if
(r < p) {
134
qh
--;
135
r +=
x
;
136
}
137
}
138
r -= p;
139
p = (r >> (
LIMB_BITS
/ 2)) *
qh
+ r;
140
ql
= (p >> (
LIMB_BITS
/ 2)) + 1;
141
r = (r << (
LIMB_BITS
/ 2)) +
LLIMB_MASK
-
ql
*
x
;
142
if
(r >= (
LIMB_MAX
& (p << (
LIMB_BITS
/ 2)))) {
143
ql
--;
144
r +=
x
;
145
}
146
m
= ((
mp_limb_t
)
qh
<< (
LIMB_BITS
/ 2)) +
ql
;
147
if
(r >=
x
) {
148
m
++;
149
r -=
x
;
150
}
151
}
152
return
m
;
153
}
lmmp_inv_1_
mp_limb_t lmmp_inv_1_(mp_limb_t x)
1阶逆元计算 (inv1)
Definition
inv.c:117
lmmp_inv_2_1_
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
LLIMB_MASK
#define LLIMB_MASK
Definition
lmmp.h:92
LIMB_MAX
#define LIMB_MAX
Definition
lmmp.h:89
mp_limb_t
uint64_t mp_limb_t
Definition
lmmp.h:76
LIMB_BITS
#define LIMB_BITS
Definition
lmmp.h:86
_umul64to128_
static void _umul64to128_(uint64_t a, uint64_t b, uint64_t *low, uint64_t *high)
Definition
longlong.h:174
n
#define n
src
lammp
lmmpn
generic
inv.c
生成于 2026年 七月 12日 星期日 16:40:19 , 为 LAMMP使用
1.9.8