11#pragma once
22
3+ #include < algorithm>
4+ #include < iterator>
35#include < map>
46#include < vector>
57#include < cmath>
@@ -16,9 +18,6 @@ namespace vtr {
1618// /@brief Calculates the value pow(base, exp)
1719int ipow (int base, int exp);
1820
19- // /@brief Returns the median of an input vector.
20- float median (std::vector<float > vector);
21-
2221// /@brief Linear interpolation/Extrapolation
2322template <typename X, typename Y>
2423Y 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) {
3534 return numerator / denominator;
3635}
3736
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 );
4760 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 ;
4869 }
4970}
5071
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));
5588}
5689
5790/* *
@@ -66,7 +99,7 @@ double median(Container c) {
6699 * geomean = exp( (1 / n) * (log(v_1) + log(v_2) + ... + log(v_n)))
67100 */
68101template <typename InputIterator>
69- double geomean (InputIterator first, InputIterator last, double init = 1 .) {
102+ double geomean (const InputIterator first, const InputIterator last, double init = 1 .) {
70103 double log_sum = std::log (init);
71104 size_t n = 0 ;
72105 for (auto iter = first; iter != last; ++iter) {
@@ -83,13 +116,13 @@ double geomean(InputIterator first, InputIterator last, double init = 1.) {
83116
84117// /@brief Returns the geometric mean of a whole container
85118template <typename Container>
86- double geomean (Container c) {
119+ double geomean (const Container & c) {
87120 return geomean (std::begin (c), std::end (c));
88121}
89122
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)
91124template <typename InputIterator>
92- double arithmean (InputIterator first, InputIterator last, double init = 0 .) {
125+ double arithmean (const InputIterator first, const InputIterator last, double init = 0 .) {
93126 double sum = init;
94127 size_t n = 0 ;
95128 for (auto iter = first; iter != last; ++iter) {
@@ -106,7 +139,7 @@ double arithmean(InputIterator first, InputIterator last, double init = 0.) {
106139
107140// /@brief Returns the aritmatic mean of a whole container
108141template <typename Container>
109- double arithmean (Container c) {
142+ double arithmean (const Container & c) {
110143 return arithmean (std::begin (c), std::end (c));
111144}
112145
0 commit comments