LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
sqrt.c 文件参考
+ sqrt.c 的引用(Include)关系图:

浏览源代码.

函数

static void lmmp_invsqrt_newton_ (mp_ptr dstis, mp_size_t ns, mp_srcptr numa, mp_size_t na)
 计算逆平方根 [dstis,ns+1]=floor(sqrt(B^(2*ns+na)/[numa,na]))-[0|1], dstis[ns]=1
 
void lmmp_sqrt_ (mp_ptr dsts, mp_ptr dstr, mp_srcptr numa, mp_size_t na, mp_size_t nf)
 计算 [numa,na] * B^(2*nf) 的平方根和余数
 
static mp_limb_t lmmp_sqrt_divide_ (mp_ptr dsts, mp_ptr numa, mp_size_t ns, int nsh)
 Copyright (C) 2026 HJimmyK(Jericho Knox)
 
static void lmmp_sqrt_newton_ (mp_ptr dsts, mp_srcptr numa, mp_size_t na, mp_size_t nf)
 计算近似平方根 [dsts,nf+na/2+1]=[floor|round](sqrt([numa,na]*B^(2*nf)))
 

函数说明

◆ lmmp_invsqrt_newton_()

static void lmmp_invsqrt_newton_ ( mp_ptr  dstis,
mp_size_t  ns,
mp_srcptr  numa,
mp_size_t  na 
)
static

计算逆平方根 [dstis,ns+1]=floor(sqrt(B^(2*ns+na)/[numa,na]))-[0|1], dstis[ns]=1

参数
dstis目标数组
nsdsts数组的 limb 长度为 ns+1
numa输入数组
nanuma数组的 limb 长度
警告
ns>0, na>0, numa[na-1]>=B/4, dstis!=NULL, numa!=NULL
注解
[dstis,ns+1]=floor(sqrt(B^(2*ns+na)/[numa,na]))-[0|1], dstis[ns]=1

在文件 sqrt.c94 行定义.

