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

浏览源代码.

宏定义

#define Ahr   (dst + nlo)
 
#define MMIN   1728
 

函数

mp_limb_t lmmp_cbrt_3_ (mp_limb_t a0, mp_limb_t a1, mp_limb_t a2)
 计算算数立方根 floor(cbrt(a0+a1*B+a2*B^2))
 
void lmmp_cbrt_6_ (mp_ptr dst, mp_srcptr numa, mp_size_t na)
 计算算数立方根 floor(cbrt([numa,na]))
 
mp_size_t lmmp_cbrtapprox_ (mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t na, mp_size_t ni)
 
mp_limb_t lmmp_cbrtapprox_3_ (mp_limb_t a0, mp_limb_t a1, mp_limb_t a2)
 计算近似立方根 floor(cbrt(a0+a1*B+a2*B^2))-[0|1]
 
void lmmp_cbrtapprox_6_ (mp_ptr dst, mp_srcptr numa, mp_size_t na)
 计算近似立方根 floor(cbrt([numa,na]))-[0|1]
 
static void lmmp_cube_3_ (mp_ptr restrict dst, mp_limb_t a)
 Copyright (C) 2026 HJimmyK(Jericho Knox)
 
static mp_size_t lmmp_cube_6_ (mp_ptr restrict dst, mp_srcptr restrict numa)
 

宏定义说明

◆ Ahr

#define Ahr   (dst + nlo)

◆ MMIN

#define MMIN   1728

函数说明

◆ lmmp_cbrt_3_()

mp_limb_t lmmp_cbrt_3_ ( mp_limb_t  a0,
mp_limb_t  a1,
mp_limb_t  a2 
)

计算算数立方根 floor(cbrt(a0+a1*B+a2*B^2))

参数
a0低位 limb
a1中位 limb
a2高位 limb
警告
a1>0
注解
a2可以为0,但a1需要大于0,即这个数至少应有65个bit
返回
floor(cbrt(a0+a1*B+a2*B^2))

在文件 cbrt.c84 行定义.

84 {
86
88 if (r == LIMB_MAX)
89 return LIMB_MAX;
90 mp_limb_t t[3], a[3] = {a0, a1, a2};
91 lmmp_cube_3_(t, r + 1);
92 int cmp = lmmp_cmp_(t, a, 3);
93 // approx的结果至多只会低估1
94 if (cmp <= 0)
95 return r + 1;
96 else
97 return r;
98}
mp_limb_t lmmp_cbrtapprox_3_(mp_limb_t a0, mp_limb_t a1, mp_limb_t a2)
计算近似立方根 floor(cbrt(a0+a1*B+a2*B^2))-[0|1]
Definition cbrt.c:42
static void lmmp_cube_3_(mp_ptr restrict dst, mp_limb_t a)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition cbrt.c:24
#define LIMB_MAX
Definition lmmp.h:126
uint64_t mp_limb_t
Definition lmmp.h:113
#define lmmp_param_assert(x)
Definition lmmp.h:496
static int lmmp_cmp_(mp_srcptr numa, mp_srcptr numb, mp_size_t n)
比较函数(内联)
Definition lmmpn.h:959
#define a0
#define a1
#define a2
#define t
#define n

引用了 a0, a1, a2, LIMB_MAX, lmmp_cbrtapprox_3_(), lmmp_cmp_(), lmmp_cube_3_(), lmmp_param_assert, n , 以及 t.

+ 函数调用图:

◆ lmmp_cbrt_6_()

void lmmp_cbrt_6_ ( mp_ptr  dst,
mp_srcptr  numa,
mp_size_t  na 
)

计算算数立方根 floor(cbrt([numa,na]))

参数
dst结果指针(长度为 2 个limb)
numa被开方数指针
na被开方数的 limb 长度
警告
dst!=NULL, numa!=NULL, 3<na<=6, numa[na-1]!=0, eqsep(dst,numa)

在文件 cbrt.c146 行定义.

