GCE-Math

GCE-Math (Generalized Constant Expression Math) is a templated C++ library enabling compile-time computation of mathematical functions.

  • The library is written in C++11 constexpr format, and is C++11/14/17 compatible.
  • Continued fraction and series expansions are implemented using recursive templates.
  • The gcem:: syntax is identical to the C++ standard library (std::).
  • Tested and accurate to floating-point precision against the C++ standard library.
  • Released under a permissive, non-GPL license.

Author: Keith O'Hara

License

 

Coverage and Documentation

A list of features includes:

  • basic library functions:
    • abs, exp, log, max, min, pow, sqrt, gcd, lcm, and more
  • trigonometric functions:
    • basic: cos, sin, tan
    • inverse: acos, asin, atan
    • hyperbolic (area) functions: cosh, sinh, tanh, acosh, asinh, atanh
  • special functions:
    • factorials and the binomial coefficient: factorial, binomial_coef
    • beta, gamma, and multivariate gamma functions: beta, lbeta, lgamma, tgamma, lmgamma
    • the Gaussian error function and inverse error function: erf, erf_inv
    • (regularized) incomplete beta and incomplete gamma functions: incomplete_beta, incomplete_gamma
    • inverse incomplete beta and incomplete gamma functions: incomplete_beta_inv, incomplete_gamma_inv

Full documentation is avaialble online:

Documentation

 

This Notebook

To run a code cell, use shift + enter.

In [1]:
// include libraries
#include <iostream>              // for printing
#include "../include/gcem.hpp"

Syntax and Examples

GCE-Math functions are written as C++ templates with constexpr specifiers. For example, the Gaussian error function (erf) is defined as:

template<typename T>
constexpr
return_t<T>
erf(const T x);

where a set of internal templated constexpr functions will implement a continued fraction expansion to return a value of type return_t<T>. This output type ('return_t<T>') is generally determined by the input type, e.g., int, float, double, long double, etc. When T is an intergral type, the output will be upgraded to return_t<T> = double, otherwise return_t<T> = T. For types not covered by std::is_integral, recasts should be used.

In [2]:
// exponential and natural logarithm functions

double exp_val_1 = gcem::exp(3);
double log_val_1 = gcem::log(2);

// compare with the standard library

double exp_val_2 = std::exp(3);
double log_val_2 = std::log(2);

std::cout << "exp(3) = " << exp_val_1 << std::endl;
std::cout << "error = " << gcem::abs(exp_val_1 - exp_val_2) << std::endl;
exp(3) = 20.0855
error = 0
In [3]:
// trig functions

double pi_dbl  = double(GCEM_PI);
double hpi_dbl = double(GCEM_HALF_PI);

double sin_val_1 = gcem::sin(pi_dbl);
double sin_val_2 = gcem::sin(hpi_dbl);

std::cout << "sin(pi)   = " << sin_val_1 << std::endl;
std::cout << "sin(pi/2) = " << sin_val_2 << std::endl;

std::cout << "gcem::tan(pi/2) = " << gcem::tan(hpi_dbl) << std::endl;
std::cout << "std::tan(pi/2)  = " << std::tan(hpi_dbl) << std::endl;

std::cout << "|gcem::tan(0.9) -  std::tan(0.9)| = " << gcem::abs(gcem::tan(1.5) - std::tan(1.5)) << std::endl;
sin(pi)   = 0
sin(pi/2) = 1
gcem::tan(pi/2) = 1.63312e+16
std::tan(pi/2)  = 1.63312e+16
|gcem::tan(0.9) -  std::tan(0.9)| = 1.77636e-15
In [4]:
// hyperbolic functions

constexpr double cosh_val = gcem::cosh(0.3);
constexpr double inp_val  = gcem::acosh(cosh_val);

std::cout << "gcem::cosh(0.3) = " << cosh_val << std::endl;
std::cout << "gcem::acosh(gcem::cosh(0.3)) = " << inp_val << std::endl;
gcem::cosh(0.3) = 1.04534
gcem::acosh(gcem::cosh(0.3)) = 0.3

Special Functions

Special functions are so-called because of their extensive use in mathematics, physics, and statisitcs. Simple examples include the basic trigonometric functions (tan, sin, cos, etc.) and the natural logarithm.

Of particular interest in statistics are integral equations, like the Gaussian error function and incomplete gamma and beta functions, necessary to calculate cumulative distribution functions.

In [5]:
// define some storage
double erf_inp_val, erf_val;
double a_par, b_par;
double ig_inp_val, bt_inp_val;
double ig_val, bt_val;
In [6]:
// Gaussian error function
erf_inp_val = 1.2;
erf_val = gcem::erf(erf_inp_val);

std::cout << "gcem::erf(" << erf_inp_val << ") = " << erf_val << std::endl;

// regularied lower incomplete gamma function
a_par = 3;
ig_inp_val = 4;

ig_val = gcem::incomplete_gamma(a_par,ig_inp_val);

std::cout << "gcem::incomplete_gamma(" << a_par << "," << ig_inp_val << ") = " << ig_val << std::endl;

// regularied lower incomplete beta function
a_par = 6;
b_par = 5;
bt_inp_val = 0.7;

bt_val = gcem::incomplete_beta(a_par,b_par,bt_inp_val);

std::cout << "gcem::incomplete_gamma(" << a_par << "," << b_par << "," << bt_inp_val << ") = " << bt_val << std::endl;
gcem::erf(1.2) = 0.910314
gcem::incomplete_gamma(3,4) = 0.761897
gcem::incomplete_gamma(6,5,0.7) = 0.849732
In [ ]: