Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Math/Statistics.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include <algorithm>
5#include <ranges>
6
7#include "Common.h"
10
11namespace Stroika::Foundation::Math {
12
13 /*
14 ********************************************************************************
15 ************************************ Mean **************************************
16 ********************************************************************************
17 */
18 template <typename RESULT_TYPE, input_iterator ITERATOR_OF_T, sentinel_for<ITERATOR_OF_T> ITERATOR_OF_T2>
19 auto Mean (const ITERATOR_OF_T& start, ITERATOR_OF_T2&& end) -> RESULT_TYPE
20 {
21 Require (start != forward<ITERATOR_OF_T2> (end)); // the mean of 0 items would be undefined
22 unsigned int cnt{};
23 RESULT_TYPE result{};
24 for (ITERATOR_OF_T i = start; i != forward<ITERATOR_OF_T2> (end); ++i) {
25 result += *i;
26 ++cnt;
27 }
28 return result / cnt;
29 }
30 template <input_iterator ITERATOR_OF_T, sentinel_for<ITERATOR_OF_T> ITERATOR_OF_T2>
31 inline auto Mean (const ITERATOR_OF_T& start, ITERATOR_OF_T2&& end) -> typename iterator_traits<ITERATOR_OF_T>::value_type
32 {
33 Require (start != forward<ITERATOR_OF_T2> (end)); // the mean of 0 items would be undefined
34 return Mean<typename iterator_traits<ITERATOR_OF_T>::value_type> (start, forward<ITERATOR_OF_T2> (end));
35 }
36 template <ranges::range CONTAINER_OF_T>
37 inline auto Mean (const CONTAINER_OF_T& container) -> typename CONTAINER_OF_T::value_type
38 {
39 Require (not container.empty ());
40 return Mean<typename CONTAINER_OF_T::value_type> (ranges::begin (container), ranges::end (container));
41 }
42
43 /*
44 ********************************************************************************
45 ********************************** Median **************************************
46 ********************************************************************************
47 */
48 template <typename RESULT_TYPE, input_iterator ITERATOR_OF_T, sentinel_for<ITERATOR_OF_T> ITERATOR_OF_T2, Common::IInOrderComparer<RESULT_TYPE> INORDER_COMPARE_FUNCTION>
49 RESULT_TYPE Median (const ITERATOR_OF_T& start, ITERATOR_OF_T2&& end, INORDER_COMPARE_FUNCTION&& compare)
50 {
51 // @todo only do the COPY conditionally - if ITERATOR_OF_T isn't already a random-access iterator...
52 Require (start != forward<ITERATOR_OF_T2> (end)); // the median of no values would be undefined
53 Memory::StackBuffer<RESULT_TYPE> tmp{start, forward<ITERATOR_OF_T2> (end)}; // copy cuz data modified
54 size_t size = tmp.size ();
55 nth_element (tmp.begin (), tmp.begin () + size / 2, tmp.end (), forward<INORDER_COMPARE_FUNCTION> (compare));
56 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wmaybe-uninitialized\""); // warning with gcc cross-compile to raspberrypi - no idea why --LGP 2018-09-13
57 RESULT_TYPE result{tmp[size / 2]};
58 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"");
59 if ((size % 2) == 0) {
60 Assert (size >= 2); // cuz require at start >=1 and since even
61 // NB: Could use sort instead of nth_element, and some on the web suggest faster, but sort is O(n*log(n)), and nth_element is O(n) (even
62 // when you do it twice.
63 nth_element (tmp.begin (), tmp.begin () + size / 2 - 1, tmp.end (), forward<INORDER_COMPARE_FUNCTION> (compare));
64 result += tmp[size / 2 - 1];
65 result /= 2;
66 }
67 return result;
68 }
69 template <input_iterator ITERATOR_OF_T, sentinel_for<ITERATOR_OF_T> ITERATOR_OF_T2, Common::IInOrderComparer<typename iterator_traits<ITERATOR_OF_T>::value_type> INORDER_COMPARE_FUNCTION>
70 inline auto Median (const ITERATOR_OF_T& start, ITERATOR_OF_T2&& end, INORDER_COMPARE_FUNCTION&& compare) ->
71 typename iterator_traits<ITERATOR_OF_T>::value_type
72 {
73 return Median<typename iterator_traits<ITERATOR_OF_T>::value_type> (start, forward<ITERATOR_OF_T2> (end),
74 forward<INORDER_COMPARE_FUNCTION> (compare));
75 }
76 template <ranges::range CONTAINER_OF_T, Common::IInOrderComparer<typename CONTAINER_OF_T::value_type> INORDER_COMPARE_FUNCTION>
77 inline auto Median (const CONTAINER_OF_T& container, INORDER_COMPARE_FUNCTION&& compare) -> typename CONTAINER_OF_T::value_type
78 {
79 Require (not container.empty ());
80 return Median<typename CONTAINER_OF_T::value_type> (ranges::begin (container), ranges::end (container),
81 forward<INORDER_COMPARE_FUNCTION> (compare));
82 }
83
84 /*
85 ********************************************************************************
86 **************************** StandardDeviation *********************************
87 ********************************************************************************
88 */
89 template <typename RESULT_TYPE, input_iterator ITERATOR_OF_T, sentinel_for<ITERATOR_OF_T> ITERATOR_OF_T2>
90 RESULT_TYPE StandardDeviation (const ITERATOR_OF_T& start, ITERATOR_OF_T2&& end)
91 {
92 Require (start != forward<ITERATOR_OF_T2> (end)); // the std-deviation of no values would be undefined
93 RESULT_TYPE mean = Mean<RESULT_TYPE> (start, forward<ITERATOR_OF_T2> (end));
94 RESULT_TYPE accum{};
95 size_t n{};
96 for (auto i = start; i != end; ++i) {
97 ++n;
98 accum += (*i - mean) * (*i - mean);
99 }
100 Require (n >= 1); // the std-deviation of no values would be undefined
101 return sqrt (accum / (n - 1));
102 }
103 template <input_iterator ITERATOR_OF_T, sentinel_for<ITERATOR_OF_T> ITERATOR_OF_T2>
104 inline auto StandardDeviation (const ITERATOR_OF_T& start, ITERATOR_OF_T2&& end) ->
105 typename iterator_traits<remove_cvref_t<ITERATOR_OF_T>>::value_type
106 {
107 Require (start != forward<ITERATOR_OF_T2> (end)); // the std-deviation of no values would be undefined
108 return StandardDeviation<typename iterator_traits<ITERATOR_OF_T>::value_type> (start, forward<ITERATOR_OF_T2> (end));
109 }
110 template <ranges::range CONTAINER_OF_T>
111 inline auto StandardDeviation (const CONTAINER_OF_T& container) -> typename CONTAINER_OF_T::value_type
112 {
113 Require (not container.empty ()); // the std-deviation of no values would be undefined
114 return StandardDeviation<typename CONTAINER_OF_T::value_type> (ranges::begin (container), ranges::end (container));
115 }
116
117 /*
118 ********************************************************************************
119 **************************** ComputeCommonStatistics ***************************
120 ********************************************************************************
121 */
122 template <typename T, input_iterator ITERATOR_OF_T, sentinel_for<ITERATOR_OF_T> ITERATOR_OF_T2>
123 CommonStatistics<T> ComputeCommonStatistics (const ITERATOR_OF_T& start, ITERATOR_OF_T2&& end)
124 {
125 CommonStatistics<T> results;
126 if (start != end) {
127 if constexpr (Common::IBuiltinArithmetic<T>) {
128 results.fMin = *min_element (start, forward<ITERATOR_OF_T2> (end));
129 results.fMax = *max_element (start, forward<ITERATOR_OF_T2> (end));
130 }
131 results.fMean = Mean (start, forward<ITERATOR_OF_T2> (end));
132 results.fMedian = Median (start, forward<ITERATOR_OF_T2> (end));
133 if constexpr (Common::IBuiltinArithmetic<T>) {
134 results.fStandardDeviation = StandardDeviation (start, forward<ITERATOR_OF_T2> (end));
135 }
136 }
137 return results;
138 }
139 template <ranges::range CONTAINER_OF_T>
140 inline auto ComputeCommonStatistics (const CONTAINER_OF_T& container) -> CommonStatistics<typename CONTAINER_OF_T::value_type>
141 {
142 return ComputeCommonStatistics<typename CONTAINER_OF_T::value_type> (ranges::begin (container), ranges::end (container));
143 }
144
145}
RESULT_TYPE StandardDeviation(const ITERATOR_OF_T &start, ITERATOR_OF_T2 &&end)
Alias: sd, standard-deviation, stddev.
CommonStatistics< T > ComputeCommonStatistics(const ITERATOR_OF_T &start, ITERATOR_OF_T2 &&end)
handy aggregation of several common random-variable statistics/measurements.
RESULT_TYPE Mean(const ITERATOR_OF_T &start, ITERATOR_OF_T2 &&end)
Mean (average) of a collection of numbers computed.
RESULT_TYPE Median(const ITERATOR_OF_T &start, ITERATOR_OF_T2 &&end, INORDER_COMPARE_FUNCTION &&compare={})
Median of a collection of numbers computed.
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
nonvirtual size_t size() const noexcept
concept true if integral or floatpoint type 'T'. Not sure why not provided by std c++
Definition Concepts.h:69