146 {
147 mp_limb_t ret[2];
149
150 if (ret[1] == LIMB_MAX && ret[0] == LIMB_MAX) {
151 dst[0] = LIMB_MAX;
152 dst[1] = LIMB_MAX;
153 } else {
154 mp_limb_t r[2];
155 r[0] = ret[0] + 1;
156 r[1] = ret[1] + (r[0] == 0 ? 1 : 0);
157 mp_limb_t t[6];
158 mp_size_t tn = lmmp_cube_6_(t, r);
159 if (tn > na) {
160 dst[0] = ret[0];
161 dst[1] = ret[1];
162 } else {
163 lmmp_debug_assert(tn == na);
164 int cmp = lmmp_cmp_(t, numa, na);
165 // approx的结果至多只会低估1
166 if (cmp <= 0) {
167 dst[0] = r[0];
168 dst[1] = r[1];
169 } else {
170 dst[0] = ret[0];
171 dst[1] = ret[1];
172 }
173 }
174 }
175}
static mp_size_t lmmp_cube_6_(mp_ptr restrict dst, mp_srcptr restrict numa)
Definition cbrt.c:33
void lmmp_cbrtapprox_6_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
计算近似立方根 floor(cbrt([numa,na]))-[0|1]
Definition cbrt.c:100
uint64_t mp_size_t
Definition lmmp.h:114
#define lmmp_debug_assert(x)
Definition lmmp.h:485

引用了 LIMB_MAX, lmmp_cbrtapprox_6_(), lmmp_cmp_(), lmmp_cube_6_(), lmmp_debug_assert, n , 以及 t.

+ 函数调用图:

◆ lmmp_cbrtapprox_()

mp_size_t lmmp_cbrtapprox_ ( mp_ptr restrict  dst,
mp_srcptr restrict  numa,
mp_size_t  na,
mp_size_t  ni 
)

假设计算 n 次根式:A^(1/n) 设 beta = B^b,alpha = Ah^(1/n),rho = A^(1/n)。 已知 tk 满足 floor(Ah^(1/n)) - 1 <= tk <= floor(Ah^(1/n)), 因此 xk = tk * beta 与真实根 rho 的误差满足(最坏情况): e = rho - xk <= 2 * beta。

牛顿迭代实数形式为: F(x) = ((n-1)*x + A / x^(n-1)) / n。 令 x = rho - e,在 rho 处泰勒展开可得: F(x) - rho = (n(n-1)/2) * (e^2 / rho) + O(e^3 / rho^2)。

由于 rho >= alpha * beta(因为 A >= Ah * beta^n,开方后略大于 alpha*beta), 将 e <= 2*beta 代入,忽略高阶小量,得到误差上限: F(x) - rho <= (n(n-1)/2) * ((2*beta)^2 / (alpha*beta)) = (2*n*(n-1)*beta) / alpha。

为使得最终取整后的绝对误差控制在 1 以内,只需令上式 <= 1: (2*n*(n-1)*beta) / alpha <= 1 => alpha >= 2*n*(n-1)*beta。

两边同时取 n 次方: Ah >= [2*n*(n-1)]^n * beta^n = [2*n*(n-1)]^n * B^(n*b)。

因此,若要保证递归校正始终收敛且误差不超过 1,常数 m 至少取: m_min = [2*n*(n-1)]^n。

对于立方根,即有:m_min = 1728

注:1728 是一个保守的上界,不满足此上界并不意味着迭代一定不收敛。

在文件 cbrt.c177 行定义.