94 {
99 mp_size_t nr = ns, namax = na, mn;
101
102 do {
103 *sizp = nr;
104 nr = (nr >> 1) + 1;
105 ++sizp;
106 } while (nr > 2);
107
108 numa += na;
109 dstis += ns;
110
111 // nr=2
112 // i2=floor((B^5-1)/(1+floor(sqrt(x*B^4))))
113 mp_limb_t numa2[6], sval[3];
114 lmmp_zero(numa2, 4);
115 numa2[5] = numa[-1];
116 if (na > 1)
117 numa2[4] = numa[-2];
118 else
119 numa2[4] = 0;
121 lmmp_inc(sval);
122 for (mp_size_t i = 0; i < 5; ++i) numa2[i] = LIMB_MAX;
123 dstis[0] = lmmp_div_s_(dstis - 2, numa2, 5, sval, 3);
124
125 TEMP_DECL;
126 mp_limb_t alloc_size = na + 2 * ns + 6;
128 do {
129 na = *--sizp;
130
131 // ar = 0:[numa-nr,nr]
132 // an = 0:[numa-na,na]
133 // ir = 1:[dst-nr,nr] = floor(B^(3*nr/2)/sqrt(ar)) - [0|1]
134 // d = B^(na+2*nr)-an*ir*ir
135 // -4*B^(na+nr) < d < 4*B^(na+nr)
136
138 // mp_size_t zeros = na - naz;
139 mp_size_t nsqr, nres = naz + nr + 1;
140 mp_ptr dp = xp + 2 * nr + 1, dip = xp + nr + 1;
141 int cmod; // 1=mod b^mn-1, 0=mod b^(naz+nr+1)
142 int sign; // 1:d<0, 0:d>=0
144
145 // ir^2
146 if (2 * SQRT_NEWTON_MODM_THRESHOLD + mn >= nr * 2 + 1) {
147 cmod = 0;
148 lmmp_sqr_(xp, dstis - nr, nr + 1);
149 nsqr = 2 * nr + 1;
150 } else {
151 cmod = 1;
152 lmmp_mul_mersenne_(xp, mn, dstis - nr, nr + 1, dstis - nr, nr + 1);
153 nsqr = mn;
154 }
155
156 // ir^2*an
157 if (naz < SQRT_NEWTON_MODM_THRESHOLD || naz * 8 < nsqr || mn >= nsqr + naz) {
158 if (cmod == 0)
160 lmmp_mul_(dp, xp, nsqr, numa - naz, naz);
161 if (cmod == 1) {
162 if (lmmp_add_(dp, dp, mn, dp + mn, naz))
163 lmmp_inc(dp);
164 }
165 } else {
166 if (nsqr > mn) { // cmod==0
167 if (lmmp_add_(xp, xp, mn, xp + mn, nsqr - mn))
168 lmmp_inc(xp);
169 }
171 cmod = 1;
172 }
173
174 if (cmod == 1) {
175 // naz+nr < mn <= naz+2*nr
176 //[dp,mn] -= B^(naz+2*nr) mod (B^mn-1)
177 dp[mn] = 1;
178 lmmp_dec(dp + naz + 2 * nr - mn);
179 if (dp[mn] == 0)
180 lmmp_dec(dp);
181 }
182
183 if (dp[nres - 1] > 3) { //-d<0
184 if (cmod == 0)
185 lmmp_dec(dp); // for neg to not
186 // else (neg to not) compensate (mod transfer)
187 dp += naz;
188 lmmp_shlnot_(xp, dp + 1, nr, LIMB_BITS - 1);
189 xp[0] ^= dp[0] >> 1;
190 xp[nr] = ~dp[nr] >> 1;
191 sign = 0;
192 } else { //-d>0
193 lmmp_shr_(xp, dp + naz, nr + 1, 1);
194 if ((dp[naz] & 1) || !lmmp_zero_q_(dp, naz))
195 lmmp_inc(xp);
196 sign = 1;
197 }
198
199 lmmp_mul_n_(dip, xp, dstis - nr, nr + 1);
200
201 if (sign) {
202 if (lmmp_zero_q_(dip, 3 * nr - na)) {
203 // a limit for dec
204 dip[2 * nr + 1] = 1;
205 lmmp_dec(dip + 3 * nr - na);
206 }
207 lmmp_not_(dstis - na, dip + 3 * nr - na, na - nr);
208 lmmp_dec_1(dstis - nr, dip[2 * nr] + 1);
209 } else {
210 lmmp_copy(dstis - na, dip + 3 * nr - na, na - nr);
211 lmmp_inc_1(dstis - nr, dip[2 * nr]);
212 }
213
214 nr = na;
215 } while (sizp != sizes);
216 TEMP_FREE;
217}
#define lmmp_mul_n_
Definition inlines.h:167
#define lmmp_sqr_
Definition inlines.h:166
mp_limb_t * mp_ptr
Definition lmmp.h:117
#define lmmp_copy(dst, src, n)
Definition lmmp.h:461
#define lmmp_zero(dst, n)
Definition lmmp.h:463
uint64_t mp_size_t
Definition lmmp.h:114
#define LIMB_MAX
Definition lmmp.h:126
uint64_t mp_limb_t
Definition lmmp.h:113
#define LMMP_MIN(l, o)
返回两个数中的较小值
Definition lmmp.h:437
#define LIMB_BITS
Definition lmmp.h:123
#define lmmp_param_assert(x)
Definition lmmp.h:496
mp_limb_t lmmp_shlnot_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t shl)
左移后按位取反操作 [dst,na] = ~([numa,na] << shl),dst的低shl位填充1
mp_limb_t lmmp_div_s_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
除法运算
void lmmp_mul_mersenne_(mp_ptr dst, mp_size_t rn, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
梅森数模乘法 [dst,rn] = [numa,na]*[numb,nb] mod B^rn-1
Definition mul_fft.c:761
static mp_limb_t lmmp_add_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
加法静态内联函数 [dst,na]=[numa,na]+[numb,nb]
Definition lmmpn.h:1013
#define lmmp_dec(p)
减1宏(预期无借位)
Definition lmmpn.h:928
#define lmmp_inc(p)
加1宏(预期无进位)
Definition lmmpn.h:901
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_size_t lmmp_fft_next_size_(mp_size_t n)
计算满足 >=n 的最小费马/梅森乘法可行尺寸
Definition mul_fft.c:95
#define lmmp_dec_1(p, dec)
减指定值宏(预期无借位)
Definition lmmpn.h:940
void lmmp_not_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
按位取反操作 [dst,na] = ~[numa,na] (对每个limb执行按位非操作)
#define lmmp_inc_1(p, inc)
加指定值宏(预期无进位)
Definition lmmpn.h:913
static int lmmp_zero_q_(mp_srcptr p, mp_size_t n)
判零函数(内联)
Definition lmmpn.h:982
#define LIMB_B_4
Definition mparam.h:159
#define SQRT_NEWTON_MODM_THRESHOLD
Definition mparam.h:43
#define n
static mp_limb_t lmmp_sqrt_divide_(mp_ptr dsts, mp_ptr numa, mp_size_t ns, int nsh)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition sqrt.c:46
#define TEMP_DECL
Definition tmp_alloc.h:131
#define TEMP_FREE
Definition tmp_alloc.h:158
#define TALLOC_TYPE(n, type)
Definition tmp_alloc.h:156

引用了 LIMB_B_4, LIMB_BITS, LIMB_MAX, lmmp_add_(), lmmp_copy, lmmp_dec, lmmp_dec_1, lmmp_div_s_(), lmmp_fft_next_size_(), lmmp_inc, lmmp_inc_1, LMMP_MIN, lmmp_mul_(), lmmp_mul_mersenne_(), lmmp_mul_n_, lmmp_not_(), lmmp_param_assert, lmmp_shlnot_(), lmmp_shr_(), lmmp_sqr_, lmmp_sqrt_divide_(), lmmp_zero, lmmp_zero_q_(), n, SQRT_NEWTON_MODM_THRESHOLD, TALLOC_TYPE, TEMP_DECL , 以及 TEMP_FREE.

被这些函数引用 lmmp_sqrt_newton_().

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ lmmp_sqrt_()

void lmmp_sqrt_ ( mp_ptr  dsts,
mp_ptr  dstr,
mp_srcptr  numa,
mp_size_t  na,
mp_size_t  nf 
)

计算 [numa,na] * B^(2*nf) 的平方根和余数

参数
dsts平方根结果输出指针
dstr余数结果输出指针(NULL表示不计算余数)
numa源操作数指针
na操作数的 limb 长度
nf精度因子
注解
if (dstr != NULL) { [dsts,nf+na/2+1], [dstr,nf+na/2+1] = sqrtrem([numa,na]*B^(2*nf)) } else { if (nf == 0) { [dsts,na/2+1] = floor(sqrt([numa,na])) } else { [dsts,nf+na/2+1] = [round|floor](sqrt([numa,na]*B^(2*nf))) } }
警告
na>0, numa[na-1]!=0, eqsep(dsts,numa), eqsep(dstr,numa)

在文件 sqrt.c276 行定义.

276 {
278 lmmp_debug_assert(numa[na - 1] > 0);
279 mp_limb_t high = numa[na - 1];
280 int nsh = lmmp_leading_zeros_(high) / 2;
281 mp_size_t nl = na + 2 * nf;
282 if (nl == 1) {
284 lmmp_sqrt_1_(&srt, high << nsh * 2);
285 srt >>= nsh;
286 dsts[0] = srt;
287 if (dstr)
288 dstr[0] = high - srt * srt;
289 } else if (!dstr && nf >= 10 * na + SQRT_NEWTON_THRESHOLD) {
291 } else {
292 TEMP_DECL;
293 mp_limb_t ns = (nl + 1) / 2;
295 if (nf)
296 lmmp_zero(numa2, 2 * nf);
297 if (nsh)
298 lmmp_shl_(numa2 + 2 * ns - na, numa, na, nsh * 2);
299 else
300 lmmp_copy(numa2 + 2 * ns - na, numa, na);
301 if (nl & 1) {
302 numa2[2 * nf] = 0;
303 nsh += LIMB_BITS / 2;
304 } else {
305 dsts[ns] = 0;
306 }
308 if (nsh) {
309 if (dstr) {
310 mp_limb_t ds = dsts[0] & (((mp_limb_t)1 << nsh) - 1);
311 rh += lmmp_addmul_1_(numa2, dsts, ns, 2 * ds);
313 if (ns == 1)
314 rh -= b;
315 else
316 rh -= lmmp_sub_1_(numa2 + 1, numa2 + 1, ns - 1, b);
317 }
319 }
320 if (dstr) {
321 numa2[ns] = rh;
322 nsh *= 2;
323 if (nsh >= LIMB_BITS) {
324 nsh -= LIMB_BITS;
325 ++numa2;
326 } else
327 ++ns;
328 if (nsh)
330 else
332 }
333 TEMP_FREE;
334 }
335}
#define lmmp_leading_zeros_
Definition inlines.h:160
#define lmmp_debug_assert(x)
Definition lmmp.h:485
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
mp_limb_t lmmp_addmul_1_(mp_ptr numa, mp_srcptr numb, mp_size_t n, mp_limb_t b)
乘以单limb并累加操作 [numa,n] += [numb,n] * b
static mp_limb_t lmmp_sub_1_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_limb_t x)
减单精度数静态内联函数 [dst,na]=[numa,na]-x
Definition lmmpn.h:1077
mp_limb_t lmmp_submul_1_(mp_ptr numa, mp_srcptr numb, mp_size_t n, mp_limb_t b)
乘以单limb并累减操作 [numa,n] -= [numb,n] * b
#define SQRT_NEWTON_THRESHOLD
Definition mparam.h:41
mp_limb_t lmmp_sqrt_1_(mp_ptr dsts, mp_limb_t x)
计算算术平方根 floor(sqrt(x))
Definition sqrt_1.c:33
static void lmmp_sqrt_newton_(mp_ptr dsts, mp_srcptr numa, mp_size_t na, mp_size_t nf)
计算近似平方根 [dsts,nf+na/2+1]=[floor|round](sqrt([numa,na]*B^(2*nf)))
Definition sqrt.c:227

