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