15 #include "absl/random/internal/chi_square.h"
19 #include "absl/random/internal/distribution_test_util.h"
23 namespace random_internal {
26 #if defined(__EMSCRIPTEN__)
28 inline double fma(
double x,
double y,
double z) {
34 template <
typename T,
unsigned N>
35 inline T EvaluatePolynomial(
T x,
const T (&
poly)[
N]) {
36 #if !defined(__EMSCRIPTEN__)
40 for (
unsigned i = 2;
i <=
N;
i++) {
41 p = fma(p, x,
poly[
N - i]);
46 static constexpr
int kLargeDOF = 150;
54 double POZ(
double z) {
55 static constexpr
double kP1[] = {
56 0.797884560593, -0.531923007300, 0.319152932694,
57 -0.151968751364, 0.059054035642, -0.019198292004,
58 0.005198775019, -0.001075204047, 0.000124818987,
60 static constexpr
double kP2[] = {
61 0.999936657524, 0.000535310849, -0.002141268741, 0.005353579108,
62 -0.009279453341, 0.011630447319, -0.010557625006, 0.006549791214,
63 -0.002034254874, -0.000794620820, 0.001390604284, -0.000676904986,
64 -0.000019538132, 0.000152529290, -0.000045255659,
67 const double kZMax = 6.0;
72 double y = 0.5 * std::fabs(z);
73 if (
y >= (kZMax * 0.5)) {
77 x = EvaluatePolynomial(w, kP1) *
y * 2.0;
80 x = EvaluatePolynomial(
y, kP2);
82 return z > 0.0 ? ((
x + 1.0) * 0.5) : ((1.0 -
x) * 0.5);
91 double normal_survival(
double z) {
94 static constexpr
double kR[] = {
95 1.0, 0.196854, 0.115194, 0.000344, 0.019527,
97 double r = EvaluatePolynomial(z, kR);
107 static constexpr
double kChiEpsilon =
109 static constexpr
double kChiMax =
112 const double p_value = 1.0 - p;
113 if (dof < 1 || p_value > 1.0) {
117 if (dof > kLargeDOF) {
124 const double mean = 1 - 2.0 / (9 * dof);
125 const double variance = 2.0 / (9 * dof);
128 double term =
z * std::sqrt(variance) + mean;
129 return dof * (term * term * term);
133 if (p_value <= 0.0)
return kChiMax;
136 double min_chisq = 0.0;
137 double max_chisq = kChiMax;
138 double current = dof / std::sqrt(p_value);
139 while ((max_chisq - min_chisq) > kChiEpsilon) {
145 current = (max_chisq + min_chisq) * 0.5;
158 static constexpr
double kLogSqrtPi =
159 0.5723649429247000870717135;
160 static constexpr
double kInverseSqrtPi =
161 0.5641895835477562869480795;
169 if (dof > kLargeDOF) {
171 const double chi_square_scaled = std::pow(chi_square / dof, 1.0 / 3);
172 const double mean = 1 - 2.0 / (9 * dof);
173 const double variance = 2.0 / (9 * dof);
176 const double z = (chi_square_scaled - mean) / std::sqrt(variance);
178 return normal_survival(
z);
180 return 1.0 - normal_survival(-
z);
189 if (chi_square <= 0.0)
return 1.0;
194 if (dof < 1)
return 0;
196 auto capped_exp = [](
double x) {
return x < -20 ? 0.0 : std::exp(
x); };
197 static constexpr
double kBigX = 20;
199 double a = 0.5 * chi_square;
200 const bool even = !(dof & 1);
201 const double y = capped_exp(-
a);
202 double s = even ?
y : (2.0 * POZ(-std::sqrt(chi_square)));
208 chi_square = 0.5 * (dof - 1.0);
209 double z = (even ? 1.0 : 0.5);
211 double e = (even ? 0.0 : kLogSqrtPi);
213 while (
z <= chi_square) {
215 s += capped_exp(c *
z -
a -
e);
221 double e = (even ? 1.0 : (kInverseSqrtPi / std::sqrt(
a)));
223 while (
z <= chi_square) {