diff --git a/maths.hpp b/maths.hpp index b839e526..c3d224c4 100644 --- a/maths.hpp +++ b/maths.hpp @@ -17,8 +17,9 @@ #ifndef __MATHS_HPP #define __MATHS_HPP -#include "debug.hpp" -#include "types/traits.hpp" +#include "./debug.hpp" +#include "./types/traits.hpp" +#include "./float.hpp" #include #include @@ -27,6 +28,13 @@ #include +/////////////////////////////////////////////////////////////////////////////// +// NOTE: You may be tempted to add all sorts of performance enhancing +// attributes (like gnu::const or gnu::pure). DO NOT DO THIS WITHOUT EXTENSIVE +// TESTING. Just about everything will break in some way with these attributes. +// +// In particular: it is safest to apply these only to leaf functions + /////////////////////////////////////////////////////////////////////////////// namespace util { @@ -45,8 +53,10 @@ namespace util { namespace util { template constexpr T - pow2 [[gnu::const]] (T value) - { return value * value; } + pow2 [[gnu::const]] (T value) + { + return value * value; + } } //----------------------------------------------------------------------------- @@ -60,26 +70,26 @@ namespace util { //----------------------------------------------------------------------------- template bool -is_pow2 [[gnu::const]] (T value); +is_pow2 (T value); //----------------------------------------------------------------------------- // Logarithms template T -log2 [[gnu::const]] (T val); +log2 (T val); template T -log2up [[gnu::const]] (T val); +log2up (T val); //----------------------------------------------------------------------------- // Roots template double -rootsquare [[gnu::const]] (T a, T b); +rootsquare (T a, T b); //----------------------------------------------------------------------------- @@ -90,7 +100,7 @@ typename std::common_type< std::enable_if_t::value,T>, std::enable_if_t::value,U> >::type -round_to [[gnu::const]] (T value, U size) +round_to (T value, U size) { if (value % size == 0) return value; @@ -101,12 +111,12 @@ round_to [[gnu::const]] (T value, U size) template T -round_pow2 [[gnu::const]] (T value); +round_pow2 (T value); template constexpr T -divup [[gnu::const]] (const T a, const U b) +divup (const T a, const U b) { return (a + b - 1) / b; } @@ -114,14 +124,14 @@ divup [[gnu::const]] (const T a, const U b) // Classification template bool -is_integer [[gnu::const]] (const T& value); +is_integer (const T& value); //----------------------------------------------------------------------------- // Properties template unsigned -digits [[gnu::const]] (const T& value); +digits (const T& value); //----------------------------------------------------------------------------- @@ -248,7 +258,7 @@ constexpr T E = T(2.71828182845904523536028747135266250); template constexpr T -to_degrees [[gnu::const]] (T radians) +to_degrees (T radians) { static_assert (std::is_floating_point::value, "undefined for integral types"); return radians * 180 / PI; @@ -257,7 +267,7 @@ to_degrees [[gnu::const]] (T radians) template constexpr T -to_radians [[gnu::const]] (T degrees) +to_radians (T degrees) { static_assert (std::is_floating_point::value, "undefined for integral types"); return degrees / 180 * PI; @@ -267,7 +277,7 @@ to_radians [[gnu::const]] (T degrees) //! Normalised sinc function template constexpr T -sincn [[gnu::const]] (T x) +sincn (T x) { return almost_zero (x) ? 1 : std::sin (PI * x) / (PI * x); } @@ -276,7 +286,7 @@ sincn [[gnu::const]] (T x) //! Unnormalised sinc function template constexpr T -sincu [[gnu::const]] (T x) +sincu (T x) { return almost_zero (x) ? 1 : std::sin (x) / x; } @@ -284,7 +294,7 @@ sincu [[gnu::const]] (T x) //----------------------------------------------------------------------------- constexpr uintmax_t -factorial [[gnu::const]] (unsigned i) +factorial (unsigned i) { return i <= 1 ? 0 : i * factorial (i - 1); } @@ -292,7 +302,7 @@ factorial [[gnu::const]] (unsigned i) /// stirlings approximation of factorials constexpr uintmax_t -stirling [[gnu::const]] (unsigned n) +stirling (unsigned n) { return static_cast ( std::sqrt (2 * PI * n) * std::pow (n / E, n) @@ -301,7 +311,7 @@ stirling [[gnu::const]] (unsigned n) constexpr uintmax_t -combination [[gnu::const]] (unsigned n, unsigned k) +combination (unsigned n, unsigned k) { return factorial (n) / (factorial (k) / (factorial (n - k))); } @@ -337,7 +347,7 @@ fsum (InputIt first, InputIt last) namespace util { template constexpr T - min [[gnu::const]] (const T a) + min (const T a) { return a; } @@ -347,7 +357,7 @@ namespace util { std::is_integral::type>::value == std::is_integral::type>::value, typename std::common_type::type >::type - min [[gnu::const]] (const T a, const U b, Args ...args) + min (const T a, const U b, Args ...args) { return min (a < b ? a : b, std::forward (args)...); } @@ -357,7 +367,7 @@ namespace util { /// Variadic maximum template constexpr T - max [[gnu::const]] (const T a) + max (const T a) { return a; } @@ -367,7 +377,7 @@ namespace util { std::is_integral::type>::value == std::is_integral::type>::value, typename std::common_type::type >::type - max [[gnu::const]] (const T a, const U b, Args ...args) + max (const T a, const U b, Args ...args) { return max (a > b ? a : b, std::forward (args)...); } @@ -379,7 +389,7 @@ namespace util { // min/max clamping template constexpr T -limit [[gnu::const]] (const T val, const U lo, const V hi) +limit (const T val, const U lo, const V hi) { lo <= hi ? (void)0 : panic (); @@ -392,7 +402,7 @@ limit [[gnu::const]] (const T val, const U lo, const V hi) // clamped cubic hermite interpolation template T -smoothstep [[gnu::const]] (T a, T b, T x) +smoothstep (T a, T b, T x) { CHECK_LE(a, b); x = limit ((x - a) / (b - a), T{0}, T{1}); @@ -411,7 +421,7 @@ constexpr typename std::enable_if< !std::is_floating_point::value && std::is_floating_point::value, U >::type -renormalise [[gnu::const]] (T t) +renormalise (T t) { return t / static_cast (std::numeric_limits::max ()); } @@ -423,7 +433,7 @@ constexpr typename std::enable_if< std::is_floating_point::value && !std::is_floating_point::value, U >::type -renormalise [[gnu::const]] (T t) +renormalise (T t) { // Ideally std::ldexp would be involved but it complicates handing // integers with greater precision than our floating point type. Also it @@ -458,7 +468,7 @@ typename std::enable_if< std::is_floating_point::value && !std::is_same::value, U >::type -renormalise [[gnu::const]] (T t) +renormalise (T t) { return static_cast (t); } @@ -472,7 +482,7 @@ typename std::enable_if< std::is_integral::value && (sizeof (T) > sizeof (U)), U >::type -renormalise [[gnu::const]] (T t) +renormalise (T t) { static_assert (sizeof (T) > sizeof (U), "assumes right shift is sufficient"); @@ -491,7 +501,7 @@ typename std::enable_if< std::is_integral::value && sizeof (T) < sizeof (U), U >::type -renormalise [[gnu::const]] (T t) +renormalise (T t) { static_assert (sizeof (T) < sizeof (U), "assumes bit creation is required to fill space"); @@ -518,7 +528,7 @@ constexpr typename std::enable_if< std::is_same::value, U >::type -renormalise [[gnu::const]] (T t) +renormalise (T t) { return t; } #include "maths.ipp"