/*============================================================================= This file is part of FLINT. FLINT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. FLINT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with FLINT; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =============================================================================*/ /****************************************************************************** Copyright (C) 2013 Tom Bachmann ******************************************************************************/ #include #include #include #include "fmpqxx.h" #include "fmpz_vecxx.h" #include "flintxx/test/helpers.h" using namespace flint; void test_init() { fmpqxx a, b = fmpqxx::frac(6, fmpzxx(10)), c = fmpqxx::frac((unsigned short)6, 10u); tassert(a.num() == 0 && a.den() == 1); tassert(b.num() == 3 && b.den() == 5); tassert(c.num() == 3 && c.den() == 5); a.num() = -2; a.den() = 4; tassert(!a.is_canonical()); a.canonicalise(); tassert(a.num() == -1 && a.den() == 2); tassert(fmpqxx::frac("4", 2) == fmpqxx::integer(-fmpzxx(-2))); tassert(fmpqxx::zero().is_zero() && fmpqxx::one().is_one()); } void test_assignment() { fmpqxx a; fmpqxx b = fmpqxx::frac("100000000000000000000", "100000000000000000001"); fmpqxx c(b); a = b; tassert(a == b && c == b); tassert(a.num()._fmpz()[0] != b.num()._fmpz()[0]); tassert(a.den()._fmpz()[0] != b.den()._fmpz()[0]); tassert(c.num()._fmpz()[0] != b.num()._fmpz()[0]); tassert(c.den()._fmpz()[0] != b.den()._fmpz()[0]); a = 7; tassert(a.num() == 7 && a.den() == 1); a = (unsigned short)8; tassert(a.num() == 8 && a.den() == 1); } void test_conversion() { fmpqxx a = fmpqxx::frac(3, 5); tassert(a.to_string() == "3/5"); tassert(a.to_string(5) == "3/10"); std::ostringstream oss; oss << a; tassert(oss.str() == "3/5"); tassert((a + a).num() == 6); tassert((a * a).den() == 25); } void test_order() { fmpqxx a(0, 1u), b(1, 1u); tassert(a < b); tassert(a <= a); tassert(b > a); tassert(b >= b); tassert(a == a); tassert(a != b); } void test_arithmetic() { fmpqxx a(3, 5u), b(2, 7u); fmpzxx c(2); tassert(a + b == fmpqxx::frac(3*7 + 2*5, 35u)); tassert(a * b == fmpqxx::frac(6, 35u)); tassert(a - b == fmpqxx::frac(3*7 - 5*2, 35u)); tassert(a / b == fmpqxx::frac(3*7, 10u)); tassert((a+a) * (c+c) == fmpqxx::frac(24, 5u)); tassert(c * a == fmpqxx::frac(6, 5u)); tassert(a / c == fmpqxx::frac(3, 10u)); tassert(-a == fmpqxx::frac(-3, 5u)); tassert(((a << 5) >> 4) == fmpzxx(2)*a); } // Won't compile if the expression is not done using addmul template bool is_ternary(const T&) { return T::ev_traits_t::temp_rule_t::TERNARY_OP_MARKER + 1; } // test stuff which we should get automatically - addmul, references etc void test_extras() { fmpqxx a(3, 5u), b(2, 7u), c(3, 1u); tassert(is_ternary((a+a) - b*c)); tassert(is_ternary(b*c + (a+a))); tassert((a+a) - b*c == fmpqxx::frac(6*7 - 5*6, 5u*7u)); tassert(b*c + (a+a) == fmpqxx::frac(6*7 + 5*6, 5u*7u)); fmpqxx_ref ar(a); fmpqxx_srcref asr(a); tassert(a == ar && ar == asr); ar = 3; tassert(a == c && asr == c); tassert((-a) + a == fmpqxx::frac(0, 0u)); tassert(a.pow(3) == pow(a, 3)); tassert(a.height() == height(a)); } void test_functions() { fmpqxx a(-3, 5u); // test lazy functions tassert(abs(a) == -a); tassert(height(a) == 5); tassert(a % fmpzxx(7) == 5); assert_exception((a % fmpzxx(5)).evaluate()); // test immediate functions tassert(height_bits(a) == 3); tassert((inv(a)*a).is_one()); tassert(sgn(a) == -1 && sgn(-a) == 1 && sgn(fmpqxx::frac(0, 0u)) == 0); // test member functions const fmpqxx zero(0, 0u), one(1, 1u); tassert(zero.is_zero() && !zero.is_one()); tassert(!one.is_zero() && one.is_one()); tassert(pow(a, -3) == inv(a*a*a)); tassert(zero.next_minimal().next_minimal().next_minimal() == fmpqxx::frac(2, 1u)); tassert(zero.next_signed_minimal().next_signed_minimal() == fmpqxx::frac(-1, 1u)); tassert(zero.next_calkin_wilf().next_calkin_wilf() == fmpqxx::frac(1, 2u)); tassert(zero.next_signed_calkin_wilf().next_signed_calkin_wilf() == fmpqxx::frac(-1, 1u)); // test static member functions frandxx rand; tassert(abs(fmpqxx::randbits(rand, 5).den()) <= 31); // NB: rand stuff comes from a single macro, no need for further testing tassert(a == fmpqxx::reconstruct( a % fmpzxx(41), fmpzxx(41), fmpzxx(3), fmpzxx(5))); assert_exception(fmpqxx::reconstruct( a % fmpzxx(7), fmpzxx(7), fmpzxx(1), fmpzxx(1)).evaluate()); tassert(a == fmpqxx::reconstruct(a % fmpzxx(71), fmpzxx(71))); assert_exception(fmpqxx::reconstruct(a % fmpzxx(7), fmpzxx(7)).evaluate()); // test partial fractions fmpz_vecxx v(5); fmpqxx tmp(7, 5u); fmpqxx rem; tassert(tmp == fmpqxx::from_cfrac(v, get_cfrac(v, rem, tmp))); tassert(rem.is_zero()); tassert(3 <= tmp.cfrac_bound()); // test swap a = 1; fmpqxx b(zero); swap(a, b); tassert(a.is_zero() && b.is_one()); tassert_fprint(fmpqxx::frac(7, 29), "7/29"); } void test_vector() { fmpq_vecxx v1(10), v2(10), v3(1); tassert(v1 == v2); tassert(v1 != v3); v1[0] = fmpqxx::frac(1, 1u); tassert(v1 != v2); v2[0] = v1[0]; tassert(v1 == v2); } void test_unified_access() { fmpqxx a = fmpqxx::frac(1, 2); const fmpqxx& b = a; tassert(b.num() == 1); const fmpqxx_ref c(a); c.num() = 3; tassert(c.num() == 3); } int main() { std::cout << "fmpqxx...."; test_init(); test_assignment(); test_conversion(); test_order(); test_arithmetic(); test_functions(); test_extras(); test_vector(); test_unified_access(); std::cout << "PASS" << std::endl; return 0; }