LAMMP 4.1.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
from_str.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/impl/mparam.h"
8#include "../../include/lammp/impl/tmp_alloc.h"
9#include "../../include/lammp/impl/base_table.h"
10#include "../../include/lammp/lmmpn.h"
11
12
13mp_size_t lmmp_from_str_len_(const mp_byte_t* src, mp_size_t len, int base) {
14 lmmp_param_assert(base >= 2 && base <= 256);
15 if (src) {
16 do {
17 if (len == 0)
18 return 1;
19 } while (src[--len] == 0);
20 ++len;
21 }
22 return lmmp_mulh_(len, lmmp_bases_table[base - 2].lg_base) + 1;
23}
24
25// assume src[len-1]!=0
26static mp_size_t lmmp_from_str_basecase_(mp_ptr dst, const mp_byte_t* src, mp_size_t len, int base) {
27 lmmp_param_assert(src[len - 1] != 0);
28 mp_size_t digitspl = lmmp_bases_table[base - 2].digits_in_limb;
29 mp_limb_t lbase = lmmp_bases_table[base - 2].large_base;
30 mp_size_t limbs = 0, i = len;
31
32 while (i) {
33 mp_limb_t curlimb;
34 if (i >= digitspl) {
35 curlimb = src[--i];
36 for (mp_size_t j = 1; j < digitspl; ++j) {
37 curlimb = curlimb * base + src[--i];
38 }
39 } else {
40 curlimb = src[--i];
41 lbase = base;
42 while (i) {
43 curlimb = curlimb * base + src[--i];
44 lbase *= base;
45 }
46 }
47
48 if (limbs == 0) {
49 dst[0] = curlimb;
50 limbs = 1;
51 } else {
52 mp_limb_t cy = lmmp_mul_1_(dst, dst, limbs, lbase);
53 cy += lmmp_add_1_(dst, dst, limbs, curlimb);
54 if (cy) {
55 dst[limbs] = cy;
56 ++limbs;
57 }
58 }
59 }
60
61 return limbs;
62}
63
64// assume src[len-1]!=0
65// N=pow->np+pow->zeros
66// limbs=return value
67// 1st level need(nh>=2, [dst,2*N], [tp,limbs])
68// recursive need(N>=2, [dst,limbs+1], [tp,2*N-1])
70 mp_ptr dst,
71 const mp_byte_t* src,
72 mp_size_t len,
73 mp_basepow_t* pow,
75) {
76 lmmp_param_assert(src[len - 1] != 0);
77 mp_size_t limbs;
78
80 limbs = lmmp_from_str_basecase_(dst, src, len, pow->base);
81 } else {
82 mp_size_t pdigits = pow->digits;
83 if (len <= pdigits) {
84 limbs = lmmp_from_str_divide_(dst, src, len, pow - 1, tp);
85 } else {
86 mp_ptr p = pow->p;
87 mp_size_t np = pow->np;
88 mp_size_t zeros = pow->zeros;
89 mp_ptr lp = tp, hp = tp + np + zeros - 2; // overwrite 2 limbs
90 mp_size_t nl = 0, nh;
91
92 mp_size_t llen = pdigits;
93 while (llen && src[llen - 1] == 0) --llen;
94 if (llen)
95 nl = lmmp_from_str_divide_(lp, src, llen, pow - 1, dst);
96
97 mp_limb_t save0 = hp[0], save1 = hp[1]; // save 2 limbs
98 nh = lmmp_from_str_divide_(hp, src + pdigits, len - pdigits, pow - 1, dst);
99 if (nh >= np)
100 lmmp_mul_(dst + zeros, hp, nh, p, np);
101 else
102 lmmp_mul_(dst + zeros, p, np, hp, nh);
103 // restore 2 limbs
104 hp[0] = save0;
105 hp[1] = save1;
106
107 if (zeros < nl) {
108 lmmp_copy(dst, lp, zeros);
109 mp_limb_t cy = lmmp_add_n_(dst + zeros, dst + zeros, lp + zeros, nl - zeros);
110 // h*p+l<=(B^nh-1)*p+(p-1)<B^nh*p, limited by nh+np limbs,
111 // so inc won't overflow
112 if (cy)
113 lmmp_inc(dst + nl);
114 } else {
115 lmmp_copy(dst, lp, nl);
116 if (zeros > nl)
117 lmmp_zero(dst + nl, zeros - nl);
118 }
119
120 limbs = nh + np + zeros;
121 limbs -= dst[limbs - 1] == 0;
122 }
123 }
124
125 return limbs;
126}
127
128mp_size_t lmmp_from_str_(mp_ptr dst, const mp_byte_t* src, mp_size_t len, int base) {
129 do {
130 if (len == 0)
131 return 0;
132 } while (src[--len] == 0);
133 ++len;
134
135 mp_size_t limbs;
136 if (LMMP_POW2_Q(base)) {
137 mp_limb_t curlimb = 0;
138 const mp_byte_t* srcend = src + len;
139 int bitspd = lmmp_bases_table[base - 2].large_base;
140 int bitpos = 0;
141 limbs = 0;
142
143 do {
144 mp_limb_t curdigit = *src;
145 curlimb |= curdigit << bitpos;
146 bitpos += bitspd;
147 if (bitpos >= LIMB_BITS) {
148 dst[limbs] = curlimb;
149 ++limbs;
150 bitpos -= LIMB_BITS;
151 curlimb = curdigit >> (bitspd - bitpos);
152 }
153 } while (++src != srcend);
154 if (curlimb) {
155 dst[limbs] = curlimb;
156 ++limbs;
157 }
158 } else if (lmmp_from_str_len_(0, len, base) < FROM_STR_BASEPOW_THRESHOLD) {
159 limbs = lmmp_from_str_basecase_(dst, src, len, base);
160 } else {
161 TEMP_DECL;
162 mp_basepow_t powers[LIMB_BITS];
163 mp_limb_t lbase = lmmp_bases_table[base - 2].large_base;
164 mp_size_t digitspl = lmmp_bases_table[base - 2].digits_in_limb;
165 mp_size_t bexp, lexp = (len - 1) / digitspl + 1;
166 mp_size_t tzbit = lmmp_tailing_zeros_(lbase);
167 // need 1 extra limb to store result
168 mp_size_t alloc_size = lmmp_from_str_len_(0, len, base) + 1;
169 mp_limb_t cy;
170 mp_ptr tp;
171
172 int cpow = lmmp_limb_bits_(lexp - 1);
173
174 for (int i = cpow; i > 0; --i) {
175 // we will calculate lbase^bexp
176 bexp = ((lexp - 1) >> i) + 1;
177 // we will calculate lbase^(bexp-1) first, and trim it s. t.
178 // it contains at most 2 tailing 0 limb, then multiply it by lbase,
179 // so we need npow limbs to store lbase^bexp
180 mp_size_t npow = lmmp_from_str_len_(0, (bexp - 1) * digitspl + 1, base) + 1;
181
182 if (tzbit) {
183 mp_size_t tzlimb = tzbit * (bexp - 1) / LIMB_BITS;
184 if (tzlimb >= 2)
185 npow -= tzlimb - 2;
186 }
187
188 // space needed for a trimmed npow-limb lbase^bexp
189 alloc_size += npow;
190 }
191
192 tp = BALLOC_TYPE(alloc_size, mp_limb_t);
193
194 for (int i = 0; i < 2; ++i) {
195 tp[0] = lbase;
196 powers[i].p = tp;
197 powers[i].np = 1;
198 tp += i + 1;
199 powers[i].zeros = 0;
200 powers[i].digits = digitspl * (i + 1);
201 powers[i].base = base;
202 }
203
204 mp_ptr p = powers[1].p;
205 mp_size_t zeros = 0, np = 1;
206 for (int i = 2; i < cpow; ++i) {
207 lmmp_sqr_(tp, p, np);
208 np *= 2;
209 np -= tp[np - 1] == 0;
210 bexp = (lexp - 1) >> (cpow - i);
211 if (bexp & 1) {
212 cy = lmmp_mul_1_(tp, tp, np, lbase);
213 tp[np] = cy;
214 np += cy != 0;
215 }
216 zeros *= 2;
217 while (tp[0] == 0) {
218 // at most 2 tailing 0 limb here
219 ++zeros;
220 ++tp;
221 --np;
222 }
223 p = tp;
224 powers[i].p = p;
225 powers[i].np = np;
226 powers[i].zeros = zeros;
227 powers[i].digits = digitspl * (bexp + 1);
228 powers[i].base = base;
229 tp += np + 1;
230 }
231
232 for (int i = 1; i < cpow; ++i) {
233 p = powers[i].p;
234 np = powers[i].np;
235 cy = lmmp_mul_1_(p, p, np, lbase);
236 p[np] = cy;
237 np += cy != 0;
238 if (p[0] == 0) {
239 ++powers[i].zeros;
240 ++p;
241 --np;
242 }
243
244 powers[i].p = p;
245 powers[i].np = np;
246 }
247
248 limbs = lmmp_from_str_divide_(tp, src, len, powers + cpow - 1, dst);
249 lmmp_copy(dst, tp, limbs);
250
251 TEMP_FREE;
252 }
253 return limbs;
254}
int digits_in_limb
Definition base_table.h:37
mp_size_t digits
Definition base_table.h:54
mp_size_t np
Definition base_table.h:46
const mp_base_t lmmp_bases_table[255]
Definition base_table.c:9
mp_limb_t large_base
Definition base_table.h:28
mp_size_t zeros
Definition base_table.h:52
mp_size_t lmmp_from_str_(mp_ptr dst, const mp_byte_t *src, mp_size_t len, int base)
字符串转大数操作 [src,len,base] to [dst,return value,B]
Definition from_str.c:128
static mp_size_t lmmp_from_str_basecase_(mp_ptr dst, const mp_byte_t *src, mp_size_t len, int base)
Definition from_str.c:26
static mp_size_t lmmp_from_str_divide_(mp_ptr dst, const mp_byte_t *src, mp_size_t len, mp_basepow_t *pow, mp_ptr tp)
Definition from_str.c:69
mp_size_t lmmp_from_str_len_(const mp_byte_t *src, mp_size_t len, int base)
计算字符串转大数所需的 limb 缓冲区长度
Definition from_str.c:13
mp_limb_t * mp_ptr
Definition lmmp.h:215
uint8_t mp_byte_t
Definition lmmp.h:210
#define lmmp_copy(dst, src, n)
Definition lmmp.h:364
#define lmmp_zero(dst, n)
Definition lmmp.h:366
#define LMMP_POW2_Q(n)
Definition lmmp.h:359
uint64_t mp_size_t
Definition lmmp.h:212
uint64_t mp_limb_t
Definition lmmp.h:211
#define LIMB_BITS
Definition lmmp.h:221
#define lmmp_param_assert(x)
Definition lmmp.h:398
int lmmp_tailing_zeros_(mp_limb_t x)
计算一个单精度数(limb)中末尾零的个数
Definition tiny.c:54
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:1111
#define lmmp_inc(p)
大数加1宏(预期无进位)
Definition lmmpn.h:946
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]
void lmmp_sqr_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
大数平方操作 [dst,2*na] = [numa,na]^2
Definition sqr.c:10
mp_limb_t lmmp_mulh_(mp_limb_t a, mp_limb_t b)
计算两个64位无符号整数相乘的高位结果 (a*b)/2^64
Definition tiny.c:73
int lmmp_limb_bits_(mp_limb_t x)
计算满足 2^k > x 的最小自然数k
Definition tiny.c:11
mp_limb_t lmmp_mul_1_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_limb_t x)
大数乘以单limb操作 [dst,na] = [numa,na] * x
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:71
#define FROM_STR_BASEPOW_THRESHOLD
Definition mparam.h:74
#define FROM_STR_DIVIDE_THRESHOLD
Definition mparam.h:72
#define tp
#define TEMP_DECL
Definition tmp_alloc.h:72
#define TEMP_FREE
Definition tmp_alloc.h:93
#define BALLOC_TYPE(n, type)
Definition tmp_alloc.h:89