1
1
#pragma once
2
2
3
+ #include < algorithm>
4
+ #include < iterator>
3
5
#include < map>
4
6
#include < vector>
5
7
#include < cmath>
@@ -16,9 +18,6 @@ namespace vtr {
16
18
// /@brief Calculates the value pow(base, exp)
17
19
int ipow (int base, int exp);
18
20
19
- // /@brief Returns the median of an input vector.
20
- float median (std::vector<float > vector);
21
-
22
21
// /@brief Linear interpolation/Extrapolation
23
22
template <typename X, typename Y>
24
23
Y linear_interpolate_or_extrapolate (const std::map<X, Y>* xy_map, X requested_x);
@@ -35,23 +34,57 @@ T safe_ratio(T numerator, T denominator) {
35
34
return numerator / denominator;
36
35
}
37
36
38
- // /@brief Returns the median of the elements in range [first, last]
39
- template <typename InputIterator>
40
- double median (InputIterator first, InputIterator last) {
41
- auto len = std::distance (first, last);
42
- auto iter = first + len / 2 ;
43
-
44
- if (len % 2 == 0 ) {
45
- return (*iter + *(iter + 1 )) / 2 ;
46
- } else {
37
+ // /@brief Returns the median of the elements in range [first, last)
38
+ // / If there are an odd number of elements in the range, returns the
39
+ // / average of the two middle elements (equal distance from the start and end).
40
+ // / NOTE: This method assumes that the container that first and last point to are
41
+ // / pre-sorted
42
+ template <typename ResultTy = double , typename InputIterator>
43
+ ResultTy median_presorted (const InputIterator first, const InputIterator last) {
44
+ // If the distance between first and last is 0 (meaning the set is empty),
45
+ // return a quiet NaN. This should be handled by the user of this code.
46
+ // NOTE: This returns a NaN of double type.
47
+ if (std::distance (first, last) == 0 )
48
+ return std::nan (" " );
49
+
50
+ // Get the distance from the first element to the last element that is included
51
+ // in the set of elements that we are getting the median of. Since "last" is
52
+ // implicitly not included in this set, this is the distance from first to
53
+ // last minus 1.
54
+ auto dist_to_last_inclusive = std::distance (first, last) - 1 ;
55
+
56
+ if (dist_to_last_inclusive % 2 == 0 ) {
57
+ // If the distance to the last inclusive element is even, then there is
58
+ // only a single median element. Return it.
59
+ auto iter = first + (dist_to_last_inclusive / 2 );
47
60
return *iter;
61
+ } else {
62
+ // If the distance to the last inclusive element is odd, then there are
63
+ // two median elements. Return the average of the two.
64
+ auto iter_1 = first + (dist_to_last_inclusive / 2 );
65
+ auto iter_2 = first + (dist_to_last_inclusive / 2 ) + 1 ;
66
+ // Note: To ensure that the division works properly, need to cast one
67
+ // of the operands to the result type.
68
+ return static_cast <ResultTy>(*iter_1 + *iter_2) / 2 ;
48
69
}
49
70
}
50
71
51
- // /@brief Returns the median of a whole container
52
- template <typename Container>
53
- double median (Container c) {
54
- return median (std::begin (c), std::end (c));
72
+ // /@brief Returns the median of a whole container, assuming the container has
73
+ // / not been pre-sorted.
74
+ // / Note: This function is pass by value since the container needs to be
75
+ // / sorted. If the container is already sorted, use median_presorted to
76
+ // / avoid the copy.
77
+ template <typename ResultTy = double , typename Container>
78
+ ResultTy median (Container c) {
79
+ std::sort (std::begin (c), std::end (c));
80
+ return median_presorted<ResultTy>(std::begin (c), std::end (c));
81
+ }
82
+
83
+ // /@brief Returns the median of a whole container, assuming that it is already
84
+ // / sorted.
85
+ template <typename ResultTy = double , typename Container>
86
+ ResultTy median_presorted (const Container &c) {
87
+ return median_presorted<ResultTy>(std::begin (c), std::end (c));
55
88
}
56
89
57
90
/* *
@@ -66,7 +99,7 @@ double median(Container c) {
66
99
* geomean = exp( (1 / n) * (log(v_1) + log(v_2) + ... + log(v_n)))
67
100
*/
68
101
template <typename InputIterator>
69
- double geomean (InputIterator first, InputIterator last, double init = 1 .) {
102
+ double geomean (const InputIterator first, const InputIterator last, double init = 1 .) {
70
103
double log_sum = std::log (init);
71
104
size_t n = 0 ;
72
105
for (auto iter = first; iter != last; ++iter) {
@@ -83,13 +116,13 @@ double geomean(InputIterator first, InputIterator last, double init = 1.) {
83
116
84
117
// /@brief Returns the geometric mean of a whole container
85
118
template <typename Container>
86
- double geomean (Container c) {
119
+ double geomean (const Container & c) {
87
120
return geomean (std::begin (c), std::end (c));
88
121
}
89
122
90
- // /@brief Returns the arithmatic mean of the elements in range [first, last]
123
+ // /@brief Returns the arithmatic mean of the elements in range [first, last)
91
124
template <typename InputIterator>
92
- double arithmean (InputIterator first, InputIterator last, double init = 0 .) {
125
+ double arithmean (const InputIterator first, const InputIterator last, double init = 0 .) {
93
126
double sum = init;
94
127
size_t n = 0 ;
95
128
for (auto iter = first; iter != last; ++iter) {
@@ -106,7 +139,7 @@ double arithmean(InputIterator first, InputIterator last, double init = 0.) {
106
139
107
140
// /@brief Returns the aritmatic mean of a whole container
108
141
template <typename Container>
109
- double arithmean (Container c) {
142
+ double arithmean (const Container & c) {
110
143
return arithmean (std::begin (c), std::end (c));
111
144
}
112
145
0 commit comments