Orbiter 2022
Combinatorial Objects
number_theory_domain.cpp
Go to the documentation of this file.
1// number_theory_domain.cpp
2//
3// Anton Betten
4// April 3, 2003
5
6#include "foundations.h"
7
8using namespace std;
9
10
11namespace orbiter {
12namespace layer1_foundations {
13namespace number_theory {
14
15
16// The First 1,000 Primes
17// (the 1,000th is 7919)
18// For more information on primes see http://primes.utm.edu/
19
20static int the_first_thousand_primes[] = {
21 2, 3, 5, 7, 11, 13, 17, 19, 23, 29
22, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71
23, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113
24, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173
25, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229
26, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281
27, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349
28, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409
29, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463
30, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541
31, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601
32, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659
33, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733
34, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809
35, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863
36, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941
37, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013
38, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069
39, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151
40, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223
41, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291
42, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373
43, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451
44, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511
45, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583
46, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657
47, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733
48, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811
49, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889
50, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987
51, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053
52, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129
53, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213
54, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287
55, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357
56, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423
57, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531
58, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617
59, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687
60, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741
61, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819
62, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903
63, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999
64, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079
65, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181
66, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257
67, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331
68, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413
69, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511
70, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571
71, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643
72, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727
73, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821
74, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907
75, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989
76, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057
77, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139
78, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231
79, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297
80, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409
81, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493
82, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583
83, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657
84, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751
85, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831
86, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937
87, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003
88, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087
89, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179
90, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279
91, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387
92, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443
93, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521
94, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639
95, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693
96, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791
97, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857
98, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939
99, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053
100, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133
101, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221
102, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301
103, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367
104, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473
105, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571
106, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673
107, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761
108, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833
109, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917
110, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997
111, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103
112, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207
113, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297
114, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411
115, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499
116, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561
117, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643
118, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723
119, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829
120, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919
121};
122
123
125{
126
127}
128
130{
131
132}
133
134long int number_theory_domain::mod(long int a, long int p)
135{
136 int f_negative = FALSE;
137 long int r;
138
139 if (a < 0) {
140 a = -1 * a; // 5/6/2020: here was an error: it was a = -1;
141 f_negative = TRUE;
142 }
143 r = a % p;
144 if (f_negative && r) {
145 r = p - r;
146 }
147 return r;
148}
149
150long int number_theory_domain::int_negate(long int a, long int p)
151{
152 long int b;
153
154 b = a % p;
155 if (b == 0) {
156 return 0;
157 }
158 else {
159 return p - b;
160 }
161}
162
163
164long int number_theory_domain::power_mod(long int a, long int n, long int p)
165{
168
169 A.create(a, __FILE__, __LINE__);
170 N.create(n, __FILE__, __LINE__);
171 M.create(p, __FILE__, __LINE__);
172 D.power_longint_mod(A, N, M, 0 /* verbose_level */);
173 return A.as_lint();
174}
175
176long int number_theory_domain::inverse_mod(long int a, long int p)
177{
180 long int u;
181
182 A.create(a, __FILE__, __LINE__);
183 B.create(p, __FILE__, __LINE__);
184 D.extended_gcd(A,B, G, U, V, 0 /* verbose_level */);
185 if (!G.is_one() && !G.is_mone()) {
186 cout << "number_theory_domain::inverse_mod a and p are not coprime" << endl;
187 cout << "a=" << a << endl;
188 cout << "p=" << p << endl;
189 cout << "gcd=" << G << endl;
190 exit(1);
191 }
192 u = U.as_lint();
193 while (u < 0) {
194 u += p;
195 }
196 return u;
197}
198
199long int number_theory_domain::mult_mod(long int a, long int b, long int p)
200{
203
204 A.create(a, __FILE__, __LINE__);
205 B.create(b, __FILE__, __LINE__);
206 P.create(p, __FILE__, __LINE__);
207 D.mult_mod(A, B, C, P, 0 /* verbose_level */);
208 return C.as_int();
209}
210
211long int number_theory_domain::add_mod(long int a, long int b, long int p)
212{
215 long int r;
216
217 A.create(a, __FILE__, __LINE__);
218 B.create(b, __FILE__, __LINE__);
219 P.create(p, __FILE__, __LINE__);
220 D.add(A, B, C);
221 D.integral_division_by_lint(C, p, Q, r);
222 return r;
223}
224
225long int number_theory_domain::ab_over_c(long int a, long int b, long int c)
226{
228 ring_theory::longinteger_object A, B, C, AB, Q;
229 long int r;
230
231 A.create(a, __FILE__, __LINE__);
232 B.create(b, __FILE__, __LINE__);
233 D.mult(A, B, AB);
234 D.integral_division_by_lint(AB, c, Q, r);
235 return Q.as_lint();
236}
237
239{
240 if (a < 0) {
241 return -a;
242 }
243 else {
244 return a;
245 }
246}
247
248long int number_theory_domain::gcd_lint(long int m, long int n)
249{
250#if 0
251 longinteger_domain D;
252 longinteger_object M, N, G, U, V;
253
254
255 M.create(m);
256 N.create(n);
257 D.extended_gcd(M, N, G, U, V, 0);
258 return G.as_int();
259#else
260 long int r, s;
261
262 if (m < 0) {
263 m *= -1;
264 }
265 if (n < 0) {
266 n *= -1;
267 }
268 if (n > m) {
269 r = m;
270 m = n;
271 n = r;
272 }
273 if (n == 0) {
274 return m;
275 }
276 while (TRUE) {
277 s = m / n;
278 r = m - (s * n);
279 if (r == 0) {
280 return n;
281 }
282 m = n;
283 n = r;
284 }
285#endif
286}
287
288void number_theory_domain::extended_gcd_int(int m, int n, int &g, int &u, int &v)
289{
292
293
294 M.create(m, __FILE__, __LINE__);
295 N.create(n, __FILE__, __LINE__);
296 D.extended_gcd(M, N, G, U, V, 0);
297 g = G.as_int();
298 u = U.as_int();
299 v = V.as_int();
300}
301
302void number_theory_domain::extended_gcd_lint(long int m, long int n,
303 long int &g, long int &u, long int &v)
304{
307
308
309 M.create(m, __FILE__, __LINE__);
310 N.create(n, __FILE__, __LINE__);
311 D.extended_gcd(M, N, G, U, V, 0);
312 g = G.as_lint();
313 u = U.as_lint();
314 v = V.as_lint();
315}
316
318 long int a, long int b, int f_key, int verbose_level)
319//Computes gcd(a,b)
320{
321 int f_v = (verbose_level >= 1);
322 long int a1, b1, q1, r1;
323
324 if (f_v) {
325 cout << "number_theory_domain::gcd_with_key_in_latex "
326 "a=" << a << ", b=" << b << ":" << endl;
327 }
328 if (a > b) {
329 a1 = a;
330 b1 = b;
331 }
332 else {
333 a1 = b;
334 b1 = a;
335 }
336
337 while (TRUE) {
338
339
340 r1 = a1 % b1;
341 q1 = (a1 - r1) / b1;
342 if (f_key) {
343 ost << "=";
344 ost << " \\gcd\\big( " << b1 << ", " << r1 << "\\big) "
345 "\\qquad \\mbox{b/c} \\; " << a1 << " = " << q1
346 << " \\cdot " << b1 << " + " << r1 << "\\\\" << endl;
347 }
348 if (f_v) {
349 cout << "number_theory_domain::gcd_with_key_in_latex "
350 "a1=" << a1 << " b1=" << b1
351 << " r1=" << r1 << " q1=" << q1
352 << endl;
353 }
354 if (r1 == 0) {
355 break;
356 }
357 a1 = b1;
358 b1 = r1;
359 }
360 if (f_key) {
361 ost << "= " << b1 << "\\\\" << endl;
362 }
363 if (f_v) {
364 cout << "number_theory_domain::gcd_with_key_in_latex done" << endl;
365 }
366 return b1;
367}
368
370{
372
374 int res;
375
376 a.create(i, __FILE__, __LINE__);
377 D.power_int(a, j);
378 res = a.as_int();
379 b.create(res, __FILE__, __LINE__);
380 b.negate();
381 D.add(a, b, c);
382 if (!c.is_zero()) {
383 cout << "i_power_j_safe int overflow when computing "
384 << i << "^" << j << endl;
385 cout << "should be " << a << endl;
386 cout << "but comes out as " << res << endl;
387 exit(1);
388 }
389 return res;
390}
391
392long int number_theory_domain::i_power_j_lint_safe(int i, int j, int verbose_level)
393{
394 int f_v = (verbose_level >= 1);
396
398 long int res;
399
400 if (f_v) {
401 cout << "number_theory_domain::i_power_j_lint_safe "
402 "i=" << i << " j=" << j << endl;
403 }
404 a.create(i, __FILE__, __LINE__);
405 D.power_int(a, j);
406 if (f_v) {
407 cout << "number_theory_domain::i_power_j_lint_safe "
408 "a=" << a << endl;
409 }
410 res = a.as_lint();
411 if (f_v) {
412 cout << "number_theory_domain::i_power_j_lint_safe "
413 "as_lint=" << res << endl;
414 }
415 b.create(res, __FILE__, __LINE__);
416 if (f_v) {
417 cout << "number_theory_domain::i_power_j_lint_safe "
418 "b=" << b << endl;
419 }
420 b.negate();
421 D.add(a, b, c);
422 if (f_v) {
423 cout << "number_theory_domain::i_power_j_lint_safe "
424 "c=" << c << endl;
425 }
426 if (!c.is_zero()) {
427 cout << "i_power_j_safe int overflow when computing "
428 << i << "^" << j << endl;
429 cout << "should be " << a << endl;
430 cout << "but comes out as " << res << endl;
431 exit(1);
432 }
433 return res;
434}
435
436long int number_theory_domain::i_power_j_lint(long int i, long int j)
437//Computes $i^j$ as integer.
438//There is no checking for overflow.
439{
440 long int k, r = 1;
441
442 //cout << "i_power_j i=" << i << ", j=" << j << endl;
443 for (k = 0; k < j; k++) {
444 r *= i;
445 }
446 //cout << "i_power_j yields" << r << endl;
447 return r;
448}
449
451//Computes $i^j$ as integer.
452//There is no checking for overflow.
453{
454 int k, r = 1;
455
456 //cout << "i_power_j i=" << i << ", j=" << j << endl;
457 for (k = 0; k < j; k++) {
458 r *= i;
459 }
460 //cout << "i_power_j yields" << r << endl;
461 return r;
462}
463
464
465void number_theory_domain::do_eulerfunction_interval(long int n_min, long int n_max, int verbose_level)
466{
467 int f_v = (verbose_level >= 1);
468 long int a, n, i;
469 long int *T;
470 int t0, t1, dt;
473 char str[1000];
474
475 t0 = Os.os_ticks();
476 if (f_v) {
477 cout << "number_theory_domain::do_eulerfunction_interval n_min=" << n_min << " n_max=" << n_max << endl;
478 }
479
480 std::vector<std::pair<long int, long int>> Table;
481
482 for (n = n_min; n <= n_max; n++) {
483
484
485 std::pair<long int, long int> P;
486
487 a = euler_function(n);
488 if (f_v) {
489 cout << "eulerfunction of " << n << " is " << a << endl;
490 }
491
492 P.first = n;
493 P.second = a;
494
495 Table.push_back(P);
496
497 }
498 T = NEW_lint(2 * Table.size());
499 for (i = 0; i < Table.size(); i++) {
500 T[2 * i + 0] = Table[i].first;
501 T[2 * i + 1] = Table[i].second;
502 }
503 sprintf(str, "table_eulerfunction_%ld_%ld.csv", n_min, n_max);
504 string fname;
505
506 fname.assign(str);
507
508 string *Headers;
509
510 Headers = new string[2];
511 Headers[0].assign("N");
512 Headers[1].assign("PHI");
513
514 Fio.lint_matrix_write_csv_override_headers(fname, Headers, T, Table.size(), 2);
515
516 cout << "Written file " << fname << " of size " << Fio.file_size(fname) << endl;
517
518 delete [] Headers;
519
520 t1 = Os.os_ticks();
521 dt = t1 - t0;
522 cout << "time: ";
523 Os.time_check_delta(cout, dt);
524 cout << endl;
525 if (f_v) {
526 cout << "number_theory_domain::do_eulerfunction_interval done" << endl;
527 }
528}
529
530
531
532
534//Computes Eulers $\varphi$-function for $n$.
535//Uses the prime factorization of $n$. before: eulerfunc
536{
537 int *primes;
538 int *exponents;
539 int len;
540 long int i, k, p1, e1;
541
542 len = factor_int(n, primes, exponents);
543
544 k = 1;
545 for (i = 0; i < len; i++) {
546 p1 = primes[i];
547 e1 = exponents[i];
548 if (e1 > 1) {
549 k *= i_power_j(p1, e1 - 1);
550 }
551 k *= (p1 - 1);
552 }
553 FREE_int(primes);
554 FREE_int(exponents);
555 return k;
556}
557
559//Computes the Moebius $\mu$-function for $n$.
560//Uses the prime factorization of $n$.
561{
562 int *primes;
563 int *exponents;
564 int len;
565 long int i;
566
567 len = factor_int(n, primes, exponents);
568
569 for (i = 0; i < len; i++) {
570 if (exponents[i] > 1) {
571 return 0;
572 }
573 }
574 FREE_int(primes);
575 FREE_int(exponents);
576 if (EVEN(len)) {
577 return 1;
578 }
579 else {
580 return -1;
581 }
582}
583
584
585
586long int number_theory_domain::order_mod_p(long int a, long int p)
587//Computes the order of $a$ mod $p$, i.~e. the smallest $k$
588//s.~th. $a^k \equiv 1$ mod $p$.
589{
590 long int o, b;
591
592 if (a < 0) {
593 cout << "number_theory_domain::order_mod_p a < 0" << endl;
594 exit(1);
595 }
596 a %= p;
597 if (a == 0) {
598 return 0;
599 }
600 if (a == 1) {
601 return 1;
602 }
603 o = 1;
604 b = a;
605 while (b != 1) {
606 b *= a;
607 b %= p;
608 o++;
609 }
610 return o;
611}
612
614// returns $\log_2(n)$
615{ int i;
616
617 if (n <= 0) {
618 cout << "int_log2 n <= 0" << endl;
619 exit(1);
620 }
621 for (i = 0; n > 0; i++) {
622 n >>= 1;
623 }
624 return i;
625}
626
628// returns $\log_{10}(n)$
629{
630 int j;
631
632 if (n <= 0) {
633 cout << "int_log10 n <= 0" << endl;
634 cout << "n = " << n << endl;
635 exit(1);
636 }
637 j = 0;
638 while (n) {
639 n /= 10;
640 j++;
641 }
642 return j;
643}
644
646// returns $\log_{10}(n)$
647{
648 long int j;
649
650 if (n <= 0) {
651 cout << "lint_log10 n <= 0" << endl;
652 cout << "n = " << n << endl;
653 exit(1);
654 }
655 j = 0;
656 while (n) {
657 n /= 10;
658 j++;
659 }
660 return j;
661}
662
664// returns the number of digits in base q representation
665{ int i;
666
667 if (n < 0) {
668 cout << "int_logq n < 0" << endl;
669 exit(1);
670 }
671 i = 0;
672 do {
673 i++;
674 n /= q;
675 } while (n);
676 return i;
677}
678
680// returns the number of digits in base q representation
681{
682 int i;
683
684 if (n < 0) {
685 cout << "int_logq n < 0" << endl;
686 exit(1);
687 }
688 i = 0;
689 do {
690 i++;
691 n /= q;
692 } while (n);
693 return i;
694}
695
697// assuming that q is a prime power, this fuction tests
698// whether or not q is a srict prime power
699{
700 int p;
701
703 if (q != p)
704 return TRUE;
705 else
706 return FALSE;
707}
708
710{
711 int p1;
712
713 p1 = smallest_primedivisor(p);
714 if (p1 != p)
715 return FALSE;
716 else
717 return TRUE;
718}
719
721{
722 int p, h;
723
724 return is_prime_power(q, p, h);
725}
726
727int number_theory_domain::is_prime_power(int q, int &p, int &h)
728{
729 int i;
730
732 //cout << "smallest prime in " << q << " is " << p << endl;
733 q = q / p;
734 h = 1;
735 while (q > 1) {
736 i = q % p;
737 //cout << "q=" << q << " i=" << i << endl;
738 if (i) {
739 return FALSE;
740 }
741 q = q / p;
742 h++;
743 }
744 return TRUE;
745}
746
748//Computes the smallest prime dividing $n$.
749//The algorithm is based on Lueneburg~\cite{Lueneburg87a}.
750{
751 int flag, i, q;
752
753 if (EVEN(n)) {
754 return(2);
755 }
756 if ((n % 3) == 0) {
757 return(3);
758 }
759 i = 5;
760 flag = 0;
761 while (TRUE) {
762 q = n / i;
763 if (n == q * i) {
764 return(i);
765 }
766 if (q < i) {
767 return(n);
768 }
769 if (flag) {
770 i += 4;
771 }
772 else {
773 i += 2;
774 }
775 flag = !flag;
776 }
777}
778
779int number_theory_domain::sp_ge(int n, int p_min)
780// Computes the smalles prime dividing $n$
781// which is greater than or equal to p\_min.
782{
783 int i, q;
784
785 if (p_min == 0)
786 p_min = 2;
787 if (p_min < 0)
788 p_min = - p_min;
789 if (p_min <= 2) {
790 if (EVEN(n))
791 return 2;
792 p_min = 3;
793 }
794 if (p_min <= 3) {
795 if ((n % 3) == 0)
796 return 3;
797 p_min = 5;
798 }
799 if (EVEN(p_min))
800 p_min--;
801 i = p_min;
802 while (TRUE) {
803 q = n / i;
804 // cout << "n=" << n << " i=" << i << " q=" << q << endl;
805 if (n == q * i)
806 return(i);
807 if (q < i)
808 return(n);
809 i += 2;
810 }
811#if 0
812 int flag;
813
814 if (EVEN((p_min - 1) >> 1))
815 /* p_min cong 1 mod 4 ? */
816 flag = FALSE;
817 else
818 flag = TRUE;
819 while (TRUE) {
820 q = n / i;
821 cout << "n=" << n << " i=" << i << " q=" << q << endl;
822 if (n == q * i)
823 return(i);
824 if (q < i)
825 return(n);
826 if (flag) {
827 i += 4;
828 flag = FALSE;
829 }
830 else {
831 i += 2;
832 flag = TRUE;
833 }
834 }
835#endif
836}
837
838int number_theory_domain::factor_int(int a, int *&primes, int *&exponents)
839{
840 int alloc_len = 10, len = 0;
841 int p, i;
842
843 primes = NEW_int(alloc_len);
844 exponents = NEW_int(alloc_len);
845
846 if (a == 1) {
847 cout << "factor_int, the number is one" << endl;
848 return 0;
849 }
850 if (a <= 0) {
851 cout << "factor_int, the number is <= 0" << endl;
852 exit(1);
853 }
854 while (a > 1) {
856 a /= p;
857 if (len == 0) {
858 primes[0] = p;
859 exponents[0] = 1;
860 len = 1;
861 }
862 else {
863 if (p == primes[len - 1]) {
864 exponents[len - 1]++;
865 }
866 else {
867 if (len == alloc_len) {
868 int *primes2, *exponents2;
869
870 alloc_len += 10;
871 primes2 = NEW_int(alloc_len);
872 exponents2 = NEW_int(alloc_len);
873 for (i = 0; i < len; i++) {
874 primes2[i] = primes[i];
875 exponents2[i] = exponents[i];
876 }
877 FREE_int(primes);
878 FREE_int(exponents);
879 primes = primes2;
880 exponents = exponents2;
881 }
882 primes[len] = p;
883 exponents[len] = 1;
884 len++;
885 }
886 }
887 }
888 return len;
889}
890
891void number_theory_domain::factor_lint(long int a, vector<long int> &primes, vector<int> &exponents)
892{
893 int p, p0;
894
895 if (a == 1) {
896 cout << "number_theory_domain::factor_lint, the number is one" << endl;
897 exit(1);
898 }
899 if (a <= 0) {
900 cout << "number_theory_domain::factor_lint, the number is <= 0" << endl;
901 exit(1);
902 }
903 p0 = -1;
904 while (a > 1) {
906 a /= p;
907 if (p == p0) {
908 exponents[exponents.size()]++;
909 }
910 else {
911 primes.push_back(p);
912 exponents.push_back(1);
913 p0 = p;
914 }
915 }
916}
917
919{
920 if (q == 1) {
921 cout << "factor_prime_power q is one" << endl;
922 exit(1);
923 }
925 q /= p;
926 e = 1;
927 while (q != 1) {
928 if ((q % p) != 0) {
929 cout << "factor_prime_power q is not a prime power" << endl;
930 exit(1);
931 }
932 q /= p;
933 e++;
934 }
935}
936
937long int number_theory_domain::primitive_root_randomized(long int p, int verbose_level)
938// Computes a primitive element for $\bbZ_p$, i.~e. an integer $k$
939// with $2 \le k \le p - 1$ s. th. the order of $k$ mod $p$ is $p-1$.
940{
941 int f_v = (verbose_level >= 1);
942 long int i, pm1, a, n, b;
943 vector<long int> primes;
944 vector<int> exponents;
946 int cnt = 0;
947
948 if (f_v) {
949 cout << "number_theory_domain::primitive_root_randomized p=" << p << endl;
950 }
951 if (p < 2) {
952 cout << "number_theory_domain::primitive_root_randomized: p < 2" << endl;
953 exit(1);
954 }
955
956 pm1 = p - 1;
957 if (f_v) {
958 cout << "number_theory_domain::primitive_root_randomized before factor_lint " << pm1 << endl;
959 }
960 factor_lint(pm1, primes, exponents);
961 if (f_v) {
962 cout << "number_theory_domain::primitive_root_randomized after factor_lint " << pm1 << endl;
963 cout << "number_theory_domain::primitive_root_randomized number of factors is " << primes.size() << endl;
964 }
965 while (TRUE) {
966 cnt++;
967 a = Os.random_integer(pm1);
968 if (a == 0) {
969 continue;
970 }
971 if (f_v) {
972 cout << "number_theory_domain::primitive_root_randomized iteration " << cnt << " : trying " << a << endl;
973 }
974 for (i = 0; i < (long int) primes.size(); i++) {
975 n = pm1 / primes[i];
976 if (f_v) {
977 cout << "number_theory_domain::primitive_root_randomized iteration " << cnt << " : trying " << a
978 << " : prime factor " << i << " / " << primes.size() << " raising to the power " << n << endl;
979 }
980 b = power_mod(a, n, p);
981 if (f_v) {
982 cout << "number_theory_domain::primitive_root_randomized iteration " << cnt
983 << " : trying " << a << " : prime factor " << i << " / " << primes.size()
984 << " raising to the power " << n << " yields " << b << endl;
985 }
986 if (b == 1) {
987 // fail
988 break;
989 }
990 }
991 if (i == (long int)primes.size()) {
992 break;
993 }
994 }
995
996 if (f_v) {
997 cout << "number_theory_domain::primitive_root_randomized done after " << cnt << " trials" << endl;
998 }
999 return a;
1000}
1001
1002long int number_theory_domain::primitive_root(long int p, int verbose_level)
1003// Computes a primitive element for $\bbZ_p$, i.~e. an integer $k$
1004// with $2 \le k \le p - 1$ s.~th. the order of $k$ mod $p$ is $p-1$.
1005{
1006 int f_v = (verbose_level >= 1);
1007 long int i, o;
1008
1009 if (p < 2) {
1010 cout << "primitive_root: p < 2" << endl;
1011 exit(1);
1012 }
1013 if (p == 2) {
1014 return 1;
1015 }
1016 for (i = 2; i < p; i++) {
1017 o = order_mod_p(i, p);
1018 if (o == p - 1) {
1019 if (f_v) {
1020 cout << i << " is primitive root mod " << p << endl;
1021 }
1022 return i;
1023 }
1024 }
1025 cout << "no primitive root found" << endl;
1026 exit(1);
1027}
1028
1029int number_theory_domain::Legendre(long int a, long int p, int verbose_level)
1030// Computes the Legendre symbol $\left( \frac{a}{p} \right)$.
1031{
1032 return Jacobi(a, p, verbose_level);
1033}
1034
1035int number_theory_domain::Jacobi(long int a, long int m, int verbose_level)
1036//Computes the Jacobi symbol $\left( \frac{a}{m} \right)$.
1037{
1038 int f_v = (verbose_level >= 1);
1039 long int a1, m1, ord2, r1;
1040 long int g;
1041 int f_negative = FALSE;
1042 long int t, t1, t2;
1043
1044 if (f_v) {
1045 cout << "Jacobi(" << a << ", " << m << ")" << endl;
1046 }
1047 a1 = a;
1048 m1 = m;
1049 r1 = 1;
1050 g = gcd_lint(a1, m1);
1051 if (ABS(g) != 1) {
1052 return 0;
1053 }
1054 while (TRUE) {
1055 /* Invariante:
1056 * r1 enthaelt bereits ausgerechnete Faktoren.
1057 * ABS(r1) == 1.
1058 * Jacobi(a, m) = r1 * Jacobi(a1, m1) und ggT(a1, m1) == 1. */
1059 if (a1 == 0) {
1060 cout << "Jacobi a1 == 0" << endl;
1061 exit(1);
1062 }
1063 a1 = a1 % m1;
1064 if (f_v) {
1065 cout << "Jacobi = " << r1
1066 << " * Jacobi(" << a1 << ", " << m1 << ")" << endl;
1067 }
1068#if 0
1069 a1 = NormRemainder(a1, m1);
1070 if (a1 < 0)
1071 f_negative = TRUE;
1072 else
1073 f_negative = FALSE;
1074#endif
1075 ord2 = ny2(a1, a1);
1076
1077 /* a1 jetzt immer noch != 0 */
1078 if (f_negative) {
1079 t = (m1 - 1) >> 1; /* t := (m1 - 1) / 2 */
1080 /* Ranmultiplizieren von (-1) hoch t an r1: */
1081 if (t % 2)
1082 r1 = -r1; /* Beachte ABS(r1) == 1 */
1083 /* und a1 wieder positiv machen: */
1084 a1 = -a1;
1085 }
1086 if (ord2 % 2) {
1087 /* tue nur dann etwas, wenn ord2 ungerade */
1088 // t = (m1 * m1 - 1) >> 3; /* t = (m1 * m1 - 1) / 8 */
1089 /* Ranmultiplizieren von (-1) hoch t an r1: */
1090 if (m1 % 8 == 3 || m1 % 8 == 5)
1091 r1 = -r1; /* Beachte ABS(r1) == 1L */
1092 }
1093 if (ABS(a1) <= 1)
1094 break;
1095 /* Reziprozitaet: */
1096 t1 = (m1 - 1) >> 1; /* t1 = (m1 - 1) / 2 */
1097 t2 = (a1 - 1) >> 1; /* t1 = (a1 - 1) / 2 */
1098 if ((t1 % 2) && (t2 % 2)) /* t1 und t2 ungerade */
1099 r1 = -r1; /* Beachte ABS(r1) == 1 */
1100 t = m1;
1101 m1 = a1;
1102 a1 = t;
1103 if (f_v) {
1104 cout << "Jacobi = " << r1
1105 << " * Jacobi(" << a1 << ", " << m1 << ")" << endl;
1106 }
1107 }
1108 if (a1 == 1) {
1109 return r1;
1110 }
1111 if (a1 <= 0) {
1112 cout << "Jacobi a1 == -1 || a1 == 0" << endl;
1113 exit(1);
1114 }
1115 cout << "Jacobi wrong termination" << endl;
1116 exit(1);
1117}
1118
1120 long int a, long int m, int verbose_level)
1121//Computes the Jacobi symbol $\left( \frac{a}{m} \right)$.
1122{
1123 int f_v = (verbose_level >= 1);
1124 long int a1, m1, ord2, r1;
1125 long int g;
1126 int f_negative = FALSE;
1127 long int t, t1, t2;
1128
1129 if (f_v) {
1130 cout << "number_theory_domain::Jacobi_with_key_in_latex(" << a << ", " << m << ")" << endl;
1131 }
1132
1133
1134 ost << "$\\Big( \\frac{" << a << " }{ "
1135 << m << "}\\Big)$\\\\" << endl;
1136
1137
1138 a1 = a;
1139 m1 = m;
1140 r1 = 1;
1141 g = gcd_lint(a1, m1);
1142 if (ABS(g) != 1) {
1143 return 0;
1144 }
1145 while (TRUE) {
1146 // Invariant:
1147 // r1 contains partial results.
1148 // ABS(r1) == 1.
1149 // Jacobi(a, m) = r1 * Jacobi(a1, m1) and gcd(a1, m1) == 1.
1150 if (a1 == 0) {
1151 cout << "number_theory_domain::Jacobi_with_key_in_latex a1 == 0" << endl;
1152 exit(1);
1153 }
1154 if (a1 % m1 < a1) {
1155
1156 ost << "$=";
1157 if (r1 == -1) {
1158 ost << "(-1) \\cdot ";
1159 }
1160 ost << " \\Big( \\frac{" << a1 % m1 << " }{ "
1161 << m1 << "}\\Big)$\\\\" << endl;
1162
1163 }
1164
1165 a1 = a1 % m1;
1166
1167 if (f_v) {
1168 cout << "Jacobi = " << r1 << " * Jacobi("
1169 << a1 << ", " << m1 << ")" << endl;
1170 }
1171 ord2 = ny2(a1, a1);
1172
1173 // a1 != 0
1174 if (f_negative) {
1175
1176 ost << "$=";
1177 if (r1 == -1) {
1178 ost << "(-1) \\cdot ";
1179 }
1180 ost << "\\Big( \\frac{-1 }{ " << m1
1181 << "}\\Big) \\cdot \\Big( \\frac{"
1182 << a1 * i_power_j(2, ord2) << " }{ "
1183 << m1 << "}\\Big)$\\\\" << endl;
1184 ost << "$=";
1185 if (r1 == -1) {
1186 ost << "(-1) \\cdot ";
1187 }
1188 ost << "(-1)^{\\frac{" << m1
1189 << "-1}{2}} \\cdot \\Big( \\frac{"
1190 << a1 * i_power_j(2, ord2) << " }{ "
1191 << m1 << "}\\Big)$\\\\" << endl;
1192
1193
1194
1195 t = (m1 - 1) >> 1;
1196 // t := (m1 - 1) / 2
1197
1198 /* Ranmultiplizieren von (-1) hoch t an r1: */
1199
1200 if (t % 2) {
1201 r1 = -r1; /* note ABS(r1) == 1 */
1202 }
1203
1204 a1 = -a1;
1205
1206 ost << "$=";
1207 if (r1 == -1) {
1208 ost << "(-1) \\cdot ";
1209 }
1210 ost << " \\Big( \\frac{"
1211 << a1 * i_power_j(2, ord2)
1212 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1213
1214
1215 }
1216 if (ord2 % 2) {
1217 /* tue nur dann etwas, wenn ord2 ungerade */
1218 // t = (m1 * m1 - 1) >> 3; /* t = (m1 * m1 - 1) / 8 */
1219 /* Ranmultiplizieren von (-1) hoch t an r1: */
1220
1221 if (ord2 > 1) {
1222 ost << "$=";
1223 if (r1 == -1) {
1224 ost << "(-1) \\cdot ";
1225 }
1226 ost << "\\Big( \\frac{2}{ " << m1
1227 << "}\\Big)^{" << ord2
1228 << "} \\cdot \\Big( \\frac{" << a1
1229 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1230 ost << "$=";
1231 if (r1 == -1) {
1232 ost << "(-1) \\cdot ";
1233 }
1234 ost << "\\Big( (-1)^{\\frac{" << m1
1235 << "^2-1}{8}} \\Big)^{" << ord2
1236 << "} \\cdot \\Big( \\frac{" << a1 << " }{ "
1237 << m1 << "}\\Big)$\\\\" << endl;
1238 }
1239 else {
1240 ost << "$=";
1241 if (r1 == -1) {
1242 ost << "(-1) \\cdot ";
1243 }
1244 ost << "\\Big( \\frac{2}{ " << m1
1245 << "}\\Big) \\cdot \\Big( \\frac{" << a1
1246 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1247 ost << "$=";
1248 if (r1 == -1) {
1249 ost << "(-1) \\cdot ";
1250 }
1251 ost << "(-1)^{\\frac{" << m1
1252 << "^2-1}{8}} \\cdot \\Big( \\frac{" << a1
1253 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1254 }
1255
1256 if (m1 % 8 == 3 || m1 % 8 == 5) {
1257 r1 = -r1; /* Beachte ABS(r1) == 1L */
1258 }
1259
1260 ost << "$=";
1261 if (r1 == -1) {
1262 ost << "(-1) \\cdot ";
1263 }
1264 ost << "\\Big( \\frac{" << a1 << " }{ " << m1
1265 << "}\\Big)$\\\\" << endl;
1266
1267
1268 }
1269 else {
1270 if (ord2) {
1271 ost << "$=";
1272 if (r1 == -1) {
1273 ost << "(-1) \\cdot ";
1274 }
1275 ost << "\\Big( \\frac{2}{ " << m1 << "}\\Big)^{"
1276 << ord2 << "} \\cdot \\Big( \\frac{" << a1
1277 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1278
1279 ost << "$=";
1280 if (r1 == -1) {
1281 ost << "(-1) \\cdot ";
1282 }
1283 ost << "\\Big( (-1)^{\\frac{" << m1
1284 << "^2-1}{8}} \\Big)^{" << ord2
1285 << "} \\cdot \\Big( \\frac{" << a1 << " }{ "
1286 << m1 << "}\\Big)$\\\\" << endl;
1287 ost << "$=";
1288 if (r1 == -1) {
1289 ost << "(-1) \\cdot ";
1290 }
1291 ost << "\\Big( \\frac{" << a1 << " }{ " << m1
1292 << "}\\Big)$\\\\" << endl;
1293 }
1294 }
1295 if (ABS(a1) <= 1) {
1296 break;
1297 }
1298
1299
1300 t = m1;
1301 m1 = a1;
1302 a1 = t;
1303
1304
1305 ost << "$=";
1306 if (r1 == -1) {
1307 ost << "(-1) \\cdot ";
1308 }
1309 ost << "\\Big( \\frac{" << a1 << " }{ " << m1
1310 << "}\\Big) \\cdot (-1)^{\\frac{" << m1
1311 << "-1}{2} \\cdot \\frac{" << a1
1312 << " - 1}{2}}$\\\\" << endl;
1313
1314
1315 // reciprocity:
1316 t1 = (m1 - 1) >> 1;
1317 // t1 = (m1 - 1) / 2
1318 t2 = (a1 - 1) >> 1;
1319 // t1 = (a1 - 1) / 2
1320 if ((t1 % 2) && (t2 % 2)) {
1321 // t1 and t2 are both odd
1322 r1 = -r1;
1323 // note ABS(r1) == 1
1324 }
1325
1326 ost << "$=";
1327 if (r1 == -1) {
1328 ost << "(-1) \\cdot ";
1329 }
1330 ost << "\\Big( \\frac{" << a1 << " }{ " << m1
1331 << "}\\Big)$\\\\" << endl;
1332
1333 if (f_v) {
1334 cout << "number_theory_domain::Jacobi_with_key_in_latex = " << r1 << " * Jacobi(" << a1
1335 << ", " << m1 << ")" << endl;
1336 }
1337 }
1338 if (a1 == 1) {
1339 ost << "$=" << r1 << "$\\\\" << endl;
1340 return r1;
1341 }
1342 if (a1 <= 0) {
1343 cout << "number_theory_domain::Jacobi_with_key_in_latex a1 == -1 || a1 == 0" << endl;
1344 exit(1);
1345 }
1346 cout << "number_theory_domain::Jacobi_with_key_in_latex wrong termination" << endl;
1347 exit(1);
1348}
1349
1351 long int a, long int m, int verbose_level)
1352//Computes the Legendre symbol $\left( \frac{a}{m} \right)$.
1353{
1354 int f_v = (verbose_level >= 1);
1355 long int a1, m1, ord2, r1;
1356 long int g;
1357 int f_negative = FALSE;
1358 long int t, t1, t2;
1359
1360 if (f_v) {
1361 cout << "number_theory_domain::Legendre_with_key_in_latex(" << a << ", " << m << ")" << endl;
1362 }
1363
1364
1365 ost << "$\\Big( \\frac{" << a << " }{ "
1366 << m << "}\\Big)$\\\\" << endl;
1367
1368
1369 a1 = a;
1370 m1 = m;
1371 r1 = 1;
1372 g = gcd_lint(a1, m1);
1373 if (ABS(g) != 1) {
1374 return 0;
1375 }
1376 while (TRUE) {
1377 // invariant:
1378 // r1 contains partial result.
1379 // ABS(r1) == 1.
1380 // Legendre(a, m) = r1 * Legendre(a1, m1) and gcd(a1, m1) == 1. */
1381 if (a1 == 0) {
1382 cout << "number_theory_domain::Legendre_with_key_in_latex a1 == 0" << endl;
1383 exit(1);
1384 }
1385 if (a1 % m1 < a1) {
1386
1387 ost << "$=";
1388 if (r1 == -1) {
1389 ost << "(-1) \\cdot ";
1390 }
1391 ost << " \\Big( \\frac{" << a1 % m1 << " }{ "
1392 << m1 << "}\\Big)$\\\\" << endl;
1393
1394 }
1395
1396 a1 = a1 % m1;
1397
1398 if (f_v) {
1399 cout << "Jacobi = " << r1 << " * Jacobi("
1400 << a1 << ", " << m1 << ")" << endl;
1401 }
1402 ord2 = ny2(a1, a1);
1403
1404 // a1 is != 0
1405 if (f_negative) {
1406
1407 ost << "$=";
1408 if (r1 == -1) {
1409 ost << "(-1) \\cdot ";
1410 }
1411 ost << "\\Big( \\frac{-1 }{ " << m1
1412 << "}\\Big) \\cdot \\Big( \\frac{"
1413 << a1 * i_power_j(2, ord2) << " }{ "
1414 << m1 << "}\\Big)$\\\\" << endl;
1415 ost << "$=";
1416 if (r1 == -1) {
1417 ost << "(-1) \\cdot ";
1418 }
1419 ost << "(-1)^{\\frac{" << m1
1420 << "-1}{2}} \\cdot \\Big( \\frac{"
1421 << a1 * i_power_j(2, ord2) << " }{ "
1422 << m1 << "}\\Big)$\\\\" << endl;
1423
1424
1425
1426 t = (m1 - 1) >> 1; /* t := (m1 - 1) / 2 */
1427
1428 if (t % 2) {
1429 r1 = -r1;
1430 }
1431
1432 a1 = -a1;
1433
1434 ost << "$=";
1435 if (r1 == -1) {
1436 ost << "(-1) \\cdot ";
1437 }
1438 ost << " \\Big( \\frac{"
1439 << a1 * i_power_j(2, ord2)
1440 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1441
1442
1443 }
1444 if (ord2 % 2) {
1445 /* tue nur dann etwas, wenn ord2 ungerade */
1446 // t = (m1 * m1 - 1) >> 3; /* t = (m1 * m1 - 1) / 8 */
1447 /* Ranmultiplizieren von (-1) hoch t an r1: */
1448
1449 if (ord2 > 1) {
1450 ost << "$=";
1451 if (r1 == -1) {
1452 ost << "(-1) \\cdot ";
1453 }
1454 ost << "\\Big( \\frac{2}{ " << m1
1455 << "}\\Big)^{" << ord2
1456 << "} \\cdot \\Big( \\frac{" << a1
1457 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1458 ost << "$=";
1459 if (r1 == -1) {
1460 ost << "(-1) \\cdot ";
1461 }
1462 ost << "\\Big( (-1)^{\\frac{" << m1
1463 << "^2-1}{8}} \\Big)^{" << ord2
1464 << "} \\cdot \\Big( \\frac{" << a1 << " }{ "
1465 << m1 << "}\\Big)$\\\\" << endl;
1466 }
1467 else {
1468 ost << "$=";
1469 if (r1 == -1) {
1470 ost << "(-1) \\cdot ";
1471 }
1472 ost << "\\Big( \\frac{2}{ " << m1
1473 << "}\\Big) \\cdot \\Big( \\frac{" << a1
1474 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1475 ost << "$=";
1476 if (r1 == -1) {
1477 ost << "(-1) \\cdot ";
1478 }
1479 ost << "(-1)^{\\frac{" << m1
1480 << "^2-1}{8}} \\cdot \\Big( \\frac{" << a1
1481 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1482 }
1483
1484 if (m1 % 8 == 3 || m1 % 8 == 5) {
1485 r1 = -r1; /* Beachte ABS(r1) == 1L */
1486 }
1487
1488 ost << "$=";
1489 if (r1 == -1) {
1490 ost << "(-1) \\cdot ";
1491 }
1492 ost << "\\Big( \\frac{" << a1 << " }{ " << m1
1493 << "}\\Big)$\\\\" << endl;
1494
1495
1496 }
1497 else {
1498 if (ord2) {
1499 ost << "$=";
1500 if (r1 == -1) {
1501 ost << "(-1) \\cdot ";
1502 }
1503 ost << "\\Big( \\frac{2}{ " << m1 << "}\\Big)^{"
1504 << ord2 << "} \\cdot \\Big( \\frac{" << a1
1505 << " }{ " << m1 << "}\\Big)$\\\\" << endl;
1506
1507 ost << "$=";
1508 if (r1 == -1) {
1509 ost << "(-1) \\cdot ";
1510 }
1511 ost << "\\Big( (-1)^{\\frac{" << m1
1512 << "^2-1}{8}} \\Big)^{" << ord2
1513 << "} \\cdot \\Big( \\frac{" << a1 << " }{ "
1514 << m1 << "}\\Big)$\\\\" << endl;
1515 ost << "$=";
1516 if (r1 == -1) {
1517 ost << "(-1) \\cdot ";
1518 }
1519 ost << "\\Big( \\frac{" << a1 << " }{ " << m1
1520 << "}\\Big)$\\\\" << endl;
1521 }
1522 }
1523 if (ABS(a1) <= 1) {
1524 break;
1525 }
1526
1527
1528 t = m1;
1529 m1 = a1;
1530 a1 = t;
1531
1532
1533 ost << "$=";
1534 if (r1 == -1) {
1535 ost << "(-1) \\cdot ";
1536 }
1537 ost << "\\Big( \\frac{" << a1 << " }{ " << m1
1538 << "}\\Big) \\cdot (-1)^{\\frac{" << m1
1539 << "-1}{2} \\cdot \\frac{" << a1
1540 << " - 1}{2}}$\\\\" << endl;
1541
1542
1543 // reciprocity:
1544
1545 t1 = (m1 - 1) >> 1;
1546 // t1 = (m1 - 1) / 2
1547 t2 = (a1 - 1) >> 1;
1548 // t1 = (a1 - 1) / 2
1549
1550 if ((t1 % 2) && (t2 % 2)) /* t1 and t2 are both odd */ {
1551 r1 = -r1; /* note: ABS(r1) == 1 */
1552 }
1553
1554 ost << "$=";
1555 if (r1 == -1) {
1556 ost << "(-1) \\cdot ";
1557 }
1558 ost << "\\Big( \\frac{" << a1 << " }{ " << m1
1559 << "}\\Big)$\\\\" << endl;
1560
1561 if (f_v) {
1562 cout << "number_theory_domain::Jacobi = " << r1 << " * Jacobi(" << a1
1563 << ", " << m1 << ")" << endl;
1564 }
1565 }
1566 if (a1 == 1) {
1567 ost << "$=" << r1 << "$\\\\" << endl;
1568 return r1;
1569 }
1570 if (a1 <= 0) {
1571 cout << "number_theory_domain::Legendre_with_key_in_latex a1 == -1 || a1 == 0" << endl;
1572 exit(1);
1573 }
1574 cout << "number_theory_domain::Legendre_with_key_in_latex wrong termination" << endl;
1575 exit(1);
1576}
1577
1578int number_theory_domain::ny2(long int x, long int &x1)
1579//returns $n = \ny_2(x).$
1580//Computes $x1 := \frac{x}{2^n}$.
1581{
1582 int xx = x;
1583 int n1;
1584 int f_negative;
1585
1586 n1 = 0;
1587 if (xx == 0) {
1588 cout << "number_theory_domain::ny2 x == 0" << endl;
1589 exit(1);
1590 }
1591 if (xx < 0) {
1592 xx = -xx;
1593 f_negative = TRUE;
1594 }
1595 else {
1596 f_negative = FALSE;
1597 }
1598 while (TRUE) {
1599 // while xx congruent 0 mod 2:
1600 if (ODD(xx)) {
1601 break;
1602 }
1603 n1++;
1604 xx >>= 1;
1605 }
1606 if (f_negative) {
1607 xx = -xx;
1608 }
1609 x1 = xx;
1610 return n1;
1611}
1612
1613int number_theory_domain::ny_p(long int n, long int p)
1614//Returns $\nu_p(n),$ the integer $k$ with $n=p^k n'$ and $p \nmid n'$.
1615{
1616 int ny_p;
1617
1618 if (n == 0) {
1619 cout << "number_theory_domain::ny_p n == 0" << endl;
1620 exit(1);
1621 }
1622 if (n < 0) {
1623 n = -n;
1624 }
1625 ny_p = 0;
1626 while (n != 1) {
1627 if ((n % p) != 0) {
1628 break;
1629 }
1630 n /= p;
1631 ny_p++;
1632 }
1633 return ny_p;
1634}
1635
1636#if 0
1637// now use longinteger_domain::square_root_mod(int a, int p, int verbose_level)
1638long int number_theory_domain::sqrt_mod_simple(long int a, long int p)
1639// solves x^2 = a mod p. Returns x
1640{
1641 long int a1, x;
1642
1643 a1 = a % p;
1644 for (x = 0; x < p; x++) {
1645 if ((x * x) % p == a1) {
1646 return x;
1647 }
1648 }
1649 cout << "number_theory_domain::sqrt_mod_simple the number a is "
1650 "not a quadratic residue mod p" << endl;
1651 cout << "a = " << a << " p=" << p << endl;
1652 exit(1);
1653}
1654#endif
1655void number_theory_domain::print_factorization(int nb_primes, int *primes, int *exponents)
1656{
1657 int i;
1658
1659 for (i = 0; i < nb_primes; i++) {
1660 cout << primes[i];
1661 if (exponents[i] > 1) {
1662 cout << "^" << exponents[i];
1663 }
1664 if (i < nb_primes - 1) {
1665 cout << " * ";
1666 }
1667 }
1668}
1669
1671 ring_theory::longinteger_object *primes, int *exponents)
1672{
1673 int i;
1674
1675 for (i = 0; i < nb_primes; i++) {
1676 cout << primes[i];
1677 if (exponents[i] > 1) {
1678 cout << "^" << exponents[i];
1679 }
1680 if (i < nb_primes - 1) {
1681 cout << " * ";
1682 }
1683 }
1684}
1685
1686
1688 int bt, int bb, int &ct, int &cb,
1689 int verbose_level)
1690{
1691 int f_v = (verbose_level >= 1);
1692 long int g, a1, b1;
1693
1694 if (at == 0) {
1695 ct = bt;
1696 cb = bb;
1697 }
1698 else if (bt == 0) {
1699 ct = at;
1700 cb = ab;
1701 }
1702 else {
1703 g = gcd_lint(ab, bb);
1704 a1 = ab / g;
1705 b1 = bb / g;
1706 cb = ab * b1;
1707 ct = at * b1 + bt * a1;
1708 }
1709 if (cb < 0) {
1710 cb *= -1;
1711 ct *= -1;
1712 }
1713 g = gcd_lint(int_abs(ct), cb);
1714 if (g > 1) {
1715 ct /= g;
1716 cb /= g;
1717 }
1718 if (f_v) {
1719 cout << "int_add_fractions " << at << "/"
1720 << ab << " + " << bt << "/" << bb << " = "
1721 << ct << "/" << cb << endl;
1722 }
1723}
1724
1726 int bt, int bb, int &ct, int &cb,
1727 int verbose_level)
1728{
1729 long int g;
1730
1731 if (at == 0) {
1732 ct = 0;
1733 cb = 1;
1734 }
1735 else if (bt == 0) {
1736 ct = 0;
1737 cb = 1;
1738 }
1739 else {
1740 g = gcd_lint(at, ab);
1741 if (g != 1 && g != -1) {
1742 at /= g;
1743 ab /= g;
1744 }
1745 g = gcd_lint(bt, bb);
1746 if (g != 1 && g != -1) {
1747 bt /= g;
1748 bb /= g;
1749 }
1750 g = gcd_lint(at, bb);
1751 if (g != 1 && g != -1) {
1752 at /= g;
1753 bb /= g;
1754 }
1755 g = gcd_lint(bt, ab);
1756 if (g != 1 && g != -1) {
1757 bt /= g;
1758 ab /= g;
1759 }
1760 ct = at * bt;
1761 cb = ab * bb;
1762 }
1763 if (cb < 0) {
1764 cb *= -1;
1765 ct *= -1;
1766 }
1767 g = gcd_lint(int_abs(ct), cb);
1768 if (g > 1) {
1769 ct /= g;
1770 cb /= g;
1771 }
1772}
1773
1774
1776{
1777 int p, r;
1778 int nb_primes = sizeof(the_first_thousand_primes) / sizeof(int);
1780
1781 while (TRUE) {
1782 r = Os.random_integer(nb_primes);
1783 p = the_first_thousand_primes[r];
1784 if (p > lower_bound) {
1785 return p;
1786 }
1787 }
1788}
1789
1790int number_theory_domain::choose_a_prime_in_interval(int lower_bound, int upper_bound)
1791{
1792 int p, r;
1793 int nb_primes = sizeof(the_first_thousand_primes) / sizeof(int);
1795
1796 while (TRUE) {
1797 r = Os.random_integer(nb_primes);
1798 p = the_first_thousand_primes[r];
1799 if (p > lower_bound && p < upper_bound) {
1800 return p;
1801 }
1802 }
1803}
1804
1806{
1807 int r;
1809
1810 while (TRUE) {
1811 r = Os.random_integer(n);
1812 if (r > lower_bound) {
1813 return r;
1814 }
1815 }
1816}
1817
1818int number_theory_domain::random_integer_in_interval(int lower_bound, int upper_bound)
1819{
1821 int r, n;
1822
1823 if (upper_bound <= lower_bound) {
1824 cout << "random_integer_in_interval upper_bound <= lower_bound" << endl;
1825 exit(1);
1826 }
1827 n = upper_bound - lower_bound;
1828 r = lower_bound + Os.random_integer(n);
1829 return r;
1830}
1831
1833{
1834 return sizeof(the_first_thousand_primes) / sizeof(int);
1835}
1836
1838{
1839 return the_first_thousand_primes[idx];
1840}
1841
1842long int number_theory_domain::ChineseRemainder2(long int a1, long int a2,
1843 long int p1, long int p2, int verbose_level)
1844{
1845 long int k, ma1, p1v, x;
1847
1848 ma1 = int_negate(a1, p2);
1849 p1v = NT.inverse_mod(p1, p2);
1850 k = NT.mult_mod(p1v, NT.add_mod(a2, ma1, p2), p2);
1851 x = a1 + k * p1;
1852 return x;
1853}
1854
1856 long int p, long int g, long int h,
1857 int f_latex, ostream &ost, int verbose_level)
1858{
1859 int f_v = (verbose_level >= 1);
1860 long int N, n;
1861 double sqrtN;
1862 long int *Table1;
1863 long int *Table2;
1864 long int *data;
1865 long int gn, gmn, hgmn;
1866 long int i, r;
1869
1870 if (f_v) {
1871 cout << "number_theory_domain::do_babystep_giantstep "
1872 "p=" << p << " g=" << g << " h=" << h << endl;
1873 }
1874 r = NT.primitive_root(p, 0 /* verbose_level */);
1875 if (f_v) {
1876 cout << "a primitive root modulo " << p << " is " << r << endl;
1877 }
1878
1879 N = p - 1;
1880 sqrtN = sqrt(N);
1881 n = 1 + (int) sqrtN;
1882 if (f_v) {
1883 cout << "do_babystep_giantstep "
1884 "p=" << p
1885 << ", g=" << g
1886 << " h=" << h
1887 << " n=" << n << endl;
1888 }
1889 Table1 = NEW_lint(n);
1890 Table2 = NEW_lint(n);
1891 data = NEW_lint(2 * n);
1892 gn = NT.power_mod(g, n, p);
1893 if (f_v) {
1894 cout << "g^n=" << gn << endl;
1895 }
1896 gmn = NT.inverse_mod(gn, p);
1897 if (f_v) {
1898 cout << "g^-n=" << gmn << endl;
1899 }
1900 hgmn = NT.mult_mod(h, gmn, p);
1901 if (f_v) {
1902 cout << "h*g^-n=" << hgmn << endl;
1903 }
1904 Table1[0] = g;
1905 Table2[0] = hgmn;
1906 for (i = 1; i < n; i++) {
1907 Table1[i] = NT.mult_mod(Table1[i - 1], g, p);
1908 Table2[i] = NT.mult_mod(Table2[i - 1], gmn, p);
1909 }
1910 Lint_vec_copy(Table1, data, n);
1911 Lint_vec_copy(Table2, data + n, n);
1912 Sorting.lint_vec_heapsort(data, 2 * n);
1913 if (f_v) {
1914 cout << "duplicates:" << endl;
1915 for (i = 1; i < 2 * n; i++) {
1916 if (data[i] == data[i - 1]) {
1917 cout << data[i] << endl;
1918 }
1919 }
1920 }
1921
1922 if (f_latex) {
1923 ost << "$$" << endl;
1924 ost << "\\begin{array}[t]{|r|r|r|}" << endl;
1925 ost << "\\hline" << endl;
1926 ost << "i & T_1[i] & T_2[i] \\\\" << endl;
1927 ost << "\\hline" << endl;
1928 ost << "\\hline" << endl;
1929 //ost << "i : g^i : h*g^{-i*n}" << endl;
1930 for (i = 0; i < n; i++) {
1931 ost << i + 1 << " & " << Table1[i] << " & "
1932 << Table2[i] << "\\\\" << endl;
1933 if ((i + 1) % 10 == 0) {
1934 ost << "\\hline" << endl;
1935 ost << "\\end{array}" << endl;
1936 ost << "\\quad" << endl;
1937 ost << "\\begin{array}[t]{|r|r|r|}" << endl;
1938 ost << "\\hline" << endl;
1939 ost << "i & T_1[i] & T_2[i] \\\\" << endl;
1940 ost << "\\hline" << endl;
1941 ost << "\\hline" << endl;
1942 }
1943 }
1944 ost << "\\hline" << endl;
1945 ost << "\\end{array}" << endl;
1946 ost << "$$" << endl;
1947 }
1948}
1949
1950void number_theory_domain::sieve(std::vector<int> &primes,
1951 int factorbase, int verbose_level)
1952{
1953 int f_v = (verbose_level >= 1);
1954 int i, from, to, l, unit_size = 1000;
1955
1956 if (f_v) {
1957 cout << "number_theory_domain::sieve" << endl;
1958 }
1959 //primes.m_l(0);
1960 for (i = 0; ; i++) {
1961 from = i * unit_size + 1;
1962 to = from + unit_size - 1;
1963 sieve_primes(primes, from, to, factorbase, FALSE);
1964 l = primes.size();
1965 cout << "[" << from << "," << to
1966 << "], total number of primes = "
1967 << l << endl;
1968 if (l >= factorbase) {
1969 break;
1970 }
1971 }
1972
1973 if (f_v) {
1974 cout << "number_theory_domain::sieve done" << endl;
1975 }
1976}
1977
1978void number_theory_domain::sieve_primes(std::vector<int> &v,
1979 int from, int to, int limit, int verbose_level)
1980{
1981 int f_v = (verbose_level >= 1);
1982 int x, y, l, k, p, f_prime;
1983
1984 if (f_v) {
1985 cout << "number_theory_domain::sieve_primes" << endl;
1986 }
1987 l = v.size();
1988 if (ODD(from)) {
1989 x = from;
1990 }
1991 else {
1992 x = from + 1;
1993 }
1994 for (; x <= to; x++, x++) {
1995 if (x <= 1) {
1996 continue;
1997 }
1998 f_prime = TRUE;
1999 for (k = 0; k < l; k++) {
2000 p = v[k];
2001 y = x / p;
2002 // cout << "x=" << x << " p=" << p << " y=" << y << endl;
2003 if ((x - y * p) == 0) {
2004 f_prime = FALSE;
2005 break;
2006 }
2007 if (y < p) {
2008 break;
2009 }
2010#if 0
2011 if ((x % p) == 0)
2012 break;
2013#endif
2014 }
2015 if (!f_prime) {
2016 continue;
2017 }
2018 if (nb_primes(x) != 1) {
2019 cout << "error: " << x << " is not prime!" << endl;
2020 }
2021 v.push_back(x);
2022 if (f_v) {
2023 cout << v.size() << " " << x << endl;
2024 }
2025 l++;
2026 if (l >= limit) {
2027 return;
2028 }
2029 }
2030 if (f_v) {
2031 cout << "number_theory_domain::sieve_primes done" << endl;
2032 }
2033}
2034
2036//Returns the number of primes in the prime factorization
2037//of $n$ (including multiplicities).
2038{
2039 int i = 0;
2040 int d;
2041
2042 if (n < 0) {
2043 n = -n;
2044 }
2045 while (n != 1) {
2046 d = smallest_primedivisor(n);
2047 i++;
2048 n /= d;
2049 }
2050 return i;
2051}
2052
2053void number_theory_domain::cyclotomic_set(std::vector<int> &cyclotomic_set,
2054 int a, int q, int n, int verbose_level)
2055{
2056 int f_v = (verbose_level >= 1);
2057 int b, c;
2058
2059 if (f_v) {
2060 cout << "number_theory_domain::cyclotomic_set" << endl;
2061 }
2062 b = a;
2063 cyclotomic_set.push_back(b);
2064 if (f_v) {
2065 cout << "push " << b << endl;
2066 }
2067 while (TRUE) {
2068 c = (b * q) % n;
2069 if (c == a) {
2070 break;
2071 }
2072 b = c;
2073 cyclotomic_set.push_back(b);
2074 if (f_v) {
2075 cout << "push " << b << endl;
2076 }
2077 }
2078 if (f_v) {
2079 cout << "number_theory_domain::cyclotomic_set done" << endl;
2080 }
2081}
2082
2083
2085 int b, int c,
2086 int x1, int x2, int x3,
2087 int y1, int y2, int y3,
2088 int &z1, int &z2, int &z3, int verbose_level)
2089{
2090 int f_v = (verbose_level >= 1);
2091 int a, two, three, top, bottom, m;
2092
2093 if (f_v) {
2094 cout << "number_theory_domain::elliptic_curve_addition" << endl;
2095 }
2096
2097 //my_nb_calls_to_elliptic_curve_addition++;
2098 if (x3 == 0) {
2099 z1 = y1;
2100 z2 = y2;
2101 z3 = y3;
2102 goto done;
2103 }
2104 if (y3 == 0) {
2105 z1 = x1;
2106 z2 = x2;
2107 z3 = x3;
2108 goto done;
2109 }
2110 if (x3 != 1) {
2111 a = F->inverse(x3);
2112 x1 = F->mult(x1, a);
2113 x2 = F->mult(x2, a);
2114 }
2115 if (y3 != 1) {
2116 a = F->inverse(y3);
2117 y1 = F->mult(y1, a);
2118 y2 = F->mult(y2, a);
2119 }
2120 if (x1 == y1 && x2 != y2) {
2121 if (F->negate(x2) != y2) {
2122 cout << "x1 == y1 && x2 != y2 && negate(x2) != y2" << endl;
2123 exit(1);
2124 }
2125 z1 = 0;
2126 z2 = 1;
2127 z3 = 0;
2128 goto done;
2129 }
2130 if (x1 == y1 && x2 == 0 && y2 == 0) {
2131 z1 = 0;
2132 z2 = 1;
2133 z3 = 0;
2134 goto done;
2135 }
2136 if (x1 == y1 && x2 == y2) {
2137 two = F->add(1, 1);
2138 three = F->add(two, 1);
2139 top = F->add(F->mult(three, F->mult(x1, x1)), b);
2140 bottom = F->mult(two, x2);
2141 a = F->inverse(bottom);
2142 m = F->mult(top, a);
2143 }
2144 else {
2145 top = F->add(y2, F->negate(x2));
2146 bottom = F->add(y1, F->negate(x1));
2147 a = F->inverse(bottom);
2148 m = F->mult(top, a);
2149 }
2150 z1 = F->add(F->add(F->mult(m, m), F->negate(x1)), F->negate(y1));
2151 z2 = F->add(F->mult(m, F->add(x1, F->negate(z1))), F->negate(x2));
2152 z3 = 1;
2153done:
2154 if (f_v) {
2155 cout << "number_theory_domain::elliptic_curve_addition done" << endl;
2156 }
2157}
2158
2160 int b, int c, int n,
2161 int x1, int y1, int z1,
2162 int &x3, int &y3, int &z3,
2163 int verbose_level)
2164{
2165 int f_v = (verbose_level >= 1);
2166 int bx, by, bz;
2167 int cx, cy, cz;
2168 int tx, ty, tz;
2169
2170 if (f_v) {
2171 cout << "number_theory_domain::elliptic_curve_point_multiple" << endl;
2172 }
2173 bx = x1;
2174 by = y1;
2175 bz = z1;
2176 cx = 0;
2177 cy = 1;
2178 cz = 0;
2179 while (n) {
2180 if (n % 2) {
2181 //cout << "finite_field::power: mult(" << b << "," << c << ")=";
2182
2184 b, c,
2185 bx, by, bz,
2186 cx, cy, cz,
2187 tx, ty, tz, verbose_level - 1);
2188 cx = tx;
2189 cy = ty;
2190 cz = tz;
2191 //c = mult(b, c);
2192 //cout << c << endl;
2193 }
2195 b, c,
2196 bx, by, bz,
2197 bx, by, bz,
2198 tx, ty, tz, verbose_level - 1);
2199 bx = tx;
2200 by = ty;
2201 bz = tz;
2202 //b = mult(b, b);
2203 n >>= 1;
2204 //cout << "finite_field::power: " << b << "^" << n << " * " << c << endl;
2205 }
2206 x3 = cx;
2207 y3 = cy;
2208 z3 = cz;
2209 if (f_v) {
2210 cout << "number_theory_domain::elliptic_curve_point_multiple done" << endl;
2211 }
2212}
2213
2216 int b, int c, int n,
2217 int x1, int y1, int z1,
2218 int &x3, int &y3, int &z3,
2219 int verbose_level)
2220{
2221 int f_v = (verbose_level >= 1);
2222 int bx, by, bz;
2223 int cx, cy, cz;
2224 int tx, ty, tz;
2225
2226 if (f_v) {
2227 cout << "number_theory_domain::elliptic_curve_point_multiple_with_log" << endl;
2228 }
2229 bx = x1;
2230 by = y1;
2231 bz = z1;
2232 cx = 0;
2233 cy = 1;
2234 cz = 0;
2235 cout << "ECMultiple$\\Big((" << bx << "," << by << "," << bz << "),";
2236 cout << "(" << cx << "," << cy << "," << cz << "),"
2237 << n << "," << b << "," << c << "," << F->p << "\\Big)$\\\\" << endl;
2238
2239 while (n) {
2240 if (n % 2) {
2241 //cout << "finite_field::power: mult(" << b << "," << c << ")=";
2242
2244 b, c,
2245 bx, by, bz,
2246 cx, cy, cz,
2247 tx, ty, tz, verbose_level - 1);
2248 cx = tx;
2249 cy = ty;
2250 cz = tz;
2251 //c = mult(b, c);
2252 //cout << c << endl;
2253 }
2255 b, c,
2256 bx, by, bz,
2257 bx, by, bz,
2258 tx, ty, tz, verbose_level - 1);
2259 bx = tx;
2260 by = ty;
2261 bz = tz;
2262 //b = mult(b, b);
2263 n >>= 1;
2264 cout << "=ECMultiple$\\Big((" << bx << "," << by << "," << bz << "),";
2265 cout << "(" << cx << "," << cy << "," << cz << "),"
2266 << n << "," << b << "," << c << "," << F->p << "\\Big)$\\\\" << endl;
2267 //cout << "finite_field::power: " << b << "^" << n << " * " << c << endl;
2268 }
2269 x3 = cx;
2270 y3 = cy;
2271 z3 = cz;
2272 cout << "$=(" << x3 << "," << y3 << "," << z3 << ")$\\\\" << endl;
2273 if (f_v) {
2274 cout << "number_theory_domain::elliptic_curve_point_multiple_with_log done" << endl;
2275 }
2276}
2277
2280 int x, int b, int c)
2281{
2282 int x2, x3, e;
2283
2284 x2 = F->mult(x, x);
2285 x3 = F->mult(x2, x);
2286 e = F->add(x3, F->mult(b, x));
2287 e = F->add(e, c);
2288 return e;
2289}
2290
2292 int b, int c, int &nb, int *&T, int verbose_level)
2293{
2294 int f_v = (verbose_level >= 1);
2295 //finite_field F;
2296 int x, y, n;
2297 int r, l;
2300
2301 if (f_v) {
2302 cout << "number_theory_domain::elliptic_curve_points" << endl;
2303 }
2304 nb = 0;
2305 //F.init(p, verbose_level);
2306 for (x = 0; x < F->p; x++) {
2307 r = elliptic_curve_evaluate_RHS(F, x, b, c);
2308 if (r == 0) {
2309 if (f_v) {
2310 cout << nb << " : (" << x << "," << 0 << ",1)" << endl;
2311 }
2312 nb++;
2313 }
2314 else {
2315 if (F->p != 2) {
2316 if (F->e > 1) {
2317 cout << "number_theory_domain::elliptic_curve_points odd characteristic and e > 1" << endl;
2318 exit(1);
2319 }
2320 l = Legendre(r, F->p, verbose_level - 1);
2321 if (l == 1) {
2322 //y = sqrt_mod_involved(r, p);
2323 y = D.square_root_mod(r, F->p, 0 /* verbose_level*/);
2324 //y = NT.sqrt_mod_simple(r, p);
2325 if (f_v) {
2326 cout << nb << " : (" << x << "," << y << ",1)" << endl;
2327 cout << nb + 1 << " : (" << x << "," << F->negate(y) << ",1)" << endl;
2328 }
2329 nb += 2;
2330 }
2331 }
2332 else {
2333 y = F->frobenius_power(r, F->e - 1);
2334 if (f_v) {
2335 cout << nb << " : (" << x << "," << y << ",1)" << endl;
2336 }
2337 nb += 1;
2338 }
2339 }
2340 }
2341 if (f_v) {
2342 cout << nb << " : (0,1,0)" << endl;
2343 }
2344 nb++;
2345 if (f_v) {
2346 cout << "the curve has " << nb << " points" << endl;
2347 }
2348 T = NEW_int(nb * 3);
2349 n = 0;
2350 for (x = 0; x < F->p; x++) {
2351 r = elliptic_curve_evaluate_RHS(F, x, b, c);
2352 if (r == 0) {
2353 T[n * 3 + 0] = x;
2354 T[n * 3 + 1] = 0;
2355 T[n * 3 + 2] = 1;
2356 n++;
2357 //cout << nb++ << " : (" << x << "," << 0 << ",1)" << endl;
2358 }
2359 else {
2360 if (F->p != 2) {
2361 // odd characteristic:
2362 l = Legendre(r, F->p, verbose_level - 1);
2363 if (l == 1) {
2364 //y = sqrt_mod_involved(r, p);
2365 //y = NT.sqrt_mod_simple(r, p);
2366 y = D.square_root_mod(r, F->p, 0 /* verbose_level*/);
2367 T[n * 3 + 0] = x;
2368 T[n * 3 + 1] = y;
2369 T[n * 3 + 2] = 1;
2370 n++;
2371 T[n * 3 + 0] = x;
2372 T[n * 3 + 1] = F->negate(y);
2373 T[n * 3 + 2] = 1;
2374 n++;
2375 //cout << nb++ << " : (" << x << "," << y << ",1)" << endl;
2376 //cout << nb++ << " : (" << x << "," << F.negate(y) << ",1)" << endl;
2377 }
2378 }
2379 else {
2380 // even characteristic
2381 y = F->frobenius_power(r, F->e - 1);
2382 T[n * 3 + 0] = x;
2383 T[n * 3 + 1] = y;
2384 T[n * 3 + 2] = 1;
2385 n++;
2386 //cout << nb++ << " : (" << x << "," << y << ",1)" << endl;
2387 }
2388 }
2389 }
2390 T[n * 3 + 0] = 0;
2391 T[n * 3 + 1] = 1;
2392 T[n * 3 + 2] = 0;
2393 n++;
2394 //print_integer_matrix_width(cout, T, nb, 3, 3, log10_of_q);
2395 if (f_v) {
2396 cout << "number_theory_domain::elliptic_curve_points done" << endl;
2397 cout << "the curve has " << nb << " points" << endl;
2398 }
2399}
2400
2402 int b, int c, int &order,
2403 int x1, int y1, int z1,
2404 std::vector<std::vector<int> > &Pts,
2405 int verbose_level)
2406{
2407 int f_v = (verbose_level >= 1);
2408 int x2, y2, z2;
2409 int x3, y3, z3;
2410
2411 if (f_v) {
2412 cout << "number_theory_domain::elliptic_curve_all_point_multiples" << endl;
2413 }
2414 order = 1;
2415
2416 x2 = x1;
2417 y2 = y1;
2418 z2 = z1;
2419 while (TRUE) {
2420 {
2421 vector<int> pts;
2422
2423 pts.push_back(x2);
2424 pts.push_back(y2);
2425 pts.push_back(z2);
2426
2427 Pts.push_back(pts);
2428 }
2429 if (z2 == 0) {
2430 return;
2431 }
2432
2434 b, c,
2435 x1, y1, z1,
2436 x2, y2, z2,
2437 x3, y3, z3, 0 /*verbose_level */);
2438
2439 x2 = x3;
2440 y2 = y3;
2441 z2 = z3;
2442
2443 order++;
2444 }
2445 if (f_v) {
2446 cout << "number_theory_domain::elliptic_curve_all_point_multiples done" << endl;
2447 }
2448}
2449
2451 int b, int c,
2452 int x1, int y1, int z1,
2453 int x3, int y3, int z3,
2454 int verbose_level)
2455{
2456 int f_v = (verbose_level >= 1);
2457 int x2, y2, z2;
2458 int a3, b3, c3;
2459 int n;
2460
2461 if (f_v) {
2462 cout << "number_theory_domain::elliptic_curve_discrete_log" << endl;
2463 }
2464 n = 1;
2465
2466 x2 = x1;
2467 y2 = y1;
2468 z2 = z1;
2469 while (TRUE) {
2470 if (x2 == x3 && y2 == y3 && z2 == z3) {
2471 break;
2472 }
2473
2475 x1, y1, z1,
2476 x2, y2, z2,
2477 a3, b3, c3, 0 /*verbose_level */);
2478
2479 n++;
2480
2481 x2 = a3;
2482 y2 = b3;
2483 z2 = c3;
2484
2485 }
2486 if (f_v) {
2487 cout << "number_theory_domain::elliptic_curve_discrete_log done" << endl;
2488 }
2489 return n;
2490}
2491
2493{
2494 int f_v = (verbose_level >= 1);
2495 int nb_primes, *primes, *exponents;
2496 int i, p, e;
2498 ring_theory::longinteger_object N, R, A, B, C;
2499
2500 if (f_v) {
2501 cout << "number_theory_domain::eulers_totient_function" << endl;
2502 }
2503 N.create(n, __FILE__, __LINE__);
2504 D.factor(N, nb_primes, primes, exponents, verbose_level);
2505 R.create(1, __FILE__, __LINE__);
2506 for (i = 0; i < nb_primes; i++) {
2507 p = primes[i];
2508 e = exponents[i];
2509 A.create(p, __FILE__, __LINE__);
2510 D.power_int(A, e);
2511 if (f_v) {
2512 cout << "p^e=" << A << endl;
2513 }
2514 B.create(p, __FILE__, __LINE__);
2515 D.power_int(B, e - 1);
2516 if (f_v) {
2517 cout << "p^{e-1}=" << A << endl;
2518 }
2519 B.negate();
2520 D.add(A, B, C);
2521 if (f_v) {
2522 cout << "p^e-p^{e-1}=" << C << endl;
2523 }
2524 D.mult(R, C, A);
2525 A.assign_to(R);
2526 }
2527 if (f_v) {
2528 cout << "number_theory_domain::eulers_totient_function done" << endl;
2529 }
2530 return R.as_int();
2531}
2532
2533
2534}}}
2535
2536
a collection of functions related to sorted vectors
void factor_lint(long int a, std::vector< long int > &primes, std::vector< int > &exponents)
int Legendre_with_key_in_latex(std::ostream &ost, long int a, long int m, int verbose_level)
void sieve(std::vector< int > &primes, int factorbase, int verbose_level)
void print_longfactorization(int nb_primes, ring_theory::longinteger_object *primes, int *exponents)
long int ChineseRemainder2(long int a1, long int a2, long int p1, long int p2, int verbose_level)
void do_eulerfunction_interval(long int n_min, long int n_max, int verbose_level)
void elliptic_curve_addition(field_theory::finite_field *F, int b, int c, int x1, int x2, int x3, int y1, int y2, int y3, int &z1, int &z2, int &z3, int verbose_level)
void elliptic_curve_all_point_multiples(field_theory::finite_field *F, int b, int c, int &order, int x1, int y1, int z1, std::vector< std::vector< int > > &Pts, int verbose_level)
void sieve_primes(std::vector< int > &v, int from, int to, int limit, int verbose_level)
long int gcd_with_key_in_latex(std::ostream &ost, long int a, long int b, int f_key, int verbose_level)
void elliptic_curve_point_multiple_with_log(field_theory::finite_field *F, int b, int c, int n, int x1, int y1, int z1, int &x3, int &y3, int &z3, int verbose_level)
void print_factorization(int nb_primes, int *primes, int *exponents)
void cyclotomic_set(std::vector< int > &cyclotomic_set, int a, int q, int n, int verbose_level)
void extended_gcd_lint(long int m, long int n, long int &g, long int &u, long int &v)
void do_babystep_giantstep(long int p, long int g, long int h, int f_latex, std::ostream &ost, int verbose_level)
int elliptic_curve_discrete_log(field_theory::finite_field *F, int b, int c, int x1, int y1, int z1, int x3, int y3, int z3, int verbose_level)
void elliptic_curve_point_multiple(field_theory::finite_field *F, int b, int c, int n, int x1, int y1, int z1, int &x3, int &y3, int &z3, int verbose_level)
void int_mult_fractions(int at, int ab, int bt, int bb, int &ct, int &cb, int verbose_level)
int Jacobi_with_key_in_latex(std::ostream &ost, long int a, long int m, int verbose_level)
void elliptic_curve_points(field_theory::finite_field *F, int b, int c, int &nb, int *&T, int verbose_level)
int elliptic_curve_evaluate_RHS(field_theory::finite_field *F, int x, int b, int c)
void int_add_fractions(int at, int ab, int bt, int bb, int &ct, int &cb, int verbose_level)
void lint_matrix_write_csv_override_headers(std::string &fname, std::string *headers, long int *M, int m, int n)
Definition: file_io.cpp:1346
domain to compute with objects of type longinteger
Definition: ring_theory.h:240
void extended_gcd(longinteger_object &a, longinteger_object &b, longinteger_object &g, longinteger_object &u, longinteger_object &v, int verbose_level)
void power_longint_mod(longinteger_object &a, longinteger_object &n, longinteger_object &m, int verbose_level)
void add(longinteger_object &a, longinteger_object &b, longinteger_object &c)
void mult(longinteger_object &a, longinteger_object &b, longinteger_object &c)
void integral_division_by_lint(longinteger_object &a, long int b, longinteger_object &q, long int &r)
void mult_mod(longinteger_object &a, longinteger_object &b, longinteger_object &c, longinteger_object &m, int verbose_level)
void factor(longinteger_object &a, int &nb_primes, int *&primes, int *&exponents, int verbose_level)
a class to represent arbitrary precision integers
Definition: ring_theory.h:366
void create(long int i, const char *file, int line)
#define Lint_vec_copy(A, B, C)
Definition: foundations.h:694
#define FREE_int(p)
Definition: foundations.h:640
#define NEW_int(n)
Definition: foundations.h:625
#define ABS(x)
Definition: foundations.h:220
#define TRUE
Definition: foundations.h:231
#define FALSE
Definition: foundations.h:234
#define EVEN(x)
Definition: foundations.h:221
#define ODD(x)
Definition: foundations.h:222
#define NEW_lint(n)
Definition: foundations.h:628
int NormRemainder(int a, int m)
Definition: global.cpp:538
the orbiter library for the classification of combinatorial objects