SDDSlib
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(linux) || (defined(_WIN32) && !defined(_MINGW))
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, value, 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 private(value) shared(sumSqr)
75 {
76 double partial_sumSqr = 0;
77#pragma omp for
78 for (i = 0; i < n; i++) {
79 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, value, 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 private(value) 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 partial_sum += (value = x[i]);
156 partial_sumSqr += sqr(value);
157 }
158#pragma omp critical
159 {
160 /* Found this is necessary to avoid variation of results in cases that should be identical */
161 if (numThreads > 1) {
162 sum += partial_sum;
163 sumSqr += partial_sumSqr;
164 } else {
165 sum = partial_sum;
166 sumSqr = partial_sumSqr;
167 }
168 }
169 }
170 *mean = sum / n;
171 *rms = sqrt(sumSqr / n);
172
173 sum = 0;
174#pragma omp parallel private(value) shared(sum, sum2)
175 {
176 double partial_sum = 0;
177 double partial_sum2 = 0;
178#pragma omp for
179 for (i = 0; i < n; i++) {
180 value = x[i] - *mean;
181 partial_sum2 += value * value;
182 partial_sum += fabs(value);
183 }
184#pragma omp critical
185 {
186 /* Found this is necessary to avoid variation of results in cases that should be identical */
187 if (numThreads > 1) {
188 sum2 += partial_sum2;
189 sum += partial_sum;
190 } else {
191 sum2 = partial_sum2;
192 sum = partial_sum;
193 }
194 }
195 }
196 if (n)
197 *standDev = sqrt(sum2 / (n - 1));
198 *meanAbsoluteDev = sum / n;
199
200 return (n - 1);
201}
202
203/**
204 * @brief Computes weighted statistical moments of an array.
205 *
206 * This function calculates the weighted mean, RMS, standard deviation, and mean absolute deviation of the provided
207 * data array by invoking the threaded version with a single thread.
208 *
209 * @param mean Pointer to store the computed weighted mean value.
210 * @param rms Pointer to store the computed weighted RMS value.
211 * @param standDev Pointer to store the computed weighted standard deviation.
212 * @param meanAbsoluteDev Pointer to store the computed weighted mean absolute deviation.
213 * @param x Pointer to the array of doubles.
214 * @param w Pointer to the array of weights corresponding to each data point.
215 * @param n Number of elements in the array.
216 * @return Returns 1 on success, 0 on failure.
217 */
218long computeWeightedMoments(double *mean, double *rms, double *standDev,
219 double *meanAbsoluteDev, double *x, double *w, long n) {
220 return computeWeightedMomentsThreaded(mean, rms, standDev, meanAbsoluteDev, x, w, n, 1);
221}
222
223/**
224 * @brief Computes weighted statistical moments of an array using multiple threads.
225 *
226 * This function calculates the weighted mean, RMS, standard deviation, and mean absolute deviation of the provided
227 * data array using the specified number of threads.
228 *
229 * @param mean Pointer to store the computed weighted mean value.
230 * @param rms Pointer to store the computed weighted RMS value.
231 * @param standDev Pointer to store the computed weighted standard deviation.
232 * @param meanAbsoluteDev Pointer to store the computed weighted mean absolute deviation.
233 * @param x Pointer to the array of doubles.
234 * @param w Pointer to the array of weights corresponding to each data point.
235 * @param n Number of elements in the array.
236 * @param numThreads Number of threads to use for computation.
237 * @return Returns 1 on success, 0 on failure.
238 */
239long computeWeightedMomentsThreaded(double *mean, double *rms, double *standDev,
240 double *meanAbsoluteDev, double *x, double *w, long n, long numThreads) {
241 long i;
242 double sumW = 0, sum = 0, sumWx = 0, sumSqrWx = 0, sum2 = 0, value;
243
244 double lMean, lRms, lStDev, lMAD;
245
246 if (!mean)
247 mean = &lMean;
248 if (!rms)
249 rms = &lRms;
250 if (!standDev)
251 standDev = &lStDev;
252 if (!meanAbsoluteDev)
253 meanAbsoluteDev = &lMAD;
254
255 *mean = *standDev = *meanAbsoluteDev = DBL_MAX;
256
257 if (n < 1)
258 return (0);
259
260 omp_set_num_threads(numThreads);
261
262#pragma omp parallel private(value) shared(sumW, sumWx, sumSqrWx)
263 {
264 double partial_sumW = 0;
265 double partial_sumWx = 0;
266 double partial_sumSqrWx = 0;
267#pragma omp for
268 for (i = 0; i < n; i++) {
269 partial_sumW += w[i];
270 partial_sumWx += (value = x[i]) * w[i];
271 partial_sumSqrWx += value * value * w[i];
272 }
273#pragma omp critical
274 {
275 /* Found this is necessary to avoid variation of results in cases that should be identical */
276 if (numThreads > 1) {
277 sumW += partial_sumW;
278 sumWx += partial_sumWx;
279 sumSqrWx += partial_sumSqrWx;
280 } else {
281 sumW = partial_sumW;
282 sumWx = partial_sumWx;
283 sumSqrWx = partial_sumSqrWx;
284 }
285 }
286 }
287
288 if (sumW) {
289 *mean = sumWx / sumW;
290 *rms = sqrt(sumSqrWx / sumW);
291#pragma omp parallel private(value) shared(sum, sum2)
292 {
293 double partial_sum = 0;
294 double partial_sum2 = 0;
295#pragma omp for
296 for (i = 0; i < n; i++) {
297 value = x[i] - *mean;
298 partial_sum += value * w[i];
299 partial_sum2 += value * value * w[i];
300 }
301#pragma omp critical
302 {
303 /* Found this is necessary to avoid variation of results in cases that should be identical */
304 if (numThreads > 1) {
305 sum += partial_sum;
306 sum2 += partial_sum2;
307 } else {
308 sum = partial_sum;
309 sum2 = partial_sum2;
310 }
311 }
312 }
313 if (n)
314 /* adjust for n-1 weighting */
315 *standDev = sqrt((sum2 * n) / (sumW * (n - 1.0)));
316 *meanAbsoluteDev = sum / sumW;
317 return (1);
318 }
319 return (0);
320}
321
322long accumulateMoments(double *mean, double *rms, double *standDev,
323 double *x, long n, long reset) {
324 return accumulateMomentsThreaded(mean, rms, standDev, x, n, reset, 1);
325}
326
327long accumulateMomentsThreaded(double *mean, double *rms, double *standDev,
328 double *x, long n, long reset, long numThreads) {
329 long i;
330 static double sum = 0, sumSqr = 0, value;
331 static long nTotal;
332
333 if (reset)
334 nTotal = sum = sumSqr = 0;
335
336 nTotal += n;
337 if (nTotal < 1)
338 return (0);
339
340 omp_set_num_threads(numThreads);
341#pragma omp parallel private(value) shared(sum, sumSqr)
342 {
343 double partial_sum = 0;
344 double partial_sumSqr = 0;
345#pragma omp for
346 for (i = 0; i < n; i++) {
347 partial_sum += (value = x[i]);
348 partial_sumSqr += sqr(value);
349 }
350#pragma omp critical
351 {
352 /* Found this is necessary to avoid variation of results in cases that should be identical */
353 if (numThreads > 1) {
354 sum += partial_sum;
355 sumSqr += partial_sumSqr;
356 } else {
357 sum = partial_sum;
358 sumSqr = partial_sumSqr;
359 }
360 }
361 }
362
363 *mean = sum / nTotal;
364 *rms = sqrt(sumSqr / nTotal);
365 *standDev = sqrt((sumSqr / nTotal - sqr(*mean)) * nTotal / (nTotal - 1.0));
366
367 return (1);
368}
369
370long accumulateWeightedMoments(double *mean, double *rms, double *standDev,
371 double *x, double *w, long n, long reset) {
372 return accumulateWeightedMomentsThreaded(mean, rms, standDev, x, w, n, reset, 1);
373}
374
375long accumulateWeightedMomentsThreaded(double *mean, double *rms, double *standDev,
376 double *x, double *w, long n, long reset, long numThreads) {
377 long i;
378 static double sumW = 0, sumWx = 0, sumSqrWx = 0;
379 static long nTotal;
380
381 nTotal += n;
382 if (nTotal < 1)
383 return (0);
384
385 if (reset)
386 sumW = sumWx = sumSqrWx = nTotal = 0;
387
388 omp_set_num_threads(numThreads);
389#pragma omp parallel shared(sumW, sumWx, sumSqrWx)
390 {
391 double partial_sumW = 0;
392 double partial_sumWx = 0;
393 double partial_sumSqrWx = 0;
394#pragma omp for
395 for (i = 0; i < n; i++) {
396 partial_sumW += w[i];
397 partial_sumWx += w[i] * x[i];
398 partial_sumSqrWx += x[i] * x[i] * w[i];
399 }
400#pragma omp critical
401 {
402 /* Found this is necessary to avoid variation of results in cases that should be identical */
403 if (numThreads > 1) {
404 sumW += partial_sumW;
405 sumWx += partial_sumWx;
406 sumSqrWx += partial_sumSqrWx;
407 } else {
408 sumW = partial_sumW;
409 sumWx = partial_sumWx;
410 sumSqrWx = partial_sumSqrWx;
411 }
412 }
413 }
414 if (sumW) {
415 *mean = sumWx / sumW;
416 *rms = sqrt(sumSqrWx / sumW);
417 *standDev = sqrt((sumSqrWx / sumW - sqr(*mean)) * (nTotal / (nTotal - 1.0)));
418 return (1);
419 }
420 return (0);
421}
422
423/**
424 * @brief Computes the correlations between two datasets.
425 *
426 * This function calculates the correlation coefficients C11, C12, and C22 between two arrays of doubles by invoking
427 * the threaded version with a single thread.
428 *
429 * @param C11 Pointer to store the computed C11 correlation coefficient.
430 * @param C12 Pointer to store the computed C12 correlation coefficient.
431 * @param C22 Pointer to store the computed C22 correlation coefficient.
432 * @param x Pointer to the first array of doubles.
433 * @param y Pointer to the second array of doubles.
434 * @param n Number of elements in each array.
435 * @return Returns 1 on success, 0 on failure.
436 */
437long computeCorrelations(double *C11, double *C12, double *C22, double *x, double *y, long n) {
438 return computeCorrelationsThreaded(C11, C12, C22, x, y, n, 1);
439}
440
441/**
442 * @brief Computes the correlations between two datasets using multiple threads.
443 *
444 * This function calculates the correlation coefficients C11, C12, and C22 between two arrays of doubles using the
445 * specified number of threads.
446 *
447 * @param C11 Pointer to store the computed C11 correlation coefficient.
448 * @param C12 Pointer to store the computed C12 correlation coefficient.
449 * @param C22 Pointer to store the computed C22 correlation coefficient.
450 * @param x Pointer to the first array of doubles.
451 * @param y Pointer to the second array of doubles.
452 * @param n Number of elements in each array.
453 * @param numThreads Number of threads to use for computation.
454 * @return Returns 1 on success, 0 on failure.
455 */
456long computeCorrelationsThreaded(double *C11, double *C12, double *C22, double *x, double *y, long n, long numThreads) {
457 long i;
458 double xAve = 0, yAve = 0, dx, dy;
459
460 *C11 = *C12 = *C22 = 0;
461 if (!n)
462 return (0);
463
464 omp_set_num_threads(numThreads);
465#pragma omp parallel shared(xAve, yAve)
466 {
467 double partial_xAve = 0;
468 double partial_yAve = 0;
469#pragma omp for
470 for (i = 0; i < n; i++) {
471 partial_xAve += x[i];
472 partial_yAve += y[i];
473 }
474#pragma omp critical
475 {
476 /* Found this is necessary to avoid variation of results in cases that should be identical */
477 if (numThreads > 1) {
478 xAve += partial_xAve;
479 yAve += partial_yAve;
480 } else {
481 xAve = partial_xAve;
482 yAve = partial_yAve;
483 }
484 }
485 }
486 xAve /= n;
487 yAve /= n;
488
489#pragma omp parallel private(dx, dy) shared(C11, C12, C22)
490 {
491 double partial_C11 = 0;
492 double partial_C12 = 0;
493 double partial_C22 = 0;
494#pragma omp for
495 for (i = 0; i < n; i++) {
496 dx = x[i] - xAve;
497 dy = y[i] - yAve;
498 partial_C11 += dx * dx;
499 partial_C12 += dx * dy;
500 partial_C22 += dy * dy;
501 }
502#pragma omp critical
503 {
504 /* Found this is necessary to avoid variation of results in cases that should be identical */
505 if (numThreads > 1) {
506 *C11 += partial_C11;
507 *C12 += partial_C12;
508 *C22 += partial_C22;
509 } else {
510 *C11 = partial_C11;
511 *C12 = partial_C12;
512 *C22 = partial_C22;
513 }
514 }
515 }
516 *C11 /= n;
517 *C12 /= n;
518 *C22 /= n;
519
520 return (1);
521}
522
523/**
524 * @brief Calculates the arithmetic average of an array of doubles.
525 *
526 * This function computes the arithmetic average of the given array by invoking the threaded version with
527 * a single thread.
528 *
529 * @param y Pointer to the array of doubles.
530 * @param n Number of elements in the array.
531 * @return Returns the arithmetic average as a double.
532 */
533double arithmeticAverage(double *y, long n) {
534 return arithmeticAverageThreaded(y, n, 1);
535}
536
537/**
538 * @brief Calculates the arithmetic average of an array of doubles using multiple threads.
539 *
540 * This function computes the arithmetic average of the given array using the specified number of threads.
541 *
542 * @param y Pointer to the array of doubles.
543 * @param n Number of elements in the array.
544 * @param numThreads Number of threads to use for computation.
545 * @return Returns the arithmetic average as a double.
546 */
547double arithmeticAverageThreaded(double *y, long n, long numThreads) {
548 long i;
549 double sum = 0;
550
551 if (!n)
552 return (0.0);
553 omp_set_num_threads(numThreads);
554#pragma omp parallel shared(sum)
555 {
556 double partial_sum = 0;
557#pragma omp for
558 for (i = 0; i < n; i++) {
559 partial_sum += y[i];
560 }
561#pragma omp critical
562 {
563 /* Found this is necessary to avoid variation of results in cases that should be identical */
564 if (numThreads > 1)
565 sum += partial_sum;
566 else
567 sum = partial_sum;
568 }
569 }
570 return (sum / n);
571}
572
573/**
574 * @brief Calculates the RMS (Root Mean Square) value of an array of doubles.
575 *
576 * This function computes the RMS value of the given array by invoking the threaded version with
577 * a single thread.
578 *
579 * @param y Pointer to the array of doubles.
580 * @param n Number of elements in the array.
581 * @return Returns the RMS value as a double.
582 */
583double rmsValue(double *y, long n) {
584 return rmsValueThreaded(y, n, 1);
585}
586
587/**
588 * @brief Calculates the RMS (Root Mean Square) value of an array of doubles using multiple threads.
589 *
590 * This function computes the RMS value of the given array using the specified number of threads.
591 *
592 * @param y Pointer to the array of doubles.
593 * @param n Number of elements in the array.
594 * @param numThreads Number of threads to use for computation.
595 * @return Returns the RMS value as a double.
596 */
597double rmsValueThreaded(double *y, long n, long numThreads) {
598 long i;
599 double sum = 0;
600
601 if (!n)
602 return (0.0);
603 omp_set_num_threads(numThreads);
604#pragma omp parallel shared(sum)
605 {
606 double partial_sum = 0;
607#pragma omp for
608 for (i = 0; i < n; i++) {
609 partial_sum += y[i] * y[i];
610 }
611#pragma omp critical
612 {
613 /* Found this is necessary to avoid variation of results in cases that should be identical */
614 if (numThreads > 1)
615 sum += partial_sum;
616 else
617 sum = partial_sum;
618 }
619 }
620 return (sqrt(sum / n));
621}
622
623/**
624 * @brief Calculates the mean absolute deviation of an array of doubles.
625 *
626 * This function computes the mean absolute deviation of the given array by invoking the threaded version with
627 * a single thread.
628 *
629 * @param y Pointer to the array of doubles.
630 * @param n Number of elements in the array.
631 * @return Returns the mean absolute deviation as a double.
632 */
633double meanAbsoluteDeviation(double *y, long n) {
634 return meanAbsoluteDeviationThreaded(y, n, 1);
635}
636
637/**
638 * @brief Calculates the mean absolute deviation of an array of doubles using multiple threads.
639 *
640 * This function computes the mean absolute deviation of the given array using the specified number of threads.
641 *
642 * @param y Pointer to the array of doubles.
643 * @param n Number of elements in the array.
644 * @param numThreads Number of threads to use for computation.
645 * @return Returns the mean absolute deviation as a double.
646 */
647double meanAbsoluteDeviationThreaded(double *y, long n, long numThreads) {
648 long i;
649 double ave = 0, sum = 0;
650
651 if (!n)
652 return (0.0);
653 omp_set_num_threads(numThreads);
654#pragma omp parallel shared(ave)
655 {
656 double partial_ave = 0;
657#pragma omp for
658 for (i = 0; i < n; i++) {
659 partial_ave += y[i];
660 }
661#pragma omp critical
662 {
663 /* Found this is necessary to avoid variation of results in cases that should be identical */
664 if (numThreads > 1)
665 ave += partial_ave;
666 else
667 ave = partial_ave;
668 }
669 }
670 ave /= n;
671#pragma omp parallel shared(sum)
672 {
673 double partial_sum = 0;
674#pragma omp for
675 for (i = 0; i < n; i++) {
676 partial_sum += fabs(y[i] - ave);
677 }
678#pragma omp critical
679 {
680 if (numThreads > 1)
681 sum += partial_sum;
682 else
683 sum = partial_sum;
684 }
685 }
686 return (sum / n);
687}
688
689/**
690 * @brief Calculates the weighted average of an array of doubles.
691 *
692 * This function computes the weighted average of the given array by invoking the threaded version with
693 * a single thread.
694 *
695 * @param y Pointer to the array of doubles.
696 * @param w Pointer to the array of weights corresponding to each data point.
697 * @param n Number of elements in the array.
698 * @return Returns the weighted average as a double.
699 */
700double weightedAverage(double *y, double *w, long n) {
701 return weightedAverageThreaded(y, w, n, 1);
702}
703
704/**
705 * @brief Calculates the weighted average of an array of doubles using multiple threads.
706 *
707 * This function computes the weighted average of the given array using the specified number of threads.
708 *
709 * @param y Pointer to the array of doubles.
710 * @param w Pointer to the array of weights corresponding to each data point.
711 * @param n Number of elements in the array.
712 * @param numThreads Number of threads to use for computation.
713 * @return Returns the weighted average as a double.
714 */
715double weightedAverageThreaded(double *y, double *w, long n, long numThreads) {
716 long i;
717 double ySum = 0, wSum = 0;
718
719 if (!n)
720 return 0.0;
721 omp_set_num_threads(numThreads);
722#pragma omp parallel shared(wSum, ySum)
723 {
724 double partial_wSum = 0;
725 double partial_ySum = 0;
726#pragma omp for
727 for (i = 0; i < n; i++) {
728 partial_wSum += w[i];
729 partial_ySum += y[i] * w[i];
730 }
731#pragma omp critical
732 {
733 /* Found this is necessary to avoid variation of results in cases that should be identical */
734 if (numThreads > 1) {
735 wSum += partial_wSum;
736 ySum += partial_ySum;
737 } else {
738 wSum = partial_wSum;
739 ySum = partial_ySum;
740 }
741 }
742 }
743 if (wSum)
744 return ySum / wSum;
745 return 0.0;
746}
747
748/**
749 * @brief Calculates the weighted RMS (Root Mean Square) value of an array of doubles.
750 *
751 * This function computes the weighted RMS value of the given array by invoking the threaded version with
752 * a single thread.
753 *
754 * @param y Pointer to the array of doubles.
755 * @param w Pointer to the array of weights corresponding to each data point.
756 * @param n Number of elements in the array.
757 * @return Returns the weighted RMS value as a double.
758 */
759double weightedRMS(double *y, double *w, long n) {
760 return weightedRMSThreaded(y, w, n, 1);
761}
762
763/**
764 * @brief Calculates the weighted RMS (Root Mean Square) value of an array of doubles using multiple threads.
765 *
766 * This function computes the weighted RMS value of the given array using the specified number of threads.
767 *
768 * @param y Pointer to the array of doubles.
769 * @param w Pointer to the array of weights corresponding to each data point.
770 * @param n Number of elements in the array.
771 * @param numThreads Number of threads to use for computation.
772 * @return Returns the weighted RMS value as a double.
773 */
774double weightedRMSThreaded(double *y, double *w, long n, long numThreads) {
775 long i;
776 double sum = 0, wSum = 0;
777
778 if (!n)
779 return (0.0);
780 omp_set_num_threads(numThreads);
781#pragma omp parallel shared(sum, wSum)
782 {
783 double partial_sum = 0;
784 double partial_wSum = 0;
785#pragma omp for
786 for (i = 0; i < n; i++) {
787 partial_sum += y[i] * y[i] * w[i];
788 partial_wSum += w[i];
789 }
790#pragma omp critical
791 {
792 /* Found this is necessary to avoid variation of results in cases that should be identical */
793 if (numThreads > 1) {
794 sum += partial_sum;
795 wSum += partial_wSum;
796 } else {
797 sum = partial_sum;
798 wSum = partial_wSum;
799 }
800 }
801 }
802 if (wSum)
803 return sqrt(sum / wSum);
804 return 0.0;
805}
806
807/**
808 * @brief Calculates the weighted mean absolute deviation of an array of doubles.
809 *
810 * This function computes the weighted mean absolute deviation of the given array by invoking the threaded version with
811 * a single thread.
812 *
813 * @param y Pointer to the array of doubles.
814 * @param w Pointer to the array of weights corresponding to each data point.
815 * @param n Number of elements in the array.
816 * @return Returns the weighted mean absolute deviation as a double.
817 */
818double weightedMAD(double *y, double *w, long n) {
819 return weightedMADThreaded(y, w, n, 1);
820}
821
822/**
823 * @brief Calculates the weighted mean absolute deviation of an array of doubles using multiple threads.
824 *
825 * This function computes the weighted mean absolute deviation of the given array using the specified number of threads.
826 *
827 * @param y Pointer to the array of doubles.
828 * @param w Pointer to the array of weights corresponding to each data point.
829 * @param n Number of elements in the array.
830 * @param numThreads Number of threads to use for computation.
831 * @return Returns the weighted mean absolute deviation as a double.
832 */
833double weightedMADThreaded(double *y, double *w, long n, long numThreads) {
834 long i;
835 double mean, sum = 0, wSum = 0;
836
837 if (!n)
838 return (0.0);
839 omp_set_num_threads(numThreads);
840#pragma omp parallel shared(sum, wSum)
841 {
842 double partial_sum = 0;
843 double partial_wSum = 0;
844#pragma omp for
845 for (i = 0; i < n; i++) {
846 partial_sum += y[i] * w[i];
847 partial_wSum += w[i];
848 }
849#pragma omp critical
850 {
851 /* Found this is necessary to avoid variation of results in cases that should be identical */
852 if (numThreads > 1) {
853 sum += partial_sum;
854 wSum += partial_wSum;
855 } else {
856 sum = partial_sum;
857 wSum = partial_wSum;
858 }
859 }
860 }
861 if (!wSum)
862 return 0.0;
863 mean = sum / wSum;
864 sum = 0;
865#pragma omp parallel shared(sum)
866 {
867 double partial_sum = 0;
868#pragma omp for
869 for (i = 0; i < n; i++) {
870 partial_sum += fabs(y[i] - mean) * w[i];
871 }
872#pragma omp critical
873 {
874 /* Found this is necessary to avoid variation of results in cases that should be identical */
875 if (numThreads > 1)
876 sum += partial_sum;
877 else
878 sum = partial_sum;
879 }
880 }
881 return sum / wSum;
882}
883
884/**
885 * @brief Calculates the weighted standard deviation of an array of doubles.
886 *
887 * This function computes the weighted standard deviation of the given array by invoking the threaded version with
888 * a single thread.
889 *
890 * @param y Pointer to the array of doubles.
891 * @param w Pointer to the array of weights corresponding to each data point.
892 * @param n Number of elements in the array.
893 * @return Returns the weighted standard deviation as a double.
894 */
895double weightedStDev(double *y, double *w, long n) {
896 return weightedStDevThreaded(y, w, n, 1);
897}
898
899/**
900 * @brief Calculates the weighted standard deviation of an array of doubles using multiple threads.
901 *
902 * This function computes the weighted standard deviation of the given array using the specified number of threads.
903 *
904 * @param y Pointer to the array of doubles.
905 * @param w Pointer to the array of weights corresponding to each data point.
906 * @param n Number of elements in the array.
907 * @param numThreads Number of threads to use for computation.
908 * @return Returns the weighted standard deviation as a double.
909 */
910double weightedStDevThreaded(double *y, double *w, long n, long numThreads) {
911 long i;
912 double mean, sum = 0, wSum = 0, value;
913
914 if (!n)
915 return (0.0);
916 omp_set_num_threads(numThreads);
917#pragma omp parallel shared(sum, wSum)
918 {
919 double partial_sum = 0;
920 double partial_wSum = 0;
921#pragma omp for
922 for (i = 0; i < n; i++) {
923 partial_sum += y[i] * w[i];
924 partial_wSum += w[i];
925 }
926#pragma omp critical
927 {
928 /* Found this is necessary to avoid variation of results in cases that should be identical */
929 if (numThreads > 1) {
930 sum += partial_sum;
931 wSum += partial_wSum;
932 } else {
933 sum = partial_sum;
934 wSum = partial_wSum;
935 }
936 }
937 }
938 if (!wSum)
939 return 0.0;
940 mean = sum / wSum;
941 sum = 0;
942#pragma omp parallel private(value) shared(sum)
943 {
944 double partial_sum = 0;
945#pragma omp for
946 for (i = 0; i < n; i++) {
947 value = y[i] - mean;
948 partial_sum += value * value * w[i];
949 }
950#pragma omp critical
951 {
952 /* Found this is necessary to avoid variation of results in cases that should be identical */
953 if (numThreads > 1)
954 sum += partial_sum;
955 else
956 sum = partial_sum;
957 }
958 }
959 return sqrt((sum * n) / (wSum * (n - 1.0)));
960}
double arithmeticAverage(double *y, long n)
Calculates the arithmetic average of an array of doubles.
Definition moments.c:533
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:910
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:218
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:239
double weightedStDev(double *y, double *w, long n)
Calculates the weighted standard deviation of an array of doubles.
Definition moments.c:895
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:597
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:547
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:774
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:456
double meanAbsoluteDeviationThreaded(double *y, long n, long numThreads)
Calculates the mean absolute deviation of an array of doubles using multiple threads.
Definition moments.c:647
long computeCorrelations(double *C11, double *C12, double *C22, double *x, double *y, long n)
Computes the correlations between two datasets.
Definition moments.c:437
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:833
double meanAbsoluteDeviation(double *y, long n)
Calculates the mean absolute deviation of an array of doubles.
Definition moments.c:633
double weightedMAD(double *y, double *w, long n)
Calculates the weighted mean absolute deviation of an array of doubles.
Definition moments.c:818
double weightedRMS(double *y, double *w, long n)
Calculates the weighted RMS (Root Mean Square) value of an array of doubles.
Definition moments.c:759
double rmsValue(double *y, long n)
Calculates the RMS (Root Mean Square) value of an array of doubles.
Definition moments.c:583
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:715
double weightedAverage(double *y, double *w, long n)
Calculates the weighted average of an array of doubles.
Definition moments.c:700
double standardDeviation(double *x, long n)
Calculates the standard deviation of an array of doubles.
Definition moments.c:37