#pragma once #include #include #include #include namespace BAN::Math { template inline constexpr T abs(T x) { return x < 0 ? -x : x; } template inline constexpr T min(T a, T b) { return a < b ? a : b; } template inline constexpr T max(T a, T b) { return a > b ? a : b; } template inline constexpr T clamp(T x, T min, T max) { return x < min ? min : x > max ? max : x; } template inline constexpr T gcd(T a, T b) { while (b) { T temp = b; b = a % b; a = temp; } return a; } template inline constexpr T lcm(T a, T b) { return a / gcd(a, b) * b; } template inline constexpr T div_round_up(T a, T b) { return (a + b - 1) / b; } template inline constexpr bool is_power_of_two(T x) { if (x == 0) return false; return (x & (x - 1)) == 0; } template requires(sizeof(T) <= 8) inline constexpr T round_up_to_power_of_two(T x) { x--; x |= x >> 1; x |= x >> 2; x |= x >> 4; if constexpr(sizeof(T) >= 2) x |= x >> 8; if constexpr(sizeof(T) >= 4) x |= x >> 16; if constexpr(sizeof(T) >= 8) x |= x >> 32; return x + 1; } template __attribute__((always_inline)) inline constexpr bool will_multiplication_overflow(T a, T b) { T dummy; return __builtin_mul_overflow(a, b, &dummy); } template __attribute__((always_inline)) inline constexpr bool will_addition_overflow(T a, T b) { T dummy; return __builtin_add_overflow(a, b, &dummy); } template requires is_same_v || is_same_v || is_same_v inline constexpr T ilog2(T x) { if constexpr(is_same_v) return sizeof(T) * 8 - __builtin_clz(x) - 1; if constexpr(is_same_v) return sizeof(T) * 8 - __builtin_clzl(x) - 1; return sizeof(T) * 8 - __builtin_clzll(x) - 1; } // This is ugly but my clangd does not like including // intrinsic headers at all #if !defined(__SSE__) || !defined(__SSE2__) #pragma GCC push_options #ifndef __SSE__ #pragma GCC target("sse") #endif #ifndef __SSE2__ #pragma GCC target("sse2") #endif #define BAN_MATH_POP_OPTIONS #endif template inline constexpr T floor(T x) { if constexpr(is_same_v) return __builtin_floorf(x); if constexpr(is_same_v) return __builtin_floor(x); if constexpr(is_same_v) return __builtin_floorl(x); } template inline constexpr T ceil(T x) { if constexpr(is_same_v) return __builtin_ceilf(x); if constexpr(is_same_v) return __builtin_ceil(x); if constexpr(is_same_v) return __builtin_ceill(x); } template inline constexpr T round(T x) { if (x == (T)0.0) return x; if (x > (T)0.0) return floor(x + (T)0.5); return ceil(x - (T)0.5); } template inline constexpr T trunc(T x) { if constexpr(is_same_v) return __builtin_truncf(x); if constexpr(is_same_v) return __builtin_trunc(x); if constexpr(is_same_v) return __builtin_truncl(x); } template inline constexpr T rint(T x) { asm("frndint" : "+t"(x)); return x; } template inline constexpr T fmod(T a, T b) { asm( "1:" "fprem;" "fnstsw %%ax;" "testb $4, %%ah;" "jne 1b;" : "+t"(a) : "u"(b) : "ax", "cc" ); return a; } template inline constexpr T remainder(T a, T b) { asm( "1:" "fprem1;" "fnstsw %%ax;" "testb $4, %%ah;" "jne 1b;" : "+t"(a) : "u"(b) : "ax", "cc" ); return a; } template static T modf(T x, T* iptr) { const T frac = BAN::Math::fmod(x, (T)1.0); *iptr = x - frac; return frac; } template inline constexpr T frexp(T num, int* exp) { if (num == (T)0.0) { *exp = 0; return (T)0.0; } T e; asm("fxtract" : "+t"(num), "=u"(e)); *exp = (int)e + 1; return num / (T)2.0; } template inline constexpr T copysign(T x, T y) { if ((x < (T)0.0) != (y < (T)0.0)) x = -x; return x; } namespace detail { template inline constexpr T fyl2x(T x, T y) { asm("fyl2x" : "+t"(x) : "u"(y) : "st(1)"); return x; } } template inline constexpr T log(T x) { return detail::fyl2x(x, numbers::ln2_v); } template inline constexpr T log2(T x) { return detail::fyl2x(x, 1.0); } template inline constexpr T log10(T x) { return detail::fyl2x(x, numbers::lg2_v); } template inline constexpr T logb(T x) { static_assert(FLT_RADIX == 2); return log2(x); } template inline constexpr T exp2(T x) { if (abs(x) <= (T)1.0) { asm("f2xm1" : "+t"(x)); return x + (T)1.0; } asm( "fld1;" "fld %%st(1);" "fprem;" "f2xm1;" "faddp;" "fscale;" "fstp %%st(1);" : "+t"(x) ); return x; } template inline constexpr T exp(T x) { return exp2(x * numbers::log2e_v); } template inline constexpr T pow(T x, T y) { if (x == (T)0.0) return (T)0.0; return exp2(y * log2(x)); } template inline constexpr T scalbn(T x, int n) { asm("fscale" : "+t"(x) : "u"(static_cast(n))); return x; } template inline constexpr T ldexp(T x, int y) { const bool exp_sign = y < 0; if (exp_sign) y = -y; T exp = (T)1.0; T mult = (T)2.0; while (y) { if (y & 1) exp *= mult; mult *= mult; y >>= 1; } if (exp_sign) exp = (T)1.0 / exp; return x * exp; } template inline constexpr T sqrt(T x) { if constexpr(BAN::is_same_v) { using v4sf = float __attribute__((vector_size(16))); return __builtin_ia32_sqrtss((v4sf) { x, 0.0f, 0.0f, 0.0f })[0]; } else if constexpr(BAN::is_same_v) { using v2df = double __attribute__((vector_size(16))); return __builtin_ia32_sqrtsd((v2df) { x, 0.0 })[0]; } else if constexpr(BAN::is_same_v) { asm("fsqrt" : "+t"(x)); return x; } } template inline constexpr T cbrt(T value) { return pow(value, (T)1.0 / (T)3.0); } template inline constexpr T sin(T x) { asm("fsin" : "+t"(x)); return x; } template inline constexpr T cos(T x) { asm("fcos" : "+t"(x)); return x; } template inline constexpr void sincos(T x, T& sin, T& cos) { asm("fsincos" : "=t"(cos), "=u"(sin) : "0"(x)); } template inline constexpr T tan(T x) { T one, ret; asm("fptan" : "=t"(one), "=u"(ret) : "0"(x)); return ret; } template inline constexpr T atan2(T y, T x) { asm("fpatan" : "+t"(x) : "u"(y) : "st(1)"); return x; } template inline constexpr T atan(T x) { return atan2(x, (T)1.0); } template inline constexpr T asin(T x) { if (x == (T)0.0) return (T)0.0; if (x == (T)1.0) return +numbers::pi_v / (T)2.0; if (x == (T)-1.0) return -numbers::pi_v / (T)2.0; return (T)2.0 * atan(x / ((T)1.0 + sqrt((T)1.0 - x * x))); } template inline constexpr T acos(T x) { if (x == (T)0.0) return numbers::pi_v / (T)2.0; if (x == (T)1.0) return (T)0.0; if (x == (T)-1.0) return numbers::pi_v; return (T)2.0 * atan(sqrt((T)1.0 - x * x) / ((T)1.0 + x)); } template inline constexpr T sinh(T x) { return (exp(x) - exp(-x)) / (T)2.0; } template inline constexpr T cosh(T x) { return (exp(x) + exp(-x)) / (T)2.0; } template inline constexpr T tanh(T x) { const T exp_px = exp(+x); const T exp_nx = exp(-x); return (exp_px - exp_nx) / (exp_px + exp_nx); } template inline constexpr T asinh(T x) { return log(x + sqrt(x * x + (T)1.0)); } template inline constexpr T acosh(T x) { return log(x + sqrt(x * x - (T)1.0)); } template inline constexpr T atanh(T x) { return (T)0.5 * log(((T)1.0 + x) / ((T)1.0 - x)); } template inline constexpr T hypot(T x, T y) { return sqrt(x * x + y * y); } #ifdef BAN_MATH_POP_OPTIONS #undef BAN_MATH_POP_OPTIONS #pragma GCC pop_options #endif }