49template <
typename Iterator>
50double range(Iterator first, Iterator last)
53 throw std::invalid_argument(
"statcpp::range: empty range");
55 auto [min_it, max_it] = std::minmax_element(first, last);
56 return static_cast<double>(*max_it) -
static_cast<double>(*min_it);
72template <
typename Iterator,
typename Projection>
73double range(Iterator first, Iterator last, Projection proj)
76 throw std::invalid_argument(
"statcpp::range: empty range");
79 double min_val =
static_cast<double>(std::invoke(proj, *it));
80 double max_val = min_val;
82 for (; it != last; ++it) {
83 double val =
static_cast<double>(std::invoke(proj, *it));
91 return max_val - min_val;
111template <
typename Iterator>
112double var(Iterator first, Iterator last, std::size_t ddof = 0)
115 throw std::invalid_argument(
"statcpp::var: ddof must be 0 or 1");
117 auto n =
static_cast<std::size_t
>(std::distance(first, last));
119 throw std::invalid_argument(
"statcpp::var: empty range");
121 if (ddof == 1 && n < 2) {
122 throw std::invalid_argument(
"statcpp::var: need at least 2 elements for ddof=1");
126 for (
auto it = first; it != last; ++it) {
127 double diff =
static_cast<double>(*it) - m;
130 return sum_sq /
static_cast<double>(n - ddof);
146template <
typename Iterator>
147double var(Iterator first, Iterator last,
double precomputed_mean, std::size_t ddof)
150 throw std::invalid_argument(
"statcpp::var: ddof must be 0 or 1");
152 auto n =
static_cast<std::size_t
>(std::distance(first, last));
154 throw std::invalid_argument(
"statcpp::var: empty range");
156 if (ddof == 1 && n < 2) {
157 throw std::invalid_argument(
"statcpp::var: need at least 2 elements for ddof=1");
160 for (
auto it = first; it != last; ++it) {
161 double diff =
static_cast<double>(*it) - precomputed_mean;
164 return sum_sq /
static_cast<double>(n - ddof);
181template <
typename Iterator,
typename Projection,
182 typename = std::enable_if_t<
183 std::is_invocable_v<Projection,
184 typename std::iterator_traits<Iterator>::value_type>>>
185double var(Iterator first, Iterator last, Projection proj, std::size_t ddof = 0)
188 throw std::invalid_argument(
"statcpp::var: ddof must be 0 or 1");
190 auto n =
static_cast<std::size_t
>(std::distance(first, last));
192 throw std::invalid_argument(
"statcpp::var: empty range");
194 if (ddof == 1 && n < 2) {
195 throw std::invalid_argument(
"statcpp::var: need at least 2 elements for ddof=1");
199 for (
auto it = first; it != last; ++it) {
200 double diff =
static_cast<double>(std::invoke(proj, *it)) - m;
203 return sum_sq /
static_cast<double>(n - ddof);
221template <
typename Iterator,
typename Projection>
222double var(Iterator first, Iterator last, Projection proj,
double precomputed_mean, std::size_t ddof)
225 throw std::invalid_argument(
"statcpp::var: ddof must be 0 or 1");
227 auto n =
static_cast<std::size_t
>(std::distance(first, last));
229 throw std::invalid_argument(
"statcpp::var: empty range");
231 if (ddof == 1 && n < 2) {
232 throw std::invalid_argument(
"statcpp::var: need at least 2 elements for ddof=1");
235 for (
auto it = first; it != last; ++it) {
236 double diff =
static_cast<double>(std::invoke(proj, *it)) - precomputed_mean;
239 return sum_sq /
static_cast<double>(n - ddof);
257template <
typename Iterator>
260 return var(first, last, 0);
275template <
typename Iterator>
278 return var(first, last, precomputed_mean, 0);
294template <
typename Iterator,
typename Projection,
295 typename = std::enable_if_t<
296 std::is_invocable_v<Projection,
297 typename std::iterator_traits<Iterator>::value_type>>>
300 return var(first, last, proj, 0);
317template <
typename Iterator,
typename Projection>
320 return var(first, last, proj, precomputed_mean, 0);
338template <
typename Iterator>
341 return var(first, last, 1);
356template <
typename Iterator>
359 return var(first, last, precomputed_mean, 1);
375template <
typename Iterator,
typename Projection,
376 typename = std::enable_if_t<
377 std::is_invocable_v<Projection,
378 typename std::iterator_traits<Iterator>::value_type>>>
381 return var(first, last, proj, 1);
398template <
typename Iterator,
typename Projection>
399double sample_variance(Iterator first, Iterator last, Projection proj,
double precomputed_mean)
401 return var(first, last, proj, precomputed_mean, 1);
419template <
typename Iterator>
437template <
typename Iterator>
438double variance(Iterator first, Iterator last,
double precomputed_mean)
456template <
typename Iterator,
typename Projection,
457 typename = std::enable_if_t<
458 std::is_invocable_v<Projection,
459 typename std::iterator_traits<Iterator>::value_type>>>
460double variance(Iterator first, Iterator last, Projection proj)
479template <
typename Iterator,
typename Projection>
480double variance(Iterator first, Iterator last, Projection proj,
double precomputed_mean)
503template <
typename Iterator>
504double stdev(Iterator first, Iterator last, std::size_t ddof = 0)
506 return std::sqrt(
var(first, last, ddof));
522template <
typename Iterator>
523double stdev(Iterator first, Iterator last,
double precomputed_mean, std::size_t ddof)
525 return std::sqrt(
var(first, last, precomputed_mean, ddof));
542template <
typename Iterator,
typename Projection,
543 typename = std::enable_if_t<
544 std::is_invocable_v<Projection,
545 typename std::iterator_traits<Iterator>::value_type>>>
546double stdev(Iterator first, Iterator last, Projection proj, std::size_t ddof = 0)
548 return std::sqrt(
var(first, last, proj, ddof));
566template <
typename Iterator,
typename Projection>
567double stdev(Iterator first, Iterator last, Projection proj,
double precomputed_mean, std::size_t ddof)
569 return std::sqrt(
var(first, last, proj, precomputed_mean, ddof));
587template <
typename Iterator>
590 return stdev(first, last, 0);
605template <
typename Iterator>
608 return stdev(first, last, precomputed_mean, 0);
624template <
typename Iterator,
typename Projection,
625 typename = std::enable_if_t<
626 std::is_invocable_v<Projection,
627 typename std::iterator_traits<Iterator>::value_type>>>
630 return stdev(first, last, proj, 0);
647template <
typename Iterator,
typename Projection>
648double population_stddev(Iterator first, Iterator last, Projection proj,
double precomputed_mean)
650 return stdev(first, last, proj, precomputed_mean, 0);
668template <
typename Iterator>
671 return stdev(first, last, 1);
686template <
typename Iterator>
689 return stdev(first, last, precomputed_mean, 1);
705template <
typename Iterator,
typename Projection,
706 typename = std::enable_if_t<
707 std::is_invocable_v<Projection,
708 typename std::iterator_traits<Iterator>::value_type>>>
711 return stdev(first, last, proj, 1);
728template <
typename Iterator,
typename Projection>
729double sample_stddev(Iterator first, Iterator last, Projection proj,
double precomputed_mean)
731 return stdev(first, last, proj, precomputed_mean, 1);
749template <
typename Iterator>
750double stddev(Iterator first, Iterator last)
767template <
typename Iterator>
768double stddev(Iterator first, Iterator last,
double precomputed_mean)
786template <
typename Iterator,
typename Projection,
787 typename = std::enable_if_t<
788 std::is_invocable_v<Projection,
789 typename std::iterator_traits<Iterator>::value_type>>>
790double stddev(Iterator first, Iterator last, Projection proj)
809template <
typename Iterator,
typename Projection>
810double stddev(Iterator first, Iterator last, Projection proj,
double precomputed_mean)
831template <
typename Iterator>
834 auto n =
static_cast<std::size_t
>(std::distance(first, last));
836 throw std::invalid_argument(
"statcpp::coefficient_of_variation: empty range");
839 throw std::invalid_argument(
"statcpp::coefficient_of_variation: need at least 2 elements");
843 throw std::invalid_argument(
"statcpp::coefficient_of_variation: mean is zero");
860template <
typename Iterator>
863 auto n =
static_cast<std::size_t
>(std::distance(first, last));
865 throw std::invalid_argument(
"statcpp::coefficient_of_variation: empty range");
868 throw std::invalid_argument(
"statcpp::coefficient_of_variation: need at least 2 elements");
870 if (precomputed_mean == 0.0) {
871 throw std::invalid_argument(
"statcpp::coefficient_of_variation: mean is zero");
873 return sample_stddev(first, last, precomputed_mean) / std::abs(precomputed_mean);
889template <
typename Iterator,
typename Projection,
890 typename = std::enable_if_t<
891 std::is_invocable_v<Projection,
892 typename std::iterator_traits<Iterator>::value_type>>>
895 auto n =
static_cast<std::size_t
>(std::distance(first, last));
897 throw std::invalid_argument(
"statcpp::coefficient_of_variation: empty range");
900 throw std::invalid_argument(
"statcpp::coefficient_of_variation: need at least 2 elements");
904 throw std::invalid_argument(
"statcpp::coefficient_of_variation: mean is zero");
923template <
typename Iterator,
typename Projection>
926 auto n =
static_cast<std::size_t
>(std::distance(first, last));
928 throw std::invalid_argument(
"statcpp::coefficient_of_variation: empty range");
931 throw std::invalid_argument(
"statcpp::coefficient_of_variation: need at least 2 elements");
933 if (precomputed_mean == 0.0) {
934 throw std::invalid_argument(
"statcpp::coefficient_of_variation: mean is zero");
936 return sample_stddev(first, last, proj, precomputed_mean) / std::abs(precomputed_mean);
955template <
typename Iterator>
956double iqr(Iterator first, Iterator last)
958 auto n =
static_cast<std::size_t
>(std::distance(first, last));
960 throw std::invalid_argument(
"statcpp::iqr: empty range");
981template <
typename Iterator,
typename Projection>
982double iqr(Iterator first, Iterator last, Projection proj)
984 auto n =
static_cast<std::size_t
>(std::distance(first, last));
986 throw std::invalid_argument(
"statcpp::iqr: empty range");
1009template <
typename Iterator>
1012 auto n =
static_cast<std::size_t
>(std::distance(first, last));
1014 throw std::invalid_argument(
"statcpp::mean_absolute_deviation: empty range");
1017 double sum_abs = 0.0;
1018 for (
auto it = first; it != last; ++it) {
1019 sum_abs += std::abs(
static_cast<double>(*it) - m);
1021 return sum_abs /
static_cast<double>(n);
1036template <
typename Iterator>
1039 auto n =
static_cast<std::size_t
>(std::distance(first, last));
1041 throw std::invalid_argument(
"statcpp::mean_absolute_deviation: empty range");
1043 double sum_abs = 0.0;
1044 for (
auto it = first; it != last; ++it) {
1045 sum_abs += std::abs(
static_cast<double>(*it) - precomputed_mean);
1047 return sum_abs /
static_cast<double>(n);
1063template <
typename Iterator,
typename Projection,
1064 typename = std::enable_if_t<
1065 std::is_invocable_v<Projection,
1066 typename std::iterator_traits<Iterator>::value_type>>>
1069 auto n =
static_cast<std::size_t
>(std::distance(first, last));
1071 throw std::invalid_argument(
"statcpp::mean_absolute_deviation: empty range");
1074 double sum_abs = 0.0;
1075 for (
auto it = first; it != last; ++it) {
1076 sum_abs += std::abs(
static_cast<double>(std::invoke(proj, *it)) - m);
1078 return sum_abs /
static_cast<double>(n);
1095template <
typename Iterator,
typename Projection>
1098 auto n =
static_cast<std::size_t
>(std::distance(first, last));
1100 throw std::invalid_argument(
"statcpp::mean_absolute_deviation: empty range");
1102 double sum_abs = 0.0;
1103 for (
auto it = first; it != last; ++it) {
1104 sum_abs += std::abs(
static_cast<double>(std::invoke(proj, *it)) - precomputed_mean);
1106 return sum_abs /
static_cast<double>(n);
1128template <
typename Iterator,
typename WeightIterator>
1129double weighted_variance(Iterator first, Iterator last, WeightIterator weight_first, WeightIterator weight_last)
1131 if (std::distance(first, last) != std::distance(weight_first, weight_last)) {
1132 throw std::invalid_argument(
"statcpp::weighted_variance: data and weight ranges differ in length");
1137 throw std::invalid_argument(
"statcpp::weighted_variance: empty range");
1141 double sum_weighted = 0.0;
1142 double sum_weights = 0.0;
1143 auto weight_it = weight_first;
1145 for (
auto it = first; it != last; ++it, ++weight_it) {
1146 double value =
static_cast<double>(*it);
1147 double weight =
static_cast<double>(*weight_it);
1150 throw std::invalid_argument(
"statcpp::weighted_variance: negative weight");
1153 sum_weighted += value * weight;
1154 sum_weights += weight;
1157 if (sum_weights == 0.0) {
1158 throw std::invalid_argument(
"statcpp::weighted_variance: sum of weights is zero");
1161 double mean = sum_weighted / sum_weights;
1164 double sum_squared_dev = 0.0;
1165 double sum_weights_squared = 0.0;
1166 weight_it = weight_first;
1168 for (
auto it = first; it != last; ++it, ++weight_it) {
1169 double value =
static_cast<double>(*it);
1170 double weight =
static_cast<double>(*weight_it);
1171 double dev = value -
mean;
1173 sum_squared_dev += weight * dev * dev;
1174 sum_weights_squared += weight * weight;
1179 double correction = sum_weights - (sum_weights_squared / sum_weights);
1181 if (correction <= 0.0) {
1182 throw std::invalid_argument(
"statcpp::weighted_variance: insufficient effective sample size");
1185 return sum_squared_dev / correction;
1204template <
typename Iterator,
typename WeightIterator>
1205[[deprecated(
"Use weighted_variance(first, last, weight_first, weight_last) overload for range safety")]]
1210 throw std::invalid_argument(
"statcpp::weighted_variance: empty range");
1214 double sum_weighted = 0.0;
1215 double sum_weights = 0.0;
1216 auto weight_it = weight_first;
1218 for (
auto it = first; it != last; ++it, ++weight_it) {
1219 double value =
static_cast<double>(*it);
1220 double weight =
static_cast<double>(*weight_it);
1223 throw std::invalid_argument(
"statcpp::weighted_variance: negative weight");
1226 sum_weighted += value * weight;
1227 sum_weights += weight;
1230 if (sum_weights == 0.0) {
1231 throw std::invalid_argument(
"statcpp::weighted_variance: sum of weights is zero");
1234 double mean = sum_weighted / sum_weights;
1237 double sum_squared_dev = 0.0;
1238 double sum_weights_squared = 0.0;
1239 weight_it = weight_first;
1241 for (
auto it = first; it != last; ++it, ++weight_it) {
1242 double value =
static_cast<double>(*it);
1243 double weight =
static_cast<double>(*weight_it);
1244 double dev = value -
mean;
1246 sum_squared_dev += weight * dev * dev;
1247 sum_weights_squared += weight * weight;
1252 double correction = sum_weights - (sum_weights_squared / sum_weights);
1254 if (correction <= 0.0) {
1255 throw std::invalid_argument(
"statcpp::weighted_variance: insufficient effective sample size");
1258 return sum_squared_dev / correction;
1278template <
typename Iterator,
typename WeightIterator,
typename Projection>
1279double weighted_variance(Iterator first, Iterator last, WeightIterator weight_first, WeightIterator weight_last, Projection proj)
1281 if (std::distance(first, last) != std::distance(weight_first, weight_last)) {
1282 throw std::invalid_argument(
"statcpp::weighted_variance: data and weight ranges differ in length");
1287 throw std::invalid_argument(
"statcpp::weighted_variance: empty range");
1291 double sum_weighted = 0.0;
1292 double sum_weights = 0.0;
1293 auto weight_it = weight_first;
1295 for (
auto it = first; it != last; ++it, ++weight_it) {
1296 double value =
static_cast<double>(std::invoke(proj, *it));
1297 double weight =
static_cast<double>(*weight_it);
1300 throw std::invalid_argument(
"statcpp::weighted_variance: negative weight");
1303 sum_weighted += value * weight;
1304 sum_weights += weight;
1307 if (sum_weights == 0.0) {
1308 throw std::invalid_argument(
"statcpp::weighted_variance: sum of weights is zero");
1311 double mean = sum_weighted / sum_weights;
1314 double sum_squared_dev = 0.0;
1315 double sum_weights_squared = 0.0;
1316 weight_it = weight_first;
1318 for (
auto it = first; it != last; ++it, ++weight_it) {
1319 double value =
static_cast<double>(std::invoke(proj, *it));
1320 double weight =
static_cast<double>(*weight_it);
1321 double dev = value -
mean;
1323 sum_squared_dev += weight * dev * dev;
1324 sum_weights_squared += weight * weight;
1327 double correction = sum_weights - (sum_weights_squared / sum_weights);
1329 if (correction <= 0.0) {
1330 throw std::invalid_argument(
"statcpp::weighted_variance: insufficient effective sample size");
1333 return sum_squared_dev / correction;
1354template <
typename Iterator,
typename WeightIterator,
typename Projection>
1355[[deprecated(
"Use weighted_variance(first, last, weight_first, weight_last, proj) overload for range safety")]]
1356double weighted_variance(Iterator first, Iterator last, WeightIterator weight_first, Projection proj)
1360 throw std::invalid_argument(
"statcpp::weighted_variance: empty range");
1364 double sum_weighted = 0.0;
1365 double sum_weights = 0.0;
1366 auto weight_it = weight_first;
1368 for (
auto it = first; it != last; ++it, ++weight_it) {
1369 double value =
static_cast<double>(std::invoke(proj, *it));
1370 double weight =
static_cast<double>(*weight_it);
1373 throw std::invalid_argument(
"statcpp::weighted_variance: negative weight");
1376 sum_weighted += value * weight;
1377 sum_weights += weight;
1380 if (sum_weights == 0.0) {
1381 throw std::invalid_argument(
"statcpp::weighted_variance: sum of weights is zero");
1384 double mean = sum_weighted / sum_weights;
1387 double sum_squared_dev = 0.0;
1388 double sum_weights_squared = 0.0;
1389 weight_it = weight_first;
1391 for (
auto it = first; it != last; ++it, ++weight_it) {
1392 double value =
static_cast<double>(std::invoke(proj, *it));
1393 double weight =
static_cast<double>(*weight_it);
1394 double dev = value -
mean;
1396 sum_squared_dev += weight * dev * dev;
1397 sum_weights_squared += weight * weight;
1400 double correction = sum_weights - (sum_weights_squared / sum_weights);
1402 if (correction <= 0.0) {
1403 throw std::invalid_argument(
"statcpp::weighted_variance: insufficient effective sample size");
1406 return sum_squared_dev / correction;
1423template <
typename Iterator,
typename WeightIterator>
1424double weighted_stddev(Iterator first, Iterator last, WeightIterator weight_first, WeightIterator weight_last)
1444template <
typename Iterator,
typename WeightIterator>
1445[[deprecated(
"Use weighted_stddev(first, last, weight_first, weight_last) overload for range safety")]]
1467template <
typename Iterator,
typename WeightIterator,
typename Projection>
1468double weighted_stddev(Iterator first, Iterator last, WeightIterator weight_first, WeightIterator weight_last, Projection proj)
1470 return std::sqrt(
weighted_variance(first, last, weight_first, weight_last, proj));
1490template <
typename Iterator,
typename WeightIterator,
typename Projection>
1491[[deprecated(
"Use weighted_stddev(first, last, weight_first, weight_last, proj) overload for range safety")]]
1492double weighted_stddev(Iterator first, Iterator last, WeightIterator weight_first, Projection proj)
1514template <
typename Iterator>
1519 throw std::invalid_argument(
"statcpp::geometric_stddev: empty range");
1523 std::vector<double> log_values;
1524 log_values.reserve(n);
1526 for (
auto it = first; it != last; ++it) {
1527 double value =
static_cast<double>(*it);
1529 throw std::invalid_argument(
"statcpp::geometric_stddev: all values must be positive");
1531 log_values.push_back(std::log(value));
1535 return std::exp(log_stddev);
1551template <
typename Iterator,
typename Projection>
1556 throw std::invalid_argument(
"statcpp::geometric_stddev: empty range");
1560 std::vector<double> log_values;
1561 log_values.reserve(n);
1563 for (
auto it = first; it != last; ++it) {
1564 double value =
static_cast<double>(std::invoke(proj, *it));
1566 throw std::invalid_argument(
"statcpp::geometric_stddev: all values must be positive");
1568 log_values.push_back(std::log(value));
1572 return std::exp(log_stddev);
Basic statistical computation functions.
double stddev(Iterator first, Iterator last)
Standard deviation (alias for sample_stddev)
double population_variance(Iterator first, Iterator last)
Population variance.
double range(Iterator first, Iterator last)
Range (maximum - minimum)
double stdev(Iterator first, Iterator last, std::size_t ddof=0)
Standard deviation (ddof = Delta Degrees of Freedom)
double sample_stddev(Iterator first, Iterator last)
Sample standard deviation.
double sample_variance(Iterator first, Iterator last)
Sample variance (unbiased variance)
double coefficient_of_variation(Iterator first, Iterator last)
Coefficient of variation.
double var(Iterator first, Iterator last, std::size_t ddof=0)
Variance (ddof = Delta Degrees of Freedom)
double interpolate_at(Iterator first, std::size_t n, double p)
Linear interpolation at position.
double geometric_stddev(Iterator first, Iterator last)
Geometric standard deviation.
double population_stddev(Iterator first, Iterator last)
Population standard deviation.
double iqr(Iterator first, Iterator last)
Interquartile range (accepts a sorted range)
double mean_absolute_deviation(Iterator first, Iterator last)
Mean absolute deviation.
double mean(Iterator first, Iterator last)
Arithmetic mean.
std::vector< double > diff(Iterator first, Iterator last, std::size_t order=1)
Difference series (first-order or d-th order differencing)
double variance(Iterator first, Iterator last)
Variance (alias for sample_variance)
double weighted_variance(Iterator first, Iterator last, WeightIterator weight_first, WeightIterator weight_last)
Weighted variance (reliability weights / analytic weights)
std::size_t count(Iterator first, Iterator last)
Data count.
double weighted_stddev(Iterator first, Iterator last, WeightIterator weight_first, WeightIterator weight_last)
Weighted standard deviation.
Order statistics implementation.