LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
perfsqr.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/tmp_alloc.h"
17#include "../../../include/lammp/numth.h"
18#include "../../../include/lammp/lmmpn.h"
19
20
21#define MASK48 (0xFFFFFFFFFFFF)
22
23#define B1 (LIMB_BITS / 4)
24#define B2 (B1 * 2)
25#define B3 (B1 * 3)
26
27#define M1 ((1ULL << B1) - 1)
28#define M2 ((1ULL << B2) - 1)
29#define M3 ((1ULL << B3) - 1)
30
31#define LOW0(n) ((n) & M3)
32#define HIGH0(n) ((n) >> B3)
33
34#define LOW1(n) (((n) & M2) << B1)
35#define HIGH1(n) ((n) >> B2)
36
37#define LOW2(n) (((n) & M1) << B2)
38#define HIGH2(n) ((n) >> B1)
39
40#define PARTS0(n) (LOW0(n) + HIGH0(n))
41#define PARTS1(n) (LOW1(n) + HIGH1(n))
42#define PARTS2(n) (LOW2(n) + HIGH2(n))
43
44// a += val, if carry, add 1 to c
45#define ADD(c, a, val) \
46 do { \
47 mp_limb_t new_a = (a) + (val); \
48 (c) += new_a < (a); \
49 (a) = new_a; \
50 } while (0)
51
53 lmmp_param_assert(n > 0 && p != NULL);
54
55 mp_limb_t c0 = 0, c1 = 0, c2 = 0;
56 mp_limb_t a0 = 0, a1 = 0, a2 = 0;
57
58 while (n >= 3) {
59 ADD(c0, a0, p[0]);
60 ADD(c1, a1, p[1]);
61 ADD(c2, a2, p[2]);
62 p += 3;
63 n -= 3;
64 }
65 if (n == 2) {
66 ADD(c0, a0, p[0]);
67 ADD(c1, a1, p[1]);
68 } else if (n == 1) {
69 ADD(c0, a0, p[0]);
70 }
71
73 + PARTS1(c0) + PARTS2(c1) + PARTS0(c2);
74
75 res = (res & MASK48) + (res >> B3);
76 if (res >= MASK48)
77 res -= MASK48;
78 return res;
79}
80
81#undef B1
82#undef B2
83#undef B3
84#undef M1
85#undef M2
86#undef M3
87#undef LOW0
88#undef HIGH0
89#undef LOW1
90#undef HIGH1
91#undef LOW2
92#undef HIGH2
93#undef PARTS0
94#undef PARTS1
95#undef PARTS2
96#undef ADD
97
98/*
99 我们选择2^48-1作为模数只是因为其计算可以非常迅速,并且拥有一组非常好的因数分解
100 2^48-1 = 9 * 5 * 7 * 13 * 17 * 97 * 241 * 257 * 673
101 而下面的每个函数,都直接硬编码了完全平方数才可能具有的模数。当然也不需要担心这
102 么多的判断会导致分支预测效率很低,因为编译器通常可以很好的将其优化为位图,并且
103 由于位图很小,可能直接变成立即数。对于更长的数,我们手动计算了位图,直接计算地址,
104 取出对应的bit,可以避免编译器将其优化为多分支结构。
105
106 只有完全平方数以及部分非完全平方数可以通过,大部分非完全平方数都无法通过。
107 在模2^48-1下,完全平方数可能的结果仅占到大约 0.277%,
108 在模256下,完全平方数可能的结果仅占到大约 17.2%
109*/
110
111static inline bool is_perfsqr_p9(uchar r) {
112 return r == 0 || r == 1 || r == 4 || r == 7;
113}
114
115static inline bool is_perfsqr_p5(uchar r) {
116 return r == 0 || r == 1 || r == 4;
117}
118
119static inline bool is_perfsqr_p7(uchar r) {
120 return r == 0 || r == 1 || r == 2 || r == 4;
121}
122
123static inline bool is_perfsqr_p13(uchar r) {
124 return r == 0 || r == 1 || r == 3 || r == 4 || r == 9 || r == 10 || r == 12;
125}
126
127static inline bool is_perfsqr_p17(uchar r) {
128 return r == 0 || r == 1 || r == 2 || r == 4 || r == 8 || r == 9 || r == 13 || r == 15 || r == 16;
129}
130
131static inline bool is_perfsqr_p97(uchar r) {
132 return r == 0 || r == 1 || r == 2 || r == 3 || r == 4 || r == 6 || r == 8 || r == 9 || r == 11 || r == 12 ||
133 r == 16 || r == 18 || r == 22 || r == 24 || r == 25 || r == 27 || r == 31 || r == 32 || r == 33 || r == 35 ||
134 r == 36 || r == 43 || r == 44 || r == 47 || r == 48 || r == 49 || r == 50 || r == 53 || r == 54 || r == 61 ||
135 r == 62 || r == 64 || r == 65 || r == 66 || r == 70 || r == 72 || r == 73 || r == 75 || r == 79 || r == 81 ||
136 r == 85 || r == 86 || r == 88 || r == 89 || r == 91 || r == 93 || r == 94 || r == 95 || r == 96;
137}
138
139static inline bool is_perfsqr_p241(ushort r) {
140 static const uint64_t p241[] = {0x3C67A3116B15977F, 0x2FD21C174C8FA909, 0x98F24257C4CBA0E1, 0x0001FBA6A35A2317};
141 ushort elem = r / 64;
143 ushort bit = r % 64;
144 return (p241[elem] >> bit) & 1ULL;
145}
146
147static inline bool is_perfsqr_p257(ushort r) {
148 static const uint64_t p257[] = {0x7E16541DE6E7AB17, 0x1F76811C93128359, 0x6B052324E205BBE3, 0xA3579D9EE0A9A1FA,
149 0x0000000000000001};
150 ushort elem = r / 64;
152 ushort bit = r % 64;
153 return (p257[elem] >> bit) & 1ULL;
154}
155
156static inline bool is_perfsqr_p673(ushort r) {
157 static const uint64_t p673[] = {0x85F744B13FA573DF, 0xC231D5979ABA4F21, 0xE944C76E98DD0C01, 0xD20E0F2BD993E915,
158 0x616259FB225208AB, 0x7E691A18F8B7B47C, 0x53C1C12F54412913, 0xDB8C8A5EA25F266F,
159 0xA6AE310E00C2EC65, 0x348BBE8613C97567, 0x00000001EF3A97F2};
160 ushort elem = r / 64;
162 ushort bit = r % 64;
163 return (p673[elem] >> bit) & 1ULL;
164}
165
166static inline bool is_perfsqr_p256(uchar r) {
167 static const uint64_t p256[] = {0x0202021202030213, 0x0202021202020213, 0x0202021202030212, 0x0202021202020212};
168 ushort elem = r / 64;
170 ushort bit = r % 64;
171 return (p256[elem] >> bit) & 1ULL;
172}
173
175 lmmp_param_assert(p > 0);
176 mp_limb_t a = p % 256;
177 if (!is_perfsqr_p256(a)) return false;
178 p = p % MASK48;
179 return is_perfsqr_p9(p % 9) && is_perfsqr_p5(p % 5) && is_perfsqr_p7(p % 7) && is_perfsqr_p13(p % 13) &&
180 is_perfsqr_p17(p % 17) && is_perfsqr_p97(p % 97) && is_perfsqr_p241(p % 241) &&
181 is_perfsqr_p257(p % 257) && is_perfsqr_p673(p % 673);
182}
183
185 lmmp_param_assert(n > 0 && p != NULL);
186 lmmp_param_assert(p[n - 1] > 0);
187 if (n == 1) return lmmp_perfsqr_filter_1_(p[0]);
188 mp_limb_t a = p[0] % 256;
189 if (!is_perfsqr_p256(a))
190 return false;
192 return is_perfsqr_p9(r % 9) && is_perfsqr_p5(r % 5) && is_perfsqr_p7(r % 7) && is_perfsqr_p13(r % 13) &&
193 is_perfsqr_p17(r % 17) && is_perfsqr_p97(r % 97) && is_perfsqr_p241(r % 241) &&
194 is_perfsqr_p257(r % 257) && is_perfsqr_p673(r % 673);
195}
196
198 lmmp_param_assert(n > 0 && p != NULL);
199 lmmp_param_assert(p[n - 1] > 0);
200 bool filter, ret;
201
203 if (filter == false) return false;
204
205 TEMP_DECL;
207 mp_ptr restrict dstr = tp + n / 2 + 1;
208 lmmp_sqrt_(tp, dstr, p, n, 0);
209 ret = lmmp_zero_q_(dstr, n / 2 + 1);
210 TEMP_FREE;
211 return ret;
212}
mp_limb_t * mp_ptr
Definition lmmp.h:117
uint64_t mp_size_t
Definition lmmp.h:114
const mp_limb_t * mp_srcptr
Definition lmmp.h:118
uint64_t mp_limb_t
Definition lmmp.h:113
#define lmmp_param_assert(x)
Definition lmmp.h:496
static int lmmp_zero_q_(mp_srcptr p, mp_size_t n)
判零函数(内联)
Definition lmmpn.h:982
#define a0
#define a1
#define a2
#define tp
#define n
#define c1
#define c0
uint8_t uchar
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition numth.h:27
uint16_t ushort
Definition numth.h:29
void lmmp_sqrt_(mp_ptr dsts, mp_ptr dstr, mp_srcptr numa, mp_size_t na, mp_size_t nf)
计算 [numa,na] * B^(2*nf) 的平方根和余数
Definition sqrt.c:276
static bool is_perfsqr_p7(uchar r)
Definition perfsqr.c:119
#define ADD(c, a, val)
Definition perfsqr.c:45
#define MASK48
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition perfsqr.c:21
#define PARTS0(n)
Definition perfsqr.c:40
static bool is_perfsqr_p241(ushort r)
Definition perfsqr.c:139
bool lmmp_perfsqr_filter_1_(mp_limb_t p)
非完全平方数过滤器
Definition perfsqr.c:174
static bool is_perfsqr_p17(uchar r)
Definition perfsqr.c:127
static bool is_perfsqr_p256(uchar r)
Definition perfsqr.c:166
static bool is_perfsqr_p673(ushort r)
Definition perfsqr.c:156
bool lmmp_perfsqr_(mp_srcptr p, mp_size_t n)
判断[p,n]是否为完全平方数
Definition perfsqr.c:197
static bool is_perfsqr_p13(uchar r)
Definition perfsqr.c:123
#define PARTS1(n)
Definition perfsqr.c:41
static bool is_perfsqr_p257(ushort r)
Definition perfsqr.c:147
static bool is_perfsqr_p9(uchar r)
Definition perfsqr.c:111
mp_limb_t lmmp_mod_2p48sub1_(mp_srcptr p, mp_size_t n)
计算 [p,n] % 2^48-1
Definition perfsqr.c:52
static bool is_perfsqr_p5(uchar r)
Definition perfsqr.c:115
#define B3
Definition perfsqr.c:25
static bool is_perfsqr_p97(uchar r)
Definition perfsqr.c:131
#define PARTS2(n)
Definition perfsqr.c:42
bool lmmp_perfsqr_filter_(mp_srcptr p, mp_size_t n)
非完全平方数过滤器
Definition perfsqr.c:184
#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