177 {
180 mp_size_t n = ni + na;
181 if (n == 1) {
183 dst[0] = a_cbrt;
184 return 1;
185 } else if (n <= 3) {
186 if (ni == 0)
187 dst[0] = lmmp_cbrtapprox_3_(numa[0], numa[1], numa[2]);
188 else if (ni == 1)
189 dst[0] = lmmp_cbrtapprox_3_(0, numa[0], numa[1]);
190 else
191 dst[0] = lmmp_cbrtapprox_3_(0, 0, numa[0]);
192 return 1;
193 } else if (n <= 6) {
194 mp_limb_t a[6];
195 mp_size_t i;
196 for (i = 0; i < ni; i++) {
197 a[i] = 0;
198 }
199 for (mp_size_t j = 0; i < n; i++, j++) {
200 a[i] = numa[j];
201 }
203 return 2;
204 } else {
205 /*
206 A = Ah * B^(3*lo) + Al
207
208 Ahr = floor(Ah^(1/3))
209 x_k = Ahr * B^lo
210
211 x_k+1 = (2*x_k + A / x_k^2 ) / 3
212 */
213 mp_size_t nhi = (n - 1) / 2;
214 mp_size_t nlo = nhi - (nhi % 3);
215 nhi = n - nlo;
216 /**
217 * 假设计算 n 次根式:A^(1/n)
218 * 设 beta = B^b,alpha = Ah^(1/n),rho = A^(1/n)。
219 * 已知 tk 满足 floor(Ah^(1/n)) - 1 <= tk <= floor(Ah^(1/n)),
220 * 因此 xk = tk * beta 与真实根 rho 的误差满足(最坏情况):
221 * e = rho - xk <= 2 * beta。
222 *
223 * 牛顿迭代实数形式为:
224 * F(x) = ((n-1)*x + A / x^(n-1)) / n。
225 * 令 x = rho - e,在 rho 处泰勒展开可得:
226 * F(x) - rho = (n(n-1)/2) * (e^2 / rho) + O(e^3 / rho^2)。
227 *
228 * 由于 rho >= alpha * beta(因为 A >= Ah * beta^n,开方后略大于 alpha*beta),
229 * 将 e <= 2*beta 代入,忽略高阶小量,得到误差上限:
230 * F(x) - rho <= (n(n-1)/2) * ((2*beta)^2 / (alpha*beta))
231 * = (2*n*(n-1)*beta) / alpha。
232 *
233 * 为使得最终取整后的绝对误差控制在 1 以内,只需令上式 <= 1:
234 * (2*n*(n-1)*beta) / alpha <= 1
235 * => alpha >= 2*n*(n-1)*beta。
236 *
237 * 两边同时取 n 次方:
238 * Ah >= [2*n*(n-1)]^n * beta^n
239 * = [2*n*(n-1)]^n * B^(n*b)。
240 *
241 * 因此,若要保证递归校正始终收敛且误差不超过 1,常数 m 至少取:
242 * m_min = [2*n*(n-1)]^n。
243 *
244 * 对于立方根,即有:m_min = 1728
245 *
246 * 注:1728 是一个保守的上界,不满足此上界并不意味着迭代一定不收敛。
247 */
248#define MMIN 1728
249#if LAMMP_DEBUG_ASSERT_CHECK == 1
250 if (nhi == nlo + 1) {
252 }
253#endif
254 nlo /= 3;
256
257 TEMP_DECL;
258 mp_size_t rn, Adivn = nhi + nlo;
260
261#define Ahr (dst + nlo)
262 if (ni >= 3 * nlo) {
263 // __________________ n ___________________
264 // |__________ na __________|_____ ni ____|
265 // |xxxxxxxxxxxxxxxxxxxxxxxx|0000000000000|
266 // |___________ nhi __________|__ 3*nlo __|
267
268 rn = lmmp_cbrtapprox_(Ahr, numa, na, ni - 3 * nlo);
269
271 lmmp_zero(Adiv, ni - 2 * nlo);
272 lmmp_copy(Adiv + ni - 2 * nlo, numa, na);
273
274 } else if (ni >= 2 * nlo) {
275 // __________________ n ___________________
276 // |__________ na __________|_____ ni ____|
277 // |xxxxxxxxxxxxxxxxxxxxxxxx|0000000000000|
278 // |_______ nhi _____|__ nlo _|__ 2*nlo __|
279
280 rn = lmmp_cbrtapprox_(Ahr, numa + na - nhi, nhi, 0);
281
283 lmmp_zero(Adiv, ni - 2 * nlo);
284 lmmp_copy(Adiv + ni - 2 * nlo, numa, na);
285
286 } else {
287 // __________________ n ___________________
288 // |__________ na __________|_____ ni ____|
289 // |xxxxxxxxxxxxxxxxxxxxxxxx|0000000000000|
290 // |_____ nhi ___|__ nlo__|____ 2*nlo ____|
291
292 rn = lmmp_cbrtapprox_(Ahr, numa + na - nhi, nhi, 0);
293
296 }
297
298 mp_size_t Ahr2n = rn * 2;
300 lmmp_sqr_(Ahr2, Ahr, rn);
301 Ahr2n -= (Ahr2[Ahr2n - 1] == 0) ? 1 : 0;
302
304 mp_size_t qn = Adivn - Ahr2n + 1;
305 mp_size_t rkdivn = (n + 2) / 3 + 2; // 额外多两个limb,因为需要作为加法缓冲区
307
309 lmmp_zero(rkdiv + qn, rkdivn - qn); //高位清零
310
312
313 mp_limb_t cy = lmmp_shl_(Ahr, Ahr, rn, 1);
314 Ahr[rn] = cy;
315 rn += cy > 0 ? 1 : 0;
316
317 lmmp_debug_assert(rn + nlo + 1 <= rkdivn);
318 cy = lmmp_add_n_(rkdiv + nlo, Ahr, rkdiv + nlo, rn);
319 rn += nlo;
320 rkdiv[rn] = cy;
321 rn += cy > 0 ? 1 : 0;
322
323 lmmp_div_1_(dst, rkdiv, rn, 3);
324
325 while (dst[rn - 1] == 0) --rn;
326
327 TEMP_FREE;
328 return rn;
329 }
330#undef Ahr
331}
#define Ahr
mp_size_t lmmp_cbrtapprox_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_size_t na, mp_size_t ni)
Definition cbrt.c:177
#define MMIN
#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
mp_limb_t lmmp_div_1_(mp_ptr dstq, mp_srcptr numa, mp_size_t na, mp_limb_t x)
单精度数除法
Definition div.c:77
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:78
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
ulong lmmp_cbrt_ulong_(ulong n)
计算算数立方根 floor(cbrt(n))
Definition cbrt_1.c:132
#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

