SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
median.c
Go to the documentation of this file.
1/**
2 * @file median.c
3 * @brief Computes statistical measures such as median, percentiles, average, and middle values.
4 *
5 * This file contains functions to compute median, percentiles, averages, and the middle value of datasets.
6 * See also the find_XX() routines in rowmedian.c which return the position of the median and other statistics.
7 *
8 * @copyright
9 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
10 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
11 *
12 * @license
13 * This file is distributed under the terms of the Software License Agreement
14 * found in the file LICENSE included with this distribution.
15 *
16 * @author M. Borland, C. Saunders, R. Soliday, Y. Wang
17 */
18
19#include "mdb.h"
20
21/**
22 * @brief Computes the median of an array of doubles.
23 *
24 * @param value Pointer to store the computed median value.
25 * @param x Pointer to the array of doubles.
26 * @param n Number of elements in the array.
27 * @return Returns 1 on success, 0 on failure.
28 */
29long compute_median(double *value, double *x, long n) {
30 static MDB_THREAD_LOCAL double *data = NULL;
31 static MDB_THREAD_LOCAL long last_n = 0;
32 long i;
33
34 if (n <= 0)
35 return 0;
36 if (n > last_n) {
37 data = trealloc(data, sizeof(*data) * n);
38 last_n = n;
39 }
40 for (i = 0; i < n; i++)
41 data[i] = x[i];
42 qsort((void *)data, n, sizeof(*data), double_cmpasc);
43 *value = data[n / 2];
44 return 1;
45}
46
47/**
48 * @brief Computes a specific percentile of an array of doubles.
49 *
50 * @param value Pointer to store the computed percentile value.
51 * @param x Pointer to the array of doubles.
52 * @param n Number of elements in the array.
53 * @param percentile The desired percentile to compute (0-100).
54 * @return Returns 1 on success, 0 on failure.
55 */
56long compute_percentile(double *value, double *x, long n, double percentile) {
57 static MDB_THREAD_LOCAL double *data = NULL;
58 static MDB_THREAD_LOCAL long last_n = 0;
59 long i;
60
61 if (n <= 0 || percentile < 0 || percentile > 100)
62 return 0;
63 if (n > last_n) {
64 data = trealloc(data, sizeof(*data) * n);
65 last_n = n;
66 }
67 for (i = 0; i < n; i++)
68 data[i] = x[i];
69 qsort((void *)data, n, sizeof(*data), double_cmpasc);
70 *value = data[(long)((n - 1) * (percentile / 100.0))];
71 return 1;
72}
73
74/**
75 * @brief Computes multiple percentiles of an array of doubles.
76 *
77 * @param position Pointer to the array to store the computed percentile values.
78 * @param percent Pointer to the array of percentiles to compute (each value between 0-100).
79 * @param positions Number of percentiles to compute.
80 * @param x Pointer to the array of doubles.
81 * @param n Number of elements in the array.
82 * @return Returns 1 on success, 0 on failure.
83 */
84long compute_percentiles(double *position, double *percent, long positions, double *x, long n) {
85 static MDB_THREAD_LOCAL double *data = NULL;
86 static MDB_THREAD_LOCAL long last_n = 0;
87 long ip;
88
89 if (n <= 0 || positions <= 0)
90 return 0;
91 for (ip = 0; ip < positions; ip++)
92 if (percent[ip] < 0 || percent[ip] > 100)
93 return 0;
94 if (n > last_n) {
95 data = trealloc(data, sizeof(*data) * n);
96 last_n = n;
97 }
98 memcpy((char *)data, (char *)x, sizeof(*x) * n);
99 qsort((void *)data, n, sizeof(*data), double_cmpasc);
100 for (ip = 0; ip < positions; ip++)
101 position[ip] = data[(long)((n - 1) * (percent[ip] / 100.0))];
102 return 1;
103}
104
105/**
106 * @brief Computes multiple percentiles of an array of doubles, considering only flagged elements.
107 *
108 * @param position Pointer to the array to store the computed percentile values.
109 * @param percent Pointer to the array of percentiles to compute (each value between 0-100).
110 * @param positions Number of percentiles to compute.
111 * @param x Pointer to the array of doubles.
112 * @param keep Pointer to the array of flags indicating which elements to include.
113 * @param n Number of elements in the array.
114 * @return Returns 1 on success, 0 on failure.
115 */
116long compute_percentiles_flagged(double *position, double *percent, long positions, double *x, int32_t *keep, int64_t n) {
117 static MDB_THREAD_LOCAL double *data = NULL;
118 static MDB_THREAD_LOCAL int64_t last_n = 0;
119 int64_t ip, jp, count;
120
121 if (n <= 0 || positions <= 0)
122 return 0;
123 for (ip = 0; ip < positions; ip++)
124 if (percent[ip] < 0 || percent[ip] > 100)
125 return 0;
126 for (ip=count=0; ip<n; ip++)
127 if (keep[ip])
128 count++;
129 if (!count)
130 return 0;
131 if (count > last_n) {
132 data = trealloc(data, sizeof(*data) * count);
133 last_n = count;
134 }
135 for (ip=jp=0; ip<n; ip++)
136 if (keep[ip])
137 data[jp++] = x[ip];
138 qsort((void *)data, count, sizeof(*data), double_cmpasc);
139 for (ip = 0; ip < positions; ip++)
140 position[ip] = data[(long)((count - 1) * (percent[ip] / 100.0))];
141 return 1;
142}
143
144/**
145 * @brief Computes the average of an array of doubles.
146 *
147 * @param value Pointer to store the computed average value.
148 * @param data Pointer to the array of doubles.
149 * @param n Number of elements in the array.
150 * @return Returns 1 on success, 0 on failure.
151 */
152long compute_average(double *value, double *data, int64_t n) {
153 double sum;
154 int64_t i;
155
156 if (n <= 0)
157 return 0;
158
159 for (i = sum = 0; i < n; i++)
160 sum += data[i];
161 *value = sum / n;
162 return 1;
163}
164
165/**
166 * @brief Computes the middle value between the minimum and maximum of an array of doubles.
167 *
168 * @param value Pointer to store the computed middle value.
169 * @param data Pointer to the array of doubles.
170 * @param n Number of elements in the array.
171 * @return Returns 1 on success, 0 on failure.
172 */
173long compute_middle(double *value, double *data, long n) {
174 double min, max;
175 if (n <= 0)
176 return 0;
177
178 if (!find_min_max(&min, &max, data, n))
179 return 0;
180 *value = (min + max) / 2;
181 return 1;
182}
183
184/**
185 * @brief Approximates multiple percentiles of an array of doubles using histogram bins.
186 *
187 * @param position Pointer to the array to store the computed percentile positions.
188 * @param percent Pointer to the array of percentiles to compute (each value between 0-100).
189 * @param positions Number of percentiles to compute.
190 * @param x Pointer to the array of doubles.
191 * @param n Number of elements in the array.
192 * @param bins Number of histogram bins to use for approximation.
193 * @return Returns 1 on success, 0 on failure.
194 */
195long approximate_percentiles(double *position, double *percent, long positions, double *x, long n,
196 long bins) {
197 double *hist, *cdf, xMin, xMax, xCenter, xRange;
198 long i, j, k;
199 if (bins < 2 || positions <= 0 || n <= 0)
200 return 0;
201 for (i = 0; i < positions; i++)
202 if (percent[i] < 0 || percent[i] > 100)
203 return 0;
204 if (!(hist = malloc(sizeof(*hist) * bins)))
205 return 0;
206 find_min_max(&xMin, &xMax, x, n);
207 xCenter = (xMax + xMin) / 2;
208 xRange = (xMax - xMin) * (1 + 1. / bins) / 2;
209 xMin = xCenter - xRange;
210 xMax = xCenter + xRange;
211 make_histogram(hist, bins, xMin, xMax, x, n, 1);
212
213 cdf = hist;
214 for (i = 1; i < bins; i++)
215 cdf[i] += cdf[i - 1];
216 for (i = 0; i < bins; i++)
217 cdf[i] /= cdf[bins - 1];
218
219 for (j = 0; j < positions; j++) {
220 for (i = k = 0; i < bins; i++) {
221 if (cdf[i] < percent[j] / 100.0)
222 k = i;
223 else
224 break;
225 }
226 position[j] = xMin + (k * (xMax - xMin)) / bins;
227 }
228 free(hist);
229 return 1;
230}
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
Definition array.c:190
int find_min_max(double *min, double *max, double *list, int64_t n)
Finds the minimum and maximum values in a list of doubles.
Definition findMinMax.c:33
long make_histogram(double *hist, long n_bins, double lo, double hi, double *data, int64_t n_pts, long new_start)
Compiles a histogram from data points.
long approximate_percentiles(double *position, double *percent, long positions, double *x, long n, long bins)
Approximates multiple percentiles of an array of doubles using histogram bins.
Definition median.c:195
long compute_average(double *value, double *data, int64_t n)
Computes the average of an array of doubles.
Definition median.c:152
long compute_middle(double *value, double *data, long n)
Computes the middle value between the minimum and maximum of an array of doubles.
Definition median.c:173
long compute_percentiles(double *position, double *percent, long positions, double *x, long n)
Computes multiple percentiles of an array of doubles.
Definition median.c:84
long compute_percentiles_flagged(double *position, double *percent, long positions, double *x, int32_t *keep, int64_t n)
Computes multiple percentiles of an array of doubles, considering only flagged elements.
Definition median.c:116
long compute_percentile(double *value, double *x, long n, double percentile)
Computes a specific percentile of an array of doubles.
Definition median.c:56
long compute_median(double *value, double *x, long n)
Computes the median of an array of doubles.
Definition median.c:29
int double_cmpasc(const void *a, const void *b)
Compare two doubles in ascending order.