Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/rings/bernmm/bernmm-test.cpp
4057 views
1
/*
2
bernmm-test.cpp: test module
3
4
Copyright (C) 2008, 2009, David Harvey
5
6
This file is part of the bernmm package (version 1.1).
7
8
bernmm is released under a BSD-style license. See the README file in
9
the source distribution for details.
10
*/
11
12
#include <iostream>
13
#include <NTL/ZZ.h>
14
#include <gmp.h>
15
#include "bern_modp_util.h"
16
#include "bern_modp.h"
17
#include "bern_rat.h"
18
19
20
NTL_CLIENT;
21
22
23
using namespace bernmm;
24
using namespace std;
25
26
27
/*
28
Computes B_0, B_1, ..., B_{n-1} using naive algorithm, writes them to res.
29
*/
30
void bern_naive(mpq_t* res, long n)
31
{
32
mpq_t t, u;
33
mpq_init(t);
34
mpq_init(u);
35
36
// compute res[j] = B_j / j! for 0 <= j < n
37
if (n > 0)
38
mpq_set_si(res[0], 1, 1);
39
40
for (long j = 1; j < n; j++)
41
{
42
mpq_set_si(res[j], 0, 1);
43
mpq_set_ui(t, 1, 1);
44
for (long k = 0; k < j; k++)
45
{
46
mpz_mul_ui(mpq_denref(t), mpq_denref(t), k + 2);
47
mpq_mul(u, res[j - 1 - k], t);
48
mpq_sub(res[j], res[j], u);
49
}
50
}
51
52
// multiply through by j! for 0 <= j < n
53
mpq_set_ui(t, 1, 1);
54
for (long j = 2; j < n; j++)
55
{
56
mpz_mul_ui(mpq_numref(t), mpq_numref(t), j);
57
mpq_mul(res[j], res[j], t);
58
}
59
60
mpq_clear(u);
61
mpq_clear(t);
62
}
63
64
65
/*
66
Tests _bern_modp_powg() for a given p and k by comparing against the
67
rational number B_k (must be supplied in b).
68
69
Returns 1 on success.
70
*/
71
int testcase__bern_modp_powg(long p, long k, mpq_t b)
72
{
73
double pinv = 1 / ((double) p);
74
75
// compute B_k mod p using _bern_modp_powg()
76
long x = _bern_modp_powg(p, pinv, k);
77
x = MulMod(x, k, p, pinv);
78
79
// compute B_k mod p from rational B_k
80
long y = mpz_fdiv_ui(mpq_numref(b), p);
81
long z = mpz_fdiv_ui(mpq_denref(b), p);
82
return y == MulMod(z, x, p, pinv);
83
}
84
85
86
87
/*
88
Tests _bern_modp_powg() by comparing against naive computation of B_k
89
(as a rational) for a range of small p and k.
90
91
Returns 1 on success.
92
*/
93
int test__bern_modp_powg()
94
{
95
int success = 1;
96
97
const long MAX = 300;
98
mpq_t bern[MAX];
99
100
// compute B_k's as rational numbers using naive algorithm
101
for (long i = 0; i < MAX; i++)
102
mpq_init(bern[i]);
103
bern_naive(bern, MAX);
104
105
// try a range of k's
106
for (long k = 2; k < MAX && success; k += 2)
107
{
108
// try a range of small p's
109
for (long p = k + 3; p < 2*MAX && success; p += 2)
110
{
111
if (!ProbPrime(p))
112
continue;
113
success = success && testcase__bern_modp_powg(p, k, bern[k]);
114
}
115
116
// try a single larger p
117
success = success && testcase__bern_modp_powg(1000003, k, bern[k]);
118
}
119
120
// if we're on a 32-bit machine, try a single example with p right near
121
// NTL's boundary (this is infeasible on a 64-bit machine)
122
if (NTL_SP_NBITS <= 32)
123
{
124
long p = NTL_SP_BOUND - 1;
125
while (!ProbPrime(p))
126
p--;
127
128
long k = (MAX/2)*2 - 2;
129
success = success && testcase__bern_modp_powg(p, k, bern[k]);
130
}
131
132
for (long i = 0; i < MAX; i++)
133
mpq_clear(bern[i]);
134
135
return success;
136
}
137
138
139
140
/*
141
Tests _bern_modp_pow2() for a given p and k by comparing against result
142
from _bern_modp_powg().
143
144
Returns 1 on success.
145
146
If 2^k = 1 mod p, then _bern_modp_pow2() won't work, so it just returns 1.
147
*/
148
int testcase__bern_modp_pow2(long p, long k)
149
{
150
double pinv = 1 / ((double) p);
151
152
if (PowerMod(2, k, p, pinv) == 1)
153
return 1;
154
155
long x = _bern_modp_powg(p, pinv, k);
156
long y = _bern_modp_pow2(p, pinv, k);
157
158
return x == y;
159
}
160
161
162
163
/*
164
Tests _bern_modp_pow2() by comparing against _bern_modp_powg() for
165
a range of p and k.
166
167
Returns 1 on success.
168
*/
169
int test__bern_modp_pow2()
170
{
171
int success = 1;
172
173
// exhaustive comparison over some small p and k
174
for (long p = 5; p < 2000 && success; p += 2)
175
{
176
if (!ProbPrime(p))
177
continue;
178
179
for (long k = 2; k <= p - 3 && success; k += 2)
180
success = success && testcase__bern_modp_pow2(p, k);
181
}
182
183
// a few larger values of p
184
for (long p = 1000000; p < 1030000; p++)
185
{
186
if (!ProbPrime(p))
187
continue;
188
189
long k = 2 * (rand() % ((p-3)/2)) + 2;
190
success = success && testcase__bern_modp_pow2(p, k);
191
}
192
193
// if we're on a 32-bit machine, try a single example with p right near
194
// NTL's boundary (this is infeasible on a 64-bit machine)
195
if (NTL_SP_NBITS <= 32)
196
{
197
long p = NTL_SP_BOUND - 1;
198
while (!ProbPrime(p))
199
p--;
200
success = success & testcase__bern_modp_pow2(p, 10);
201
}
202
203
// try a few just below the REDC barrier
204
if (ULONG_BITS == 32)
205
{
206
long boundary = 1L << (ULONG_BITS/2 - 1);
207
for (long p = boundary - 1000; p < boundary && success; p++)
208
{
209
if (ProbPrime(p))
210
{
211
for (long trial = 0; trial < 1000 && success; trial++)
212
{
213
long k = 2 * (rand() % ((p-3)/2)) + 2;
214
success = success && testcase__bern_modp_pow2(p, k);
215
}
216
}
217
}
218
}
219
else
220
{
221
// on a 64-bit machine, only try one, since these are huge!
222
long p = 1L << (ULONG_BITS/2 - 1);
223
while (!ProbPrime(p))
224
p--;
225
success = success && testcase__bern_modp_pow2(p, 10);
226
}
227
228
return success;
229
}
230
231
232
/*
233
Tests bern_rat() by comparing against the naive algorithm for several small
234
k, and testing against bern_modp() for a couple of larger k.
235
236
Returns 1 on success.
237
*/
238
int test_bern_rat()
239
{
240
int success = 1;
241
242
const long MAX = 300;
243
mpq_t bern[MAX];
244
245
// compute B_k's as rational numbers using naive algorithm
246
for (long i = 0; i < MAX; i++)
247
mpq_init(bern[i]);
248
bern_naive(bern, MAX);
249
250
mpq_t x;
251
mpq_init(x);
252
253
// exhaustive test for small k
254
for (long k = 0; k < MAX && success; k++)
255
{
256
bern_rat(x, k, 4); // try with 4 threads just for fun
257
success = success && mpq_equal(x, bern[k]);
258
}
259
260
// try a few larger k
261
for (long i = 0; i < 50 && success; i++)
262
{
263
long k = ((random() % 20000) / 2) * 2;
264
bern_rat(x, k, 4);
265
266
// compare with modular information
267
long p = 1000003;
268
long num = mpz_fdiv_ui(mpq_numref(x), p);
269
long den = mpz_fdiv_ui(mpq_denref(x), p);
270
success = success && (MulMod(bern_modp(p, k), den, p) == num);
271
}
272
273
mpq_clear(x);
274
for (long i = 0; i < MAX; i++)
275
mpq_clear(bern[i]);
276
277
return success;
278
}
279
280
281
void report(int success)
282
{
283
if (success)
284
cout << "ok" << endl;
285
else
286
{
287
cout << "failed!" << endl;
288
abort();
289
}
290
}
291
292
293
int main(int argc, char* argv[])
294
{
295
if (argc == 1)
296
{
297
cout << "bernmm test module" << endl;
298
cout << endl;
299
cout << " bernmm-test --test" << endl;
300
cout << " runs test suite" << endl;
301
cout << " bernmm-test --rational <k> <threads>" << endl;
302
cout << " computes B_k with <threads> threads" << endl;
303
cout << " bernmm-test --modular <p> <k>" << endl;
304
cout << " computes B_k mod p" << endl;
305
return 0;
306
}
307
308
if (!strcmp(argv[1], "--test"))
309
{
310
cout << "testing _bern_modp_powg()... " << flush;
311
report(test__bern_modp_powg());
312
313
cout << "testing _bern_modp_pow2()... " << flush;
314
report(test__bern_modp_pow2());
315
316
cout << "testing bern_rat()... " << flush;
317
report(test_bern_rat());
318
}
319
else if (!strcmp(argv[1], "--rational"))
320
{
321
if (argc <= 3)
322
{
323
cout << "not enough arguments" << endl;
324
return 0;
325
}
326
long k = atol(argv[2]);
327
long threads = atol(argv[3]);
328
mpq_t r;
329
mpq_init(r);
330
bern_rat(r, k, threads);
331
gmp_printf("%Zd/%Zd\n", mpq_numref(r), mpq_denref(r));
332
mpq_clear(r);
333
}
334
else if (!strcmp(argv[1], "--modular"))
335
{
336
if (argc <= 3)
337
{
338
cout << "not enough arguments" << endl;
339
return 0;
340
}
341
long p = atol(argv[2]);
342
long k = atol(argv[3]);
343
cout << bern_modp(p, k) << endl;
344
}
345
else
346
{
347
cout << "unknown command" << endl;
348
}
349
350
return 0;
351
}
352
353
354
// end of file ================================================================
355
356