/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2010-2014 Danny Robson */ #ifndef __MATHS_HPP #define __MATHS_HPP #include "debug.hpp" #include "types/traits.hpp" #include #include #include #include #include template T abs (T value) { return value > 0 ? value : -value; } //----------------------------------------------------------------------------- // Exponentials template constexpr T pow2 [[gnu::pure]] (T value) { return value * value; } template constexpr T pow [[gnu::pure]] (T x, unsigned y); template bool is_pow2 [[gnu::pure]] (T value); //----------------------------------------------------------------------------- // Logarithms template T log2 [[gnu::pure]] (T val); template T log2up [[gnu::pure]] (T val); //----------------------------------------------------------------------------- // Roots template double rootsquare [[gnu::pure]] (T a, T b); //----------------------------------------------------------------------------- // Rounding template typename std::common_type::type align [[gnu::pure]] (T value, U size); template T round_pow2 [[gnu::pure]] (T value); template constexpr T divup [[gnu::pure]] (const T a, const U b) { return (a + b - 1) / b; } //----------------------------------------------------------------------------- // Classification template bool is_integer [[gnu::pure]] (const T& value); //----------------------------------------------------------------------------- // Properties template unsigned digits [[gnu::pure]] (const T& value); //----------------------------------------------------------------------------- constexpr int sign (int); constexpr float sign (float); constexpr double sign (double); //----------------------------------------------------------------------------- // Comparisons template bool almost_equal [[gnu::pure]] (const T &a, const T &b) { return a == b; } template <> bool almost_equal [[gnu::pure]] (const float &a, const float &b); template <> bool almost_equal [[gnu::pure]] (const double &a, const double &b); template typename std::enable_if< std::is_arithmetic::value && std::is_arithmetic::value, bool >::type almost_equal [[gnu::pure]] (Ta a, Tb b) { return almost_equal (static_cast(a), static_cast(b)); } template typename std::enable_if< !std::is_arithmetic::value || !std::is_arithmetic::value, bool >::type almost_equal [[gnu::pure]] (const Ta &a, const Tb &b) { return a == b; } // Useful for explictly ignore equality warnings #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" template bool exactly_equal [[gnu::pure]] (const T &a, const U &b) { return a == b; } #pragma GCC diagnostic pop template bool almost_zero [[gnu::pure]] (T a) { return almost_equal (a, 0); } template bool exactly_zero [[gnu::pure]] (T a) { return exactly_equal (a, static_cast (0)); } //----------------------------------------------------------------------------- // angles, trig template struct constants { }; constexpr double PI_d = 3.141592653589793238462643; constexpr float PI_f = 3.141592653589793238462643f; constexpr float E_f = 2.71828182845904523536028747135266250f; constexpr double E_d = 2.71828182845904523536028747135266250; template constexpr T to_degrees [[gnu::pure]] (T radians) { return radians * 180 / constants::PI; } template constexpr T to_radians [[gnu::pure]] (T degrees) { return degrees / 180 * constants::PI; } //! Normalised sinc function template constexpr T sincn [[gnu::pure]] (T x) { return almost_zero (x) ? 1 : std::sin (constants::PI * x) / (constants::PI * x); } //! Unnormalised sinc function template constexpr T sincu [[gnu::pure]] (T x) { return almost_zero (x) ? 1 : std::sin (x) / x; } //----------------------------------------------------------------------------- constexpr uintmax_t factorial [[gnu::pure]] (unsigned i) { return i <= 1 ? 0 : i * factorial (i - 1); } constexpr uintmax_t stirling [[gnu::pure]] (unsigned n) { return static_cast (std::sqrt (2 * PI_f * n) * std::pow (n / E_f, n)); } constexpr uintmax_t combination [[gnu::pure]] (unsigned n, unsigned k) { return factorial (n) / (factorial (k) / (factorial (n - k))); } //----------------------------------------------------------------------------- /// Variadic minimum namespace util { template constexpr T min [[gnu::pure]] (const T a) { return a; } template constexpr typename std::enable_if< std::is_unsigned::type>::value == std::is_unsigned::type>::value && std::is_integral::type>::value == std::is_integral::type>::value, typename std::common_type::type >::type min [[gnu::pure]] (const T a, const U b, Args ...args) { return min (a < b ? a : b, std::forward (args)...); } //----------------------------------------------------------------------------- /// Variadic maximum template constexpr T max [[gnu::pure]] (const T a) { return a; } template constexpr typename std::enable_if< std::is_unsigned::type>::value == std::is_unsigned::type>::value && std::is_integral::type>::value == std::is_integral::type>::value, typename std::common_type::type >::type max [[gnu::pure]] (const T a, const U b, Args ...args) { return max (a > b ? a : b, std::forward (args)...); } } //----------------------------------------------------------------------------- // Limiting functions // min/max clamping template T limit [[gnu::pure]] (const T val, const U lo, const V hi) { CHECK_LE( decltype (lo+hi) (lo), decltype (hi+lo) (hi) ); return val > hi ? hi: val < lo ? lo: val; } // clamped cubic hermite interpolation template T smoothstep [[gnu::pure]] (T a, T b, T x) { CHECK_LE(a, b); x = limit ((x - a) / (b - a), T{0}, T{1}); return x * x * (3 - 2 * x); } #include "types/string.hpp" //----------------------------------------------------------------------------- template U renormalise [[gnu::pure]] (T t) { static const T T_max = std::numeric_limits::max (); static const U U_max = std::numeric_limits::max (); static const bool shrinking = sizeof (U) < sizeof (T); static const bool T_float = std::is_floating_point::value; static const bool U_float = std::is_floating_point::value; if (T_float && U_float) return U (t); if (T_float) { return U (limit (t, 0, 1) * U_max); } if (U_float) return U(U (t) / T_max); if (shrinking) return U (t / (sizeof (T) / sizeof (U))); else return U (t) * (sizeof (U) / sizeof (T)); } #include "maths.ipp" #endif // __MATHS_HPP