1 /*
2 Copyright (C) 2013 Tom Bachmann
3
4 This file is part of FLINT.
5
6 FLINT 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 2.1 of the License, or
9 (at your option) any later version. See <http://www.gnu.org/licenses/>.
10 */
11
12 #include <iostream>
13 #include <sstream>
14 #include <string>
15
16 #include "fmpzxx.h"
17 #include "flintxx/test/helpers.h"
18
19 #if !HAVE_FAST_COMPILER
20 #warning "Some tests are disabled because your compiler is slow."
21 #endif
22
23 using namespace flint;
24
25 void
test_printing()26 test_printing()
27 {
28 fmpzxx a(31);
29
30 tassert(a.to_string() == "31");
31 tassert(a.to_string(2) == "11111");
32
33 std::ostringstream oss;
34 oss << a << '\n' << std::oct << a << '\n'
35 << std::hex << a << '\n' << std::dec << a;
36 tassert(oss.str() == "31\n37\n1f\n31");
37
38 fmpzxx b(-15);
39 tassert((a + b).to_string() == "16");
40
41 char astr[] = "15";
42 tassert(fmpzxx(astr) == 15);
43 }
44
45 void
test_order()46 test_order()
47 {
48 fmpzxx a(0);
49 fmpzxx b(1);
50 fmpzxx c(0);
51 fmpzxx d(-1);
52
53 #define TO(xzero, zero, one, mone) \
54 tassert(xzero == zero); \
55 tassert(xzero != one); \
56 tassert(!(xzero == one)); \
57 tassert(!(xzero != zero)); \
58 tassert(xzero < one); \
59 tassert(xzero <= one); \
60 tassert(xzero <= zero); \
61 tassert(!(xzero < zero)); \
62 tassert(!(xzero <= mone)); \
63 tassert(xzero > mone); \
64 tassert(xzero >= mone); \
65 tassert(xzero >= zero); \
66 tassert(!(xzero > zero)); \
67 tassert(!(xzero >= one));
68
69 TO(a, c, b, d);
70 TO(a, 0, 1, -1);
71 TO(a, 0u, 1u, -1);
72 TO(a, (signed short)(0), (signed short)(1), (signed short)(-1));
73 TO(a, (unsigned short)(0), (unsigned short)(1), -1);
74 TO(a, WORD(0), WORD(1), WORD(-1));
75 TO(0, c, b, d);
76 TO(0u, c, b, d);
77 TO(WORD(0), c, b, d);
78 TO((short)0, c, b, d);
79 TO((unsigned short)0, c, b, d);
80 }
81
82 void
test_conversion()83 test_conversion()
84 {
85 fmpzxx a(4);
86 tassert(a.to<slong>() == 4);
87 tassert(a.to<ulong>() == 4);
88 tassert(a.to<double>() == 4.0);
89 // NB: to_string is tested in test_printing
90 }
91
92 void
test_initialisation_assignment()93 test_initialisation_assignment()
94 {
95 fmpzxx a(4), b(WORD(4)), c(4u), d("4");
96 fmpzxx e(a);
97 fmpzxx f, g, h, i;
98 f = 4;
99 g = WORD(4);
100 h = 4u;
101 i = fmpzxx("4");
102 tassert(a == b && a == c&& a == d && a == e && a == f && a == g && a == h
103 && a == i);
104
105 // test deep copying of fmpzxx with more than one digit
106 a = fmpzxx("100000000000000000000");
107 b = a;
108 tassert(a._fmpz()[0] != b._fmpz()[0]);
109 fmpzxx j(a);
110 tassert(a._fmpz()[0] != j._fmpz()[0]);
111 tassert(a == b && a == j);
112
113 // just here to test our assumptions on data format
114 tassert(c._fmpz()[0] == d._fmpz()[0]);
115
116 // some more exotic "assignments"
117 a.set_ui_smod(15, 16);
118 tassert(a == -1);
119 a.set_uiui(27, 15);
120 tassert(a % (fmpzxx(1) << FLINT_BITS) == 15);
121 tassert((a >> FLINT_BITS) == 27);
122 b.neg_uiui(27, 15);
123 tassert(b == -a);
124 }
125
126 void
test_arithmetic()127 test_arithmetic()
128 {
129 #define TAC(seven, three) \
130 tassert(seven + three == 10); \
131 tassert(seven * three == 21);
132
133 #define TA(seven, three) \
134 TAC(seven, three); \
135 tassert(seven - three == 4); \
136 tassert(seven / three == 2); \
137 tassert(seven % three == 1)
138
139 TA(fmpzxx(7), fmpzxx(3));
140 TA(fmpzxx(7), 3u);
141 TAC(UWORD(7), fmpzxx(3));
142
143 // test signed builtins
144 tassert(-7 + fmpzxx(3) == -fmpzxx(4));
145 tassert(fmpzxx(3) + 7 == fmpzxx(10));
146 tassert(7 + fmpzxx(3) == fmpzxx(10));
147 tassert(fmpzxx(3) + (-7) == -fmpzxx(4));
148 tassert(fmpzxx(3) - 7 == -4);
149 tassert(-7 * fmpzxx(3) == -21);
150 tassert(fmpzxx(7) * (WORD(-3)) == -21);
151 tassert(fmpzxx(21) / -3 == -7);
152
153 // test composite arithmetic
154 fmpzxx a(3), b(7);
155 tassert(3*(a + b) - (b + (a - 4u)) + ((-(a - b)) % (b / 2)) == 25);
156
157 // test unary minus
158 tassert(-a == -3);
159
160 // test assignment arithmetic
161 #define TAA(op, res) \
162 { \
163 fmpzxx tmp1(10), tmp2(10), tmp3(10); \
164 fmpzxx three(3); \
165 tmp1 op three; \
166 tmp2 op 3u; \
167 tmp3 op three*1; \
168 tassert(tmp1 == res); \
169 tassert(tmp2 == res); \
170 tassert(tmp3 == res); \
171 }
172 TAA(+=, 13);
173 TAA(*=, 30);
174 TAA(/=, 3);
175 TAA(%=, 1);
176
177 // shifting
178 tassert((fmpzxx(1) << 10) == 1024);
179 tassert((fmpzxx(1024) >> 9) == 2);
180
181 // binary logic
182 tassert((fmpzxx(1) | fmpzxx(2)) == 3);
183 tassert((fmpzxx(3) & fmpzxx(5)) == 1);
184 tassert((fmpzxx(17) ^ fmpzxx(23)) == (UWORD(17) ^ UWORD(23)));
185 tassert(~fmpzxx(17) == ~WORD(17));
186 }
187
188 void
test_functions()189 test_functions()
190 {
191 fmpzxx a(2);
192 fmpzxx b(16);
193 fmpzxx_srcref c(a);
194
195 tassert(sgn(a) == 1);
196 tassert(size(b) == 1);
197 tassert(val2(b) == 4);
198 tassert(bits(b) == 5);
199 tassert(sizeinbase(b, 2) == 5);
200 tassert(b.tstbit(0) == false);
201
202 tassert(pow(a, 4u) == 16);
203 tassert(root(b, 4) == 2);
204 tassert(root(b, (unsigned short)4) == 2);
205 tassert(sqrt(b) == 4);
206 tassert(sqrt(a) == 1);
207 tassert(rfac(a, 3u) == 2*3*4);
208 tassert(a + fac(4u) == 2 + 4*3*2);
209 tassert(fib(4u) == 3);
210 tassert(bin(4u, 2u) == 6);
211 tassert(abs(a) == a);
212 tassert(gcd(a, b) == 2);
213 tassert(lcm(a, b) == 16);
214 fmpzxx p(31);
215 tassert((invmod(b % p, p) * b) % p == 1);
216 tassert((negmod(b % p, p) + b) % p == 0);
217
218 fmpzxx mb(-b);
219 fmpzxx three(3);
220 tassert(cdiv_q(mb, three) == -5);
221 tassert(fdiv_r(mb, three) == 2);
222 tassert(tdiv_q(mb, three) == -5);
223 tassert(cdiv_q(mb, 3) == -5);
224 tassert(tdiv_q(mb, 3) == -5);
225 tassert(cdiv_q(mb, 3u) == -5);
226 tassert(tdiv_q(mb, 3u) == -5);
227 tassert(tdiv_q_2exp(mb, 2u) == -4);
228 tassert(fdiv_r_2exp(mb, 2u) == 0);
229 tassert(divexact(b, a) == 8 && divexact(b, 2) == 8 && divexact(b, 2u) == 8);
230
231 // check a composite expression
232 tassert(2u + sqrt(a + a) == 4);
233
234 // check immediate functions
235 tassert(divisible(b, a + a));
236 tassert(divisible(b, a + a + 2u) == false);
237 tassert(divisible(a + a, (unsigned short)2));
238 tassert(divisible(-a + b, 3) == false);
239 tassert(divisible(c, a) == true);
240
241 fmpzxx f(15);
242 tassert(clog(f, a) == 4 && clog(f, 2u) == 4);
243 tassert(flog(f, a) == 3 && flog(f, 2u) == 3);
244 tassert(2.7 < dlog(f) && dlog(f) < 2.8);
245
246 tassert(mul2(a, 15u, 16u) == a*15*16);
247 tassert(divexact2(b, 2u, 2u) == 4);
248 tassert(powm(a, 4u, fmpzxx(5)) == 1);
249 tassert(powm(a, fmpzxx(4), fmpzxx(5)) == 1);
250 tassert(mul_tdiv_q_2exp(a, fmpzxx(-3), 2u) == -1);
251 tassert(mul_tdiv_q_2exp(a, -3, 2u) == -1);
252
253 fmpzxx q(1), rem(2);
254 tassert(fdiv_qr(b, a) == ltuple(8, 0));
255 tassert(tdiv_qr(b, a) == ltuple(8, 0));
256
257 bool worked;
258 ltupleref(worked, q) = sqrtmod(fmpzxx(4), fmpzxx(5));
259 tassert(worked && (q == 2 || q == 3));
260 tassert(sqrtrem(fmpzxx(5)) == ltuple(2, 1));
261 // TODO gcdinv, xgcd
262
263 // check member functions
264 slong exp = 0;
265 double d = fmpzxx(3).get_d_2exp(exp);
266 double r = d * (WORD(1) << exp);
267 tassert(r >= 2.9 && r <= 3.1);
268 fmpzxx one(1), mone(-1), zero(0), two(2);
269 tassert(one.is_one() && one.is_pm1() && one.is_odd() &&
270 !one.is_even() && !one.is_zero());
271 tassert(!zero.is_one() && !zero.is_pm1() && zero.is_zero());
272 tassert(mone.is_pm1());
273 tassert(two.is_even() && !two.is_odd());
274 tassert(one.is_square() && !two.is_square());
275 tassert(jacobi(b, p) == 1);
276 tassert(p.is_probabprime());
277 tassert(p.is_prime_pseudosquare());
278
279 tassert((3*b).remove(a) == ltuple(4, 3));
280
281 a = 17;
282 a.clrbit(0);
283 tassert(a == 16);
284 a.combit(1);
285 tassert(a == 18);
286 tassert(a.popcnt() == 2);
287
288
289 frandxx rand;
290 mp_bitcnt_t bits = 123; // some extra space in two words
291 std::vector<mp_bitcnt_t> arr(bits / FLINT_BITS + 2);
292 fmpzxx tostore = fmpzxx::randtest_unsigned(rand, bits);
293 bit_pack(arr, bits, tostore);
294 tassert(tostore == fmpzxx::bit_unpack_unsigned(arr, bits));
295 tassert(tostore == fmpzxx::bit_unpack(arr, bits).get<1>());
296 }
297
298 void
test_member_functions()299 test_member_functions()
300 {
301 // NB: only a sample, since these are done by macros anyway
302 fmpzxx a(2), b(3);
303 tassert((a*b).divisible(b));
304 tassert((a*b).divisible(3));
305 tassert(b.flog(3u) == 1);
306 tassert(a.clog(a) == 1);
307 tassert(a.rfac(3u) == rfac(a, 3u));
308 tassert(a.gcd(b) == gcd(a, b));
309 tassert(a.lcm(b) == lcm(a, b));
310 tassert(a.cdiv_q(b) == cdiv_q(a, b));
311 tassert(a.mul2(3u, 4u) == mul2(a, 3u, 4u));
312 tassert(a.sqrtmod(b) == sqrtmod(a, b));
313 tassert(b.sqrt() == sqrt(b));
314 }
315
316 template<class T>
assert_is_fmpzxx(const T &)317 void assert_is_fmpzxx(const T&)
318 {
319 tassert(traits::is_fmpzxx<T>::val);
320 }
321 struct newtype {typedef void data_ref_t; typedef void data_srcref_t;};
322 void
test_traits()323 test_traits()
324 {
325 tassert(traits::is_fmpzxx<fmpzxx>::val == true);
326 tassert(traits::is_fmpzxx<int>::val == false);
327 assert_is_fmpzxx(fmpzxx(1) + fmpzxx(2));
328 // the following does not even compile:
329 //tassert((traits::is_fmpzxx<fmpzxx_expression<
330 // operations::immediate, newtype> >::val == false));
331 }
332
333 template<class T>
count_temporaries2(const T &)334 unsigned count_temporaries2(const T&)
335 {
336 return T::ev_traits_t::temp_rule_t::temporaries_t::len
337 // this term is always zero, but causes compiler error
338 // if we are not actually in the ternary case
339 + T::ev_traits_t::temp_rule_t::TERNARY_OP_MARKER;
340 }
341
342 void
test_temporaries()343 test_temporaries()
344 {
345 fmpzxx a, b, c;
346 tassert(count_temporaries(a + b) == 0);
347 tassert(count_temporaries(a + b + c + a + b + c) == 1);
348 tassert(count_temporaries(((a / c) + (b % a)) / ((b + c) + (c / a))) == 3);
349 tassert(count_temporaries((a/b) + (a/c) + (b/c) + (c/b)) == 2);
350 tassert(count_temporaries2((a*b) + (a*c) + (b*c) + (c*b)) == 1);
351
352 // test a bug in evaluate_2 (if addmul is used on the right, this can
353 // be done with two temporaries, else need three)
354 tassert(count_temporaries(((a+b)+(a+c)) + (((a+c) + a*c))) == 2);
355 }
356
357 void
test_ternary()358 test_ternary()
359 {
360 fmpzxx b(2), c(3), d(4);
361
362 #define T0 fac(4u)
363 #define T1 (b + b + b)
364 #define T2 (T1 + T1)
365 #define T3 (T2 + T2)
366 #define T4 (T3 + T3)
367
368 // The inner struct is a trickery to get gcc to free some of its data
369 // structures. It reduces the resident set by 50%, and compile time by 75%.
370 #define TT3(m1, m2, m3, ntemps) \
371 do{ struct inner { static void doit() { \
372 fmpzxx b(2), c(3), d(4); \
373 tassert(count_temporaries2(m1 + m2*m3) == ntemps); \
374 tassert(b + (m1 + m2*m3) == 2 + m1.to<slong>() + m2.to<slong>()*m3.to<slong>()); \
375 tassert(count_temporaries2(m1 + m3*m2) == ntemps); \
376 tassert(b + (m1 + m3*m2) == 2 + m1.to<slong>() + m2.to<slong>()*m3.to<slong>()); \
377 \
378 tassert(count_temporaries2(m2*m3 + m1) == ntemps); \
379 tassert(b + (m2*m3 + m1) == 2 + m1.to<slong>() + m2.to<slong>()*m3.to<slong>()); \
380 tassert(count_temporaries2(m1 + m3*m2) == ntemps); \
381 tassert(b + (m3*m2 + m1) == 2 + m1.to<slong>() + m2.to<slong>()*m3.to<slong>()); \
382 \
383 tassert(count_temporaries2(m1 - m2*m3) == ntemps); \
384 tassert(b + (m1 - m2*m3) == 2 + m1.to<slong>() - m2.to<slong>()*m3.to<slong>()); \
385 tassert(count_temporaries2(m1 - m3*m2) == ntemps); \
386 tassert(b + (m1 - m3*m2) == 2 + m1.to<slong>() - m2.to<slong>()*m3.to<slong>()); \
387 } }; inner::doit();} while(0)
388 #define TT(m1, m2, ntemps) TT3(m1, m2, d, ntemps)
389
390 TT(T0, c, 1);
391 TT(T1, c, 1);
392 TT(T2, c, 2);
393 TT(T3, c, 3);
394
395 TT(T0, T0, 2);
396 TT(T0, T1, 2);
397 TT(T0, T2, 2);
398 TT(T0, T3, 3);
399
400 #if HAVE_FAST_COMPILER
401 TT(T1, T0, 2);
402 TT(T1, T1, 2);
403 TT(T1, T2, 2);
404 TT(T1, T3, 3);
405
406 TT(T2, T0, 2);
407 TT(T2, T1, 2);
408 TT(T2, T2, 3);
409 TT(T2, T3, 3);
410
411 TT(T3, T0, 3);
412 TT(T3, T1, 3);
413 TT(T3, T2, 3);
414 TT(T3, T3, 4);
415
416 // NB: TT3 is symmetric in m2 and m3
417 #define TT6(m1, m2, m3, ntemps) \
418 TT3(m1, m2, m3, ntemps); \
419 TT3(m2, m1, m3, ntemps); \
420 TT3(m3, m1, m2, ntemps);
421
422 TT6(fac(2u), fac(3u), fac(4u), 3);
423 TT6(T1, T2, T3, 3);
424 TT6(T1, T2, T4, 4);
425 TT6(T1, (d+d+d) /* T1' */, T4, 4);
426 TT6(T0, fac(2u), T2, 3);
427 TT6(T0, T1, (d+d+d), 3);
428 TT6(T1, T3, (T2 + T1) /* T3' */, 3);
429 #endif
430 }
431
432 void
test_ternary_assigments()433 test_ternary_assigments()
434 {
435 fmpzxx a(2), b(3), c(4);
436 tassert((a += b*c) == 14);
437 tassert(a == 14);
438 tassert((a -= b*c) == 2);
439 tassert(a == 2);
440
441 tassert((a += (b+b)*c) == 26);
442 tassert((a -= (b+b)*c) == 2);
443 tassert((a += c*(b+b)) == 26);
444 tassert((a -= c*(b+b)) == 2);
445
446 tassert((a += (b+b)*(c+c)) == 50);
447 tassert((a -= (b+b)*(c+c)) == 2);
448
449 // Make sure that the general rule kicks
450 tassert((a += 3*c) == 14);
451 tassert((a -= 3*c) == 2);
452 }
453
454 bool
try_implicit_conversion(fmpzxx_ref,const fmpzxx_ref &,fmpzxx_srcref,const fmpzxx_srcref &,fmpzxx_srcref,const fmpzxx_srcref &)455 try_implicit_conversion(fmpzxx_ref, const fmpzxx_ref&,
456 fmpzxx_srcref, const fmpzxx_srcref&, fmpzxx_srcref, const fmpzxx_srcref&)
457 {
458 return true;
459 }
460 void
test_references()461 test_references()
462 {
463 fmpzxx a(2), b(3);
464 fmpzxx_ref ar(a);
465 fmpzxx_srcref acr(a), bcr(b);
466
467 tassert(ar == 2 && bcr == 3 && ar == acr && ar == a);
468
469 // test assignments
470 fmpzxx d(ar);
471 a = 4;
472 tassert(ar == 4 && acr == 4 && d == 2);
473 ar = 2;
474 tassert(a == 2);
475
476 // test some arithmetic
477 tassert(a + bcr == 5);
478 tassert(acr + bcr == 5);
479 tassert(ar + 3u == 5);
480 tassert(a < bcr && ar < b && acr < bcr);
481 tassert(rfac(acr, 1u) == 2);
482
483 ar = bin(4u, 2u); tassert(acr == 6);
484 tassert(acr.to<slong>() == WORD(6));
485 tassert(ar.to_string() == "6");
486 ar += b;
487 ar += bcr;
488 tassert(a == 12);
489
490 // test conversion of reference types
491 tassert(try_implicit_conversion(a, a, a, a, ar, ar));
492 tassert((!traits::_is_convertible<fmpzxx, fmpzxx_ref>::val));
493 tassert((!traits::_is_convertible<fmpzxx, fmpzxx_srcref>::val));
494 tassert((!traits::_is_convertible<fmpzxx_ref, fmpzxx_srcref>::val));
495
496 // test creation from C types
497 fmpzxx_ref ar2 = fmpzxx_ref::make(a._fmpz());
498 fmpzxx_srcref acr2 = fmpzxx_srcref::make(acr._fmpz());
499 a = 7;
500 tassert(ar2 == 7 && acr2 == 7);
501
502 // test swapping
503 a = 2;
504 b = 3;
505 swap(b, ar);
506 tassert(a == 3 && b == 2);
507 // make sure ADL is preferred over the general version in std
508 using namespace std;
509 swap(b, b);
510 }
511
512 void
test_randomisation()513 test_randomisation()
514 {
515 frandxx rand;
516 tassert(abs(fmpzxx::randbits(rand, 5)) <= 31);
517 tassert(abs(fmpzxx::randbits(rand, 5)) >= 16);
518 tassert(abs(fmpzxx::randtest(rand, 5)) <= 31);
519 tassert(fmpzxx::randtest_unsigned(rand, 5) <= 31);
520 tassert(fmpzxx::randtest_unsigned(rand, 5) >= 0);
521 tassert(fmpzxx::randtest_not_zero(rand, 5) != 0);
522 fmpzxx thirty(30);
523 tassert(fmpzxx::randm(rand, thirty) >= 0);
524 tassert(fmpzxx::randm(rand, thirty) <= 29);
525 tassert(fmpzxx::randtest_mod(rand, thirty) >= 0);
526 tassert(fmpzxx::randtest_mod(rand, thirty) <= 29);
527 tassert(fmpzxx::randtest_mod_signed(rand, thirty) > -15);
528 tassert(fmpzxx::randtest_mod_signed(rand, thirty) <= 15);
529 }
530
531 void
test_factoring()532 test_factoring()
533 {
534 fmpz_factorxx f;f = factor(-2*3*5);
535 tassert(f.size() == 3);
536 tassert(f.sign() == -1);
537 tassert(f.p(0) == 2 && f.exp(0) == 1);
538 tassert(f.p(1) == 3 && f.exp(1) == 1);
539 tassert(f.p(2) == 5 && f.exp(2) == 1);
540 tassert(f == factor(fmpzxx(-2*3*5)));
541 tassert(f == fmpz_factorxx(f));
542 tassert(f == factor_trial_range(fmpzxx(-2*3*5), 0u, 2u).get<1>());
543 tassert(factor_trial_range(fmpzxx(-2*3*5), 0u, 2u).get<0>());
544
545 tassert(f.expand() == -2*3*5);
546 tassert(f.expand() == f.expand_iterative());
547 tassert(f.expand() == f.expand_multiexp());
548
549 if(0)
550 print(f); // make sure this compiles
551 }
552
553 void
test_crt()554 test_crt()
555 {
556 frandxx rand;
557 fmpzxx x = fmpzxx::randtest_unsigned(rand, 25);
558 std::vector<mp_limb_t> primes;
559 primes.push_back(1031);
560 primes.push_back(1033);
561 primes.push_back(1039);
562
563 fmpz_combxx comb(primes);
564 std::vector<mp_limb_t> residues(primes.size());
565 multi_mod(residues, x, comb);
566
567 fmpzxx prod(1);
568 fmpzxx res;
569 for(unsigned i = 0;i < primes.size();++i)
570 {
571 tassert(residues[i] == x % primes[i]);
572 res = res.CRT(prod, residues[i], primes[i], false);
573 prod *= primes[i];
574 }
575 tassert(res == x);
576
577 res = multi_CRT(residues, comb, false);
578 tassert(res == x);
579 }
580
581 int
main()582 main()
583 {
584 std::cout << "fmpzxx....";
585
586 test_printing();
587 test_order();
588 test_conversion();
589 test_initialisation_assignment();
590 test_arithmetic();
591 test_functions();
592 test_member_functions();
593 test_traits();
594 test_temporaries();
595 test_ternary();
596 test_ternary_assigments();
597 test_references();
598 test_randomisation();
599 test_factoring();
600 test_crt();
601 test_print_read(fmpzxx(-17));
602
603 // TODO test that certain things *don't* compile?
604 // TODO test enable_all_fmpzxx
605
606 std::cout << "PASS" << std::endl;
607 }
608