引用了 Ahr, lmmp_add_n_(), lmmp_cbrt_ulong_(), lmmp_cbrtapprox_(), lmmp_cbrtapprox_3_(), lmmp_cbrtapprox_6_(), lmmp_copy, lmmp_debug_assert, lmmp_div_(), lmmp_div_1_(), lmmp_param_assert, lmmp_shl_(), lmmp_sqr_, lmmp_zero, MMIN, n, TALLOC_TYPE, TEMP_DECL , 以及 TEMP_FREE.

被这些函数引用 lmmp_cbrtapprox_().

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

◆ lmmp_cbrtapprox_3_()

mp_limb_t lmmp_cbrtapprox_3_ ( mp_limb_t  a0,
mp_limb_t  a1,
mp_limb_t  a2 
)

计算近似立方根 floor(cbrt(a0+a1*B+a2*B^2))-[0|1]

参数
a0低位 limb
a1中位 limb
a2高位 limb
警告
a1>0
注解
a2可以为0,但a1需要大于0,即这个数至少应有65个bit
返回
floor(cbrt(a0+a1*B+a2*B^2))-[0|1]

在文件 cbrt.c42 行定义.

42 {
44 mp_limb_t x[2];
45 /* exact high 65 bits */
48 if (a2 == 0) {
51 a1_bits--;
52 if (a1_bits == 0)
53 a_hi = a0;
54 else
55 a_hi = (a1 << (LIMB_BITS - a1_bits)) | (a0 >> a1_bits);
56 } else {
58 bits = LIMB_BITS * 2 + a2_bits;
59 a2_bits--;
60 if (a2_bits == 0)
61 a_hi = a1;
62 else
63 a_hi = (a2 << (LIMB_BITS - a2_bits)) | (a1 >> a2_bits);
64 }
66
67 x[1] = bits - 1;
68 x[0] = log2_fixed_64(a_hi);
69
70 mp_limb_t r = lmmp_div_1_(x, x, 2, 3);
71 if (2 * r >= 3) // round
72 lmmp_inc(x);
73
74 mp_bitcnt_t shift = x[1];
75 x[0] = exp2_fixed_64(x[0]);
76
78 if (shift == 64)
79 return LIMB_MAX;
80 else
81 return (x[0] >> (64 - shift)) | (1ULL << shift);
82}
#define lmmp_limb_bits_
Definition inlines.h:162
size_t mp_bitcnt_t
Definition lmmp.h:119
#define LIMB_BITS
Definition lmmp.h:123
#define lmmp_inc(p)
加1宏(预期无进位)
Definition lmmpn.h:901
uint64_t exp2_fixed_64(uint64_t x)
floor(exp2(x/B)*B-B), B=2^64
Definition log2_exp2.c:485
uint64_t log2_fixed_64(uint64_t x)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition log2_exp2.c:458

引用了 a0, a1, a2, exp2_fixed_64(), LIMB_BITS, LIMB_MAX, lmmp_debug_assert, lmmp_div_1_(), lmmp_inc, lmmp_limb_bits_, lmmp_param_assert, log2_fixed_64() , 以及 n.