引用了 LIMB_BITS, lmmp_addmul_1_(), lmmp_copy, lmmp_debug_assert, lmmp_leading_zeros_, lmmp_shl_(), lmmp_shr_(), lmmp_sqrt_1_(), lmmp_sqrt_divide_(), lmmp_sqrt_newton_(), lmmp_sub_1_(), lmmp_submul_1_(), lmmp_zero, n, SQRT_NEWTON_THRESHOLD, TALLOC_TYPE, TEMP_DECL , 以及 TEMP_FREE.

被这些函数引用 lmmp_perfsqr_().

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ lmmp_sqrt_divide_()

static mp_limb_t lmmp_sqrt_divide_ ( mp_ptr  dsts,
mp_ptr  numa,
mp_size_t  ns,
int  nsh 
)
static

Copyright (C) 2026 HJimmyK(Jericho Knox)

This file is part of LAMMP.

LAMMP is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.

This program is distributed WITHOUT ANY WARRANTY.

See https://www.gnu.org/licenses/.

分治法计算整数平方根

参数
dsts输出:平方根的整数部分,长度为 ns。
numa输入/输出:被开方数,长度为 2*ns。
  • 输入时存放原被开方数。
  • 返回时,若 nsh==0,低 ns 个 limb 存放余数。
ns平方根占用的 limb 数。
nsh右移位数(0 <= nsh < LIMB_BITS),仅顶层调用时有效。表示最终结果需要右移 nsh 位。
警告
ns>0, numa[2*ns-1]>=B/4, 0<=nsh<LIMB_BITS, dsts!=NULL, numa!=NULL
返回
返回值语义取决于 nsh 和计算路径:
  • 若 nsh == 0: 返回余数的高位 limb(rh),余数低位部分写入 [numa,ns]。
  • 若 nsh > 0:
    1. 如果 dsts[0] 的低 nsh 位非零(即右移会丢弃有效低位), 函数提前终止,直接返回 1(固定哨兵值)。 此时 numa 中的余数未经计算,不可使用;返回值 1 不代表余数高位。 (此优化用于调用者不需要余数的情况,避免昂贵的余数计算。)
    2. 如果低 nsh 位全为零,则继续计算精确余数, 并返回真实的余数高位 limb(rh),同时余数低 ns 位写入 numa。 但鉴于调用者通常不关心余数,该返回值可能被忽略。
