#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) { T t; while (b) { t = b; b = a % b; a = t; } 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 static constexpr bool will_multiplication_overflow(T a, T b) { if (a == 0 || b == 0) return false; if ((a > 0) == (b > 0)) return a > BAN::numeric_limits::max() / b; else return a < BAN::numeric_limits::min() / b; } template static constexpr bool will_addition_overflow(T a, T b) { if (a > 0 && b > 0) return a > BAN::numeric_limits::max() - b; if (a < 0 && b < 0) return a < BAN::numeric_limits::min() - b; return false; } 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; } 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" ); return a; } template static T modf(T x, T* iptr) { const T frac = BAN::Math::fmod(x, 1); *iptr = x - frac; return frac; } template inline constexpr T frexp(T num, int* exp) { if (num == 0.0) { *exp = 0; return 0.0; } T _exp; asm("fxtract" : "+t"(num), "=u"(_exp)); *exp = (int)_exp + 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) { asm( "fyl2x;" "fld1;" "fld %%st(1);" "fprem;" "f2xm1;" "faddp;" "fscale;" : "+t"(x), "+u"(y) ); return 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) { asm("fsqrt" : "+t"(x)); return x; } template inline constexpr T cbrt(T value) { if (value == 0.0) return 0.0; return pow(value, 1.0 / 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, 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); } }