LAMMP 4.1.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
lmmpn.h
浏览该文件的文档.
1/*
2 * [LAMMP]
3 * Copyright (C) [2025-2026] [HJimmyK(Jericho Knox)]
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19/*
20 本库的实现部分灵感来源于或改编自
21
22 GNU-MP (https://gmplib.org/),
23 FLINT (https://www.flintlib.org/),
24
25 符号说明:
26
27 B 基数,固定为 2^64
28
29 [p,n,b] 表示指针p指向的、以b为基数的n位数
30 p[i-1] 代表其第i位最低有效位 (0<i<=n)
31 如果省略b,则默认基数为B。通常情况下,
32 用此符号表示函数参数时,一般暗指高位不存在0,
33 而用此符号表示函数返回值时,表示将会写入的区间,
34 即使可能写入为0。
35
36 sep 指针指向的内存区域完全分离
37
38 eqsep 完全相同的内存区域或者完全分离
39
40 备注:我们都假定地址是向上增长的,dst <= num+1
41 的内存布局可以这样表示
42 dst ──┐
43 num ──┐ |00000000|00000000|
44 |********|********|
45
46 MSB(x) x的最高有效位,比如最高有效位为1,MSB(x)=1
47 代表 x >= B / 2
48
49 [x|y] x或y,用于表示参数或返回值的取值范围
50*/
51
52#ifndef LAMMP_LMMPN_H
53#define LAMMP_LMMPN_H
54
55#include <stdbool.h>
56#include <stdio.h>
57#include "lmmp.h"
58
59#define INLINE_ static inline
60
61#ifdef __cplusplus
62extern "C" {
63#endif
64
65/**
66 * @brief 运行时判断端序
67 * @return true 表示小端序,false 表示大端序
68 */
69INLINE_ bool lmmp_endian(void) {
70 int num = 1;
71 return (*(char*)&num) == 0;
72}
73
74/**
75 * @brief 计算满足 2^k > x 的最小自然数k
76 * @param x 输入的64位无符号整数
77 * @return 满足条件的最小自然数k
78 */
80
81/**
82 * @brief 计算一个64位无符号整数中1的个数
83 * @param x 输入的64位无符号整数
84 * @return 1的个数
85 */
87
88/**
89 * @brief 计算一个单精度数(limb)中前导零的个数
90 * @param x 输入的64位无符号整数
91 * @return 前导零的位数(范围:0~64)
92 */
94
95/**
96 * @brief 计算一个单精度数(limb)中末尾零的个数
97 * @param x 输入的64位无符号整数
98 * @return 末尾零的位数(范围:0~64)
99 */
101
102/**
103 * @brief 计算两个64位无符号整数相乘的高位结果 (a*b)/2^64
104 * @param a 第一个64位无符号整数
105 * @param b 第二个64位无符号整数
106 * @return 乘积的高64位结果
107 */
109
110/**
111 * @brief 计算两个64位无符号整数相乘的128位结果 (a*b)
112 * @param dst 输出结果缓冲区,存储乘积结果,长度为 2
113 * @param a 第一个64位无符号整数
114 * @param b 第二个64位无符号整数
115 * @warning dst 必须指向一个长度为 2 的数组
116 * @return 无返回值
117 */
119
120/**
121 * @brief 带进位的n位加法 [dst,n] = [numa,n] + [numb,n] + c
122 * @param dst 结果输出指针
123 * @param numa 第一个加数指针
124 * @param numb 第二个加数指针
125 * @param n limb长度
126 * @param c 初始进位值 [0|1]
127 * @warning c=[0|1], n>0, eqsep(dst,[numa|numb])
128 * @return 运算后的最终进位值 [0|1]
129 */
131
132/**
133 * @brief 无进位的n位加法 [dst,n] = [numa,n] + [numb,n]
134 * @param dst 结果输出指针
135 * @param numa 第一个加数指针
136 * @param numb 第二个加数指针
137 * @param n limb长度
138 * @warning n>0, eqsep(dst,[numa|numb])
139 * @return 运算后的最终进位值 [0|1]
140 */
142
143/**
144 * @brief 带借位的n位减法 [dst,n] = [numa,n] - [numb,n] - c
145 * @param dst 结果输出指针
146 * @param numa 被减数指针
147 * @param numb 减数指针
148 * @param n limb长度
149 * @param c 初始借位值 [0|1]
150 * @warning c=[0|1], n>0, eqsep(dst,[numa|numb])
151 * @return 运算后的最终借位值 [0|1]
152 */
154
155/**
156 * @brief 无借位的n位减法 [dst,n] = [numa,n] - [numb,n]
157 * @param dst 结果输出指针
158 * @param numa 被减数指针
159 * @param numb 减数指针
160 * @param n limb长度
161 * @warning n>0, eqsep(dst,[numa|numb])
162 * @return 运算后的最终借位值 [0|1]
163 */
165
166/**
167 * @brief 同时执行n位加法和减法 ([dsta,n],[dstb,n]) = ([numa,n]+[numb,n],[numa,n]-[numb,n])
168 * @param dsta 加法结果输出指针
169 * @param dstb 减法结果输出指针
170 * @param numa 第一个操作数指针(被加数/被减数)
171 * @param numb 第二个操作数指针(加数/减数)
172 * @param n limb长度
173 * @warning n>0, eqsep(dsta,[numa|numb]), eqsep(dstb,[numa|numb])
174 * @return 组合返回值 cb = 2*c + b (c为加法进位, b为减法借位)
175 * 返回值范围: 0(无进位无借位),1(无进位有借位),2(有进位无借位),3(有进位有借位)
176 */
178
179/**
180 * @brief 加法后右移1位 [dst,n] = ([numa,n] + [numb,n]) >> 1
181 * @param dst 结果输出指针
182 * @param numa 第一个加数指针
183 * @param numb 第二个加数指针
184 * @param n limb长度
185 * @warning n>0, eqsep(dst,[numa|numb])
186 * @return 右移操作产生的进位值 [0|1]
187 */
189
190/**
191 * @brief 带进位加法后右移1位 [dst,n] = ([numa,n] + [numb,n] + c) >> 1
192 * @param dst 结果输出指针
193 * @param numa 第一个加数指针
194 * @param numb 第二个加数指针
195 * @param n limb长度
196 * @param c 初始进位值 [0|1]
197 * @warning n>0, c=[0|1], eqsep(dst,[numa|numb])
198 * @return 右移操作产生的进位值 [0|1]
199 */
201
202/**
203 * @brief 减法后右移1位 [dst,n] = ([numa,n] - [numb,n]) >> 1
204 * @param dst 结果输出指针
205 * @param numa 被减数指针
206 * @param numb 减数指针
207 * @param n 操作数的位数(limb数量)
208 * @warning n>0, eqsep(dst,[numa|numb])
209 * @return 右移操作产生的进位值 (0或1)
210 */
212
213/**
214 * @brief 带借位减法后右移1位 [dst,n] = ([numa,n] - [numb,n] - c) >> 1
215 * @param dst 结果输出指针
216 * @param numa 被减数指针
217 * @param numb 减数指针
218 * @param n limb长度
219 * @param c 初始借位值 [0|1]
220 * @warning n>0, c=[0|1], eqsep(dst,[numa|numb])
221 * @return 右移操作产生的进位值 [0|1]
222 */
224
225/**
226 * @brief 大数右移操作 [dst,na] = [numa,na] >> shr,dst的高shr位填充0
227 * @param dst 结果输出指针
228 * @param numa 源操作数指针
229 * @param na limb长度
230 * @param shr 右移的位数 (0~63)
231 * @warning na>0, 0<=shr<64, eqsep(dst,numa)
232 * 允许dst指针地址小于numa(即支持原地长移位操作)
233 * @return 其最高shr个比特位填充[numa,na]被移出的shr个最低位,其余比特位为0
234 */
236
237/**
238 * @brief 带进位的大数右移操作 [dst,na] = [numa,na]>>shr,dst的高shr位填充c的高shr位
239 * @param dst 结果输出指针
240 * @param numa 源操作数指针
241 * @param na limb长度
242 * @param shr 右移的位数 (0~63)
243 * @param c 进位值(其低(64-shr)位必须为0)
244 * @warning na>0, 0<=shr<64, eqsep(dst,numa)
245 * c的低(64-shr)位必须为0
246 * 允许dst指针地址小于numa(即支持原地长移位操作)
247 * @return 其最高shr个比特位填充[numa,na]被移出的shr个最低位,其余比特位为0
248 */
250
251/**
252 * @brief 大数左移操作 [dst,na] = [numa,na]<<shl,dst的低shl位填充0
253 * @param dst 结果输出指针
254 * @param numa 源操作数指针
255 * @param na limb长度
256 * @param shl 左移的位数 (0~63)
257 * @warning na>0, 0<=shl<64, eqsep(dst,numa)
258 * 允许dst指针地址大于numa(即支持原地长移位操作)
259 * @return 其最低shl个比特位填充[numa,na]被移出的shl个最高位,其余比特位为0
260 */
262
263/**
264 * @brief 带进位的大数左移操作 [dst,na] = [numa,na]<<shl,dst的低shl位填充c的低shl位
265 * @param dst 结果输出指针
266 * @param numa 源操作数指针
267 * @param na limb长度
268 * @param shl 左移的位数 (0~63)
269 * @param c 进位值(其高(64-shl)位必须为0)
270 * @warning na>0, 0<=shl<64, eqsep(dst,numa)
271 * c的高(64-shl)位必须为0
272 * 允许dst指针地址大于numa(即支持原地长移位操作)
273 * @return 其最低shl个比特位填充[numa,na]被移出的shl个最高位,其余比特位为0
274 */
276
277/**
278 * @brief 大数按位取反操作 [dst,na] = ~[numa,na] (对每个limb执行按位非操作)
279 * @param dst 结果输出指针
280 * @param numa 源操作数指针
281 * @param na limb长度
282 * @warning na>0, eqsep(dst,numa)
283 */
285
286/**
287 * @brief 左移后按位取反操作 [dst,na] = ~([numa,na] << shl),dst的低shl位填充1
288 * @param dst 结果输出指针
289 * @param numa 源操作数指针
290 * @param na limb长度
291 * @param shl 左移的位数 (0~63)
292 * @warning na>0, 0<=shl<64, eqsep(dst,numa)
293 * @return 其最低shl个比特位填充[numa,na]被移出的shl个最高位,其余比特位为0
294 */
296
297/**
298 * @brief 加法结合左移1位操作 [dst,n] = [numa,n] + ([numb,n] << 1)
299 * @param dst 结果输出指针
300 * @param numa 被加数指针
301 * @param numb 加数指针(先左移1位)
302 * @param n limb长度
303 * @warning n>0, eqsep(dst,[numa|numb])
304 * @return 运算后的进位值 [0|1|2]
305 */
307
308/**
309 * @brief 减法结合左移1位操作 [dst,n] = [numa,n] - ([numb,n] << 1)
310 * @param dst 结果输出指针
311 * @param numa 被减数指针
312 * @param numb 减数指针(先左移1位)
313 * @param n limb长度
314 * @warning n>0, eqsep(dst,[numa|numb])
315 * @return 运算后的借位值 [0|1|2]
316 */
318
319/**
320 * @brief 大数乘以单limb并累加操作 [numa,n] += [numb,n] * b
321 * @param numa 被加数指针(结果也存储在此)
322 * @param numb 乘数指针
323 * @param n limb长度
324 * @param b 乘数
325 * @warning n>0, eqsep(numa,numb))
326 * @return 运算后的进位limb值
327 */
329
330/**
331 * @brief 大数乘以单limb并累减操作 [numa,n] -= [numb,n] * b
332 * @param numa 被减数指针(结果也存储在此)
333 * @param numb 乘数指针
334 * @param n limb长度
335 * @param b 乘数
336 * @warning n>0, eqsep(numa,numb))
337 * @return 运算后的借位limb值
338 */
340
341/**
342 * @brief 大数乘以单limb操作 [dst,na] = [numa,na] * x
343 * @param dst 结果输出指针
344 * @param numa 被乘数指针
345 * @param na 操作数的位数(limb数量)
346 * @param x 单个limb乘数
347 * @warning na>0, eqsep(dst,numa)
348 * 支持 dst<=numa+1 的内存布局
349 * @return 运算后的进位limb值
350 */
352
353/**
354 * @brief 基础平方运算 [dst,2*na] = [numa,na]^2
355 * @param dst 输出结果缓冲区,长度至少为2*na
356 * @param numa 输入操作数,长度为na
357 * @param na 输入操作数的 limb 长度
358 * @warning 0<na, sep(dst,numa)
359 * @return 无返回值,结果存储在dst中
360 */
362
363/**
364 * @brief Toom-2平方运算 [dst,2*na] = [numa,na]^2
365 * @param dst 输出结果缓冲区,长度至少为 2*na
366 * @param numa 输入操作数,长度为na
367 * @param na 输入操作数的 limb 长度
368 * @warning ??<na, sep(dst,numa)
369 * @return 无返回值,结果存储在dst中
370 */
372
373/**
374 * @brief Toom-3平方运算 [dst,2*na] = [numa,na]^2
375 * @param dst 输出结果缓冲区,长度至少为2*na
376 * @param numa 输入操作数,长度为na
377 * @param na 输入操作数的单精度数(limb)长度
378 * @warning ??<na, sep(dst,numa)
379 * @return 无返回值,结果存储在dst中
380 */
382
383/**
384 * @brief Toom-4平方运算 [dst,2*na] = [numa,na]^2
385 * @param dst 输出结果缓冲区,长度至少为2*na
386 * @param numa 输入操作数,长度为na
387 * @param na 输入操作数的单精度数(limb)长度
388 * @warning ??<na, sep(dst,numa)
389 * @return 无返回值,结果存储在dst中
390 */
392
393/**
394 * @brief 基础乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
395 * @param dst 输出结果缓冲区,长度至少为 na+nb
396 * @param numa 第一个输入操作数,长度为 na
397 * @param na 第一个操作数的 limb 长度
398 * @param numb 第二个输入操作数,长度为 nb
399 * @param nb 第二个操作数的 limb 长度
400 * @warning 0<nb<=na, sep(dst,[numa|numb])
401 * @return 无返回值,结果存储在dst中
402 */
404
405/**
406 * @brief Toom-22乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
407 * @param dst 输出结果缓冲区,长度至少为 na+nb
408 * @param numa 第一个输入操作数,长度为 na
409 * @param na 第一个操作数的 limb 长度
410 * @param numb 第二个输入操作数,长度为 nb
411 * @param nb 第二个操作数的 limb 长度
412 * @warning 4/5<=nb/na<=1, nb>=5, sep(dst,[numa|numb])
413 * @return 无返回值,结果存储在dst中
414 */
416
417/**
418 * @brief Toom-32乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
419 * @param dst 输出结果缓冲区,长度至少为 na+nb
420 * @param numa 第一个输入操作数,长度为 na
421 * @param na 第一个操作数的 limb 长度
422 * @param numb 第二个输入操作数,长度为 nb
423 * @param nb 第二个操作数的 limb 长度
424 * @warning 5/9<=nb/na<=4/5, nb>=12, sep(dst,[numa|numb])
425 * @return 无返回值,结果存储在dst中
426 */
428
429/**
430 * @brief Toom-33乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
431 * @param dst 输出结果缓冲区,长度至少为 na+nb
432 * @param numa 第一个输入操作数,长度为 na
433 * @param na 第一个操作数的 limb 长度
434 * @param numb 第二个输入操作数,长度为 nb
435 * @param nb 第二个操作数的 limb 长度
436 * @warning 4/5<=nb/na<=1, nb>=26, sep(dst,[numa|numb])
437 * @return 无返回值,结果存储在dst中
438 */
440
441/**
442 * @brief Toom-42乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
443 * @param dst 输出结果缓冲区,长度至少为 na+nb
444 * @param numa 第一个输入操作数,长度为 na
445 * @param na 第一个操作数的 limb 长度
446 * @param numb 第二个输入操作数,长度为 nb
447 * @param nb 第二个操作数的 limb 长度
448 * @warning 1/3<=nb/na<=5/9, nb>=20, sep(dst,[numa|numb])
449 * @return 无返回值,结果存储在dst中
450 */
452
453/**
454 * @brief Toom-42不平衡乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
455 * @param dst 输出结果缓冲区,长度至少为 na+nb
456 * @param numa 第一个输入操作数,长度为 na
457 * @param na 第一个操作数的 limb 长度
458 * @param numb 第二个输入操作数,长度为 nb
459 * @param nb 第二个操作数的 limb 长度
460 * @warning na>=3*nb, nb>=20, sep(dst,[numa|numb])
461 * @return 无返回值,结果存储在dst中
462 */
464
465/**
466 * @brief Toom-43乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
467 * @param dst 输出结果缓冲区,长度至少为 na+nb
468 * @param numa 第一个输入操作数,长度为 na
469 * @param na 第一个操作数的 limb 长度
470 * @param numb 第二个输入操作数,长度为 nb
471 * @param nb 第二个操作数的 limb 长度
472 * @warning 3/5<=nb/na<=4/5, nb>=??, sep(dst,[numa|numb])
473 * @return 无返回值,结果存储在dst中
474 */
476
477/**
478 * @brief Toom-44乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
479 * @param dst 输出结果缓冲区,长度至少为 na+nb
480 * @param numa 第一个输入操作数,长度为 na
481 * @param na 第一个操作数的 limb 长度
482 * @param numb 第二个输入操作数,长度为 nb
483 * @param nb 第二个操作数的 limb 长度
484 * @warning 4/5<=nb/na<=1, nb>=??, sep(dst,[numa|numb])
485 * @return 无返回值,结果存储在dst中
486 */
488
489/**
490 * @brief Toom-52乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
491 * @param dst 输出结果缓冲区,长度至少为 na+nb
492 * @param numa 第一个输入操作数,长度为 na
493 * @param na 第一个操作数的 limb 长度
494 * @param numb 第二个输入操作数,长度为 nb
495 * @param nb 第二个操作数的 limb 长度
496 * @warning 1/3<=nb/na<=9/20, nb>=??, sep(dst,[numa|numb])
497 * @return 无返回值,结果存储在dst中
498 */
500
501/**
502 * @brief Toom-53乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
503 * @param dst 输出结果缓冲区,长度至少为 na+nb
504 * @param numa 第一个输入操作数,长度为 na
505 * @param na 第一个操作数的 limb 长度
506 * @param numb 第二个输入操作数,长度为 nb
507 * @param nb 第二个操作数的 limb 长度
508 * @warning 9/20<=nb/na<=3/5, nb>=??, sep(dst,[numa|numb])
509 * @return 无返回值,结果存储在dst中
510 */
512
513/**
514 * @brief Toom-62乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
515 * @param dst 输出结果缓冲区,长度至少为 na+nb
516 * @param numa 第一个输入操作数,长度为 na
517 * @param na 第一个操作数的 limb 长度
518 * @param numb 第二个输入操作数,长度为 nb
519 * @param nb 第二个操作数的 limb 长度
520 * @warning 1/5<=nb/na<=1/3, nb>=??, sep(dst,[numa|numb])
521 * @return 无返回值,结果存储在dst中
522 */
524
525/**
526 * @brief Toom-62不平衡乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
527 * @param dst 输出结果缓冲区,长度至少为 na+nb
528 * @param numa 第一个输入操作数,长度为 na
529 * @param na 第一个操作数的 limb 长度
530 * @param numb 第二个输入操作数,长度为 nb
531 * @param nb 第二个操作数的 limb 长度
532 * @warning na>=5*nb, nb>=??, sep(dst,[numa|numb])
533 * @return 无返回值,结果存储在dst中
534 */
536
537/**
538 * @brief 计算满足 >=n 的最小费马/梅森乘法可行尺寸
539 * @param n 输入的目标尺寸
540 * @return 满足条件的SSA乘法最小尺寸
541 */
543
544/**
545 * @brief 费马数模乘法 [dst,rn+1]=[numa,na]*[numb,nb] mod B^rn+1
546 * @param dst 输出结果缓冲区,长度至少为 rn+1
547 * @param rn 模运算的阶数参数,rn = lmmp_fft_next_size_((na + nb + 1) >> 1)
548 * @param numa 第一个输入操作数,长度为 na
549 * @param na 第一个操作数的 limb 长度
550 * @param numb 第二个输入操作数,长度为 nb
551 * @param nb 第二个操作数的 limb 长度
552 * @warning 0<=[numa,na]<2*B^rn, 0<=[numb,nb]<2*B^rn, rn = lmmp_fft_next_size_((na + nb + 1) >> 1)
553 * @return 无返回值,结果存储在dst中
554 */
556
557/**
558 * @brief 梅森数模乘法 [dst,rn] = [numa,na]*[numb,nb] mod B^rn-1
559 * @param dst 输出结果缓冲区,长度至少为 rn
560 * @param rn 模运算的阶数参数,rn = lmmp_fft_next_size_((na + nb + 1) >> 1)
561 * @param numa 第一个输入操作数,长度为 na
562 * @param na 第一个操作数的 limb 长度
563 * @param numb 第二个输入操作数,长度为 nb
564 * @param nb 第二个操作数的 limb 长度
565 * @warning 0<=[numa,na]<B^rn, 0<=[numb,nb]<B^rn, rn = lmmp_fft_next_size_((na + nb + 1) >> 1)
566 * @return 无返回值,结果存储在dst中,
567 */
569
570/**
571 * @brief FFT乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
572 * @param dst 输出结果缓冲区,长度至少为 na+nb
573 * @param numa 第一个输入操作数,长度为 na
574 * @param na 第一个操作数的 limb 长度
575 * @param numb 第二个输入操作数,长度为 nb
576 * @param nb 第二个操作数的 limb 长度
577 * @warning ???<=nb<=na, sep(dst,[numa|numb])
578 * @return 无返回值,结果存储在dst中
579 */
581
582/**
583 * @brief FFT不平衡乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
584 * @param dst 输出结果缓冲区,长度至少为 na+nb
585 * @param hn FFT模域参数
586 * @param numa 第一个输入操作数,长度为 na
587 * @param na 第一个操作数的 limb 长度
588 * @param numb 第二个输入操作数,长度为 nb
589 * @param nb 第二个操作数的 limb 长度
590 * @warning ???<=nb<=na, na>=3*nb, sep(dst,[numa|numb])
591 * @return 无返回值,结果存储在dst中
592 */
594
595/**
596 * @brief 大数平方操作 [dst,2*na] = [numa,na]^2
597 * @warning na>0, sep(dst,numa)
598 * @param dst 平方结果输出指针(需要2*na的limb长度)
599 * @param numa 源操作数指针
600 * @param na limb长度
601 */
602LAMMP_API void lmmp_sqr_(mp_ptr dst, mp_srcptr numa, mp_size_t na);
603
604/**
605 * @brief 等长大数乘法操作 [dst,2*n] = [numa,n] * [numb,n]
606 * @warning n>0, sep(dst,[numa|numb])
607 * 特殊情况: n==1时dst<=numa+1是允许的
608 * n==2时dst<=numa是允许的
609 * @param dst 乘积结果输出指针(需要 2*n 的 limb 长度)
610 * @param numa 第一个乘数指针
611 * @param numb 第二个乘数指针
612 * @param n limb长度
613 */
615
616/**
617 * @brief 不等长大数乘法操作 [dst,na+nb] = [numa,na] * [numb,nb]
618 * @warning 0<nb<=na, sep(dst,[numa|numb])
619 * 特殊情况: nb==1时dst<=numa+1是允许的
620 * nb==2时dst<=numa是允许的
621 * @param dst 乘积结果输出指针(需要 na+nb 的 limb 长度)
622 * @param numa 第一个乘数指针(较长的操作数)
623 * @param na 第一个操作数的 limb 长度
624 * @param numb 第二个乘数指针(较短的操作数)
625 * @param nb 第二个操作数的 limb 长度
626 */
628
629/**
630 * @brief 低位乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
631 * @param dst 输出结果缓冲区,长度至少为 n
632 * @param numa 第一个输入操作数,长度为 n
633 * @param numb 第二个输入操作数,长度为 n
634 * @param n limb长度
635 * @warning n>0, sep(dst,[numa|numb])
636 * 特殊情况:当 n >= MULLO_DC_THRESHOLD 时,eqsep(dst,[numa|numb])是允许的
637 * @return 无返回值,结果存储在dst中,[dst,n]=[numa,n] * [numb,n] mod B^n
638 */
640
641/**
642 * @brief 低位乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
643 * @param dst 输出结果缓冲区,长度至少为 n
644 * @param numa 第一个输入操作数,长度为 n
645 * @param numb 第二个输入操作数,长度为 n
646 * @param tp 临时缓冲区,长度至少为 2*n
647 * @param n limb长度
648 * @warning n>0, sep(dst,[numa|numb],tp)
649 * @return 无返回值,结果存储在dst中,[dst,n]=[numa,n] * [numb,n] mod B^n
650 */
652
653/**
654 * @brief 低位平方 [dst,n] = [numa,n]^2 mod B^n
655 * @param dst 输出结果缓冲区,长度至少为 n
656 * @param numa 第一个输入操作数,长度为 n
657 * @param tp 临时缓冲区,长度至少为 2*n
658 * @param n limb长度
659 * @warning n>0, sep(dst,numa,tp)
660 * @return 无返回值,结果存储在dst中,[dst,n]=[numa,n]^2 mod B^n
661 */
663
664/**
665 * @brief 低位FFT乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
666 * @param dst 输出结果缓冲区,长度至少为 n
667 * @param numa 第一个输入操作数,长度为 n
668 * @param numb 第二个输入操作数,长度为 n
669 * @param scratch 临时缓冲区,长度至少为 2*n
670 * @param n 缓冲区 limb 长度
671 * @warning ???<n, sep(scratch,[numa|numb]), eqsep(dst,scratch)
672 * @return 无返回值,结果存储在dst中,[dst,n]=[numa,n] * [numb,n] mod B^n
673 */
675
676/**
677 * @brief 1阶逆元计算 (inv1)
678 * @param x 输入的64位无符号整数,最高位为1(MSB(x)=1)
679 * @return 计算结果:(B^2-1)/x - B
680 * @warning MSB(x)=1, 即x>=2^63
681 */
683
684/**
685 * @brief 2-1阶逆元计算 (inv21)
686 * @param xh 输入数的高64位部分
687 * @param xl 输入数的低64位部分
688 * @return 计算结果:(B^3-1)/(xh*B+xl) - B
689 * @warning MSB(xh)=1, 即xh>=2^63
690 */
692
693/**
694 * @brief 近似逆元计算
695 * @param dst 输出结果缓冲区,长度为na
696 * @param numa 输入操作数,长度为na
697 * @param na 输入操作数的 limb 长度
698 * @warning na>0, MSB(numa)=1, sep(dst,numa)
699 * @return 无返回值,结果存储在dst中,[dst,na]=(B^(2*na)-1)/[numa,na] - B^na
700 */
702
703/**
704 * @brief 近似逆元计算(牛顿迭代法)
705 * @param dst 输出结果缓冲区,长度为na
706 * @param numa 输入操作数,长度为na
707 * @param na 输入操作数的 limb 长度
708 * @warning na>4, MSB(numa)=1, sep(dst,numa)
709 * @return 无返回值,结果存储在dst中,[dst,na]=(B^(2*na)-1)/[numa,na]-B^na+[0|-1]
710 */
712
713/**
714 * @brief 近似逆元计算 (invappr)
715 * @param dst 输出结果缓冲区,长度为na
716 * @param numa 输入操作数,长度为na
717 * @param na 输入操作数的 limb 长度
718 * @warning na>0, MSB(numa)=1, sep(dst,numa)
719 * @return 无返回值,结果存储在dst中,[dst,na] = (B^(2*na)-1)/[numa,na] - B^na + [0|-1]
720 */
722
723/**
724 * @brief 3/2位除法运算 [numa,2]=[numa,3] mod [numb,2]
725 * @param numa 输入被除数(长度3),运算后存储余数(长度2)
726 * @param numb 输入除数(长度2)
727 * @param inv21 除数的2-1阶逆元(提前计算好的inv21([numb,2]))
728 * @return 商值(单精度数)
729 * @warning [numa,3]<[numb,2]*B, MSB(numb)=1, inv21=inv21([numb,2]), eqsep(numa,numb)
730 */
732
733/**
734 * @brief 单精度数除法
735 * @param dstq 输出商的缓冲区(可为NULL,此时仅计算余数)
736 * @param numa 输入被除数,长度为na
737 * @param na 被除数的 limb 长度
738 * @param x 除数(单个 limb )
739 * @return 除法余数(单个 limb )
740 * @warning na>0, x!=0, eqsep(dstq,numa), dstq>=numa-1 是可以接受的
741 * @note if (dstq!=NULL) [dstq,na] = [numa,na] div x
742 */
744
745/**
746 * @brief 单精度数取余
747 * @param numa 输入被除数,长度为na
748 * @param na 被除数的 limb 长度
749 * @param x 除数(单个 limb )
750 * @return 除法余数(单个 limb )
751 * @warning na>0, x!=0, eqsep(dstq,numa), dstq>=numa-1 是可以接受的
752 */
754
755/**
756 * @brief 双精度数除法 (除数为2个limb)
757 * @param dstq 输出商的缓冲区,长度至少为na-1
758 * @param numa 输入被除数(长度na)
759 * @param na 被除数的 limb 长度
760 * @param numb 输入除数(长度2)[numb,2]=[numa,na] mod [numb,2]
761 * @warning na>=2, numb[1]!=0, eqsep(dstq,numa), dstq>=numa 是可以接受的
762 * @note if (dstq!=NULL) [dstq,na-1]=[numa,na] div [numb,2]
763 */
764LAMMP_API void lmmp_div_2_(mp_ptr dstq, mp_srcptr numa, mp_size_t na, mp_ptr numb);
765
766/**
767 * @brief 双精度数取余 (除数为2个limb)
768 * @param numa 输入被除数(长度na)
769 * @param na 被除数的 limb 长度
770 * @param numb 输入除数(长度2)[numb,2]=[numa,na] mod [numb,2]
771 * @warning na>=2, numb[1]!=0, eqsep(dstq,numa), dstq>=numa 是可以接受的
772 */
773LAMMP_API void lmmp_mod_2_(mp_srcptr numa, mp_size_t na, mp_ptr numb);
774
775/**
776 * @brief 基础除法运算
777 * @param dstq 输出商的缓冲区,长度至少为na-nb
778 * @param numa 输入被除数(长度na),运算后存储余数(长度nb)
779 * @param na 被除数的单精度数(limb)长度
780 * @param numb 输入除数,长度为nb
781 * @param nb 除数的单精度数(limb)长度
782 * @param inv21 除数的2-1阶逆元(inv21([numb+nb-2,2]))
783 * @return 商的最高位(qh)
784 * @warning na>=nb>=3, MSB(numb)=1, inv21=inv21([numb+nb-2,2]), sep(dstq,numa,numb)
785 * @note qh:[dstq,na-nb]=[numa,na] div [numb,nb], [numa,na-nb]=[numa,na] mod [numb,nb], return qh
786 */
788lmmp_div_basecase_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb, mp_limb_t inv21);
789
790/**
791 * @brief 分治除法运算
792 * @param dstq 输出商的缓冲区,长度至少为na-nb
793 * @param numa 输入被除数(长度na),运算后存储余数(长度nb)
794 * @param na 被除数的单精度数(limb)长度
795 * @param numb 输入除数,长度为nb
796 * @param nb 除数的单精度数(limb)长度
797 * @param inv21 除数的2-1阶逆元(inv21([numb+nb-2,2]))
798 * @return 商的最高位(qh)
799 * @warning na>=2*nb, nb>=6, MSB(numb)=1, inv21=inv21([numb+nb-2,2]), sep(dstq,numa,numb)
800 * @note qh:[dstq,na-nb]=[numa,na] div [numb,nb], [numa,na-nb]=[numa,na] mod [numb,nb], return qh
801 */
803lmmp_div_divide_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb, mp_limb_t inv21);
804
805/**
806 * @brief 计算预计算逆元的尺寸
807 * @param nq 商的 limb 长度
808 * @param nb 除数的 limb 长度
809 * @return 计算需要预计算逆元尺寸ni(ni<=nb)
810 * @note 用于已归一化除法([nq+nb]/[nb]=[nq])的逆元 ni 尺寸
811 */
813 mp_size_t ni, b;
814 if (nq > nb) {
815 b = (nq - 1) / nb + 1; // ceil(nq/nb), number of blocks
816 ni = (nq - 1) / b + 1; // ceil(nq/b)
817 } else if (3 * nq > nb) {
818 ni = (nq - 1) / 2 + 1; // b=2
819 } else {
820 ni = (nq - 1) / 1 + 1; // b=1
821 }
822 return ni;
823}
824
825/**
826 * @brief 除法前的逆元预计算,[dst,ni] = invappr( (ni+1 MSLs of numa) + 1 ) / B
827 * @param dst 输出预计算逆元的缓冲区,长度为ni
828 * @param numa 输入操作数,长度为na
829 * @param na 输入操作数的 limb 长度
830 * @param ni 预计算逆元的目标尺寸
831 * @warning na>=ni>0, MSB(numa)=1, eqsep(dst,numa)
832 * @note if (ni=na) [dst,na] = (B^(2*na)-1) / [numa,na] - B^na
833 */
835
836/**
837 * @brief 大数求逆操作 [dst,na+nf+1] = (B^(2*(na+nf)) - 1) / ([numa,na]*B^nf) + [0|-1]
838 * @param dst 逆元结果输出指针
839 * @param numa 源操作数指针
840 * @param na 操作数的 limb 长度
841 * @param nf 精度因子
842 * @warning na>0, numa[na-1]!=0, eqsep(dst,numa)
843 */
844LAMMP_API void lmmp_inv_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t nf);
845
846/**
847 * @brief 精确逆元计算 [dstq,na+ni+2] = B^(2*(na+ni)) / ([numa,na] * B^ni)
848 * @param dstq 输出商的缓冲区,长度至少为na+ni+2
849 * @param numa 输入被除数(长度na)
850 * @param na 被除数的 limb 长度
851 * @param ni 精度因子
852 * @warning na>0, sep(dstq,numa), dstq!=NULL, numa[na-1]!=0
853 * @note 也就是计算 B^(2*na+ni) div ([numa,na]
854 */
856
857/**
858 * @brief 乘法逆元除法
859 * @param dstq 输出商的缓冲区,长度至少为na-nb
860 * @param numa 输入被除数(长度na),运算后存储余数(长度nb)
861 * @param na 被除数的 limb 长度
862 * @param numb 输入除数,长度为nb
863 * @param nb 除数的 limb 长度
864 * @param invappr 预计算的近似逆元,长度为ni
865 * @param ni 预计算逆元的 limb 长度
866 * @return 商的最高位(qh)
867 * @warning na>=nb>=ni>0, MSB(numb)=1, [invappr,ni]=inv_prediv([numb,nb]), sep(dstq,numa,numb,invappr))
868 * @note qh:[dstq,na-1]=[numa,na] div x, [numa,1]=[numa,na] mod x, return qh
869 */
871lmmp_div_mulinv_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb, mp_srcptr invappr, mp_size_t ni);
872
873/**
874 * @brief 单精度数除法(除数为1个limb)
875 * @param dstq 输出商的缓冲区,长度至少为na-1
876 * @param numa 输入被除数(长度na),运算后存储余数(长度1)
877 * @param na 被除数的 limb 长度
878 * @param x 除数(单个 limb )
879 * @return 商的最高位(qh)
880 * @warning na>1, MSB(x)=1, sep(dstq,numa)
881 * @note qh:[dstq,na-1]=[numa,na] div x, [numa,1]=[numa,na] mod x, return qh
882 */
884
885/**
886 * @brief 双精度数除法(除数为2个limb)
887 * @param dstq 输出商的缓冲区,长度至少为na-2
888 * @param numa 输入被除数(长度na),运算后存储余数(长度2)
889 * @param na 被除数的 limb 长度
890 * @param numb 输入除数,长度为2
891 * @return 商的最高位(qh)
892 * @warning na>2, MSB(numb)=1, sep(dstq,numa,numb)
893 * @note qh:[dstq,na-2]=[numa,na] div [numb,2], [numa,2]=[numa,na] mod [numb,2], return qh
894 */
896
897/**
898 * @brief 除法运算
899 * @param dstq 输出商的缓冲区,长度至少为na-nb
900 * @param numa 输入被除数(长度na),运算后存储余数(长度nb)
901 * @param na 被除数的 limb 长度
902 * @param numb 输入除数,长度为nb
903 * @param nb 除数的 limb 长度
904 * @return 商的最高位(qh)
905 * @warning na>=nb>0, MSB(numb)=1, sep(dstq,numa,numb)
906 * @note qh:[dstq,na-nb]=[numa,na] div [numb,nb], [numa,nb]=[numa,na] mod [numb,nb], return qh
907 */
909
910/**
911 * @brief 大数除法和取模操作
912 * @note 如果dstq不为NULL: [dstq,na-nb+1] = [numa,na] / [numb,nb] (商)
913 * 如果dstr不为NULL: [dstr,nb] = [numa,na] mod [numb,nb] (余数)
914 * @warning 0<nb<=na, numb[nb-1]!=0, sep(dstq,[numa|numb]), eqsep(dstr,[numa|numb]))
915 * 特殊情况: nb==1时, dstq>=numa-1 是允许的
916 * nb==2时, dstq>=numa 是允许的
917 * @param dstq 商结果输出指针(NULL表示不计算商)
918 * @param dstr 余数结果输出指针(NULL表示不计算余数)
919 * @param numa 被除数指针
920 * @param na 被除数的 limb 长度
921 * @param numb 除数指针
922 * @param nb 除数的 limb 长度
923 */
924LAMMP_API void lmmp_div_(mp_ptr dstq, mp_ptr dstr, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb);
925
926/**
927 * @brief 大数平方根和取余操作
928 * @note 如果dstr不为NULL: [dsts,nf+na/2+1], [dstr,nf+na/2+1] = sqrtrem([numa,na]*B^(2*nf))
929 * 也即 [numa,na] × B^(2×nf) = [dsts,nf+na/2+1]^2 + [dstr,nf+na/2+1]
930 * 且 0 <= [dstr,nf+na/2+1] < 2 * [dsts,nf+na/2+1] + 1
931 * 如果dstr为NULL: [dsts,nf+na/2+1] = [round|floor](sqrt([numa,na]*B^(2*nf)))
932 * @warning na>0, numa[na-1]!=0, eqsep(dsts,numa), eqsep(dstr,numa)
933 * @param dsts 平方根结果输出指针
934 * @param dstr 余数结果输出指针(NULL表示不计算余数)
935 * @param numa 源操作数指针
936 * @param na 操作数的 limb 长度
937 * @param nf 精度因子
938 */
939LAMMP_API void lmmp_sqrt_(mp_ptr dsts, mp_ptr dstr, mp_srcptr numa, mp_size_t na, mp_size_t nf);
940
941/**
942 * @brief 大数加1宏(预期无进位)
943 * @param p 指向大数起始位置的指针
944 * @note 从最低位开始加1,直到遇到非零值(预期无进位溢出)
945 */
946#define lmmp_inc(p) \
947 do { \
948 mp_ptr _p_ = (p); \
949 while (++(*(_p_++)) == 0); \
950 } while (0)
951
952/**
953 * @brief 大数加指定值宏(预期无进位)
954 * @param p 指向大数起始位置的指针
955 * @param inc 要加的单精度数值
956 * @note 先加最低位,若产生进位则逐位加1,直到无进位(预期无溢出)
957 */
958#define lmmp_inc_1(p, inc) \
959 do { \
960 mp_ptr _p_ = (p); \
961 mp_limb_t _inc_ = (inc), _x_; \
962 _x_ = *_p_ + _inc_; \
963 *_p_ = _x_; \
964 if (_x_ < _inc_) \
965 while (++(*(++_p_)) == 0); \
966 } while (0)
967
968/**
969 * @brief 大数减1宏(预期无借位)
970 * @param p 指向大数起始位置的指针
971 * @note 从最低位开始减1,直到遇到非零值(预期无借位溢出)
972 */
973#define lmmp_dec(p) \
974 do { \
975 mp_ptr _p_ = (p); \
976 while ((*(_p_++))-- == 0); \
977 } while (0)
978
979/**
980 * @brief 大数减指定值宏(预期无借位)
981 * @param p 指向大数起始位置的指针
982 * @param dec 要减的单精度数值
983 * @note 先减最低位,若产生借位则逐位减1,直到无借位(预期无溢出)
984 */
985#define lmmp_dec_1(p, dec) \
986 do { \
987 mp_ptr _p_ = (p); \
988 mp_limb_t _dec_ = (dec), _x_; \
989 _x_ = *_p_; \
990 *_p_ = _x_ - _dec_; \
991 if (_x_ < _dec_) \
992 while ((*(++_p_))-- == 0); \
993 } while (0)
994
995/**
996 * @brief 大数比较函数(内联)
997 * @param numa 第一个大数,长度为n
998 * @param numb 第二个大数,长度为n
999 * @param n 大数的单精度数(limb)长度
1000 * @return 1(numa>numb) / 0(numa==numb) / -1(numa<numb)
1001 * @warning n>0, numa!=NULL, numb!=NULL
1002 * @note 从最高位开始逐位比较,直到找到不同位
1003 */
1005 lmmp_param_assert(n > 0);
1006 lmmp_param_assert(numa != NULL);
1007 lmmp_param_assert(numb != NULL);
1008 mp_ssize_t i = n;
1009 mp_limb_t x, y;
1010 while (--i >= 0) {
1011 x = numa[i];
1012 y = numb[i];
1013 if (x != y)
1014 return (x > y ? 1 : -1);
1015 }
1016 return 0;
1017}
1018
1019/**
1020 * @brief 大数判零函数(内联)
1021 * @param p 指向大数起始位置的指针
1022 * @param n 大数的单精度数(limb)长度
1023 * @return 1(全零) / 0(非零)
1024 * @warning n>0
1025 * @note 从最高位开始检查,只要有非零位则返回0
1026 */
1028 do {
1029 if (p[--n] != 0)
1030 return 0;
1031 } while (n != 0);
1032 return 1;
1033}
1034
1035#define LMMP_AORS_(FUNCTION, TEST) \
1036 mp_limb_t _x_; \
1037 if (FUNCTION(dst, numa, numb, nb)) { \
1038 do { \
1039 if (nb >= na) \
1040 return 1; \
1041 _x_ = numa[nb]; \
1042 } while (TEST); \
1043 } \
1044 if (dst != numa && na != nb) \
1045 lmmp_copy(dst + nb, numa + nb, na - nb); \
1046 return 0
1047
1048/**
1049 * @brief 大数加法静态内联函数 [dst,na]=[numa,na]+[numb,nb]
1050 * @param dst 输出结果缓冲区,存储numa + numb
1051 * @param numa 第一个加数,长度为na
1052 * @param na 第一个加数的 limb 长度
1053 * @param numb 第二个加数,长度为nb
1054 * @param nb 第二个加数的 limb 长度
1055 * @return 进位标志(1表示有进位,0表示无进位)
1056 * @warning 0<nb<=na, eqsep(dst,[numa|numb])
1057 */
1059 LMMP_AORS_(lmmp_add_n_, ((dst[nb++] = _x_ + 1) == 0));
1060}
1061
1062/**
1063 * @brief 大数减法静态内联函数 [dst,na]=[numa,na]-[numb,nb]
1064 * @param dst 输出结果缓冲区,存储numa - numb
1065 * @param numa 被减数,长度为na
1066 * @param na 被减数的 limb 长度
1067 * @param numb 减数,长度为nb
1068 * @param nb 减数的 limb 长度
1069 * @return 借位标志(1表示有借位,0表示无借位)
1070 * @warning 0<nb<=na, eqsep(dst,[numa|numb])
1071 */
1073 LMMP_AORS_(lmmp_sub_n_, ((dst[nb++] = _x_ - 1), _x_ == 0));
1074}
1075
1076#undef LMMP_AORS_
1077
1078// 单精度加减运算通用宏:封装单精度加减的公共逻辑
1079#define LMMP_AORS_1_(OP, CB) \
1080 mp_size_t _i_ = 1; \
1081 mp_limb_t _x_ = numa[0], _r_ = _x_ OP x; \
1082 dst[0] = _r_; \
1083 if (CB(_r_, _x_, x)) { \
1084 do { \
1085 if (_i_ >= na) \
1086 return 1; \
1087 _x_ = numa[_i_]; \
1088 _r_ = _x_ OP 1; \
1089 dst[_i_] = _r_; \
1090 ++_i_; \
1091 } while (CB(_r_, _x_, 1)); \
1092 } \
1093 if (numa != dst && na != _i_) \
1094 lmmp_copy(dst + _i_, numa + _i_, na - _i_); \
1095 return 0
1096
1097// 加法进位判断宏:判断加法是否产生进位
1098#define LMMP_ADDCB_(r, x, y) ((r) < (y))
1099// 减法借位判断宏:判断减法是否产生借位
1100#define LMMP_SUBCB_(r, x, y) ((x) < (y))
1101
1102/**
1103 * @brief 大数加单精度数静态内联函数 [dst,na]=[numa,na]+x
1104 * @param dst 输出结果缓冲区,存储numa + x
1105 * @param numa 被加数,长度为na
1106 * @param na 被加数的 limb 长度
1107 * @param x 加数(单个 limb )
1108 * @return 进位标志(1表示有进位,0表示无进位)
1109 * @warning na>0, eqsep(dst,numa)
1110 */
1112
1113/**
1114 * @brief 大数减单精度数静态内联函数 [dst,na]=[numa,na]-x
1115 * @param dst 输出结果缓冲区,存储numa - x
1116 * @param numa 被减数,长度为na
1117 * @param na 被减数的 limb 长度
1118 * @param x 减数(单个 limb )
1119 * @return 借位标志(1表示有借位,0表示无借位)
1120 * @warning na>0, eqsep(dst,numa)
1121 */
1123
1124/**
1125 * @brief 计算大数转换为字符串,字符串需要的缓冲区长度
1126 * @param numa 输入大数,长度为na
1127 * @param na 大数的 limb 长度
1128 * @param base 目标基数(2~256)
1129 * @return 大数在指定基数下的位数
1130 * @warning na>=0, 2<=base<=256
1131 * @note 将会忽略numa的前导零,
1132 * 1. if (numa!=NULL) 返回的长度可能会多分配一个字符空间
1133 * 2. if (numa==NULL) 返回na个limb长度的数的最大可能字符长度(最坏情况)
1134 */
1136
1137/**
1138 * @brief 计算字符串转大数所需的 limb 缓冲区长度
1139 * @param src 输入字符串指针
1140 * @param len 字符串长度
1141 * @param base 字符串的基数(2~256)
1142 * @return 存储该字符串数值所需的 limb 缓冲区长度
1143 * @warning len>=0, 2<=base<=256
1144 * @note 将会忽略前导零,
1145 * 1. if (src!=NULL) 返回的长度可能会多分配一个 limb 空间
1146 * 2. if (src==NULL) 返回len位base进制数的最大可能 limb 长度(最坏情况)
1147 */
1148LAMMP_API mp_size_t lmmp_from_str_len_(const mp_byte_t* src, mp_size_t len, int base);
1149
1150/**
1151 * @brief 字符串转大数操作 [src,len,base] to [dst,return value,B]
1152 * @warning len>=0, 2<=base<=256
1153 * @param dst 大数结果输出指针
1154 * @param src 字符串源指针
1155 * @param len 字符串长度
1156 * @param base 字符串的进制基数
1157 * @return 转换后的大数 limb 长度
1158 */
1159LAMMP_API mp_size_t lmmp_from_str_(mp_ptr dst, const mp_byte_t* src, mp_size_t len, int base);
1160
1161/**
1162 * @brief 大数转字符串操作 [numa,na,B] to [dst,return value,base]
1163 * @warning na>=0, 2<=base<=256
1164 * @param dst 字符串结果输出指针
1165 * @param numa 大数源指针
1166 * @param na 大数的 limb 长度
1167 * @param base 目标字符串的进制基数
1168 * @return 转换后的字符串长度
1169 */
1171
1172/**
1173 * @brief 提取高位指定位数,并返回低位bits位数
1174 * @param num 待提取的大数指针
1175 * @param n num的 limb 长度
1176 * @param bits 待提取的位数(1-64)
1177 * @param ext 提取结果输出指针
1178 * @warning n>0, 1<=bits<=64, ext!=NULL
1179 * @note 如果bits大于num的实际位数,则不会保证ext有效位数为bits位;
1180 * 如果bits小于等于num的实际位数,则ext将会有bits位有效位数。
1181 * @return 剩余的低位bits数量
1182 */
1184
1185#ifdef __cplusplus
1186} // extern "C"
1187#endif
1188
1189#undef LMMP_ADDCB_
1190#undef LMMP_SUBCB_
1191#undef LMMP_AORS_1_
1192
1193
1194#undef INLINE_
1195
1196#endif // LAMMP_LMMPN_H
#define scratch
#define an
mp_limb_t * mp_ptr
Definition lmmp.h:215
uint8_t mp_byte_t
Definition lmmp.h:210
size_t mp_bitcnt_t
Definition lmmp.h:217
uint64_t mp_size_t
Definition lmmp.h:212
const mp_limb_t * mp_srcptr
Definition lmmp.h:216
int64_t mp_ssize_t
Definition lmmp.h:214
uint64_t mp_limb_t
Definition lmmp.h:211
#define LAMMP_API
Definition lmmp.h:64
#define lmmp_param_assert(x)
Definition lmmp.h:398
void lmmp_mullh_(mp_limb_t a, mp_limb_t b, mp_ptr dst)
计算两个64位无符号整数相乘的128位结果 (a*b)
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
#define LMMP_SUBCB_(r, x, y)
Definition lmmpn.h:1100
mp_limb_t lmmp_div_3_2_(mp_ptr numa, mp_srcptr numb, mp_limb_t inv21)
3/2位除法运算 [numa,2]=[numa,3] mod [numb,2]
void lmmp_mul_toom22_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-22乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
mp_limb_t lmmp_div_s_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
除法运算
Definition div.c:11
void lmmp_invappr_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
近似逆元计算 (invappr)
Definition inv.c:176
static mp_size_t lmmp_div_inv_size_(mp_size_t nq, mp_size_t nb)
计算预计算逆元的尺寸
Definition lmmpn.h:812
mp_limb_t lmmp_div_1_s_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_limb_t x)
单精度数除法(除数为1个limb)
mp_limb_t lmmp_div_1_(mp_ptr dstq, mp_srcptr numa, mp_size_t na, mp_limb_t x)
单精度数除法
Definition div.c:66
void lmmp_mul_toom44_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-44乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
#define LMMP_AORS_(FUNCTION, TEST)
Definition lmmpn.h:1035
int lmmp_leading_zeros_(mp_limb_t x)
计算一个单精度数(limb)中前导零的个数
Definition tiny.c:35
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:752
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:1058
mp_limb_t lmmp_shr1add_nc_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_limb_t c)
带进位加法后右移1位 [dst,n] = ([numa,n] + [numb,n] + c) >> 1
Definition shr.c:79
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:30
mp_limb_t lmmp_shr1add_n_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
加法后右移1位 [dst,n] = ([numa,n] + [numb,n]) >> 1
Definition shr.c:52
static int lmmp_cmp_(mp_srcptr numa, mp_srcptr numb, mp_size_t n)
大数比较函数(内联)
Definition lmmpn.h:1004
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
void lmmp_mul_toom42_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-42乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
void lmmp_inv_prediv_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t ni)
除法前的逆元预计算,[dst,ni] = invappr( (ni+1 MSLs of numa) + 1 ) / B
Definition div_mulinv.c:11
void lmmp_div_2_(mp_ptr dstq, mp_srcptr numa, mp_size_t na, mp_ptr numb)
双精度数除法 (除数为2个limb)
Definition div.c:223
void lmmp_sqr_basecase_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
基础平方运算 [dst,2*na] = [numa,na]^2
void lmmp_mul_toom42_unbalance_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-42不平衡乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
void lmmp_mullo_dc_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_ptr tp, mp_size_t n)
低位乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
mp_limb_t lmmp_subshl1_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:73
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:9
mp_bitcnt_t lmmp_extract_bits_(mp_srcptr num, mp_size_t n, mp_limb_t *ext, int bits)
提取高位指定位数,并返回低位bits位数
void lmmp_mul_toom43_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-43乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
mp_limb_t lmmp_mod_1_(mp_srcptr numa, mp_size_t na, mp_limb_t x)
单精度数取余
Definition div.c:20
mp_size_t lmmp_to_str_(mp_byte_t *dst, mp_srcptr numa, mp_size_t na, int base)
大数转字符串操作 [numa,na,B] to [dst,return value,base]
Definition to_str.c:147
void lmmp_mod_2_(mp_srcptr numa, mp_size_t na, mp_ptr numb)
双精度数取余 (除数为2个limb)
Definition div.c:144
#define LMMP_AORS_1_(OP, CB)
Definition lmmpn.h:1079
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]
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_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
void lmmp_mul_toom32_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-32乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
mp_size_t lmmp_to_str_len_(mp_srcptr numa, mp_size_t na, int base)
计算大数转换为字符串,字符串需要的缓冲区长度
Definition to_str.c:12
void lmmp_sqr_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
大数平方操作 [dst,2*na] = [numa,na]^2
Definition sqr.c:10
void lmmp_mul_fermat_(mp_ptr dst, mp_size_t rn, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
费马数模乘法 [dst,rn+1]=[numa,na]*[numb,nb] mod B^rn+1
Definition mul_fft.c:677
#define INLINE_
Definition lmmpn.h:59
void lmmp_invappr_newton_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
近似逆元计算(牛顿迭代法)
Definition inv.c:40
void lmmp_mul_toom52_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-52乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
void lmmp_mul_n_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
等长大数乘法操作 [dst,2*n] = [numa,n] * [numb,n]
Definition mul.c:99
mp_limb_t lmmp_shl_c_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t shl, mp_limb_t c)
带进位的大数左移操作 [dst,na] = [numa,na]<<shl,dst的低shl位填充c的低shl位
Definition shl.c:32
mp_limb_t lmmp_mulh_(mp_limb_t a, mp_limb_t b)
计算两个64位无符号整数相乘的高位结果 (a*b)/2^64
Definition tiny.c:73
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:56
int lmmp_limb_bits_(mp_limb_t x)
计算满足 2^k > x 的最小自然数k
Definition tiny.c:11
void lmmp_mul_toom62_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-62乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
void lmmp_sqr_toom2_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
Toom-2平方运算 [dst,2*na] = [numa,na]^2
mp_limb_t lmmp_add_nc_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_limb_t c)
带进位的n位加法 [dst,n] = [numa,n] + [numb,n] + c
Definition add_n.c:9
void lmmp_sqr_toom3_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
Toom-3平方运算 [dst,2*na] = [numa,na]^2
void lmmp_mul_fft_unbalance_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
FFT不平衡乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
mp_limb_t lmmp_shr1sub_nc_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_limb_t c)
带借位减法后右移1位 [dst,n] = ([numa,n] - [numb,n] - c) >> 1
Definition shr.c:133
void lmmp_bninv_(mp_ptr dstq, mp_srcptr numa, mp_size_t na, mp_size_t ni)
精确逆元计算 [dstq,na+ni+2] = B^(2*(na+ni)) / ([numa,na] * B^ni)
mp_size_t lmmp_fft_next_size_(mp_size_t n)
计算满足 >=n 的最小费马/梅森乘法可行尺寸
Definition mul_fft.c:84
void lmmp_sqrlo_dc_(mp_ptr dst, mp_srcptr numa, mp_ptr tp, mp_size_t n)
低位平方 [dst,n] = [numa,n]^2 mod B^n
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:9
#define LMMP_ADDCB_(r, x, y)
Definition lmmpn.h:1098
static mp_limb_t lmmp_sub_(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:1072
void lmmp_sqr_toom4_(mp_ptr pp, mp_srcptr ap, mp_size_t an)
Toom-4平方运算 [dst,2*na] = [numa,na]^2
void lmmp_mul_toom53_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-53乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
void lmmp_mullo_fft_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_ptr scratch)
低位FFT乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
Definition mullo.c:11
int lmmp_limb_popcnt_(mp_limb_t x)
计算一个64位无符号整数中1的个数
Definition tiny.c:20
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
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
void lmmp_inv_basecase_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
近似逆元计算
Definition inv.c:11
mp_limb_t lmmp_add_n_sub_n_(mp_ptr dsta, mp_ptr dstb, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
同时执行n位加法和减法 ([dsta,n],[dstb,n]) = ([numa,n]+[numb,n],[numa,n]-[numb,n])
Definition add_n_sub_n.c:10
static bool lmmp_endian(void)
运行时判断端序
Definition lmmpn.h:69
mp_limb_t lmmp_div_mulinv_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb, mp_srcptr invappr, mp_size_t ni)
乘法逆元除法
Definition div_mulinv.c:36
void lmmp_inv_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t nf)
大数求逆操作 [dst,na+nf+1] = (B^(2*(na+nf)) - 1) / ([numa,na]*B^nf) + [0|-1]
Definition inv.c:152
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:1122
mp_limb_t lmmp_div_2_s_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb)
双精度数除法(除数为2个limb)
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:57
void lmmp_mul_fft_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
FFT乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
Definition mul_fft.c:1085
void lmmp_not_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
大数按位取反操作 [dst,na] = ~[numa,na] (对每个limb执行按位非操作)
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
void lmmp_sqrt_(mp_ptr dsts, mp_ptr dstr, mp_srcptr numa, mp_size_t na, mp_size_t nf)
大数平方根和取余操作
Definition sqrt.c:323
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:70
mp_limb_t lmmp_inv_1_(mp_limb_t x)
1阶逆元计算 (inv1)
Definition inv.c:107
mp_limb_t lmmp_shr1sub_n_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
减法后右移1位 [dst,n] = ([numa,n] - [numb,n]) >> 1
Definition shr.c:106
mp_limb_t lmmp_inv_2_1_(mp_limb_t xh, mp_limb_t xl)
2-1阶逆元计算 (inv21)
Definition inv.c:10
mp_limb_t lmmp_div_basecase_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb, mp_limb_t inv21)
基础除法运算
void lmmp_mul_toom62_unbalance_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-62不平衡乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
void lmmp_mullo_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
低位乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
mp_limb_t lmmp_sub_nc_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_limb_t c)
带借位的n位减法 [dst,n] = [numa,n] - [numb,n] - c
Definition sub_n.c:9
mp_limb_t lmmp_div_divide_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb, mp_limb_t inv21)
分治除法运算
Definition div_divide.c:53
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
static int lmmp_zero_q_(mp_srcptr p, mp_size_t n)
大数判零函数(内联)
Definition lmmpn.h:1027
void lmmp_mul_toom33_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
Toom-33乘法运算 [dst,na+nb] = [numa,na] * [numb,nb]
mp_size_t lmmp_from_str_len_(const mp_byte_t *src, mp_size_t len, int base)
计算字符串转大数所需的 limb 缓冲区长度
Definition from_str.c:13
#define tp