LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
mullo.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/inlines.h"
17#include "../../../include/lammp/impl/mparam.h"
18#include "../../../include/lammp/impl/tmp_alloc.h"
19#include "../../../include/lammp/lmmpn.h"
20
21
24 mp_size_t hn = lmmp_fft_next_size_((n + n + 1) >> 1);
25 lmmp_assert(n + n > hn);
27
29 mp_size_t nam = n;
30 if (n > hn) {
31 /*
32 Z = B^hb - 1
33 amodm = a mod Z
34 */
35 if (lmmp_add_(scratch, numa, hn, numa + hn, n - hn))
37 amodm = scratch;
38 nam = hn;
39 }
41
43 mp_size_t nap = n;
44 if (n > hn) {
45 /*
46 Z = B^hp - 1
47 amodp = a mod Z
48 */
49 tp[hn] = 0;
50 if (lmmp_sub_(tp, numa, hn, numa + hn, n - hn))
51 lmmp_inc(tp);
52 amodp = tp;
53 nap = hn + 1;
54 }
56
58 cy <<= LIMB_BITS - 1;
59 scratch[hn - 1] += cy;
60 if (scratch[hn - 1] < cy)
62
63 if (n == hn) {
65 // cy==1 means [tp,hn+1]!=0, then [dst,hn]!=0
66 // cy==2 is impossible since [tp,hn+1] is normalized.
67 // so the following dec won't overflow.
69 } else {
70 mp_size_t n2 = 2 * n;
72 cy = tp[hn] + lmmp_sub_nc_(tp + n2 - hn, scratch + n2 - hn, tp + n2 - hn, 2 * hn - n2, cy);
74 }
77}
78
79/*
80 <---t---><---m--->
81 |--a1---|---a0---|
82 |--b1---|---b0---|
83
84 ,
85 |\
86 | \
87 | \
88 +-----,
89 | |
90 | |\
91 | | \
92 | | \
93 +-----+---`
94 ^ m ^ t ^
95
96 此算法是一种不平衡分块的算法,朴素的想法是计算平衡分块,计算一次完整的乘法,然后两次递归的调用此函数计算低位,
97 事实上,我们也可以不平衡的分块,以减少递归深度,具体分析如下:
98 取a和b的低位一定宽度为m,高位宽度为t,则有:
99 计算一次完整的平衡乘法m,然后递归调用计算mullo,长度为t
100 复杂度模型:
101 ML(n) = 2*ML(a*n) + M((1-a)*n)
102 其中ML为mullo的复杂度,M为mul_n的复杂度
103 我们可以假定 M(n)=O(n^e) 即多项式复杂度
104 则有:
105 ML(n) = C(a) * n^e
106 C(a) = a^e / (1-2*(1-a)^e)
107 我们希望C(a)尽可能小,即希望ML(n)尽可能小,则有:
108 a_opt = 1 - 2^(-1/(e-1))
109 e=log(3)/log(2) [Toom-2] -> a ~= 0.694
110 e=log(5)/log(3) [Toom-3] -> a ~= 0.775
111 e=log(7)/log(4) [Toom-4] -> a ~= 0.820
112 e=log(11)/log(6) [Toom-6] -> a ~= 0.871
113 e=log(15)/log(8) [Toom-8] -> a ~= 0.899
114*/
115
116#define MUL_TOOM66_THRESHOLD MUL_FFT_THRESHOLD
117#define MUL_TOOM88_THRESHOLD 5621
118
125) {
127 lmmp_mul_1_(dst, numa, n, numb[0]);
128 for (mp_size_t i = 1; i < n; ++i) {
129 lmmp_mul_1_(tp, numa, n - i, numb[i]);
130 lmmp_add_n_(dst + i, dst + i, tp, n - i);
131 }
132 return;
133 } else {
134 mp_size_t m, t;
135 if (n < MUL_TOOM33_THRESHOLD) {
136 m = 25 * n / 36;
137 } else if (n < MUL_TOOM44_THRESHOLD) {
138 m = 31 * n / 40;
139 } else if (n < MUL_TOOM66_THRESHOLD) {
140 m = 32 * n / 39;
141 } else if (n < MUL_TOOM88_THRESHOLD) {
142 m = 27 * n / 31;
143 } else {
144 m = 9 * n / 10;
145 }
146 t = n - m;
147 lmmp_debug_assert(2 * n > 4 * t);
148
149#define a0 (numa) // [numa, m]
150#define a1 (numa + m) // [numa+m, t]
151#define b0 (numb) // [numb, m]
152#define b1 (numb + m) // [numb+m, t]
153#define c0 (dst) // [dst, m]
154#define c1 (dst + m) // [dst+m, t]
155#define lo1 (tp) // [tp, t]
156#define lo2 (tp + t) // [tp+t, t]
157#define scratch (tp + 2 * t) // [tp+2*t, 2*t]
158 lmmp_mul_n_(tp, a0, b0, m);
159 lmmp_copy(c0, tp, n);
162 lmmp_add_n_(c1, c1, lo1, t);
163 lmmp_add_n_(c1, c1, lo2, t);
164 return;
165 }
166#undef a0
167#undef a1
168#undef b0
169#undef b1
170#undef c0
171#undef c1
172#undef lo1
173#undef lo2
174#undef scratch
175}
176
179 lmmp_mul_1_(dst, numa, n, numa[0]);
180 for (mp_size_t i = 1; i < n; ++i) {
181 lmmp_mul_1_(tp, numa, n - i, numa[i]);
182 lmmp_add_n_(dst + i, dst + i, tp, n - i);
183 }
184 return;
185 } else {
186 mp_size_t m, t;
187 if (n < MUL_TOOM33_THRESHOLD) {
188 m = 25 * n / 36;
189 } else if (n < MUL_TOOM44_THRESHOLD) {
190 m = 31 * n / 40;
191 } else if (n < MUL_TOOM66_THRESHOLD) {
192 m = 32 * n / 39;
193 } else if (n < MUL_TOOM88_THRESHOLD) {
194 m = 27 * n / 31;
195 } else {
196 m = 9 * n / 10;
197 }
198 t = n - m;
199
200#define a0 (numa)
201#define a1 (numa + m)
202#define c0 (dst)
203#define c1 (dst + m)
204#define lo (tp) // [tp, t]
205#define scratch (tp + t) // [tp+t, 2*t]
206 lmmp_sqr_(tp, a0, m);
207 lmmp_copy(c0, tp, n);
210 }
211#undef a0
212#undef a1
213#undef c0
214#undef c1
215#undef lo
216#undef scratch
217}
218
220 lmmp_param_assert(n > 0);
221 if (n < MULLO_DC_THRESHOLD) {
222 if (numa == numb) {
223 TEMP_DECL;
226 TEMP_FREE;
227 return;
228 }
229 TEMP_DECL;
232 TEMP_FREE;
233 return;
234 } else {
235 TEMP_DECL;
238 TEMP_FREE;
239 return;
240 }
241}
#define lmmp_mul_n_
Definition inlines.h:167
#define lmmp_sqr_
Definition inlines.h:166
mp_limb_t * mp_ptr
Definition lmmp.h:80
#define lmmp_copy(dst, src, n)
Definition lmmp.h:367
uint64_t mp_size_t
Definition lmmp.h:77
#define lmmp_debug_assert(x)
Definition lmmp.h:390
const mp_limb_t * mp_srcptr
Definition lmmp.h:81
void lmmp_free(void *ptr)
内存释放函数(调用lmmp_heap_free_fn)
Definition memory.c:202
uint64_t mp_limb_t
Definition lmmp.h:76
#define lmmp_assert(x)
Definition lmmp.h:373
#define LIMB_BITS
Definition lmmp.h:86
#define lmmp_param_assert(x)
Definition lmmp.h:401
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:1050
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:89
#define lmmp_inc(p)
大数加1宏(预期无进位)
Definition lmmpn.h:938
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:687
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_size_t lmmp_fft_next_size_(mp_size_t n)
计算满足 >=n 的最小费马/梅森乘法可行尺寸
Definition mul_fft.c:95
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:1064
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
#define lmmp_dec_1(p, dec)
大数减指定值宏(预期无借位)
Definition lmmpn.h:977
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:1114
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_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:19
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 MULLO_BASECASE_THRESHOLD
Definition mparam.h:57
#define MUL_TOOM33_THRESHOLD
Definition mparam.h:50
#define MULLO_DC_THRESHOLD
Definition mparam.h:59
#define MUL_TOOM44_THRESHOLD
Definition mparam.h:52
#define t
#define numb
#define tp
#define n
void lmmp_mullo_dc_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_srcptr restrict numb, mp_ptr restrict tp, mp_size_t n)
Definition mullo.c:119
#define lo
#define lo2
#define b0
#define MUL_TOOM66_THRESHOLD
Definition mullo.c:116
#define b1
void lmmp_mullo_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_srcptr restrict numb, mp_size_t n)
Definition mullo.c:219
#define scratch
#define c1
void lmmp_sqrlo_dc_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_ptr restrict tp, mp_size_t n)
Definition mullo.c:177
#define a0
#define a1
void lmmp_mullo_fft_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_ptr scratch)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition mullo.c:22
#define c0
#define MUL_TOOM88_THRESHOLD
Definition mullo.c:117
#define lo1
#define TEMP_DECL
Definition tmp_alloc.h:131
#define ALLOC_TYPE(n, type)
Definition tmp_alloc.h:173
#define TEMP_FREE
Definition tmp_alloc.h:150
#define TALLOC_TYPE(n, type)
Definition tmp_alloc.h:148