diff --git a/.travis.yml b/.travis.yml index 46f20e5..4e40507 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,11 @@ language: c -compiler: clang +compiler: g++-4.8 sudo: required +dist: trusty + +install: + - sudo apt-get update -qq + - sudo apt-get install gcc-4.8 -y -qq script: - make all diff --git a/Makefile b/Makefile index 545eb15..e5be43e 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,73 @@ # Compiler flags -CFLAGS=-I ./include -std=c++11 -Wall -CFLAGS_LIB=-I ./include -std=c++11 -c +CFLAGS=-I./include -std=gnu++11 -Wall +CFLAGS_LIB=-I./include -std=gnu++11 -c +CFLAGS_TEST=test/tmath_test.cpp build/libtmath.a -all: lib +all: lib test + @echo Done. -lib: tmath.o - mkdir -p build - echo "Packaging library ..." +lib: build_folder tmath.o ar rcs build/libtmath.a build/tmath.o -test: lib - echo "Running tests ..." +test: test_sine test_cosine test_tangent test_cosecant test_cotangent test_secant test_rad_deg test_abs test_factorial test_roots test_power test_exp_log + @echo all tests passed -examples: lib - echo "Building examples ..." +build_folder: + @mkdir -p build -tmath.o: - echo "Building source files ..." - mkdir -p build +test_folder: + @mkdir -p build/test + +test_sine: test_folder + $(CC) $(CFLAGS) test/sine/test.cpp -o build/test/sine $(CFLAGS_TEST) + @build/test/sine + +test_cosine: test_folder + $(CC) $(CFLAGS) test/cosine/test.cpp -o build/test/cosine $(CFLAGS_TEST) + @build/test/cosine + +test_tangent: test_folder + $(CC) $(CFLAGS) test/tangent/test.cpp -o build/test/tangent $(CFLAGS_TEST) + @build/test/tangent + +test_cosecant: test_folder + $(CC) $(CFLAGS) test/cosecant/test.cpp -o build/test/cosecant $(CFLAGS_TEST) + @build/test/cosecant + +test_cotangent: test_folder + $(CC) $(CFLAGS) test/cotangent/test.cpp -o build/test/cotangent $(CFLAGS_TEST) + @build/test/cotangent + +test_secant: test_folder + $(CC) $(CFLAGS) test/secant/test.cpp -o build/test/secant $(CFLAGS_TEST) + @build/test/secant + +test_rad_deg: test_folder + $(CC) $(CFLAGS) test/rad-deg/test.cpp -o build/test/rad-deg $(CFLAGS_TEST) + @build/test/rad-deg + +test_abs: test_folder + $(CC) $(CFLAGS) test/abs/test.cpp -o build/test/abs $(CFLAGS_TEST) + @build/test/abs + +test_factorial: test_folder + $(CC) $(CFLAGS) test/factorial/test.cpp -o build/test/factorial $(CFLAGS_TEST) + @build/test/factorial + +test_roots: test_folder + $(CC) $(CFLAGS) test/roots/test.cpp -o build/test/roots $(CFLAGS_TEST) + @build/test/roots + +test_power: test_folder + $(CC) $(CFLAGS) test/power/test.cpp -o build/test/power $(CFLAGS_TEST) + @build/test/power + +test_exp_log: test_folder + $(CC) $(CFLAGS) test/exp-log/test.cpp -o build/test/exp-log $(CFLAGS_TEST) + @build/test/exp-log + +tmath.o: build_folder $(CC) $(CFLAGS_LIB) src/tmath.cpp -o build/tmath.o -clean: - echo "Cleaning up ..." +clean: build_folder rm build -f -r diff --git a/examples/arcsec_demo.cpp b/examples/arcsec_demo.cpp deleted file mode 100644 index 86c2343..0000000 --- a/examples/arcsec_demo.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include "tmath.h" - -/* -Demonstration of the TaylorMath (TMath) math function collection. -*/ -int main(void) { - printf("%.128f \n", TMath::arcsec(2)); - return 0; -} diff --git a/include/tmath.hpp b/include/tmath.hpp index 0c03b23..c716c3a 100644 --- a/include/tmath.hpp +++ b/include/tmath.hpp @@ -31,7 +31,7 @@ DOUBLE sec(DOUBLE x); // secant DOUBLE asec(DOUBLE x); // arcsecant DOUBLE sech(DOUBLE x); // hyperbolic secant -DOUBLE cosec(DOUBLE x); // cosecant +DOUBLE csc(DOUBLE x); // cosecant DOUBLE acsc(DOUBLE x); // arccosecant DOUBLE csch(DOUBLE x); // hyperbolic cosecant @@ -54,6 +54,8 @@ LONG fac(LONG n); DOUBLE facd(LONG n); LONG oddfac(LONG n); DOUBLE oddfacd(LONG n); + +DOUBLE abs(DOUBLE x); } #endif diff --git a/include/tmath_test.hpp b/include/tmath_test.hpp new file mode 100644 index 0000000..61e0722 --- /dev/null +++ b/include/tmath_test.hpp @@ -0,0 +1,14 @@ +#ifndef _TMATH_TEST_HPP +#define _TMATH_TEST_HPP + +#include +#include "tmath.hpp" + +namespace TMathTest { +const TMath::DOUBLE DEFAULT_TOLERANCE = 0.001; +bool equal(TMath::DOUBLE x, TMath::DOUBLE y, TMath::DOUBLE tolerance); +void assert(TMath::DOUBLE value, TMath::DOUBLE correct, std::string expression); +void assert(TMath::DOUBLE value, TMath::DOUBLE correct, std::string expression, TMath::DOUBLE tolerance); +} + +#endif diff --git a/src/tmath.cpp b/src/tmath.cpp index 20bcc01..390cd0f 100644 --- a/src/tmath.cpp +++ b/src/tmath.cpp @@ -21,7 +21,7 @@ TMath::DOUBLE TMath::asin(DOUBLE x) DOUBLE f = facd(odd); DOUBLE p = pow(x, odd); DOUBLE d = p / f * oddf * oddf; - delta = d; + delta = abs(d); r += p / f * oddf * oddf; } return r; @@ -56,9 +56,13 @@ TMath::DOUBLE TMath::tan(DOUBLE x) TMath::DOUBLE TMath::atan(DOUBLE x) { DOUBLE r = 0; - for (LONG n = 0; n <= 8; n++) + DOUBLE delta = 1; + for (LONG n = 0; delta > 1e-4; n++) { - r += pow(DOUBLE(-1), n) * pow(x, 2 * n + 1) / (2 * n + 1); + LONG odd = 2 * n + 1; + DOUBLE d = DOUBLE(pow(-1LL, n)) * pow(x, odd) / DOUBLE(odd); + delta = abs(d); + r += d; } return r; } @@ -93,7 +97,7 @@ TMath::DOUBLE TMath::sech(DOUBLE x) return 1 / cosh(x); } /* ================================ COSECANT ======================================== */ -TMath::DOUBLE TMath::cosec(DOUBLE x) +TMath::DOUBLE TMath::csc(DOUBLE x) { return 1 / sin(x); } @@ -139,7 +143,7 @@ TMath::DOUBLE TMath::exp(DOUBLE x) DOUBLE r = 0; for (LONG n = 0; n <= 15L; n++) { - r += pow(x, n) / fac(n); + r += pow(x, n) / facd(n); } return r; } @@ -223,7 +227,7 @@ TMath::DOUBLE TMath::facd(LONG n) { } TMath::LONG TMath::oddfac(LONG n) { LONG r = 1; - for (LONG i = 3; i <= n; i++) { + for (LONG i = 3; i <= n; i += 2) { r *= i; } return r; @@ -235,6 +239,10 @@ TMath::DOUBLE TMath::oddfacd(LONG n) { } return r; } +TMath::DOUBLE TMath::abs(DOUBLE x) { + if (x < 0) return -x; + else return x; +} /* ========================================== DEGREE / RADIANT CONVERSION ================================*/ TMath::DOUBLE TMath::rad(DOUBLE deg) { diff --git a/test/abs/test.cpp b/test/abs/test.cpp new file mode 100644 index 0000000..37ded0b --- /dev/null +++ b/test/abs/test.cpp @@ -0,0 +1,17 @@ +/* + This test checks the abs function. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::abs; + + assert(abs(0.0), 0.0, "abs(0) == 0"); + assert(abs(1.0), 1.0, "abs(1) == 1"); + assert(abs(-1.0), 1.0, "abs(-1) == 1"); + + return 0; +} diff --git a/test/cosecant/test.cpp b/test/cosecant/test.cpp new file mode 100644 index 0000000..6dd9404 --- /dev/null +++ b/test/cosecant/test.cpp @@ -0,0 +1,25 @@ +/* + This test checks the cosecant, arccosecant and hyperbolic cosecant function. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::csc; + using TMath::acsc; + using TMath::csch; + using TMath::PI; + + assert(csc(PI / 2.0), 1.0, "csc(PI/2) == 1"); + assert(csc(-PI / 2.0), -1.0, "csc(-PI/2) == -1"); + + assert(acsc(1.1884), 1.0, "acsc(1.1884) == 1"); + assert(acsc(-1.1884), -1.0, "acsc(-1.1884) == -1"); + + assert(csch(0.88137), 1.0, "csch(0.88137) == 1.0"); + assert(csch(-0.88137), -1.0, "csch(-0.88137) == -1.0"); + + return 0; +} diff --git a/test/cosine/test.cpp b/test/cosine/test.cpp new file mode 100644 index 0000000..a56845c --- /dev/null +++ b/test/cosine/test.cpp @@ -0,0 +1,29 @@ +/* + This test checks the cosine, arccosine and hyperbolic cosine function. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::cos; + using TMath::acos; + using TMath::cosh; + using TMath::PI; + + assert(cos(0.0), 1, "cos(0) == 1"); + assert(cos(PI/2.0), 0, "cos(PI/2) == 0"); + assert(cos(PI), -1, "cos(PI) == -1"); + assert(cos(PI * 1.5), 0, "cos(PI * 1.5) == 0"); + + assert(acos(0), PI * 0.5, "acos(0) == PI/2"); + assert(acos(0.70711), PI * 0.25, "acos(1/sqrt(2)) == 1/4 PI"); + assert(acos(-0.70711), PI * 0.75, "acos(1/sqrt(2)) == 3/4 PI"); + + assert(cosh(0), 1, "cosh(0) == 1"); + assert(cosh(1.31696), 2, "cosh(1.31696) == 2"); + assert(cosh(-1.31696), 2, "cosh(-1.31696) == 2"); + + return 0; +} diff --git a/test/cotangent/test.cpp b/test/cotangent/test.cpp new file mode 100644 index 0000000..c2da3de --- /dev/null +++ b/test/cotangent/test.cpp @@ -0,0 +1,26 @@ +/* + This test checks the cotangent, arccotangent and hyperbolic cotangent function. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::cot; + using TMath::acot; + using TMath::coth; + using TMath::PI; + + assert(cot(PI / 2.0), 0.0, "cot(PI/2) == 0"); + assert(cot(-PI / 2.0), 0.0, "cot(-PI/2) == 0"); + + assert(acot(0), PI * 0.5, "acot(0) == 1/2 PI"); + assert(acot(1.0), PI * 0.25, "acot(1) == 1/4 PI"); + assert(acot(-1.0), PI * 0.75, "acot(-1) == 3/4 PI"); + + assert(coth(0.54931), 2.0, "coth(0.54931) == 2.0"); + assert(coth(-0.54931), -2.0, "coth(-0.54931) == -2.0"); + + return 0; +} diff --git a/test/exp-log/test.cpp b/test/exp-log/test.cpp new file mode 100644 index 0000000..711edc9 --- /dev/null +++ b/test/exp-log/test.cpp @@ -0,0 +1,39 @@ +/* + This test checks the exp, ln, lg, lb and log function. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::exp; + using TMath::E; + using TMath::ln; + using TMath::lb; + using TMath::lg; + using TMath::log; + + assert(exp(0.0), 1.0, "exp(0) == 1"); + assert(exp(1.0), E, "exp(1) == e"); + assert(exp(2.0), E * E, "exp(2) == e*e"); + assert(exp(-1.0), 1.0 / E, "exp(-1) == 1/e"); + + assert(ln(1), 0.0, "ln(1) == 0"); + assert(ln(E), 1.0, "ln(e) == 1"); + assert(ln(1.0 / E), -1.0, "ln(1/e) == -1"); + + assert(lb(2), 1.0, "lb(2) == 1"); + assert(lb(4), 2.0, "lb(4) == 2"); + assert(lb(16), 4.0, "lb(128) == 4"); + + assert(lg(10), 1.0, "lg(10) == 1"); + assert(lg(1), 0.0, "lg(1) == 0"); + assert(lg(100), 2.0, "lg(100) == 2", 0.01); + + assert(log(E, E), 1.0, "log_e(e) == 1"); + assert(log(1, E), 0.0, "log_e(1) == 0"); + assert(log(27, 3), 3.0, "log_3(27) == 3"); + + return 0; +} diff --git a/test/factorial/test.cpp b/test/factorial/test.cpp new file mode 100644 index 0000000..7a72c73 --- /dev/null +++ b/test/factorial/test.cpp @@ -0,0 +1,38 @@ +/* + This test checks the factorial functions; + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::fac; + using TMath::facd; + using TMath::oddfac; + using TMath::oddfacd; + + assert(fac(1), 1, "fac(1) == 1"); + assert(fac(2), 2, "fac(2) == 2"); + assert(fac(3), 6, "fac(3) == 6"); + assert(fac(4), 24, "fac(4) == 24"); + + assert(facd(1), 1.0, "facd(1) == 1.0"); + assert(facd(2), 2.0, "facd(2) == 2.0"); + assert(facd(3), 6.0, "facd(3) == 6.0"); + assert(facd(4), 24.0, "facd(4) == 24.0"); + + assert(oddfac(1), 1, "oddfac(1) == 1"); + assert(oddfac(2), 1, "oddfac(2) == 1"); + assert(oddfac(3), 3, "oddfac(3) == 3"); + assert(oddfac(4), 3, "oddfac(4) == 3"); + assert(oddfac(5), 15, "oddfac(5) == 15"); + + assert(oddfacd(1), 1.0, "oddfacd(1) == 1.0"); + assert(oddfacd(2), 1.0, "oddfacd(2) == 1.0"); + assert(oddfacd(3), 3.0, "oddfacd(3) == 3.0"); + assert(oddfacd(4), 3.0, "oddfacd(4) == 3.0"); + assert(oddfacd(5), 15.0, "oddfacd(5) == 15.0"); + + return 0; +} diff --git a/test/power/test.cpp b/test/power/test.cpp new file mode 100644 index 0000000..e37e858 --- /dev/null +++ b/test/power/test.cpp @@ -0,0 +1,26 @@ +/* + This test checks the power functions. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::pow; + + assert(pow(2.0L, 2.0L), 4.0L, "pow(2, 2) == 4"); + assert(pow(2.0L, 0.5L), 1.41421356237L, "pow(2, 0.5) == 1.414"); + assert(pow(2.0L, -1.0L), 0.5L, "pow(2, -1) == 0.5"); + assert(pow(2.0L, 0.0L), 1.0L, "pow(2, 0) == 1"); + + assert(pow(2LL, 2LL), 4LL, "pow(2, 2) == 4"); + assert(pow(1LL, -1LL), 1LL, "pow(1, -1) == 1"); + assert(pow(2LL, 0LL), 1LL, "pow(2, 0) == 1"); + + assert(pow(0.5L, 2LL), 0.25L, "pow(0.5, 2) == 0.25"); + assert(pow(0.5L, -1LL), 2.0L, "pow(0.5, -1) == 2"); + assert(pow(0.5L, 0LL), 1.0L, "pow(0.5, 0) == 1"); + + return 0; +} diff --git a/test/rad-deg/test.cpp b/test/rad-deg/test.cpp new file mode 100644 index 0000000..5bfa6bc --- /dev/null +++ b/test/rad-deg/test.cpp @@ -0,0 +1,31 @@ +/* + This test checks the rad-deg conversion functions. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::rad; + using TMath::deg; + using TMath::PI; + + assert(rad(0), 0.0, "rad(0) == 0"); + assert(rad(45), PI * 0.25, "rad(45) == 1/4 PI"); + assert(rad(90), PI * 0.5, "rad(90) == 1/2 PI"); + assert(rad(135), PI * 0.75, "rad(135) == 3/4 PI"); + assert(rad(180), PI, "rad(180) == PI"); + assert(rad(270), PI * 1.5, "rad(270) == 3/2 PI"); + assert(rad(360), PI * 2.0, "rad(360) == 2 PI"); + + assert(deg(0), 0, "deg(0) == 0"); + assert(deg(PI * 0.25), 45, "deg(1/4 PI) == 45"); + assert(deg(PI * 0.5), 90, "deg(1/2 PI) == 90"); + assert(deg(PI * 0.75), 135, "deg(3/4 PI) == 135"); + assert(deg(PI), 180, "deg(PI) == 180"); + assert(deg(PI * 1.5), 270, "deg(3/2 PI) == 270"); + assert(deg(PI * 2.0), 360, "deg(2 * PI) == 360"); + + return 0; +} diff --git a/test/roots/test.cpp b/test/roots/test.cpp new file mode 100644 index 0000000..d6235e5 --- /dev/null +++ b/test/roots/test.cpp @@ -0,0 +1,21 @@ +/* + This test checks the root functions. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::root; + using TMath::sqrt; + + assert(root(27.0L, 3.0L), 3.0L, "root(27, 3) == 3"); + assert(root(1.0L, 1.0L), 1.0L, "root(1, 1) == 1"); + + assert(sqrt(4.0L), 2.0L, "sqrt(4) == 2"); + assert(sqrt(9.0L), 3.0L, "sqrt(9) == 3"); + assert(sqrt(1.0L), 1.0L, "sqrt(1) == 1"); + + return 0; +} diff --git a/test/secant/test.cpp b/test/secant/test.cpp new file mode 100644 index 0000000..38ab817 --- /dev/null +++ b/test/secant/test.cpp @@ -0,0 +1,27 @@ +/* + This test checks the secant, arcsecant and hyperbolic secant function. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::sec; + using TMath::asec; + using TMath::sech; + using TMath::PI; + + assert(sec(0), 1.0, "sec(0) == 1"); + assert(sec(-PI), -1.0, "sec(-PI) == -1"); + assert(sec(PI), -1.0, "sec(PI) == -1"); + + assert(asec(1.41421356237L), PI * 0.25, "asec(sqrt(2)) == 1/4 PI"); + assert(asec(-1.41421356237L), PI * 0.75, "asec(-sqrt(2)) == 3/4 PI"); + + assert(sech(0), 1.0, "sech(0) == 1"); + assert(sech(1.31696), 0.5, "sech(1.31696) == 0.5"); + assert(sech(-1.31696), 0.5, "sech(-1.31696) == 0.5"); + + return 0; +} diff --git a/test/sine/test.cpp b/test/sine/test.cpp new file mode 100644 index 0000000..8ea9ab7 --- /dev/null +++ b/test/sine/test.cpp @@ -0,0 +1,30 @@ +/* + This test checks the sine, arcsine and hyperbolic sine function. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::sin; + using TMath::asin; + using TMath::sinh; + using TMath::PI; + + assert(sin(0), 0, "sin(0) == 0"); + assert(sin(PI/2.0), 1.0, "sin(PI/2) == 1"); + assert(sin(PI), 0.0, "sin(PI) == 0"); + assert(sin(1.5 * PI), -1.0, "sin(1.5 * PI) == -1"); + assert(sin(2.0 * PI), 0.0, "sin(2 * PI) == 0"); + + assert(asin(0), 0, "asin(0) == 0"); + assert(asin(0.5), PI/6.0, "asin(0.5) == PI/6"); + assert(asin(-0.5), -PI/6.0, "asin(-0.5) == -PI/6"); + + assert(sinh(0), 0, "sinh(0) == 0"); + assert(sinh(0.88137), 1.0, "sinh(0.88137) == 1"); + assert(sinh(-0.88137), -1.0, "sinh(-0.88137) == -1"); + + return 0; +} diff --git a/test/tangent/test.cpp b/test/tangent/test.cpp new file mode 100644 index 0000000..de0741e --- /dev/null +++ b/test/tangent/test.cpp @@ -0,0 +1,28 @@ +/* + This test checks the tangent, arctangent and hyperbolic tangent function. + */ + +#include "tmath.hpp" +#include "tmath_test.hpp" + +int main(int argc, char const *argv[]) { + using TMathTest::assert; + using TMath::tan; + using TMath::atan; + using TMath::tanh; + using TMath::PI; + + assert(tan(0), 0, "tan(0) == 0"); + assert(tan(PI/4.0), 1.0, "tan(PI/4) == 1"); + assert(tan(-PI/4.0), -1.0, "tan(-PI/4) == -1"); + + assert(atan(0), 0, "atan(0) == 0"); + assert(atan(1), PI/4.0, "atan(1) == PI/4"); + assert(atan(-1), -PI/4.0, "atan(-1) == -PI/4"); + + assert(tanh(0), 0, "tanh(0) == 0"); + assert(tanh(0.549306), 0.5, "tanh(0.549306) == 0.5"); + assert(tanh(-0.549306), -0.5, "tanh(-0.549306) == -0.5"); + + return 0; +} diff --git a/test/tmath_test.cpp b/test/tmath_test.cpp new file mode 100644 index 0000000..2b661d2 --- /dev/null +++ b/test/tmath_test.cpp @@ -0,0 +1,24 @@ +#include "tmath_test.hpp" +#include +#include + +bool TMathTest::equal(TMath::DOUBLE x, TMath::DOUBLE y, TMath::DOUBLE tolerance) { + if (x - tolerance <= y && x + tolerance >= y) return true; + else return false; +} + +void TMathTest::assert(TMath::DOUBLE value, TMath::DOUBLE correct, std::string expression) { + assert(value, correct, expression, TMathTest::DEFAULT_TOLERANCE); +} + +void TMathTest::assert(TMath::DOUBLE value, TMath::DOUBLE correct, std::string expression, TMath::DOUBLE tolerance) { + if (!equal(value, correct, tolerance)) { + std::cout << "Assert: " << expression << " failed" << std::endl; + std::cout << value << " is not nearly equal " << correct << std::endl; + exit(1); + } else { + double deviation = value - correct; + deviation = deviation < 0 ? -deviation : deviation; + std::cout << "Test (" << expression << ") passed with deviation of " << deviation << std::endl; + } +}