SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
moments.c
Go to the documentation of this file.
1/**
2 * @file moments.c
3 * @brief Computes statistical moments and related measures.
4 *
5 * This file contains functions to compute various statistical measures such as standard deviation, moments,
6 * weighted moments, correlations, averages, RMS values, and more. It also includes threaded versions of these
7 * functions for parallel computation using OpenMP.
8 *
9 * @copyright
10 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
11 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
12 *
13 * @license
14 * This file is distributed under the terms of the Software License Agreement
15 * found in the file LICENSE included with this distribution.
16 *
17 * @author M. Borland, C. Saunders, R. Soliday
18 */
19
20#include "mdb.h"
21#if defined(_OPENMP)
22# include <omp.h>
23#else
24void omp_set_num_threads(int a) {}
25#endif
26
27/**
28 * @brief Calculates the standard deviation of an array of doubles.
29 *
30 * This function computes the standard deviation of the given array by invoking the threaded version with
31 * a single thread.
32 *
33 * @param x Pointer to the array of doubles.
34 * @param n Number of elements in the array.
35 * @return Returns the standard deviation as a double.
36 */
37double standardDeviation(double *x, long n) {
38 return standardDeviationThreaded(x, n, 1);
39}
40
41/**
42 * @brief Calculates the standard deviation of an array of doubles using multiple threads.
43 *
44 * This function computes the standard deviation of the given array using the specified number of threads.
45 *
46 * @param x Pointer to the array of doubles.
47 * @param n Number of elements in the array.
48 * @param numThreads Number of threads to use for computation.
49 * @return Returns the standard deviation as a double.
50 */
51double standardDeviationThreaded(double *x, long n, long numThreads) {
52 long i;
53 double sum = 0, sumSqr = 0, mean;
54 if (n < 1)
55 return (0.0);
56 omp_set_num_threads(numThreads);
57#pragma omp parallel shared(sum)
58 {
59 double partial_sum = 0;
60#pragma omp for
61 for (i = 0; i < n; i++) {
62 partial_sum += x[i];
63 }
64#pragma omp critical
65 {
66 /* Found this is necessary to avoid variation of results in cases that should be identical */
67 if (numThreads > 1)
68 sum += partial_sum;
69 else
70 sum = partial_sum;
71 }
72 }
73 mean = sum / n;
74#pragma omp parallel shared(sumSqr)
75 {
76 double partial_sumSqr = 0;
77#pragma omp for
78 for (i = 0; i < n; i++) {
79 double value = x[i] - mean;
80 partial_sumSqr += value * value;
81 }
82#pragma omp critical
83 {
84 /* Found this is necessary to avoid variation of results in cases that should be identical */
85 if (numThreads > 1)
86 sumSqr += partial_sumSqr;
87 else
88 sumSqr = partial_sumSqr;
89 }
90 }
91 return sqrt(sumSqr / (n - 1));
92}
93
94/**
95 * @brief Computes the mean, RMS, standard deviation, and mean absolute deviation of an array.
96 *
97 * This function calculates multiple statistical moments of the provided data array by invoking the threaded
98 * version with a single thread.
99 *
100 * @param mean Pointer to store the computed mean value.
101 * @param rms Pointer to store the computed RMS value.
102 * @param standDev Pointer to store the computed standard deviation.
103 * @param meanAbsoluteDev Pointer to store the computed mean absolute deviation.
104 * @param x Pointer to the array of doubles.
105 * @param n Number of elements in the array.
106 * @return Returns the number of degrees of freedom (n - 1) on success, 0 on failure.
107 */
108long computeMoments(double *mean, double *rms, double *standDev,
109 double *meanAbsoluteDev, double *x, long n) {
110 return computeMomentsThreaded(mean, rms, standDev, meanAbsoluteDev, x, n, 1);
111}
112
113/**
114 * @brief Computes the mean, RMS, standard deviation, and mean absolute deviation of an array using multiple threads.
115 *
116 * This function calculates multiple statistical moments of the provided data array using the specified number of threads.
117 *
118 * @param mean Pointer to store the computed mean value.
119 * @param rms Pointer to store the computed RMS value.
120 * @param standDev Pointer to store the computed standard deviation.
121 * @param meanAbsoluteDev Pointer to store the computed mean absolute deviation.
122 * @param x Pointer to the array of doubles.
123 * @param n Number of elements in the array.
124 * @param numThreads Number of threads to use for computation.
125 * @return Returns the number of degrees of freedom (n - 1) on success, 0 on failure.
126 */
127long computeMomentsThreaded(double *mean, double *rms, double *standDev,
128 double *meanAbsoluteDev, double *x, long n, long numThreads) {
129 long i;
130 double sum = 0, sumSqr = 0, sum2 = 0;
131 double lMean, lRms, lStDev, lMAD;
132
133 if (!mean)
134 mean = &lMean;
135 if (!rms)
136 rms = &lRms;
137 if (!standDev)
138 standDev = &lStDev;
139 if (!meanAbsoluteDev)
140 meanAbsoluteDev = &lMAD;
141
142 *mean = *standDev = *meanAbsoluteDev = DBL_MAX;
143
144 if (n < 1)
145 return (0);
146
147 omp_set_num_threads(numThreads);
148
149#pragma omp parallel shared(sumSqr, sum)
150 {
151 double partial_sumSqr = 0;
152 double partial_sum = 0;
153#pragma omp for
154 for (i = 0; i < n; i++) {
155 double value = x[i];
156 partial_sum += value;
157 partial_sumSqr += sqr(value);
158 }
159#pragma omp critical
160 {
161 /* Found this is necessary to avoid variation of results in cases that should be identical */
162 if (numThreads > 1) {
163 sum += partial_sum;
164 sumSqr += partial_sumSqr;
165 } else {
166 sum = partial_sum;
167 sumSqr = partial_sumSqr;
168 }
169 }
170 }
171 *mean = sum / n;
172 *rms = sqrt(sumSqr / n);
173
174 sum = 0;
175#pragma omp parallel shared(sum, sum2)
176 {
177 double partial_sum = 0;
178 double partial_sum2 = 0;
179#pragma omp for
180 for (i = 0; i < n; i++) {
181 double value = x[i] - *mean;
182 partial_sum2 += value * value;
183 partial_sum += fabs(value);
184 }
185#pragma omp critical
186 {
187 /* Found this is necessary to avoid variation of results in cases that should be identical */
188 if (numThreads > 1) {
189 sum2 += partial_sum2;
190 sum += partial_sum;
191 } else {
192 sum2 = partial_sum2;
193 sum = partial_sum;
194 }
195 }
196 }
197 if (n)
198 *standDev = sqrt(sum2 / (n - 1));
199 *meanAbsoluteDev = sum / n;
200
201 return (n - 1);
202}
203
204/**
205 * @brief Computes weighted statistical moments of an array.
206 *
207 * This function calculates the weighted mean, RMS, standard deviation, and mean absolute deviation of the provided
208 * data array by invoking the threaded version with a single thread.
209 *
210 * @param mean Pointer to store the computed weighted mean value.
211 * @param rms Pointer to store the computed weighted RMS value.
212 * @param standDev Pointer to store the computed weighted standard deviation.
213 * @param meanAbsoluteDev Pointer to store the computed weighted mean absolute deviation.
214 * @param x Pointer to the array of doubles.
215 * @param w Pointer to the array of weights corresponding to each data point.
216 * @param n Number of elements in the array.
217 * @return Returns 1 on success, 0 on failure.
218 */
219long computeWeightedMoments(double *mean, double *rms, double *standDev,
220 double *meanAbsoluteDev, double *x, double *w, long n) {
221 return computeWeightedMomentsThreaded(mean, rms, standDev, meanAbsoluteDev, x, w, n, 1);
222}
223
224/**
225 * @brief Computes weighted statistical moments of an array using multiple threads.
226 *
227 * This function calculates the weighted mean, RMS, standard deviation, and mean absolute deviation of the provided
228 * data array using the specified number of threads.
229 *
230 * @param mean Pointer to store the computed weighted mean value.
231 * @param rms Pointer to store the computed weighted RMS value.
232 * @param standDev Pointer to store the computed weighted standard deviation.
233 * @param meanAbsoluteDev Pointer to store the computed weighted mean absolute deviation.
234 * @param x Pointer to the array of doubles.
235 * @param w Pointer to the array of weights corresponding to each data point.
236 * @param n Number of elements in the array.
237 * @param numThreads Number of threads to use for computation.
238 * @return Returns 1 on success, 0 on failure.
239 */
240long computeWeightedMomentsThreaded(double *mean, double *rms, double *standDev,
241 double *meanAbsoluteDev, double *x, double *w, long n, long numThreads) {
242 long i;
243 double sumW = 0, sum = 0, sumWx = 0, sumSqrWx = 0, sum2 = 0;
244
245 double lMean, lRms, lStDev, lMAD;
246
247 if (!mean)
248 mean = &lMean;
249 if (!rms)
250 rms = &lRms;
251 if (!standDev)
252 standDev = &lStDev;
253 if (!meanAbsoluteDev)
254 meanAbsoluteDev = &lMAD;
255
256 *mean = *standDev = *meanAbsoluteDev = DBL_MAX;
257
258 if (n < 1)
259 return (0);
260
261 omp_set_num_threads(numThreads);
262
263#pragma omp parallel shared(sumW, sumWx, sumSqrWx)
264 {
265 double partial_sumW = 0;
266 double partial_sumWx = 0;
267 double partial_sumSqrWx = 0;
268#pragma omp for
269 for (i = 0; i < n; i++) {
270 partial_sumW += w[i];
271 double value = x[i];
272 partial_sumWx += value * w[i];
273 partial_sumSqrWx += value * value * w[i];
274 }
275#pragma omp critical
276 {
277 /* Found this is necessary to avoid variation of results in cases that should be identical */
278 if (numThreads > 1) {
279 sumW += partial_sumW;
280 sumWx += partial_sumWx;
281 sumSqrWx += partial_sumSqrWx;
282 } else {
283 sumW = partial_sumW;
284 sumWx = partial_sumWx;
285 sumSqrWx = partial_sumSqrWx;
286 }
287 }
288 }
289
290 if (sumW) {
291 *mean = sumWx / sumW;
292 *rms = sqrt(sumSqrWx / sumW);
293#pragma omp parallel shared(sum, sum2)
294 {
295 double partial_sum = 0;
296 double partial_sum2 = 0;
297#pragma omp for
298 for (i = 0; i < n; i++) {
299 double value = x[i] - *mean;
300 partial_sum += value * w[i];
301 partial_sum2 += value * value * w[i];
302 }
303#pragma omp critical
304 {
305 /* Found this is necessary to avoid variation of results in cases that should be identical */
306 if (numThreads > 1) {
307 sum += partial_sum;
308 sum2 += partial_sum2;
309 } else {
310 sum = partial_sum;
311 sum2 = partial_sum2;
312 }
313 }
314 }
315 if (n)
316 /* adjust for n-1 weighting */
317 *standDev = sqrt((sum2 * n) / (sumW * (n - 1.0)));
318 *meanAbsoluteDev = sum / sumW;
319 return (1);
320 }
321 return (0);
322}
323
324long accumulateMoments(double *mean, double *rms, double *standDev,
325 double *x, long n, long reset) {
326 return accumulateMomentsThreaded(mean, rms, standDev, x, n, reset, 1);
327}
328
329long accumulateMomentsThreaded(double *mean, double *rms, double *standDev,
330 double *x, long n, long reset, long numThreads) {
331 long i;
332 static MDB_THREAD_LOCAL double savedSum = 0, savedSumSqr = 0;
333 static MDB_THREAD_LOCAL long savedNTotal;
334 double sum = savedSum, sumSqr = savedSumSqr;
335 long nTotal = savedNTotal;
336
337 if (reset)
338 nTotal = sum = sumSqr = 0;
339
340 nTotal += n;
341 if (nTotal < 1) {
342 savedSum = sum;
343 savedSumSqr = sumSqr;
344 savedNTotal = nTotal;
345 return (0);
346 }
347
348 omp_set_num_threads(numThreads);
349#pragma omp parallel shared(sum, sumSqr)
350 {
351 double partial_sum = 0;
352 double partial_sumSqr = 0;
353#pragma omp for
354 for (i = 0; i < n; i++) {
355 double value = x[i];
356 partial_sum += value;
357 partial_sumSqr += sqr(value);
358 }
359#pragma omp critical
360 {
361 /* Found this is necessary to avoid variation of results in cases that should be identical */
362 if (numThreads > 1) {
363 sum += partial_sum;
364 sumSqr += partial_sumSqr;
365 } else {
366 sum = partial_sum;
367 sumSqr = partial_sumSqr;
368 }
369 }
370 }
371
372 *mean = sum / nTotal;
373 *rms = sqrt(sumSqr / nTotal);
374 *standDev = sqrt((sumSqr / nTotal - sqr(*mean)) * nTotal / (nTotal - 1.0));
375 savedSum = sum;
376 savedSumSqr = sumSqr;
377 savedNTotal = nTotal;
378
379 return (1);
380}
381
382long accumulateWeightedMoments(double *mean, double *rms, double *standDev,
383 double *x, double *w, long n, long reset) {
384 return accumulateWeightedMomentsThreaded(mean, rms, standDev, x, w, n, reset, 1);
385}
386
387long accumulateWeightedMomentsThreaded(double *mean, double *rms, double *standDev,
388 double *x, double *w, long n, long reset, long numThreads) {
389 long i;
390 static MDB_THREAD_LOCAL double savedSumW = 0, savedSumWx = 0, savedSumSqrWx = 0;
391 static MDB_THREAD_LOCAL long savedNTotal;
392 double sumW = savedSumW, sumWx = savedSumWx, sumSqrWx = savedSumSqrWx;
393 long nTotal = savedNTotal;
394
395 if (reset)
396 sumW = sumWx = sumSqrWx = nTotal = 0;
397
398 nTotal += n;
399 if (nTotal < 1) {
400 savedSumW = sumW;
401 savedSumWx = sumWx;
402 savedSumSqrWx = sumSqrWx;
403 savedNTotal = nTotal;
404 return (0);
405 }
406
407 omp_set_num_threads(numThreads);
408#pragma omp parallel shared(sumW, sumWx, sumSqrWx)
409 {
410 double partial_sumW = 0;
411 double partial_sumWx = 0;
412 double partial_sumSqrWx = 0;
413#pragma omp for
414 for (i = 0; i < n; i++) {
415 partial_sumW += w[i];
416 partial_sumWx += w[i] * x[i];
417 partial_sumSqrWx += x[i] * x[i] * w[i];
418 }
419#pragma omp critical
420 {
421 /* Found this is necessary to avoid variation of results in cases that should be identical */
422 if (numThreads > 1) {
423 sumW += partial_sumW;
424 sumWx += partial_sumWx;
425 sumSqrWx += partial_sumSqrWx;
426 } else {
427 sumW = partial_sumW;
428 sumWx = partial_sumWx;
429 sumSqrWx = partial_sumSqrWx;
430 }
431 }
432 }
433 if (sumW) {
434 *mean = sumWx / sumW;
435 *rms = sqrt(sumSqrWx / sumW);
436 *standDev = sqrt((sumSqrWx / sumW - sqr(*mean)) * (nTotal / (nTotal - 1.0)));
437 savedSumW = sumW;
438 savedSumWx = sumWx;
439 savedSumSqrWx = sumSqrWx;
440 savedNTotal = nTotal;
441 return (1);
442 }
443 savedSumW = sumW;
444 savedSumWx = sumWx;
445 savedSumSqrWx = sumSqrWx;
446 savedNTotal = nTotal;
447 return (0);
448}
449
450/**
451 * @brief Computes the correlations between two datasets.
452 *
453 * This function calculates the correlation coefficients C11, C12, and C22 between two arrays of doubles by invoking
454 * the threaded version with a single thread.
455 *
456 * @param C11 Pointer to store the computed C11 correlation coefficient.
457 * @param C12 Pointer to store the computed C12 correlation coefficient.
458 * @param C22 Pointer to store the computed C22 correlation coefficient.
459 * @param x Pointer to the first array of doubles.
460 * @param y Pointer to the second array of doubles.
461 * @param n Number of elements in each array.
462 * @return Returns 1 on success, 0 on failure.
463 */
464long computeCorrelations(double *C11, double *C12, double *C22, double *x, double *y, long n) {
465 return computeCorrelationsThreaded(C11, C12, C22, x, y, n, 1);
466}
467
468/**
469 * @brief Computes the correlations between two datasets using multiple threads.
470 *
471 * This function calculates the correlation coefficients C11, C12, and C22 between two arrays of doubles using the
472 * specified number of threads.
473 *
474 * @param C11 Pointer to store the computed C11 correlation coefficient.
475 * @param C12 Pointer to store the computed C12 correlation coefficient.
476 * @param C22 Pointer to store the computed C22 correlation coefficient.
477 * @param x Pointer to the first array of doubles.
478 * @param y Pointer to the second array of doubles.
479 * @param n Number of elements in each array.
480 * @param numThreads Number of threads to use for computation.
481 * @return Returns 1 on success, 0 on failure.
482 */
483long computeCorrelationsThreaded(double *C11, double *C12, double *C22, double *x, double *y, long n, long numThreads) {
484 long i;
485 double xAve = 0, yAve = 0;
486
487 *C11 = *C12 = *C22 = 0;
488 if (!n)
489 return (0);
490
491 omp_set_num_threads(numThreads);
492#pragma omp parallel shared(xAve, yAve)
493 {
494 double partial_xAve = 0;
495 double partial_yAve = 0;
496#pragma omp for
497 for (i = 0; i < n; i++) {
498 partial_xAve += x[i];
499 partial_yAve += y[i];
500 }
501#pragma omp critical
502 {
503 /* Found this is necessary to avoid variation of results in cases that should be identical */
504 if (numThreads > 1) {
505 xAve += partial_xAve;
506 yAve += partial_yAve;
507 } else {
508 xAve = partial_xAve;
509 yAve = partial_yAve;
510 }
511 }
512 }
513 xAve /= n;
514 yAve /= n;
515
516#pragma omp parallel shared(C11, C12, C22)
517 {
518 double partial_C11 = 0;
519 double partial_C12 = 0;
520 double partial_C22 = 0;
521#pragma omp for
522 for (i = 0; i < n; i++) {
523 double dx = x[i] - xAve;
524 double dy = y[i] - yAve;
525 partial_C11 += dx * dx;
526 partial_C12 += dx * dy;
527 partial_C22 += dy * dy;
528 }
529#pragma omp critical
530 {
531 /* Found this is necessary to avoid variation of results in cases that should be identical */
532 if (numThreads > 1) {
533 *C11 += partial_C11;
534 *C12 += partial_C12;
535 *C22 += partial_C22;
536 } else {
537 *C11 = partial_C11;
538 *C12 = partial_C12;
539 *C22 = partial_C22;
540 }
541 }
542 }
543 *C11 /= n;
544 *C12 /= n;
545 *C22 /= n;
546
547 return (1);
548}
549
550/**
551 * @brief Calculates the arithmetic average of an array of doubles.
552 *
553 * This function computes the arithmetic average of the given array by invoking the threaded version with
554 * a single thread.
555 *
556 * @param y Pointer to the array of doubles.
557 * @param n Number of elements in the array.
558 * @return Returns the arithmetic average as a double.
559 */
560double arithmeticAverage(double *y, long n) {
561 return arithmeticAverageThreaded(y, n, 1);
562}
563
564/**
565 * @brief Calculates the arithmetic average of an array of doubles using multiple threads.
566 *
567 * This function computes the arithmetic average of the given array using the specified number of threads.
568 *
569 * @param y Pointer to the array of doubles.
570 * @param n Number of elements in the array.
571 * @param numThreads Number of threads to use for computation.
572 * @return Returns the arithmetic average as a double.
573 */
574double arithmeticAverageThreaded(double *y, long n, long numThreads) {
575 long i;
576 double sum = 0;
577
578 if (!n)
579 return (0.0);
580 omp_set_num_threads(numThreads);
581#pragma omp parallel shared(sum)
582 {
583 double partial_sum = 0;
584#pragma omp for
585 for (i = 0; i < n; i++) {
586 partial_sum += y[i];
587 }
588#pragma omp critical
589 {
590 /* Found this is necessary to avoid variation of results in cases that should be identical */
591 if (numThreads > 1)
592 sum += partial_sum;
593 else
594 sum = partial_sum;
595 }
596 }
597 return (sum / n);
598}
599
600/**
601 * @brief Calculates the RMS (Root Mean Square) value of an array of doubles.
602 *
603 * This function computes the RMS value of the given array by invoking the threaded version with
604 * a single thread.
605 *
606 * @param y Pointer to the array of doubles.
607 * @param n Number of elements in the array.
608 * @return Returns the RMS value as a double.
609 */
610double rmsValue(double *y, long n) {
611 return rmsValueThreaded(y, n, 1);
612}
613
614/**
615 * @brief Calculates the RMS (Root Mean Square) value of an array of doubles using multiple threads.
616 *
617 * This function computes the RMS value of the given array using the specified number of threads.
618 *
619 * @param y Pointer to the array of doubles.
620 * @param n Number of elements in the array.
621 * @param numThreads Number of threads to use for computation.
622 * @return Returns the RMS value as a double.
623 */
624double rmsValueThreaded(double *y, long n, long numThreads) {
625 long i;
626 double sum = 0;
627
628 if (!n)
629 return (0.0);
630 omp_set_num_threads(numThreads);
631#pragma omp parallel shared(sum)
632 {
633 double partial_sum = 0;
634#pragma omp for
635 for (i = 0; i < n; i++) {
636 partial_sum += y[i] * y[i];
637 }
638#pragma omp critical
639 {
640 /* Found this is necessary to avoid variation of results in cases that should be identical */
641 if (numThreads > 1)
642 sum += partial_sum;
643 else
644 sum = partial_sum;
645 }
646 }
647 return (sqrt(sum / n));
648}
649
650/**
651 * @brief Calculates the mean absolute deviation of an array of doubles.
652 *
653 * This function computes the mean absolute deviation of the given array by invoking the threaded version with
654 * a single thread.
655 *
656 * @param y Pointer to the array of doubles.
657 * @param n Number of elements in the array.
658 * @return Returns the mean absolute deviation as a double.
659 */
660double meanAbsoluteDeviation(double *y, long n) {
661 return meanAbsoluteDeviationThreaded(y, n, 1);
662}
663
664/**
665 * @brief Calculates the mean absolute deviation of an array of doubles using multiple threads.
666 *
667 * This function computes the mean absolute deviation of the given array using the specified number of threads.
668 *
669 * @param y Pointer to the array of doubles.
670 * @param n Number of elements in the array.
671 * @param numThreads Number of threads to use for computation.
672 * @return Returns the mean absolute deviation as a double.
673 */
674double meanAbsoluteDeviationThreaded(double *y, long n, long numThreads) {
675 long i;
676 double ave = 0, sum = 0;
677
678 if (!n)
679 return (0.0);
680 omp_set_num_threads(numThreads);
681#pragma omp parallel shared(ave)
682 {
683 double partial_ave = 0;
684#pragma omp for
685 for (i = 0; i < n; i++) {
686 partial_ave += y[i];
687 }
688#pragma omp critical
689 {
690 /* Found this is necessary to avoid variation of results in cases that should be identical */
691 if (numThreads > 1)
692 ave += partial_ave;
693 else
694 ave = partial_ave;
695 }
696 }
697 ave /= n;
698#pragma omp parallel shared(sum)
699 {
700 double partial_sum = 0;
701#pragma omp for
702 for (i = 0; i < n; i++) {
703 partial_sum += fabs(y[i] - ave);
704 }
705#pragma omp critical
706 {
707 if (numThreads > 1)
708 sum += partial_sum;
709 else
710 sum = partial_sum;
711 }
712 }
713 return (sum / n);
714}
715
716/**
717 * @brief Calculates the weighted average of an array of doubles.
718 *
719 * This function computes the weighted average of the given array by invoking the threaded version with
720 * a single thread.
721 *
722 * @param y Pointer to the array of doubles.
723 * @param w Pointer to the array of weights corresponding to each data point.
724 * @param n Number of elements in the array.
725 * @return Returns the weighted average as a double.
726 */
727double weightedAverage(double *y, double *w, long n) {
728 return weightedAverageThreaded(y, w, n, 1);
729}
730
731/**
732 * @brief Calculates the weighted average of an array of doubles using multiple threads.
733 *
734 * This function computes the weighted average of the given array using the specified number of threads.
735 *
736 * @param y Pointer to the array of doubles.
737 * @param w Pointer to the array of weights corresponding to each data point.
738 * @param n Number of elements in the array.
739 * @param numThreads Number of threads to use for computation.
740 * @return Returns the weighted average as a double.
741 */
742double weightedAverageThreaded(double *y, double *w, long n, long numThreads) {
743 long i;
744 double ySum = 0, wSum = 0;
745
746 if (!n)
747 return 0.0;
748 omp_set_num_threads(numThreads);
749#pragma omp parallel shared(wSum, ySum)
750 {
751 double partial_wSum = 0;
752 double partial_ySum = 0;
753#pragma omp for
754 for (i = 0; i < n; i++) {
755 partial_wSum += w[i];
756 partial_ySum += y[i] * w[i];
757 }
758#pragma omp critical
759 {
760 /* Found this is necessary to avoid variation of results in cases that should be identical */
761 if (numThreads > 1) {
762 wSum += partial_wSum;
763 ySum += partial_ySum;
764 } else {
765 wSum = partial_wSum;
766 ySum = partial_ySum;
767 }
768 }
769 }
770 if (wSum)
771 return ySum / wSum;
772 return 0.0;
773}
774
775/**
776 * @brief Calculates the weighted RMS (Root Mean Square) value of an array of doubles.
777 *
778 * This function computes the weighted RMS value of the given array by invoking the threaded version with
779 * a single thread.
780 *
781 * @param y Pointer to the array of doubles.
782 * @param w Pointer to the array of weights corresponding to each data point.
783 * @param n Number of elements in the array.
784 * @return Returns the weighted RMS value as a double.
785 */
786double weightedRMS(double *y, double *w, long n) {
787 return weightedRMSThreaded(y, w, n, 1);
788}
789
790/**
791 * @brief Calculates the weighted RMS (Root Mean Square) value of an array of doubles using multiple threads.
792 *
793 * This function computes the weighted RMS value of the given array using the specified number of threads.
794 *
795 * @param y Pointer to the array of doubles.
796 * @param w Pointer to the array of weights corresponding to each data point.
797 * @param n Number of elements in the array.
798 * @param numThreads Number of threads to use for computation.
799 * @return Returns the weighted RMS value as a double.
800 */
801double weightedRMSThreaded(double *y, double *w, long n, long numThreads) {
802 long i;
803 double sum = 0, wSum = 0;
804
805 if (!n)
806 return (0.0);
807 omp_set_num_threads(numThreads);
808#pragma omp parallel shared(sum, wSum)
809 {
810 double partial_sum = 0;
811 double partial_wSum = 0;
812#pragma omp for
813 for (i = 0; i < n; i++) {
814 partial_sum += y[i] * y[i] * w[i];
815 partial_wSum += w[i];
816 }
817#pragma omp critical
818 {
819 /* Found this is necessary to avoid variation of results in cases that should be identical */
820 if (numThreads > 1) {
821 sum += partial_sum;
822 wSum += partial_wSum;
823 } else {
824 sum = partial_sum;
825 wSum = partial_wSum;
826 }
827 }
828 }
829 if (wSum)
830 return sqrt(sum / wSum);
831 return 0.0;
832}
833
834/**
835 * @brief Calculates the weighted mean absolute deviation of an array of doubles.
836 *
837 * This function computes the weighted mean absolute deviation of the given array by invoking the threaded version with
838 * a single thread.
839 *
840 * @param y Pointer to the array of doubles.
841 * @param w Pointer to the array of weights corresponding to each data point.
842 * @param n Number of elements in the array.
843 * @return Returns the weighted mean absolute deviation as a double.
844 */
845double weightedMAD(double *y, double *w, long n) {
846 return weightedMADThreaded(y, w, n, 1);
847}
848
849/**
850 * @brief Calculates the weighted mean absolute deviation of an array of doubles using multiple threads.
851 *
852 * This function computes the weighted mean absolute deviation of the given array using the specified number of threads.
853 *
854 * @param y Pointer to the array of doubles.
855 * @param w Pointer to the array of weights corresponding to each data point.
856 * @param n Number of elements in the array.
857 * @param numThreads Number of threads to use for computation.
858 * @return Returns the weighted mean absolute deviation as a double.
859 */
860double weightedMADThreaded(double *y, double *w, long n, long numThreads) {
861 long i;
862 double mean, sum = 0, wSum = 0;
863
864 if (!n)
865 return (0.0);
866 omp_set_num_threads(numThreads);
867#pragma omp parallel shared(sum, wSum)
868 {
869 double partial_sum = 0;
870 double partial_wSum = 0;
871#pragma omp for
872 for (i = 0; i < n; i++) {
873 partial_sum += y[i] * w[i];
874 partial_wSum += w[i];
875 }
876#pragma omp critical
877 {
878 /* Found this is necessary to avoid variation of results in cases that should be identical */
879 if (numThreads > 1) {
880 sum += partial_sum;
881 wSum += partial_wSum;
882 } else {
883 sum = partial_sum;
884 wSum = partial_wSum;
885 }
886 }
887 }
888 if (!wSum)
889 return 0.0;
890 mean = sum / wSum;
891 sum = 0;
892#pragma omp parallel shared(sum)
893 {
894 double partial_sum = 0;
895#pragma omp for
896 for (i = 0; i < n; i++) {
897 partial_sum += fabs(y[i] - mean) * w[i];
898 }
899#pragma omp critical
900 {
901 /* Found this is necessary to avoid variation of results in cases that should be identical */
902 if (numThreads > 1)
903 sum += partial_sum;
904 else
905 sum = partial_sum;
906 }
907 }
908 return sum / wSum;
909}
910
911/**
912 * @brief Calculates the weighted standard deviation of an array of doubles.
913 *
914 * This function computes the weighted standard deviation of the given array by invoking the threaded version with
915 * a single thread.
916 *
917 * @param y Pointer to the array of doubles.
918 * @param w Pointer to the array of weights corresponding to each data point.
919 * @param n Number of elements in the array.
920 * @return Returns the weighted standard deviation as a double.
921 */
922double weightedStDev(double *y, double *w, long n) {
923 return weightedStDevThreaded(y, w, n, 1);
924}
925
926/**
927 * @brief Calculates the weighted standard deviation of an array of doubles using multiple threads.
928 *
929 * This function computes the weighted standard deviation of the given array using the specified number of threads.
930 *
931 * @param y Pointer to the array of doubles.
932 * @param w Pointer to the array of weights corresponding to each data point.
933 * @param n Number of elements in the array.
934 * @param numThreads Number of threads to use for computation.
935 * @return Returns the weighted standard deviation as a double.
936 */
937double weightedStDevThreaded(double *y, double *w, long n, long numThreads) {
938 long i;
939 double mean, sum = 0, wSum = 0;
940
941 if (!n)
942 return (0.0);
943 omp_set_num_threads(numThreads);
944#pragma omp parallel shared(sum, wSum)
945 {
946 double partial_sum = 0;
947 double partial_wSum = 0;
948#pragma omp for
949 for (i = 0; i < n; i++) {
950 partial_sum += y[i] * w[i];
951 partial_wSum += w[i];
952 }
953#pragma omp critical
954 {
955 /* Found this is necessary to avoid variation of results in cases that should be identical */
956 if (numThreads > 1) {
957 sum += partial_sum;
958 wSum += partial_wSum;
959 } else {
960 sum = partial_sum;
961 wSum = partial_wSum;
962 }
963 }
964 }
965 if (!wSum)
966 return 0.0;
967 mean = sum / wSum;
968 sum = 0;
969#pragma omp parallel shared(sum)
970 {
971 double partial_sum = 0;
972#pragma omp for
973 for (i = 0; i < n; i++) {
974 double value = y[i] - mean;
975 partial_sum += value * value * w[i];
976 }
977#pragma omp critical
978 {
979 /* Found this is necessary to avoid variation of results in cases that should be identical */
980 if (numThreads > 1)
981 sum += partial_sum;
982 else
983 sum = partial_sum;
984 }
985 }
986 return sqrt((sum * n) / (wSum * (n - 1.0)));
987}
double arithmeticAverage(double *y, long n)
Calculates the arithmetic average of an array of doubles.
Definition moments.c:560
double weightedStDevThreaded(double *y, double *w, long n, long numThreads)
Calculates the weighted standard deviation of an array of doubles using multiple threads.
Definition moments.c:937
double standardDeviationThreaded(double *x, long n, long numThreads)
Calculates the standard deviation of an array of doubles using multiple threads.
Definition moments.c:51
long computeWeightedMoments(double *mean, double *rms, double *standDev, double *meanAbsoluteDev, double *x, double *w, long n)
Computes weighted statistical moments of an array.
Definition moments.c:219
long computeWeightedMomentsThreaded(double *mean, double *rms, double *standDev, double *meanAbsoluteDev, double *x, double *w, long n, long numThreads)
Computes weighted statistical moments of an array using multiple threads.
Definition moments.c:240
double weightedStDev(double *y, double *w, long n)
Calculates the weighted standard deviation of an array of doubles.
Definition moments.c:922
double rmsValueThreaded(double *y, long n, long numThreads)
Calculates the RMS (Root Mean Square) value of an array of doubles using multiple threads.
Definition moments.c:624
long computeMoments(double *mean, double *rms, double *standDev, double *meanAbsoluteDev, double *x, long n)
Computes the mean, RMS, standard deviation, and mean absolute deviation of an array.
Definition moments.c:108
double arithmeticAverageThreaded(double *y, long n, long numThreads)
Calculates the arithmetic average of an array of doubles using multiple threads.
Definition moments.c:574
double weightedRMSThreaded(double *y, double *w, long n, long numThreads)
Calculates the weighted RMS (Root Mean Square) value of an array of doubles using multiple threads.
Definition moments.c:801
long computeCorrelationsThreaded(double *C11, double *C12, double *C22, double *x, double *y, long n, long numThreads)
Computes the correlations between two datasets using multiple threads.
Definition moments.c:483
double meanAbsoluteDeviationThreaded(double *y, long n, long numThreads)
Calculates the mean absolute deviation of an array of doubles using multiple threads.
Definition moments.c:674
long computeCorrelations(double *C11, double *C12, double *C22, double *x, double *y, long n)
Computes the correlations between two datasets.
Definition moments.c:464
long computeMomentsThreaded(double *mean, double *rms, double *standDev, double *meanAbsoluteDev, double *x, long n, long numThreads)
Computes the mean, RMS, standard deviation, and mean absolute deviation of an array using multiple th...
Definition moments.c:127
double weightedMADThreaded(double *y, double *w, long n, long numThreads)
Calculates the weighted mean absolute deviation of an array of doubles using multiple threads.
Definition moments.c:860
double meanAbsoluteDeviation(double *y, long n)
Calculates the mean absolute deviation of an array of doubles.
Definition moments.c:660
double weightedMAD(double *y, double *w, long n)
Calculates the weighted mean absolute deviation of an array of doubles.
Definition moments.c:845
double weightedRMS(double *y, double *w, long n)
Calculates the weighted RMS (Root Mean Square) value of an array of doubles.
Definition moments.c:786
double rmsValue(double *y, long n)
Calculates the RMS (Root Mean Square) value of an array of doubles.
Definition moments.c:610
double weightedAverageThreaded(double *y, double *w, long n, long numThreads)
Calculates the weighted average of an array of doubles using multiple threads.
Definition moments.c:742
double weightedAverage(double *y, double *w, long n)
Calculates the weighted average of an array of doubles.
Definition moments.c:727
double standardDeviation(double *x, long n)
Calculates the standard deviation of an array of doubles.
Definition moments.c:37