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) {
128 return;
129 } else {
130 mp_size_t m, t;
131 if (n < MUL_TOOM33_THRESHOLD) {
132 m = 25 * n / 36;
133 } else if (n < MUL_TOOM44_THRESHOLD) {
134 m = 31 * n / 40;
135 } else if (n < MUL_TOOM66_THRESHOLD) {
136 m = 32 * n / 39;
137 } else if (n < MUL_TOOM88_THRESHOLD) {
138 m = 27 * n / 31;
139 } else {
140 m = 9 * n / 10;
141 }
142 t = n - m;
143 lmmp_debug_assert(2 * n > 4 * t);
144
145#define a0 (numa) // [numa, m]
146#define a1 (numa + m) // [numa+m, t]
147#define b0 (numb) // [numb, m]
148#define b1 (numb + m) // [numb+m, t]
149#define c0 (dst) // [dst, m]
150#define c1 (dst + m) // [dst+m, t]
151#define lo1 (tp) // [tp, t]
152#define lo2 (tp + t) // [tp+t, t]
153#define scratch (tp + 2 * t) // [tp+2*t, 2*t]
154 lmmp_mul_n_(tp, a0, b0, m);
155 lmmp_copy(c0, tp, n);
158 lmmp_add_n_(c1, c1, lo1, t);
159 lmmp_add_n_(c1, c1, lo2, t);
160 return;
161 }
162#undef a0
163#undef a1
164#undef b0
165#undef b1
166#undef c0
167#undef c1
168#undef lo1
169#undef lo2
170#undef scratch
171}
172
176 return;
177 } else {
178 mp_size_t m, t;
179 if (n < MUL_TOOM33_THRESHOLD) {
180 m = 25 * n / 36;
181 } else if (n < MUL_TOOM44_THRESHOLD) {
182 m = 31 * n / 40;
183 } else if (n < MUL_TOOM66_THRESHOLD) {
184 m = 32 * n / 39;
185 } else if (n < MUL_TOOM88_THRESHOLD) {
186 m = 27 * n / 31;
187 } else {
188 m = 9 * n / 10;
189 }
190 t = n - m;
191
192#define a0 (numa)
193#define a1 (numa + m)
194#define c0 (dst)
195#define c1 (dst + m)
196#define lo (tp) // [tp, t]
197#define scratch (tp + t) // [tp+t, 2*t]
198 lmmp_sqr_(tp, a0, m);
199 lmmp_copy(c0, tp, n);
202 }
203#undef a0
204#undef a1
205#undef c0
206#undef c1
207#undef lo
208#undef scratch
209}
210
212 lmmp_param_assert(n > 0);
213 if (n < MULLO_DC_THRESHOLD) {
214 if (numa == numb) {
215 TEMP_DECL;
218 TEMP_FREE;
219 return;
220 }
221 TEMP_DECL;
224 TEMP_FREE;
225 return;
226 } else {
227 TEMP_DECL;
230 TEMP_FREE;
231 return;
232 }
233}
#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
uint64_t mp_size_t
Definition lmmp.h:114
#define lmmp_debug_assert(x)
Definition lmmp.h:485
const mp_limb_t * mp_srcptr
Definition lmmp.h:118
void lmmp_free(void *ptr)
内存释放函数(调用lmmp_heap_free_fn)
Definition memory.c:423
uint64_t mp_limb_t
Definition lmmp.h:113
#define lmmp_assert(x)
Definition lmmp.h:468
#define LIMB_BITS
Definition lmmp.h:123
#define lmmp_param_assert(x)
Definition lmmp.h:496
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
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
void lmmp_mullo_basecase_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
基础低位乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
#define lmmp_inc(p)
加1宏(预期无进位)
Definition lmmpn.h:901
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:1027
#define lmmp_dec_1(p, dec)
减指定值宏(预期无借位)
Definition lmmpn.h:940
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_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:211
#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:173
#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:182
#define TEMP_FREE
Definition tmp_alloc.h:158
#define TALLOC_TYPE(n, type)
Definition tmp_alloc.h:156