5#ifndef LINE_API_SIM_SIM_SHAPIROWILK_H
6#define LINE_API_SIM_SIM_SHAPIROWILK_H
41#include <boost/math/constants/constants.hpp>
64inline std::vector<double> shapirowilk_weights(std::size_t n) {
65 std::vector<double> a(n, 0.0);
67 a[0] = -std::sqrt(0.5);
69 a[2] = std::sqrt(0.5);
73 static const double c1[6] = {0.0, 0.221157, -0.147981, -2.071190, 4.434685, -2.706056};
74 static const double c2[6] = {0.0, 0.042981, -0.293762, -1.752461, 5.682633, -3.582633};
76 std::vector<double> m(n, 0.0);
78 for (std::size_t i = 0; i < n; ++i) {
79 m[i] =
sim_norminv((
static_cast<double>(i + 1) - 0.375) /
80 (
static_cast<double>(n) + 0.25));
83 const double u = 1.0 / std::sqrt(
static_cast<double>(n));
86 double p1 = 0.0, p2 = 0.0, uk = 1.0;
87 for (
int k = 0; k < 6; ++k) {
94 const double an = m[n - 1] / std::sqrt(mm) + p1;
96 const double anm1 = m[n - 2] / std::sqrt(mm) + p2;
97 const double phi = (mm - 2.0 * m[n - 1] * m[n - 1] - 2.0 * m[n - 2] * m[n - 2]) /
98 (1.0 - 2.0 * an * an - 2.0 * anm1 * anm1);
99 for (std::size_t i = 2; i + 2 < n; ++i) a[i] = m[i] / std::sqrt(phi);
105 const double phi = (mm - 2.0 * m[n - 1] * m[n - 1]) / (1.0 - 2.0 * an * an);
106 for (std::size_t i = 1; i + 1 < n; ++i) a[i] = m[i] / std::sqrt(phi);
124 "sim_shapirowilk: the weights and the p-value are transcendental, so exact "
125 "arithmetic is refused");
126 if (!(alpha > 0.0) || !(alpha < 1.0))
127 throw InputError(
"sim_shapirowilk: alpha must be a real scalar in (0,1)");
129 const std::size_t n = x.size();
131 throw InputError(
"sim_shapirowilk: at least 3 observations are required");
133 throw InputError(
"sim_shapirowilk: the AS R94 approximation is valid up to n = 5000");
134 for (std::size_t i = 0; i < n; ++i)
135 if (!detail::num_isfinite(x[i]))
136 throw InputError(
"sim_shapirowilk: the sample must be finite");
139 std::sort(s.begin(), s.end());
142 for (std::size_t i = 0; i < n; ++i)
sum += s[i];
145 for (std::size_t i = 0; i < n; ++i) {
146 const T d = T(s[i] - mean);
150 throw InputError(
"sim_shapirowilk: the sample is constant, W is undefined");
152 const std::vector<double> a = detail::shapirowilk_weights(n);
158 r.
W = T(T(ax * ax) / ssd);
160 if (r.
W > one) r.
W = one;
165 const double pi = boost::math::constants::pi<double>();
166 double p = 6.0 / pi * (std::asin(std::sqrt(Wd)) - std::asin(std::sqrt(0.75)));
167 r.
pvalue = std::min(std::max(p, 0.0), 1.0);
168 r.
zscore = std::numeric_limits<double>::quiet_NaN();
170 const double nd =
static_cast<double>(n);
173 const double g = -2.273 + 0.459 * nd;
174 w = -std::log(g - std::log(1.0 - Wd));
175 mu = 0.5440 - 0.39978 * nd + 0.025054 * nd * nd - 0.0006714 * nd * nd * nd;
176 sigma = std::exp(1.3822 - 0.77857 * nd + 0.062767 * nd * nd -
177 0.0020322 * nd * nd * nd);
179 const double ln = std::log(nd);
180 w = std::log(1.0 - Wd);
181 mu = -1.5861 - 0.31082 *
ln - 0.083751 *
ln *
ln + 0.0038915 *
ln *
ln *
ln;
182 sigma = std::exp(-0.4803 - 0.082676 *
ln + 0.0030302 *
ln *
ln);
184 r.
zscore = (w - mu) / sigma;
The exception types the port throws.
double sim_norminv(double p)
Standard normal quantile function.
double sim_normcdf(double z)
Standard normal cumulative distribution function.
ShapiroWilkResult< T > sim_shapirowilk(const std::vector< T > &x, double alpha=0.05)
Shapiro-Wilk test for univariate normality.
Number-type abstraction for the templated API port.
Normal and Student t quantiles used by the output-analysis routines.
Shared arithmetic helpers for the templated simulation output-analysis port.
Outcome of the Shapiro-Wilk normality test.
std::size_t nobs
Number of observations n.
bool reject
True when pvalue < alpha.
double pvalue
p-value, small means normality is rejected
double zscore
Normalized statistic, NaN when n = 3.
T W
The Shapiro-Wilk statistic.