16 #ifndef INLCUDE_MOLASSEMBLER_TEMPLE_CONSTEXPR_MATH_H
17 #define INLCUDE_MOLASSEMBLER_TEMPLE_CONSTEXPR_MATH_H
23 #include <type_traits>
26 namespace Molassembler {
31 template<
typename T,
typename U>
32 using enableIfFloatingWithReturn = std::enable_if_t<
33 std::is_floating_point<T>::value,
37 template<
typename T,
typename U>
38 using enableIfIntegralWithReturn = std::enable_if_t<
39 std::is_integral<T>::value,
43 template<
typename T,
typename U>
44 using enableIfArithmeticWithReturn = std::enable_if_t<
45 std::is_arithmetic<T>::value,
49 template<
typename FloatingPo
int>
51 std::is_floating_point<FloatingPoint>::value,
53 > isnan(
const FloatingPoint x) {
62 template<
typename ... Bools>
63 constexpr
bool XOR(Bools ... bools);
68 inline constexpr Traits::enableIfArithmeticWithReturn<T, T> abs(T x) noexcept;
72 constexpr Traits::enableIfArithmeticWithReturn<T, T>
max(T a, T b) noexcept;
76 constexpr Traits::enableIfArithmeticWithReturn<T, T>
min(T a, T b) noexcept;
82 constexpr Traits::enableIfFloatingWithReturn<T, T> toRadians(T inDegrees) noexcept;
86 constexpr Traits::enableIfFloatingWithReturn<T, T> toDegrees(T inRadians) noexcept;
90 constexpr Traits::enableIfFloatingWithReturn<T, int> ceil(T value) noexcept;
94 constexpr Traits::enableIfFloatingWithReturn<T, int> floor(T value) noexcept;
98 constexpr Traits::enableIfArithmeticWithReturn<T, T> pow(T base,
unsigned exponent) noexcept;
101 constexpr Traits::enableIfArithmeticWithReturn<T, double> pow(T base,
int exponent) noexcept;
105 constexpr Traits::enableIfFloatingWithReturn<T, T> sqrt(T x);
109 constexpr Traits::enableIfIntegralWithReturn<T, T> factorial(T x);
113 constexpr Traits::enableIfFloatingWithReturn<T, T> ln(T x);
117 constexpr Traits::enableIfFloatingWithReturn<T, T> log10(T x);
121 constexpr Traits::enableIfFloatingWithReturn<T, T> log(T x, T base);
129 constexpr Traits::enableIfFloatingWithReturn<T, T> asin(T x);
133 constexpr Traits::enableIfFloatingWithReturn<T, T> acos(T x);
137 constexpr Traits::enableIfFloatingWithReturn<T, T> atan(T x);
145 constexpr
unsigned TPPSum() {
150 template<
typename T1,
typename... T>
151 constexpr
unsigned TPPSum(T1 a, T ... pack) {
152 return a + TPPSum(pack ...);
165 throw "Ln domain error: x <= 0";
168 const T epsilon = std::numeric_limits<T>::epsilon();
176 const T iterationMultiplier = countingPower * countingPower;
186 for(
unsigned n = 3; Temple::Math::abs(previous - value) > epsilon; n += 2) {
191 countingPower *= iterationMultiplier;
194 value += 2 * countingPower / n;
206 if(!(0.0 <= x && x <= 1.0)) {
207 throw "Asin approximation domain error: only applicable for 0 < x < 1!";
211 const T x4 = x2 * x2;
215 - Math::sqrt(1 - x) * (
219 - 0.0501743046 * x2 * x
221 - 0.0170881256 * x4 * x
222 + 0.0066700901 * x4 * x2
223 - 0.0012624911 * x4 * x2 * x
230 template<
typename ... Bools>
231 constexpr
bool XOR(Bools ... bools) {
232 return Detail::TPPSum(bools ...) == 1;
236 PURITY_STRONG inline constexpr Traits::enableIfArithmeticWithReturn<T, T> abs(
const T x) noexcept {
237 return (x >= 0) ? x : -x;
241 PURITY_STRONG constexpr Traits::enableIfArithmeticWithReturn<T, T>
max(
const T a,
const T b) noexcept {
242 return (a > b) ? a : b;
246 PURITY_STRONG constexpr Traits::enableIfArithmeticWithReturn<T, T>
min(
const T a,
const T b) noexcept {
247 return (a < b) ? a : b;
251 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, T> toRadians(
const T inDegrees) noexcept {
252 return M_PI * inDegrees / 180;
256 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, T> toDegrees(
const T inRadians) noexcept {
257 return 180 * inRadians / M_PI;
261 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, int> ceil(
const T value) noexcept {
263 const auto truncated =
static_cast<int>(value);
265 if(truncated < value) {
266 return truncated + 1;
273 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, int> floor(
const T value) noexcept {
275 const auto truncated =
static_cast<int>(value);
277 if(truncated > value) {
278 return truncated - 1;
286 PURITY_STRONG constexpr Traits::enableIfArithmeticWithReturn<T, T> pow(
const T base,
const unsigned exponent) noexcept {
293 for(
unsigned n = 1; n < exponent; n++) {
301 PURITY_STRONG constexpr T recPow(
const T base,
const unsigned exponent) noexcept {
310 if(exponent % 2 == 0) {
311 auto halfProblem = recPow(base, exponent / 2);
312 return halfProblem * halfProblem;
315 return base * recPow(base, exponent - 1);
323 PURITY_STRONG constexpr Traits::enableIfArithmeticWithReturn<T, double> pow(
const T base,
const int exponent) noexcept {
325 return 1.0 / pow(base, static_cast<unsigned>(Temple::Math::abs(exponent)));
332 return pow(base, static_cast<unsigned>(exponent));
338 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, T> sqrt(
const T x) {
340 throw "Square-root domain error: Only real if x >= 0!";
343 const T epsilon = std::numeric_limits<T>::epsilon();
347 while(Temple::Math::abs(previous - value) > epsilon) {
352 value = 0.5 * (value + x / value);
359 PURITY_STRONG constexpr Traits::enableIfIntegralWithReturn<T, T> factorial(
const T x) {
361 throw "Factorial domain error!";
368 return x * factorial(x - 1);
372 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, T> ln(
const T x) {
373 unsigned decimalReduction = 0;
376 while(abs(calcX) > 10) {
378 decimalReduction += 1;
382 if(Math::abs(calcX / 10 - 1) < Math::abs(calcX - 1)) {
384 decimalReduction += 1;
387 return Detail::lnSeries(calcX) + decimalReduction * M_LN10;
391 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, T> log10(
const T x) {
393 throw "Log10 domain error!";
399 return ln(x) / M_LN10;
403 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, T> log(
const T x,
const T base) {
405 throw "Log domain error!";
411 return ln(x) / ln(base);
420 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, T> asin(
const T x) {
421 if(!(-1 <= x && x <= 1)) {
422 throw "Inverse sine domain error: only real if -1 < x < 1!";
425 if(Temple::Math::abs(x) > 0.90) {
426 return (x >= 0) ? Detail::asinApprox(x) : -Detail::asinApprox(-x);
429 const T epsilon = std::numeric_limits<T>::epsilon();
432 T upper_factorial = 1;
433 T lower_factorial = 1;
436 for(
unsigned n = 1; Temple::Math::abs(term) > epsilon; ++n) {
437 upper_factorial *= 2 * (n - 1) + 1;
438 lower_factorial *= 2 * n;
441 upper_factorial / lower_factorial
442 ) * pow(x, 2 * n + 1) / (2 * n + 1);
444 if(Traits::isnan(term)) {
455 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, T> acos(
const T x) {
456 if(!(-1 <= x && x <= 1)) {
457 throw "Inverse cosine domain error: only real if -1 <= x <= 1!";
460 return M_PI / 2 - asin(x);
464 PURITY_STRONG constexpr Traits::enableIfFloatingWithReturn<T, T> atan(
const T x) {
465 if(!(-M_PI / 2 < x && x < M_PI / 2)) {
466 throw "Inverse cosine domain error: only real if -1 < x < 1!";
constexpr auto max(const ContainerType &container)
Composable max function. Returns the smallest value of any container.
Definition: Numeric.h:188
Defines a set of useful preprocessor macros.
#define PURITY_STRONG
Definition: Preprocessor.h:65
constexpr auto min(const ContainerType &container)
Composable min_element function. Returns the smallest value of any container.
Definition: Numeric.h:164