注解
本函数被设计为递归使用,递归层级均传递 nsh=0,因此 nsh>0 的情形只可能 出现在最外层调用,且通常伴随调用者不需要余数(如 lmmp_sqrt_ 中 dstr==NULL)。

在文件 sqrt.c46 行定义.

46 {
50 lmmp_param_assert(numa[2 * ns - 1] >= LIMB_B_4);
52 if (ns == 1) {
54 } else {
55 mp_size_t lo = ns / 2, hi = ns - lo;
56 mp_limb_t qh = lmmp_sqrt_divide_(dsts + lo, numa + 2 * lo, hi, 0);
57 if (qh)
58 lmmp_sub_n_(numa + 2 * lo, numa + 2 * lo, dsts + lo, hi);
59 qh += lmmp_div_s_(dsts, numa + lo, ns, dsts + lo, hi);
60 rh = lmmp_shr_c_(dsts, dsts, lo, 1, qh << (LIMB_BITS - 1));
61 // now dsts is either correct or 1 too big,
62 // if nsh-LSBs are non-zero, subtracting 1
63 // will not affect anything after de-normalization
64 if (dsts[0] & (((mp_limb_t)1 << nsh) - 1))
65 return 1;
66 if (rh)
67 rh = lmmp_add_n_(numa + lo, numa + lo, dsts + lo, hi);
68 qh >>= 1;
69 lmmp_sqr_(numa + ns, dsts, lo);
70 mp_limb_t b = qh + lmmp_sub_n_(numa, numa, numa + ns, lo * 2);
71 if (lo == hi)
72 rh -= b;
73 else
74 rh -= lmmp_sub_1_(numa + 2 * lo, numa + 2 * lo, 1, b);
75 if (rh < 0) {
76 qh = lmmp_add_1_(dsts + lo, dsts + lo, hi, qh);
77 rh += 2 * qh + lmmp_addshl1_n_(numa, numa, dsts, ns);
78 rh -= lmmp_sub_1_(numa, numa, ns, 1);
79 qh -= lmmp_sub_1_(dsts, dsts, ns, 1);
80 }
81 }
82 return rh;
83}
int64_t mp_slimb_t
Definition lmmp.h:115
mp_limb_t lmmp_shr_c_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t shr, mp_limb_t c)
带进位的右移操作 [dst,na] = [numa,na]>>shr,dst的高shr位填充c的高shr位
Definition shr.c:40
static mp_limb_t lmmp_add_1_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_limb_t x)
加单精度数静态内联函数 [dst,na]=[numa,na]+x
Definition lmmpn.h:1066
mp_limb_t lmmp_addshl1_n_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
加法结合左移1位操作 [dst,n] = [numa,n] + ([numb,n] << 1)
Definition shl.c:66
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_add_n_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
无进位的n位加法 [dst,n] = [numa,n] + [numb,n]
Definition add_n.c:81
#define lo
mp_limb_t lmmp_sqrt_2_(mp_ptr dsts, mp_ptr dstr, mp_srcptr numa)
计算算术平方根 floor(sqrt([numa,2]))
Definition sqrt_1.c:40

