/*
Copyright (C) 2013 Tom Bachmann
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
#include
#include
#include
#include "fmpzxx.h"
#include "flintxx/test/helpers.h"
#if !HAVE_FAST_COMPILER
#warning "Some tests are disabled because your compiler is slow."
#endif
using namespace flint;
void
test_printing()
{
fmpzxx a(31);
tassert(a.to_string() == "31");
tassert(a.to_string(2) == "11111");
std::ostringstream oss;
oss << a << '\n' << std::oct << a << '\n'
<< std::hex << a << '\n' << std::dec << a;
tassert(oss.str() == "31\n37\n1f\n31");
fmpzxx b(-15);
tassert((a + b).to_string() == "16");
char astr[] = "15";
tassert(fmpzxx(astr) == 15);
}
void
test_order()
{
fmpzxx a(0);
fmpzxx b(1);
fmpzxx c(0);
fmpzxx d(-1);
#define TO(xzero, zero, one, mone) \
tassert(xzero == zero); \
tassert(xzero != one); \
tassert(!(xzero == one)); \
tassert(!(xzero != zero)); \
tassert(xzero < one); \
tassert(xzero <= one); \
tassert(xzero <= zero); \
tassert(!(xzero < zero)); \
tassert(!(xzero <= mone)); \
tassert(xzero > mone); \
tassert(xzero >= mone); \
tassert(xzero >= zero); \
tassert(!(xzero > zero)); \
tassert(!(xzero >= one));
TO(a, c, b, d);
TO(a, 0, 1, -1);
TO(a, 0u, 1u, -1);
TO(a, (signed short)(0), (signed short)(1), (signed short)(-1));
TO(a, (unsigned short)(0), (unsigned short)(1), -1);
TO(a, WORD(0), WORD(1), WORD(-1));
TO(0, c, b, d);
TO(0u, c, b, d);
TO(WORD(0), c, b, d);
TO((short)0, c, b, d);
TO((unsigned short)0, c, b, d);
}
void
test_conversion()
{
fmpzxx a(4);
tassert(a.to() == 4);
tassert(a.to() == 4);
tassert(a.to() == 4.0);
// NB: to_string is tested in test_printing
}
void
test_initialisation_assignment()
{
fmpzxx a(4), b(WORD(4)), c(4u), d("4");
fmpzxx e(a);
fmpzxx f, g, h, i;
f = 4;
g = WORD(4);
h = 4u;
i = fmpzxx("4");
tassert(a == b && a == c&& a == d && a == e && a == f && a == g && a == h
&& a == i);
// test deep copying of fmpzxx with more than one digit
a = fmpzxx("100000000000000000000");
b = a;
tassert(a._fmpz()[0] != b._fmpz()[0]);
fmpzxx j(a);
tassert(a._fmpz()[0] != j._fmpz()[0]);
tassert(a == b && a == j);
// just here to test our assumptions on data format
tassert(c._fmpz()[0] == d._fmpz()[0]);
// some more exotic "assignments"
a.set_ui_smod(15, 16);
tassert(a == -1);
a.set_uiui(27, 15);
tassert(a % (fmpzxx(1) << FLINT_BITS) == 15);
tassert((a >> FLINT_BITS) == 27);
b.neg_uiui(27, 15);
tassert(b == -a);
}
void
test_arithmetic()
{
#define TAC(seven, three) \
tassert(seven + three == 10); \
tassert(seven * three == 21);
#define TA(seven, three) \
TAC(seven, three); \
tassert(seven - three == 4); \
tassert(seven / three == 2); \
tassert(seven % three == 1)
TA(fmpzxx(7), fmpzxx(3));
TA(fmpzxx(7), 3u);
TAC(UWORD(7), fmpzxx(3));
// test signed builtins
tassert(-7 + fmpzxx(3) == -fmpzxx(4));
tassert(fmpzxx(3) + 7 == fmpzxx(10));
tassert(7 + fmpzxx(3) == fmpzxx(10));
tassert(fmpzxx(3) + (-7) == -fmpzxx(4));
tassert(fmpzxx(3) - 7 == -4);
tassert(-7 * fmpzxx(3) == -21);
tassert(fmpzxx(7) * (WORD(-3)) == -21);
tassert(fmpzxx(21) / -3 == -7);
// test composite arithmetic
fmpzxx a(3), b(7);
tassert(3*(a + b) - (b + (a - 4u)) + ((-(a - b)) % (b / 2)) == 25);
// test unary minus
tassert(-a == -3);
// test assignment arithmetic
#define TAA(op, res) \
{ \
fmpzxx tmp1(10), tmp2(10), tmp3(10); \
fmpzxx three(3); \
tmp1 op three; \
tmp2 op 3u; \
tmp3 op three*1; \
tassert(tmp1 == res); \
tassert(tmp2 == res); \
tassert(tmp3 == res); \
}
TAA(+=, 13);
TAA(*=, 30);
TAA(/=, 3);
TAA(%=, 1);
// shifting
tassert((fmpzxx(1) << 10) == 1024);
tassert((fmpzxx(1024) >> 9) == 2);
// binary logic
tassert((fmpzxx(1) | fmpzxx(2)) == 3);
tassert((fmpzxx(3) & fmpzxx(5)) == 1);
tassert((fmpzxx(17) ^ fmpzxx(23)) == (UWORD(17) ^ UWORD(23)));
tassert(~fmpzxx(17) == ~WORD(17));
}
void
test_functions()
{
fmpzxx a(2);
fmpzxx b(16);
fmpzxx_srcref c(a);
tassert(sgn(a) == 1);
tassert(size(b) == 1);
tassert(val2(b) == 4);
tassert(bits(b) == 5);
tassert(sizeinbase(b, 2) == 5);
tassert(b.tstbit(0) == false);
tassert(pow(a, 4u) == 16);
tassert(root(b, 4) == 2);
tassert(root(b, (unsigned short)4) == 2);
tassert(sqrt(b) == 4);
tassert(sqrt(a) == 1);
tassert(rfac(a, 3u) == 2*3*4);
tassert(a + fac(4u) == 2 + 4*3*2);
tassert(fib(4u) == 3);
tassert(bin(4u, 2u) == 6);
tassert(abs(a) == a);
tassert(gcd(a, b) == 2);
tassert(lcm(a, b) == 16);
fmpzxx p(31);
tassert((invmod(b % p, p) * b) % p == 1);
tassert((negmod(b % p, p) + b) % p == 0);
fmpzxx mb(-b);
fmpzxx three(3);
tassert(cdiv_q(mb, three) == -5);
tassert(fdiv_r(mb, three) == 2);
tassert(tdiv_q(mb, three) == -5);
tassert(cdiv_q(mb, 3) == -5);
tassert(tdiv_q(mb, 3) == -5);
tassert(cdiv_q(mb, 3u) == -5);
tassert(tdiv_q(mb, 3u) == -5);
tassert(tdiv_q_2exp(mb, 2u) == -4);
tassert(fdiv_r_2exp(mb, 2u) == 0);
tassert(divexact(b, a) == 8 && divexact(b, 2) == 8 && divexact(b, 2u) == 8);
// check a composite expression
tassert(2u + sqrt(a + a) == 4);
// check immediate functions
tassert(divisible(b, a + a));
tassert(divisible(b, a + a + 2u) == false);
tassert(divisible(a + a, (unsigned short)2));
tassert(divisible(-a + b, 3) == false);
tassert(divisible(c, a) == true);
fmpzxx f(15);
tassert(clog(f, a) == 4 && clog(f, 2u) == 4);
tassert(flog(f, a) == 3 && flog(f, 2u) == 3);
tassert(2.7 < dlog(f) && dlog(f) < 2.8);
tassert(mul2(a, 15u, 16u) == a*15*16);
tassert(divexact2(b, 2u, 2u) == 4);
tassert(powm(a, 4u, fmpzxx(5)) == 1);
tassert(powm(a, fmpzxx(4), fmpzxx(5)) == 1);
tassert(mul_tdiv_q_2exp(a, fmpzxx(-3), 2u) == -1);
tassert(mul_tdiv_q_2exp(a, -3, 2u) == -1);
fmpzxx q(1), rem(2);
tassert(fdiv_qr(b, a) == ltuple(8, 0));
tassert(tdiv_qr(b, a) == ltuple(8, 0));
bool worked;
ltupleref(worked, q) = sqrtmod(fmpzxx(4), fmpzxx(5));
tassert(worked && (q == 2 || q == 3));
tassert(sqrtrem(fmpzxx(5)) == ltuple(2, 1));
// TODO gcdinv, xgcd
// check member functions
slong exp = 0;
double d = fmpzxx(3).get_d_2exp(exp);
double r = d * (WORD(1) << exp);
tassert(r >= 2.9 && r <= 3.1);
fmpzxx one(1), mone(-1), zero(0), two(2);
tassert(one.is_one() && one.is_pm1() && one.is_odd() &&
!one.is_even() && !one.is_zero());
tassert(!zero.is_one() && !zero.is_pm1() && zero.is_zero());
tassert(mone.is_pm1());
tassert(two.is_even() && !two.is_odd());
tassert(one.is_square() && !two.is_square());
tassert(jacobi(b, p) == 1);
tassert(p.is_probabprime());
tassert(p.is_prime_pseudosquare());
tassert((3*b).remove(a) == ltuple(4, 3));
a = 17;
a.clrbit(0);
tassert(a == 16);
a.combit(1);
tassert(a == 18);
tassert(a.popcnt() == 2);
frandxx rand;
mp_bitcnt_t bits = 123; // some extra space in two words
std::vector arr(bits / FLINT_BITS + 2);
fmpzxx tostore = fmpzxx::randtest_unsigned(rand, bits);
bit_pack(arr, bits, tostore);
tassert(tostore == fmpzxx::bit_unpack_unsigned(arr, bits));
tassert(tostore == fmpzxx::bit_unpack(arr, bits).get<1>());
}
void
test_member_functions()
{
// NB: only a sample, since these are done by macros anyway
fmpzxx a(2), b(3);
tassert((a*b).divisible(b));
tassert((a*b).divisible(3));
tassert(b.flog(3u) == 1);
tassert(a.clog(a) == 1);
tassert(a.rfac(3u) == rfac(a, 3u));
tassert(a.gcd(b) == gcd(a, b));
tassert(a.lcm(b) == lcm(a, b));
tassert(a.cdiv_q(b) == cdiv_q(a, b));
tassert(a.mul2(3u, 4u) == mul2(a, 3u, 4u));
tassert(a.sqrtmod(b) == sqrtmod(a, b));
tassert(b.sqrt() == sqrt(b));
}
template
void assert_is_fmpzxx(const T&)
{
tassert(traits::is_fmpzxx::val);
}
struct newtype {typedef void data_ref_t; typedef void data_srcref_t;};
void
test_traits()
{
tassert(traits::is_fmpzxx::val == true);
tassert(traits::is_fmpzxx::val == false);
assert_is_fmpzxx(fmpzxx(1) + fmpzxx(2));
// the following does not even compile:
//tassert((traits::is_fmpzxx >::val == false));
}
template
unsigned count_temporaries2(const T&)
{
return T::ev_traits_t::temp_rule_t::temporaries_t::len
// this term is always zero, but causes compiler error
// if we are not actually in the ternary case
+ T::ev_traits_t::temp_rule_t::TERNARY_OP_MARKER;
}
void
test_temporaries()
{
fmpzxx a, b, c;
tassert(count_temporaries(a + b) == 0);
tassert(count_temporaries(a + b + c + a + b + c) == 1);
tassert(count_temporaries(((a / c) + (b % a)) / ((b + c) + (c / a))) == 3);
tassert(count_temporaries((a/b) + (a/c) + (b/c) + (c/b)) == 2);
tassert(count_temporaries2((a*b) + (a*c) + (b*c) + (c*b)) == 1);
// test a bug in evaluate_2 (if addmul is used on the right, this can
// be done with two temporaries, else need three)
tassert(count_temporaries(((a+b)+(a+c)) + (((a+c) + a*c))) == 2);
}
void
test_ternary()
{
fmpzxx b(2), c(3), d(4);
#define T0 fac(4u)
#define T1 (b + b + b)
#define T2 (T1 + T1)
#define T3 (T2 + T2)
#define T4 (T3 + T3)
// The inner struct is a trickery to get gcc to free some of its data
// structures. It reduces the resident set by 50%, and compile time by 75%.
#define TT3(m1, m2, m3, ntemps) \
do{ struct inner { static void doit() { \
fmpzxx b(2), c(3), d(4); \
tassert(count_temporaries2(m1 + m2*m3) == ntemps); \
tassert(b + (m1 + m2*m3) == 2 + m1.to() + m2.to()*m3.to()); \
tassert(count_temporaries2(m1 + m3*m2) == ntemps); \
tassert(b + (m1 + m3*m2) == 2 + m1.to() + m2.to()*m3.to()); \
\
tassert(count_temporaries2(m2*m3 + m1) == ntemps); \
tassert(b + (m2*m3 + m1) == 2 + m1.to() + m2.to()*m3.to()); \
tassert(count_temporaries2(m1 + m3*m2) == ntemps); \
tassert(b + (m3*m2 + m1) == 2 + m1.to() + m2.to()*m3.to()); \
\
tassert(count_temporaries2(m1 - m2*m3) == ntemps); \
tassert(b + (m1 - m2*m3) == 2 + m1.to() - m2.to()*m3.to()); \
tassert(count_temporaries2(m1 - m3*m2) == ntemps); \
tassert(b + (m1 - m3*m2) == 2 + m1.to() - m2.to()*m3.to()); \
} }; inner::doit();} while(0)
#define TT(m1, m2, ntemps) TT3(m1, m2, d, ntemps)
TT(T0, c, 1);
TT(T1, c, 1);
TT(T2, c, 2);
TT(T3, c, 3);
TT(T0, T0, 2);
TT(T0, T1, 2);
TT(T0, T2, 2);
TT(T0, T3, 3);
#if HAVE_FAST_COMPILER
TT(T1, T0, 2);
TT(T1, T1, 2);
TT(T1, T2, 2);
TT(T1, T3, 3);
TT(T2, T0, 2);
TT(T2, T1, 2);
TT(T2, T2, 3);
TT(T2, T3, 3);
TT(T3, T0, 3);
TT(T3, T1, 3);
TT(T3, T2, 3);
TT(T3, T3, 4);
// NB: TT3 is symmetric in m2 and m3
#define TT6(m1, m2, m3, ntemps) \
TT3(m1, m2, m3, ntemps); \
TT3(m2, m1, m3, ntemps); \
TT3(m3, m1, m2, ntemps);
TT6(fac(2u), fac(3u), fac(4u), 3);
TT6(T1, T2, T3, 3);
TT6(T1, T2, T4, 4);
TT6(T1, (d+d+d) /* T1' */, T4, 4);
TT6(T0, fac(2u), T2, 3);
TT6(T0, T1, (d+d+d), 3);
TT6(T1, T3, (T2 + T1) /* T3' */, 3);
#endif
}
void
test_ternary_assigments()
{
fmpzxx a(2), b(3), c(4);
tassert((a += b*c) == 14);
tassert(a == 14);
tassert((a -= b*c) == 2);
tassert(a == 2);
tassert((a += (b+b)*c) == 26);
tassert((a -= (b+b)*c) == 2);
tassert((a += c*(b+b)) == 26);
tassert((a -= c*(b+b)) == 2);
tassert((a += (b+b)*(c+c)) == 50);
tassert((a -= (b+b)*(c+c)) == 2);
// Make sure that the general rule kicks
tassert((a += 3*c) == 14);
tassert((a -= 3*c) == 2);
}
bool
try_implicit_conversion(fmpzxx_ref, const fmpzxx_ref&,
fmpzxx_srcref, const fmpzxx_srcref&, fmpzxx_srcref, const fmpzxx_srcref&)
{
return true;
}
void
test_references()
{
fmpzxx a(2), b(3);
fmpzxx_ref ar(a);
fmpzxx_srcref acr(a), bcr(b);
tassert(ar == 2 && bcr == 3 && ar == acr && ar == a);
// test assignments
fmpzxx d(ar);
a = 4;
tassert(ar == 4 && acr == 4 && d == 2);
ar = 2;
tassert(a == 2);
// test some arithmetic
tassert(a + bcr == 5);
tassert(acr + bcr == 5);
tassert(ar + 3u == 5);
tassert(a < bcr && ar < b && acr < bcr);
tassert(rfac(acr, 1u) == 2);
ar = bin(4u, 2u); tassert(acr == 6);
tassert(acr.to() == WORD(6));
tassert(ar.to_string() == "6");
ar += b;
ar += bcr;
tassert(a == 12);
// test conversion of reference types
tassert(try_implicit_conversion(a, a, a, a, ar, ar));
tassert((!traits::_is_convertible::val));
tassert((!traits::_is_convertible::val));
tassert((!traits::_is_convertible::val));
// test creation from C types
fmpzxx_ref ar2 = fmpzxx_ref::make(a._fmpz());
fmpzxx_srcref acr2 = fmpzxx_srcref::make(acr._fmpz());
a = 7;
tassert(ar2 == 7 && acr2 == 7);
// test swapping
a = 2;
b = 3;
swap(b, ar);
tassert(a == 3 && b == 2);
// make sure ADL is preferred over the general version in std
using namespace std;
swap(b, b);
}
void
test_randomisation()
{
frandxx rand;
tassert(abs(fmpzxx::randbits(rand, 5)) <= 31);
tassert(abs(fmpzxx::randbits(rand, 5)) >= 16);
tassert(abs(fmpzxx::randtest(rand, 5)) <= 31);
tassert(fmpzxx::randtest_unsigned(rand, 5) <= 31);
tassert(fmpzxx::randtest_unsigned(rand, 5) >= 0);
tassert(fmpzxx::randtest_not_zero(rand, 5) != 0);
fmpzxx thirty(30);
tassert(fmpzxx::randm(rand, thirty) >= 0);
tassert(fmpzxx::randm(rand, thirty) <= 29);
tassert(fmpzxx::randtest_mod(rand, thirty) >= 0);
tassert(fmpzxx::randtest_mod(rand, thirty) <= 29);
tassert(fmpzxx::randtest_mod_signed(rand, thirty) > -15);
tassert(fmpzxx::randtest_mod_signed(rand, thirty) <= 15);
}
void
test_factoring()
{
fmpz_factorxx f;f = factor(-2*3*5);
tassert(f.size() == 3);
tassert(f.sign() == -1);
tassert(f.p(0) == 2 && f.exp(0) == 1);
tassert(f.p(1) == 3 && f.exp(1) == 1);
tassert(f.p(2) == 5 && f.exp(2) == 1);
tassert(f == factor(fmpzxx(-2*3*5)));
tassert(f == fmpz_factorxx(f));
tassert(f == factor_trial_range(fmpzxx(-2*3*5), 0u, 2u).get<1>());
tassert(factor_trial_range(fmpzxx(-2*3*5), 0u, 2u).get<0>());
tassert(f.expand() == -2*3*5);
tassert(f.expand() == f.expand_iterative());
tassert(f.expand() == f.expand_multiexp());
if(0)
print(f); // make sure this compiles
}
void
test_crt()
{
frandxx rand;
fmpzxx x = fmpzxx::randtest_unsigned(rand, 25);
std::vector primes;
primes.push_back(1031);
primes.push_back(1033);
primes.push_back(1039);
fmpz_combxx comb(primes);
std::vector residues(primes.size());
multi_mod(residues, x, comb);
fmpzxx prod(1);
fmpzxx res;
for(unsigned i = 0;i < primes.size();++i)
{
tassert(residues[i] == x % primes[i]);
res = res.CRT(prod, residues[i], primes[i], false);
prod *= primes[i];
}
tassert(res == x);
res = multi_CRT(residues, comb, false);
tassert(res == x);
}
int
main()
{
std::cout << "fmpzxx....";
test_printing();
test_order();
test_conversion();
test_initialisation_assignment();
test_arithmetic();
test_functions();
test_member_functions();
test_traits();
test_temporaries();
test_ternary();
test_ternary_assigments();
test_references();
test_randomisation();
test_factoring();
test_crt();
test_print_read(fmpzxx(-17));
// TODO test that certain things *don't* compile?
// TODO test enable_all_fmpzxx
std::cout << "PASS" << std::endl;
}