#ifndef _MATH_H
#define _MATH_H

#ifdef __cplusplus
extern "C" {
#endif

// ---- Special values --------------------------------------------------
// Use compiler builtins so const-folding works in user code.
#define HUGE_VAL  (__builtin_huge_val())
#define HUGE_VALF (__builtin_huge_valf())
// long double on this target is not distinct from double; alias HUGE_VAL.
#define HUGE_VALL (__builtin_huge_val())
#define INFINITY  (__builtin_inff())
#define NAN       (__builtin_nanf(""))

// ---- Classification (functions, exposed via macros below) -----------
int __isnan_d   (double x);
int __isinf_d   (double x);
int __isfinite_d(double x);
int __signbit_d (double x);

#define isnan(x)    __isnan_d((double)(x))
#define isinf(x)    __isinf_d((double)(x))
#define isfinite(x) __isfinite_d((double)(x))
#define signbit(x)  __signbit_d((double)(x))

// ---- Absolute / sign ------------------------------------------------
double fabs    (double x);
float  fabsf   (float  x);
double copysign (double x, double y);
float  copysignf(float  x, float  y);

// ---- Rounding -------------------------------------------------------
double floor  (double x);
float  floorf (float  x);
double ceil   (double x);
float  ceilf  (float  x);
double trunc  (double x);
float  truncf (float  x);
double round  (double x);
float  roundf (float  x);

// ---- Min / max / positive difference --------------------------------
double fmax (double x, double y);
double fmin (double x, double y);
double fdim (double x, double y);
float  fmaxf(float  x, float  y);
float  fminf(float  x, float  y);
float  fdimf(float  x, float  y);

// ---- Mod / remainder ------------------------------------------------
double fmod (double x, double y);
float  fmodf(float  x, float  y);

// ---- FP decomposition -----------------------------------------------
double ldexp(double x, int n);
float  ldexpf(float x, int n);
double frexp(double x, int *e);
float  frexpf(float x, int *e);
double modf (double x, double *iptr);
float  modff(float  x, float  *iptr);

// ---- Power / root ---------------------------------------------------
double sqrt    (double x);
float  sqrtf   (float  x);
double cbrt    (double x);
float  cbrtf   (float  x);
double pow     (double x, double y);
float  powf    (float  x, float  y);
double hypot   (double x, double y);
float  hypotf  (float  x, float  y);

// ---- Exponential / log ----------------------------------------------
double exp    (double x);
float  expf   (float  x);
double exp2   (double x);
float  exp2f  (float  x);
double expm1  (double x);
float  expm1f (float  x);
double log    (double x);
float  logf   (float  x);
double log10  (double x);
float  log10f (float  x);
double log2   (double x);
float  log2f  (float  x);
double log1p  (double x);
float  log1pf (float  x);

// ---- Trigonometric --------------------------------------------------
double sin     (double x);
float  sinf    (float  x);
double cos     (double x);
float  cosf    (float  x);
double tan     (double x);
float  tanf    (float  x);
double atan    (double x);
float  atanf   (float  x);
double atan2   (double y, double x);
float  atan2f  (float  y, float  x);
double asin    (double x);
float  asinf   (float  x);
double acos    (double x);
float  acosf   (float  x);

// ---- Hyperbolic -----------------------------------------------------
double sinh    (double x);
float  sinhf   (float  x);
double cosh    (double x);
float  coshf   (float  x);
double tanh    (double x);
float  tanhf   (float  x);
double asinh   (double x);
float  asinhf  (float  x);
double acosh   (double x);
float  acoshf  (float  x);
double atanh   (double x);
float  atanhf  (float  x);

// ---- Fused multiply-add (not actually fused — rounds at each step) -
double fma  (double x, double y, double z);
float  fmaf (float  x, float  y, float  z);

// ---- NaN payload helpers (tagp ignored — returns canonical NaN) ----
double nan (const char *tagp);
float  nanf(const char *tagp);

// ---- IEEE 754 remainder -------------------------------------------
double remainder  (double x, double y);
float  remainderf (float  x, float  y);

// ---- Round to floating-point integer ------------------------------
double rint        (double x);
float  rintf       (float  x);
double nearbyint   (double x);
float  nearbyintf  (float  x);

// ---- Round to integer ----------------------------------------------
long lround  (double x);
long lroundf (float  x);
long lrint   (double x);
long lrintf  (float  x);

// ---- Scaling -------------------------------------------------------
double scalbn  (double x, int  n);
float  scalbnf (float  x, int  n);
double scalbln (double x, long n);
float  scalblnf(float  x, long n);

// ---- Classification ------------------------------------------------
#define FP_NAN       0
#define FP_INFINITE  1
#define FP_NORMAL    2
#define FP_SUBNORMAL 3
#define FP_ZERO      4
int fpclassify(double x);

// ---- Common constants -----------------------------------------------
// (Not in C99 strict, but defined by glibc/BSD math.h and widely used.)
#define M_E         2.7182818284590452354
#define M_LOG2E     1.4426950408889634074
#define M_LOG10E    0.43429448190325182765
#define M_LN2       0.69314718055994530942
#define M_LN10      2.30258509299404568402
#define M_PI        3.14159265358979323846
#define M_PI_2      1.57079632679489661923
#define M_PI_4      0.78539816339744830962
#define M_1_PI      0.31830988618379067154
#define M_2_PI      0.63661977236758134308
#define M_2_SQRTPI  1.12837916709551257390
#define M_SQRT2     1.41421356237309504880
#define M_SQRT1_2   0.70710678118654752440

#ifdef __cplusplus
}
#endif

#endif
