A C++ compile-time math library using generalized constant expressions
GCE-Math (Generalized Constant Expression Math) is a templated C++ library enabling compile-time computation of mathematical functions.
Features:
constexpr
format, and is C11/14/17/20 compatible.gcem::
syntax is identical to that of the C++ standard library (std::
).Author: Keith O’Hara
The library is actively maintained and is still being extended. A list of features includes:
abs
, max
, min
, pow
, sqrt
, inv_sqrt
,ceil
, floor
, round
, trunc
, fmod
,exp
, expm1
, log
, log1p
, log2
, log10
, and morecos
, sin
, tan
acos
, asin
, atan
, atan2
cosh
, sinh
, tanh
, acosh
, asinh
, atanh
gcd
, lcm
factorial
, binomial_coef
beta
, lbeta
, lgamma
, tgamma
, lmgamma
erf
, erf_inv
incomplete_beta
, incomplete_gamma
incomplete_beta_inv
, incomplete_gamma_inv
Full documentation is available online:
A PDF version of the documentation is available here.
GCE-Math is a header-only library and does not require any additional libraries or utilities (beyond a C++11 compatible compiler). Simply add the header files to your project using:
#include "gcem.hpp"
You can install GCE-Math using the Conda package manager.
conda install -c conda-forge gcem
You can also install the library from source using CMake.
# clone gcem from GitHub
git clone https://github.com/kthohr/gcem ./gcem
# make a build directory
cd ./gcem
mkdir build
cd build
# generate Makefiles and install
cmake .. -DCMAKE_INSTALL_PREFIX=/gcem/install/location
make install
For example, /gcem/install/location
could be /usr/local/
.
There are two ways to build the test suite. On Unix-alike systems, a Makefile is available under tests/
.
cd ./gcem/tests
make
./run_tests
With CMake, the option GCEM_BUILD_TESTS=1
generates the necessary Makefiles to build the test suite.
cd ./gcem
mkdir build
cd build
cmake ../ -DGCEM_BUILD_TESTS=1 -DCMAKE_INSTALL_PREFIX=/gcem/install/location
make gcem_tests
cd tests
./exp.test
You can test the library online using an interactive Jupyter notebook:
GCE-Math functions are written as C++ templates with constexpr
specifiers, the format of which might appear confusing to users unfamiliar with template-based programming.
For example, the Gaussian error function (erf
) is defined as:
template<typename T>
constexpr
return_t<T>
erf(const T x) noexcept;
A set of internal templated constexpr
functions will implement a continued fraction expansion and return a value of type return_t<T>
. The output type (‘return_t<T>
’) is generally determined by the input type, e.g., int
, float
, double
, long double
, etc.; when T
is an integral 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.
To calculate 10!:
#include "gcem.hpp"
int main()
{
constexpr int x = 10;
constexpr int res = gcem::factorial(x);
return 0;
}
Inspecting the assembly code generated by Clang 7.0.0:
push rbp
mov rbp, rsp
xor eax, eax
mov dword ptr [rbp - 4], 0
mov dword ptr [rbp - 8], 10
mov dword ptr [rbp - 12], 3628800
pop rbp
ret
We see that a function call has been replaced by a numeric value (10! = 3628800).
Similarly, to compute the log Gamma function at a point:
#include "gcem.hpp"
int main()
{
constexpr long double x = 1.5;
constexpr long double res = gcem::lgamma(x);
return 0;
}
Assembly code:
.LCPI0_0:
.long 1069547520 # float 1.5
.LCPI0_1:
.quad -622431863250842976 # x86_fp80 -0.120782237635245222719
.short 49147
.zero 6
main: # @main
push rbp
mov rbp, rsp
xor eax, eax
mov dword ptr [rbp - 4], 0
fld dword ptr [rip + .LCPI0_0]
fstp tbyte ptr [rbp - 32]
fld tbyte ptr [rip + .LCPI0_1]
fstp tbyte ptr [rbp - 48]
pop rbp
ret