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