diff options
| author | Ethan Werner <mail@ethanwerner.com> | 2026-07-01 09:42:39 +0400 |
|---|---|---|
| committer | Ethan Werner <mail@ethanwerner.com> | 2026-07-01 09:42:39 +0400 |
| commit | 07e18043145f3d91c8ea7ec3ad41b3c905585277 (patch) | |
| tree | 2bdeae46973f4bdfce263679a4008ac768011f28 /lib/gaussian_quantile.c | |
initial commit: ts time series analysis library v0.1.0
- 354 financial and mathematical time-series indicators
- Uniform C11 API with consistent function signatures
- 349 passing tests with -Werror
- Static and shared library builds
- pkg-config integration
- Python bindings
- Fuzzing and sanitizer support
- Security hardening flags
Diffstat (limited to 'lib/gaussian_quantile.c')
| -rw-r--r-- | lib/gaussian_quantile.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/lib/gaussian_quantile.c b/lib/gaussian_quantile.c new file mode 100644 index 0000000..337262c --- /dev/null +++ b/lib/gaussian_quantile.c @@ -0,0 +1,94 @@ +// Gaussian Quantile +// +// gaussian_quantile +// +// Gaussian quantile function (inverse CDF) +// +// Q(p) = Φ^(-1)(p) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_gaussian_quantile_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_gaussian_quantile_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_gaussian_quantile( + fp_t * const *y, uint_t y_n, + fp_t const * const *x, uint_t x_n, + uint_t n, ts_constant_t const *c +) +{ + TS_PROLOGUE( ts_gaussian_quantile_p ); + (void)c; + /* Peter Acklam's approximation for inverse normal CDF */ + /* Coefficients for rational approximation */ + fp_t const a[] = { + -3.969683028665376e+01, 2.209460984245205e+02, + -2.759285104469687e+02, 1.383577518672690e+02, + -3.066479806614716e+01, 2.506628277459239e+00 + }; + fp_t const b[] = { + -5.447609879822406e+01, 1.615858368580409e+02, + -1.556989798598866e+02, 6.680131188771972e+01, + -1.328068155288572e+01 + }; + fp_t const cc[] = { + -7.784894002430993e-03, 3.223964580411365e-01, + -2.400758277161838e+00, -2.549732539343734e+00, + 4.374664141464968e+00, 2.938163982698783e+00 + }; + fp_t const d[] = { + 7.784695709041462e-03, 3.224671290700398e-01, + 2.445134137142996e+00, 3.754408661907416e+00 + }; + + fp_t const p_low = 0.02425; + fp_t const p_high = 1.0 - p_low; + + for (uint_t i = 0; i < n; ++i) + { + fp_t p = x[0][i]; + if (p <= 0.0) + { + y[0][i] = -INFINITY; + continue; + } + if (p >= 1.0) + { + y[0][i] = INFINITY; + continue; + } + + fp_t q, r; + + if (p < p_low) { + q = sqrt(-2.0 * log(p)); + y[0][i] = -(((((cc[0]*q + cc[1])*q + cc[2])*q + cc[3])*q + cc[4])*q + cc[5]) / + ((((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0); + } else if (p <= p_high) { + q = p - 0.5; + r = q * q; + y[0][i] = (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q / + (((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1.0); + } else { + q = sqrt(-2.0 * log(1.0 - p)); + y[0][i] = (((((cc[0]*q + cc[1])*q + cc[2])*q + cc[3])*q + cc[4])*q + cc[5]) / + ((((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0); + } + } + return 0; +} + + + |