The header, Harlinn/Math/Math.h, provides alternatives to many of the core mathematical function that is specified in the C and C++ standards. All of the functions can be constexpr evaluated, and several offer runtime performance benefits as well.

Harlinn/Math/Math.h is header only.

The functions are implemented in the Harlinn::Math namespace.

Concepts

Functions

Background

The functions were created to explore constexpr evaluation of mathematical expressions with Visual C++. Constexpr, introduced in C++11 and further enhanced in subsequent versions, allows developers to perform computations at compile time. This means less runtime overhead, optimized code, and a significant boost in execution speed.

Since constexpr evaluation doesn’t allow undefined behavior, this can be used to improve the safety of C++ code by performing constexpr evaluation of code in unit tests. The constexpr evaluated code will not compile until all code with undefined behavior is eliminated from the execution path of the constexpr evaluated code.

While C++ 26 will enable constexpr evaluation of many of the functions within <cmath>, Harlinn/Math/Math.h makes this possible right now.

Much of the code is based on version 0.8.5 of the OpenLibm mathematical C library used by the Julia programming language.

The functions return NaN and +/- infinity as expected, but does not always set the exception flags in the floating point environment. The reason for this is that the code that generated the floating point exceptions in OpenLibm prevented full compile time constant evaluation.

The API is template based, which may seem odd, but this helps to reduce the number of unintended conversions between numeric types. Most functions designed to work with floating point values do not accept integer values without an explicit cast to float or double.

Unit Tests

Unit tests for constexpr evaluation of the core functions from Harlinn/Math/Math.h are provided in ConstexprMathTests.cpp.

Harlinn.Common.Core.Math.Tests contains 678 test cases, striving to demonstrate the accuracy of the computations. Be aware that running the release build of the full test suite takes nearly an hour, as several of the tests seeks to determine the result for every possible input, or very large subsets of the possible inputs - comparing the results with those produced by the standard implementation.

Benchmarks

The performance of the functions is benchmarked using the Google benchmark library, and can be verified by building and executing BasicMathBenchmarks included in the Harlinn.Windows solution.

See Benchmarks for the benchmark results.

PBRTO a micro optimized raytracing app

Benchmarks for individual functions cannot always be relied upon to accurately determine how well they will perform perform in a real application. Benchmarks provides a good idea about how the functions will perform, but when the compiler, and linker, employs global optimizations across all the compilation units, there are often a few surprises. PBRTO was created as a tool to help uncovering these surprises.

PBRTO is a micro optimized version of PBRT-v4, under development as an example of how the functionality in Harlinn/Math/Math.h, Harlinn/Math/Simd.h and Harlinn/Math/VectorMath.h can be used to optimize the performance of real, computationally intensive, apps. It’s now about 91 % faster than the release build of the original PBRT. more…

Implementation quality

The quality of the implementation is, since it is based on OpenLibm, high. OpenLibm does many things very well, but sometimes the Visual C++ runtime, an intrinsic function, or another alternative implemented by the library, perform better. When this is the case, the library selects the implementation with the best runtime performance.

Since some functions are implemented differently for constexpr evaluation, they will not always return identical results when executed at runtime. The difference is small; and can, in most cases, be ignored, as in these cases both implementations are based on approximations.