被这些函数引用 lmmp_cbrt_3_() , 以及 lmmp_cbrtapprox_().

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

◆ lmmp_cbrtapprox_6_()

void lmmp_cbrtapprox_6_ ( mp_ptr  dst,
mp_srcptr  numa,
mp_size_t  na 
)

计算近似立方根 floor(cbrt([numa,na]))-[0|1]

参数
dst结果指针(长度为 2 个limb)
numa被开方数指针
na被开方数的 limb 长度
警告
dst!=NULL, numa!=NULL, 3<na<=6, numa[na-1]!=0, eqsep(dst,numa)

在文件 cbrt.c100 行定义.

100 {
101 lmmp_param_assert(na > 3 && na <= 6);
103 lmmp_param_assert(numa[na - 1] != 0);
104 /* extract the first 129 bits */
105 int bits = lmmp_limb_bits_(numa[na - 1]);
106 mp_bitcnt_t n = bits - 1;
108 if (bits == 1) {
109 high = numa[na - 2];
110 low = numa[na - 3];
111 } else {
112 bits--;
113 high = (numa[na - 1] << (64 - bits)) | (numa[na - 2] >> bits);
114 low = (numa[na - 2] << (64 - bits)) | (numa[na - 3] >> bits);
115 }
116
117 n += LIMB_BITS * (na - 1);
118 mp_limb_t x[3] = {0, 0, n};
119
121 mp_limb_t r = lmmp_div_1_(x, x, 3, 3);
122 if (2 * r >= 3) // round
123 lmmp_inc(x);
124
125 n = x[2];
126 high = x[1];
127 low = x[0];
128
130
131 lmmp_debug_assert(n >= 64 && n <= 128);
132 if (n == 64) {
133 dst[0] = x[1];
134 dst[1] = 1;
135 } else if (n < 128) {
136 n -= 64;
137 mp_limb_t t = 1ULL << n;
138 dst[1] = (x[1] >> (64 - n)) | t;
139 dst[0] = (x[1] << n) | (x[0] >> (64 - n));
140 } else {
141 dst[1] = LIMB_MAX;
142 dst[0] = LIMB_MAX;
143 }
144}
void exp2_fixed_128(uint64_t *dst, uint64_t high, uint64_t low)
floor(exp2(x/B)*B-B), B=2^128
Definition log2_exp2.c:409
void log2_fixed_128(uint64_t *dst, uint64_t high, uint64_t low)
floor(log2(1+x/B)*B), B=2^128
Definition log2_exp2.c:292

引用了 exp2_fixed_128(), LIMB_BITS, LIMB_MAX, lmmp_debug_assert, lmmp_div_1_(), lmmp_inc, lmmp_limb_bits_, lmmp_param_assert, log2_fixed_128(), n , 以及 t.

被这些函数引用 lmmp_cbrt_6_() , 以及 lmmp_cbrtapprox_().

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

◆ lmmp_cube_3_()

static void lmmp_cube_3_ ( mp_ptr restrict  dst,
mp_limb_t  a 
)
inlinestatic

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/.

在文件 cbrt.c24 行定义.

24 {
25 mp_limb_t t[2];
26 lmmp_mullh_(a, a, t);
27 lmmp_mullh_(t[0], a, dst);
28 lmmp_mullh_(t[1], a, t);
29 dst[1] += t[0];
30 dst[2] = t[1] + (dst[1] < t[0] ? 1 : 0);
31}
#define lmmp_mullh_
Definition inlines.h:164

引用了 lmmp_mullh_, n , 以及 t.

被这些函数引用 lmmp_cbrt_3_().

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

◆ lmmp_cube_6_()

static mp_size_t lmmp_cube_6_ ( mp_ptr restrict  dst,
mp_srcptr restrict  numa 
)
inlinestatic

在文件 cbrt.c33 行定义.

33 {
34 mp_limb_t t[4];
37 mp_size_t n = 6;
38 while (dst[n - 1] == 0) --n;
39 return n;
40}
void lmmp_sqr_basecase_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
基础平方运算 [dst,2*na] = [numa,na]^2
void lmmp_mul_basecase_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
基础乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]

引用了 lmmp_mul_basecase_(), lmmp_sqr_basecase_(), n , 以及 t.

被这些函数引用 lmmp_cbrt_6_().

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