// Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #include #include #include #include "tester.h" namespace { using namespace test; using namespace dlib; using namespace std; logger dlog("test.bigint"); namespace bigint_kernel_test_helpers { template < typename bint > bint short_fact (unsigned short value) /*! ensures - returns the factorial of value !*/ { using namespace relational_operators; bint a = 1; for (unsigned short i = 2; i <= value; ++i) a *= i; return a; } template < typename bint > bint short_fact_squared (unsigned short value) /*! ensures - returns the square of the factorial of value !*/ { using namespace relational_operators; bint a = 1; for (unsigned short i = 2; i <= value; ++i) { a *= i; a *= i; } return a; } template < typename bint > bint big_fact (unsigned short value) /*! ensures - returns the factorial of value !*/ { using namespace relational_operators; bint a = 1; int k = 0; for (bint i = 2; i <= value; ++i) { ++k; if (k%10 == 0) print_spinner(); a *= i; } return a; } } template < typename bint > void bigint_kernel_test ( ) /*! requires - bint is an implementation of bigint/bigint_kernel_abstract.h ensures - runs tests on bint for compliance with the specs !*/ { using namespace bigint_kernel_test_helpers; using namespace relational_operators; istringstream sin; ostringstream sout; bint i = 0; bint a(5), b, c(0); DLIB_TEST(5 - a == 0); DLIB_TEST(a - 5 == 0); DLIB_TEST(0 - c == 0); DLIB_TEST(c - 0 == 0); DLIB_TEST(0 + c == 0); DLIB_TEST(c + 0 == 0); DLIB_TEST(0 + a == 5); DLIB_TEST(a + 0 == 5); DLIB_TEST(0 - b == 0); DLIB_TEST(b - 0 == 0); DLIB_TEST(0 + b == 0); DLIB_TEST(b + 0 == 0); DLIB_TEST(i == 0); DLIB_TEST(a == 5); DLIB_TEST(b == 0); DLIB_TEST(c == 0); a -= 5; DLIB_TEST(a == 0); for (int k = 0; k < 100; ++k) { // compute the factorial of k using the O(n) multiplication algorithm a = short_fact(k); // compute the factorial of k using the full blown big int // multiplication algorithm. b = big_fact(k); // compute the square of the factorial of k using the full blown // big int multiplication algorithm. c = a*b; // make sure a and b ended up being the same number DLIB_TEST_MSG(a == b, "k: " << k << "\n" "short_fact: " << a << "\n" "big_fact: " << b ); // make sure c really is the square of the factorial of k DLIB_TEST_MSG(short_fact_squared(k) == c,"k: " << k); print_spinner(); } // do the same thing as the last loop but do it with way bigger numbers for (int k = 1000; k < 10000; k += 2000) { bint a = short_fact(k); bint b = big_fact(k); bint c = a*b; DLIB_TEST_MSG(a == b, "k: " << k << "\n" "short_fact: " << a << "\n" "big_fact: " << b ); DLIB_TEST_MSG(short_fact_squared(k) == c,"k: " << k); print_spinner(); } // test the << and >> operators a little a = big_fact(20); sout << a; DLIB_TEST_MSG( sout.str() == "2432902008176640000","was: " << a); sin.str("684626312793279327952039475203945"); sin >> a; sout.str(""); sout << a; DLIB_TEST(sout.str() == "684626312793279327952039475203945"); print_spinner(); DLIB_TEST(a > 0); // make sure that when you try to read something that isn't a number // into a bigint you get an error DLIB_TEST(sin.fail() == false); sin.str("the cat ate some cheese"); sin >> a; DLIB_TEST(sin.fail() == true); sin.clear(); sin.str(""); sin.str("3628913"); sin >> i; DLIB_TEST(short_fact(10) + short_fact(5) - 7 == i); sin.str("2432902008173011193"); sin >> i; DLIB_TEST(short_fact(20) - short_fact(10) - 7 == i); // test the serialization stuff sout.str(""); serialize(i,sout); i = 0; sin.str(sout.str()); deserialize(i,sin); DLIB_TEST(short_fact(20) - short_fact(10) - 7 == i); print_spinner(); sin.str("100000"); sin >> b; a = b; ++b; DLIB_TEST_MSG ( a + 1 == b,"a==" << a << endl << "b==" << b << endl); // compute some stuff and see if you get the right value a = 0; b = 0; sin.str("1000000"); sin >> b; int mel = 0; for (i = a; i <= b; ++i) { // switch it up on em if (i%2 == 0) a = a + i; else a += i; ++mel; if ((mel&0xFFF) == 0) print_spinner(); } DLIB_TEST_MSG(a == b*(b+1)/2, "a==" << a << endl << "b*(b+1)/2==" << b*(b+1)/2 << endl); print_spinner(); // compute some stuff and see if you get the right value // this time going the other way using operator-- a = 0; b = 0; sin.str("100000"); sin >> b; i = b; DLIB_TEST(i == b); DLIB_TEST_MSG(i > 0,"i==" << i); mel = 0; for (i = b; i > 0; --i) { // switch it up on em if (i%2 == 0) a = a + i; else a += i; ++mel; if ((mel&0xFF) == 0) print_spinner(); } DLIB_TEST_MSG(a == b*(b+1)/2, "a==" << a << endl << "b*(b+1)/2==" << b*(b+1)/2 << endl); DLIB_TEST(short_fact(10)/short_fact(5) == 30240); DLIB_TEST(short_fact(10)/(short_fact(5)+1) == 29990); sin.str("221172909834240000"); sin >> a; DLIB_TEST(short_fact(20)/(short_fact(5)+1) == a/11); sin.str("670442388044"); sin >> b; DLIB_TEST(short_fact(20)/(short_fact(10)+1) == b); print_spinner(); sin.str("1860479"); sin >> i; DLIB_TEST_MSG(short_fact(20)/(short_fact(15)+1) == i,short_fact(20)/(short_fact(15)+1)); // test the serialization stuff sout.str(""); serialize(i,sout); i = 0; sin.str(sout.str()); deserialize(i,sin); DLIB_TEST_MSG(short_fact(20)/(short_fact(15)+1) == i,short_fact(20)/(short_fact(15)+1)); print_spinner(); // test the serialization stuff sout.str(""); i = 0; serialize(i,sout); i = 1234; sin.str(sout.str()); deserialize(i,sin); DLIB_TEST(i == 0); DLIB_TEST(short_fact(10000)/short_fact(9999) == 10000); DLIB_TEST(bint(5)%bint(1) == 0); DLIB_TEST(bint(5)%bint(6) == 5); DLIB_TEST(bint(25)%bint(6) == 1); print_spinner(); DLIB_TEST(bint(354)%bint(123) == 108); DLIB_TEST(bint(20)%(bint(10)) == 0); DLIB_TEST(bint(20)%(bint(10)+1) == 9); DLIB_TEST(bint(20)%(bint(15)+1) == 4); DLIB_TEST(short_fact(10)%(short_fact(5)+2) == 32); sin.str("2908082"); sin >> i; DLIB_TEST(short_fact(15)%(short_fact(10)+2) == i); // same as some of the above stuff but using big_fact DLIB_TEST(big_fact(10)%(big_fact(5)+2) == 32); sin.str("2908082"); sin >> i; DLIB_TEST(big_fact(15)%(big_fact(10)+2) == i); print_spinner(); DLIB_TEST(big_fact(10)/big_fact(5) == 30240); DLIB_TEST(big_fact(10)/(big_fact(5)+1) == 29990); sin.str("221172909834240000"); sin >> a; DLIB_TEST(big_fact(20)/(big_fact(5)+1) == a/11); sin.str("670442388044"); sin >> b; DLIB_TEST(big_fact(20)/(big_fact(10)+1) == b); sin.str("1860479"); sin >> i; DLIB_TEST_MSG(big_fact(20)/(big_fact(15)+1) == i,big_fact(20)/(big_fact(15)+1)); DLIB_TEST(big_fact(100)/big_fact(99) == 100); sout.str(""); sout << "148571596448176149730952273362082573788556996128468876694221686370498539309"; sout << "4065876545992131370884059645617234469978112000000000000000000000"; sin.str(sout.str()); sin >> a; sout.str(""); sout << "933262154439441526816992388562667004907159682643816214685929638952175999932"; sout << "299156089414639761565182862536979208272237582511852109168640000000000000000"; sout << "000000"; sin.str(sout.str()); sin >> b; sout.str(""); sout << "138656248189732152054159609718432247180282092567575172939636909224427929240"; sout << "834642263988043338170905744175653189424779336521852536242160190545537133916"; sout << "649622615351174407746524657461692702500613722228638559932561661493048332720"; sout << "6050692647868232055316807680000000000000000000000000000000000000000000"; sin.str(sout.str()); sin >> c; DLIB_TEST_MSG(a*b == c, "a*b: " << a*b << "\nc: " << c); print_spinner(); i = 0; mel = 0; unsigned long j; for (j = 0; i < bint(100000); ++j) { DLIB_TEST(i++ == bint(j)); ++mel; if((mel&0xFF) == 0) print_spinner(); } DLIB_TEST(j == 100000); i = 1234; DLIB_TEST(i == 1234); DLIB_TEST(i < 2345 ); DLIB_TEST(i > 0 ); DLIB_TEST(i > 123 ); DLIB_TEST(i != 1334); DLIB_TEST(i <= 2345); DLIB_TEST(i >= 0 ); DLIB_TEST(i >= 123 ); DLIB_TEST(i >= 1234); DLIB_TEST(i <= 1234); DLIB_TEST(1234 == i); DLIB_TEST(2345 > i); DLIB_TEST(0 < i); DLIB_TEST(123 < i); DLIB_TEST(1334 != i); DLIB_TEST(2345 >= i); DLIB_TEST(0 <= i); DLIB_TEST(123 <= i); DLIB_TEST(1234 <= i); DLIB_TEST(1234 >= i); a = big_fact(200); b = big_fact(100); DLIB_TEST(a > b); DLIB_TEST(a != b); DLIB_TEST(b < a); DLIB_TEST(b != a); DLIB_TEST(b <= a); DLIB_TEST(a >= b); a = 10000; a = a*a*a*a; a = a*a; a = a*a; b = 2; DLIB_TEST((a/b)*b == a); a = 10000*5; a = a*a*a*a; a = a*a; a = a*a; b = 5; DLIB_TEST((a/b)*b == a); } class bigint_tester : public tester { public: bigint_tester ( ) : tester ("test_bigint", "Runs tests on the bigint component.") {} void perform_test ( ) { dlog << LINFO << "testing kernel_1a"; bigint_kernel_test(); print_spinner(); dlog << LINFO << "testing kernel_1a_c"; bigint_kernel_test(); print_spinner(); dlog << LINFO << "testing kernel_2a"; bigint_kernel_test(); print_spinner(); dlog << LINFO << "testing kernel_2a_c"; bigint_kernel_test(); print_spinner(); } } a; }