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
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) {
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
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}
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 LLIMB_MASK
Definition lmmp.h:92
#define LIMB_MAX
Definition lmmp.h:89
uint64_t mp_limb_t
Definition lmmp.h:76
#define LIMB_BITS
Definition lmmp.h:86
static void _umul64to128_(uint64_t a, uint64_t b, uint64_t *low, uint64_t *high)
Definition longlong.h:174
#define n