/* File: math.h Author: Taylor Robbins Date: 08\28\2025 */ #ifndef _MATH_H #define _MATH_H //NOTE: clang was shadowing our intrinsics implementations (like floor, ceil, scalbnf, sqrt, etc.) with it's builtin ones, // we've decided to route through our functions using macros and functions prefixed with _. // Even if they route to builtins at the end of the day, this gives us the ability // to test our implementation and the control to route these however we want. // +--------------------------------------------------------------+ // | Defines | // +--------------------------------------------------------------+ #define NAN __builtin_nanf("") #define INFINITY __builtin_inff() #define FP_NAN 0 #define FP_INFINITE 1 #define FP_ZERO 2 #define FP_SUBNORMAL 3 #define FP_NORMAL 4 #define M_E 2.7182818284590452354 // e #define M_LOG2E 1.4426950408889634074 // log_2 e #define M_LOG10E 0.43429448190325182765 // log_10 e #define M_LN2 0.69314718055994530942 // log_e 2 #define M_LN10 2.30258509299404568402 // log_e 10 #define M_PI 3.14159265358979323846 // pi #define M_PI_2 1.57079632679489661923 // pi/2 #define M_PI_4 0.78539816339744830962 // pi/4 #define M_1_PI 0.31830988618379067154 // 1/pi #define M_2_PI 0.63661977236758134308 // 2/pi #define M_2_SQRTPI 1.12837916709551257390 // 2/sqrt(pi) #define M_SQRT2 1.41421356237309504880 // sqrt(2) #define M_SQRT1_2 0.70710678118654752440 // 1/sqrt(2) // +--------------------------------------------------------------+ // | Macros | // +--------------------------------------------------------------+ #define isinf(value) (sizeof(value) == sizeof(float) \ ? (__FLOAT_BITS((float)value) & 0x7fffffff) == 0x7f800000 \ : (__DOUBLE_BITS((double)value) & -1ULL>>1) == 0x7ffULL<<52 \ ) #define isnan(value) (sizeof(value) == sizeof(float) \ ? (__FLOAT_BITS((float)value) & 0x7fffffff) > 0x7f800000 \ : (__DOUBLE_BITS((double)value) & -1ULL>>1) > 0x7ffULL<<52 \ ) #define signbit(value) (sizeof(value) == sizeof(float) \ ? (int)(__FLOAT_BITS((float)value)>>31) \ : (int)(__DOUBLE_BITS((double)value)>>63) \ ) #define isnormal(value) (sizeof(value) == sizeof(float) \ ? ((__FLOAT_BITS(value)+0x00800000) & 0x7fffffff) >= 0x01000000 \ : ((__DOUBLE_BITS(value)+(1ULL<<52)) & -1ULL>>1) >= 1ULL<<53 \ ) #define fpclassify(value) (sizeof(value) == sizeof(float) \ ? __fpclassifyf(value) \ : __fpclassify(value) \ ) #define FORCE_EVAL(value) do { \ if (sizeof(value) == sizeof(float)) { fp_force_evalf(value); } \ else { fp_force_eval(value); } \ } while(0) #define asuint(value) ((union { float _value; uint32_t _integer; }){ value })._integer #define asfloat(value) ((union { uint32_t _value; float _float; }){ value })._float #define asuint64(value) ((union { double _value; uint64_t _integer; }){ value })._integer #define asdouble(value) ((union { uint64_t _value; double _double; }){ value })._double #define EXTRACT_WORDS(highWord, lowWord, value) do { uint64_t __u = asuint64(value); (highWord) = (__u >> 32); (lowWord) = (uint32_t)__u; } while (0) #define INSERT_WORDS(doubleVar, highWord, lowWord) do { (doubleVar) = asdouble(((uint64_t)(highWord)<<32) | (uint32_t)(lowWord)); } while (0) #define GET_HIGH_WORD(wordVar, value) do { (wordVar) = asuint64(value) >> 32; } while (0) #define GET_LOW_WORD(wordVar, value) do { (wordVar) = (uint32_t)asuint64(value); } while (0) #define SET_HIGH_WORD(doubleVar, wordValue) INSERT_WORDS(doubleVar, wordValue, (uint32_t)asuint64(doubleVar)) #define SET_LOW_WORD(doubleVar, wordValue) INSERT_WORDS(doubleVar, asuint64(doubleVar)>>32, wordValue) #define GET_FLOAT_WORD(wordVar, value) do { (wordVar) = asuint(value); } while (0) #define SET_FLOAT_WORD(floatVar, value) do { (floatVar) = asfloat(value); } while (0) // Helps static branch prediction so hot path can be better optimized. #define predict_true(condition) __builtin_expect(!!(condition), 1) #define predict_false(condition) __builtin_expect(condition, 0) MAYBE_START_EXTERN_C // +--------------------------------------------------------------+ // | Builtin Functions | // +--------------------------------------------------------------+ #define copysignf(magnitude, sign) __builtin_copysignf((magnitude), (sign)) //results in f32.copysign instruction #define copysign(magnitude, sign) __builtin_copysign((magnitude), (sign)) //results in f64.copysign instruction #define fabsf(value) __builtin_fabsf(value) //results in f32.abs instruction #define fabs(value) __builtin_fabs(value) //results in f64.abs instruction #define floorf(value) __builtin_floorf(value) //results in f32.floor instruction #define floor(value) __builtin_floor(value) //results in f64.floor instruction #define ceilf(value) __builtin_ceilf(value) //results in f32.ceil instruction #define ceil(value) __builtin_ceil(value) //results in f64.ceil instruction // +--------------------------------------------------------------+ // | Helper Functions | // +--------------------------------------------------------------+ int __fpclassifyf(float value); int __fpclassify(double value); unsigned __FLOAT_BITS(float value); unsigned long long __DOUBLE_BITS(double value); void fp_force_evalf(float value); void fp_force_eval(double value); float __math_invalidf(float value); double __math_invalid(double value); float eval_as_float(float x); double eval_as_double(double x); float __math_divzerof(uint32_t sign); double __math_divzero(uint32_t sign); // Top 16 bits of a double. uint32_t top16(double x); // Top 12 bits of a double (sign and exponent bits). uint32_t top12(double value); uint32_t top12f(float x); float fp_barrierf(float x); double fp_barrier(double x); // +--------------------------------------------------------------+ // | Functions | // +--------------------------------------------------------------+ // TODO: long double fabsl(long double value); // TODO: long double fmodl(long double numer, long double denom); float fminf(float value1, float value2); double fmin(double value1, double value2); float fmaxf(float value1, float value2); double fmax(double value1, double value2); float fmodf(float numer, float denom); double fmod(double numer, double denom); float roundf(float value); double round(double value); float _scalbnf(float value, int power); double _scalbn(double value, int power); // TODO: long double _scalbnl(long double value, int power); #define scalbnf(value, power) _scalbnf(value, power) #define scalbn(value, power) _scalbn(value, power) float sqrtf(float value); double sqrt(double value); float _cbrtf(float value); double _cbrt(double value); #define cbrtf(value) _cbrtf(value) #define cbrt(value) _cbrt(value) float sinf(float value); double sin(double value); float cosf(float value); double cos(double value); float tanf(float value); double tan(double value); float asinf(float value); double asin(double value); float acosf(float value); double acos(double value); float atanf(float value); double atan(double value); float atan2f(float numer, float denom); double atan2(double numer, double denom); float powf(float value, float exponent); double pow(double value, double exponent); float logf(float value); double log(double value); float log2f(float value); double log2(double value); float log10f(float value); double log10(double x); float ldexpf(float value, int exponent); double ldexp(double value, int exponent); float expf(float value); double exp(double value); // TODO: long double copysignl(long double magnitude, long double sign); MAYBE_END_EXTERN_C #endif // _MATH_H