引用了 LIMB_B_4, LIMB_BITS, lmmp_add_1_(), lmmp_add_n_(), lmmp_addshl1_n_(), lmmp_div_s_(), lmmp_param_assert, lmmp_shr_c_(), lmmp_sqr_, lmmp_sqrt_2_(), lmmp_sqrt_divide_(), lmmp_sub_1_(), lmmp_sub_n_(), lo , 以及 n.

被这些函数引用 lmmp_invsqrt_newton_(), lmmp_sqrt_() , 以及 lmmp_sqrt_divide_().

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ lmmp_sqrt_newton_()

static void lmmp_sqrt_newton_ ( mp_ptr  dsts,
mp_srcptr  numa,
mp_size_t  na,
mp_size_t  nf 
)
static

计算近似平方根 [dsts,nf+na/2+1]=[floor|round](sqrt([numa,na]*B^(2*nf)))

参数
dsts目标数组
numa输入数组
nanuma数组的 limb 长度
nf精度因子
警告
na>0, nf>=2, dsts!=NULL, numa!=NULL, eqsep(dsts,numa)

在文件 sqrt.c227 行定义.

227 {
229 lmmp_param_assert(nf >= 2);
231 mp_limb_t high = numa[na - 1];
232 int nsh = lmmp_leading_zeros_(high) / 2;
233 mp_size_t ns = na / 2 + 1 + nf;
234
235 TEMP_DECL;
236 mp_limb_t alloc_size = (nsh ? na : 0) + ns + 1;
238 if (nsh) {
239 numa2 = tp;
240 lmmp_shl_(numa2, numa, na, nsh * 2);
241 tp += na;
242 } else
243 numa2 = (mp_ptr)numa;
244
246
248
249 if (ns + 1 > na)
250 lmmp_mul_(msqr, tp, ns + 1, numa2, na);
251 else
252 lmmp_mul_(msqr, numa2, na, tp, ns + 1);
253
255 if (na & 1) {
256 nsh += LIMB_BITS / 2;
257 lmmp_shr_(dsts, msqr + na, ns, nsh);
258 cceil = msqr[na] >> (nsh - 1);
259 } else {
260 if (nsh) {
261 lmmp_shr_(dsts, msqr + na + 1, ns - 1, nsh);
262 cceil = msqr[na + 1] >> (nsh - 1);
263 } else {
264 lmmp_copy(dsts, msqr + na + 1, ns - 1);
265 cceil = msqr[na] >> (LIMB_BITS - 1);
266 }
267 dsts[ns - 1] = 0;
268 }
269
270 if (cceil & 1)
271 lmmp_inc(dsts);
272
273 TEMP_FREE;
274}
#define tp
static void lmmp_invsqrt_newton_(mp_ptr dstis, mp_size_t ns, mp_srcptr numa, mp_size_t na)
计算逆平方根 [dstis,ns+1]=floor(sqrt(B^(2*ns+na)/[numa,na]))-[0|1], dstis[ns]=1
Definition sqrt.c:94

引用了 LIMB_BITS, lmmp_copy, lmmp_inc, lmmp_invsqrt_newton_(), lmmp_leading_zeros_, lmmp_mul_(), lmmp_param_assert, lmmp_shl_(), lmmp_shr_(), n, TALLOC_TYPE, TEMP_DECL, TEMP_FREE , 以及 tp.

被这些函数引用 lmmp_sqrt_().

+ 函数调用图:
+ 这是这个函数的调用关系图: