-
Notifications
You must be signed in to change notification settings - Fork 18
/
trimmean.cpp
296 lines (209 loc) · 7.42 KB
/
trimmean.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
//
// TRIMMEAN.cpp
// TRIMMEAN
//
// Created by Kevin Tan on 6/11/17.
//
#include "TRIMMEAN.h"
#include <cstdlib>
///////////////////////////////////////////////////////////////////////////
// Helper Functions
///////////////////////////////////////////////////////////////////////////
/* Partitioning algorithm for QuickSort and QuickSelect */
static long long int partition(long long int array[], long long int low, long long int high) {
// Pick the first element to be the pivot.
long long int pivotIndex = low;
long long int pivot = array[low];
do {
while (low <= high && array[low] <= pivot)
low++;
while (array[high] > pivot)
high--;
if (low < high) {
long long int temp = array[low];
array[low] = array[high];
array[high] = temp;
}
} while (low < high);
long long int temp = array[pivotIndex];
array[pivotIndex] = array[high];
array[high] = temp;
pivotIndex = high;
return pivotIndex;
}
/* QuickSort algorithm */
static void quickSort(long long int array[], long long int first, long long int last) {
if (last - first >= 1) {
long long int pivotIndex = partition(array, first, last);
quickSort(array, first, pivotIndex - 1);
quickSort(array, pivotIndex + 1, last);
}
}
/* QuickSelect algorithm */
static long long int quickSelect(long long int array[], long long int first, long long int last, long long int k) {
if (last - first >= 1) {
long long int pivotIndex = partition(array, first, last);
if (pivotIndex == k)
return array[pivotIndex];
else if (k < pivotIndex)
return quickSelect(array, first, pivotIndex - 1, k);
else
return quickSelect(array, pivotIndex + 1, last, k);
}
return array[first];
}
/* Calculate mean given starting and ending array index */
inline
static double mean(long long int array[], long long int low, long long int high) {
long long int acc = 0;
for (long long int i = low; i <= high; i++)
acc += array[i];
return acc / (double)(high - low + 1);
}
///////////////////////////////////////////////////////////////////////////
// slowTRIMMEAN Implementation
///////////////////////////////////////////////////////////////////////////
// Given an array of long long integers, exclude "percent" percent of data polong long ints from the top and bottom tails
// of a data set. Calculate and return the mean of the remaining data.
//
// inputArray: data set; array of long long integers to examine
// n: size of data set
// percent: fractional number of data polong long ints to exclude, where 0 <= percent < 1
// errorno (optional): polong long inter to ErrorNumber enumerated type for additional error information
//
// If any problems are encountered, return NaN. If the errorno argument is defined, additional information
// about the offending error will be provided in the form of an error code.
double slowTRIMMEAN(long long int inputArray[], long long int n, double percent, ErrorNumber* errorno) {
/* Error Handling */
double NaN = 0 * (1e308 * 1e308);
bool enoIsDefined = errorno != nullptr;
if (n <= 0) {
// size (n) out of range.
if (enoIsDefined)
*errorno = EBADN;
return NaN;
}
if (percent < 0 || percent >= 1) {
// Percent out of range.
if (enoIsDefined)
*errorno = EBADPCNT;
return NaN;
}
if (inputArray == nullptr) {
// inputArray is null.
if (enoIsDefined)
*errorno = EBADARR;
return NaN;
}
/* TRIMMEAN */
// Copy inputArray long long into a local array which we will sort: we don't want to modify the original
// input array.
long long int* array = (long long int*)malloc(sizeof(long long int) * n);
if (array == NULL)
{
if (enoIsDefined)
*errorno = MALLOC_FAILED;
return NaN;
}
for (long long int i = 0; i < n; i++)
array[i] = inputArray[i];
// Use QuickSort algorithm to sort the array.
quickSort(array, 0, n - 1);
// Calculate the number of elements to exclude and round down to the nearest even number.
long long int elementsToExclude = n * percent;
if (elementsToExclude % 2 != 0)
elementsToExclude--;
// Using our sorted array, exclude the lowest and highest (elementsToExclude / 2) elements and
// return the trimmed average.
long long int low = elementsToExclude / 2;
long long int high = n - (elementsToExclude / 2) - 1;
double result = mean(array, low, high);
free(array);
return result;
}
///////////////////////////////////////////////////////////////////////////
// TRIMMEAN Implementation
///////////////////////////////////////////////////////////////////////////
// Given an array of long long integers, exclude "percent" percent of data polong long ints from the top and bottom tails
// of a data set. Calculate and return the mean of the remaining data.
//
// inputArray: data set; array of long long integers to examine
// n: size of data set
// percent: fractional number of data polong long ints to exclude, where 0 <= percent < 1
// errorno (optional): polong long inter to ErrorNumber enumerated type for additional error information
//
// If any errors are encountered, return NaN. If the errorno argument is defined, additional information
// about the offending error will be provided in the form of an error code.
double TRIMMEAN(long long int inputArray[], long long int n, double percent, ErrorNumber* errorno) {
/* Error Handling */
double NaN = 0 * (1e308 * 1e308);
bool enoIsDefined = errorno != nullptr;
if (n <= 0) {
// size (n) out of range.
if (enoIsDefined)
*errorno = EBADN;
return NaN;
}
if (percent < 0 || percent >= 1) {
// Percent out of range.
if (enoIsDefined)
*errorno = EBADPCNT;
return NaN;
}
if (inputArray == nullptr) {
// inputArray is null.
if (enoIsDefined)
*errorno = EBADARR;
return NaN;
}
/* fastTRIMMEAN */
// Calculate the number of elements to exclude and round down to the nearest even number.
long long int elementsToExclude = n * percent;
if (elementsToExclude % 2 != 0)
elementsToExclude--;
// Calculate number of elements trimmed from top/bottom.
long long int half = elementsToExclude / 2;
// Use QuickSelect algorithm to find the lowest and highest values we include in our trimmed sum.
long long int lowBound = quickSelect(inputArray, 0, n - 1, half);
long long int highBound = quickSelect(inputArray, 0, n - 1, n - half - 1);
// Compute weights. If there is only one occurrence of lowBound and highBound in the data set,
// a == b == c == d == weight1 == weight2 == 1.
double a, b = 0, c, d = 0, dm = 0, bm = 0;
double weight1, weight2;
long long int curr;
for (long long int i = 0; i < n; i++) {
curr = inputArray[i];
if (curr < lowBound)
bm++;
else if (curr == lowBound)
b++;
if (curr < highBound)
dm++;
else if (curr == highBound)
d++;
}
a = b + bm - half;
c = n - half - dm;
weight1 = a / b;
weight2 = c / d;
// Compute a trimmed sum.
double trimmedSum = 0;
for (long long int i = 0; i < n; i++) {
// Calculate all possible values and and use conditional moves to optimize branch prediction.
long long int curr = inputArray[i];
double weighted1 = weight1 * curr;
double weighted2 = weight2 * curr;
double toAdd = 0;
if (curr == lowBound)
toAdd = weighted1;
else if (curr == highBound)
toAdd = weighted2;
else if (lowBound < curr && curr < highBound)
toAdd = curr;
// if (curr < lowBound || curr > highBound), exclude the element from our trimmed sum; just
// continue without performing any operations on trimmedSum.
trimmedSum += toAdd;
}
// Return trimmed sum / number of elements in our trimmed sum.
return trimmedSum / (n - 2 * half);
}