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