Ocean
Loading...
Searching...
No Matches
Median.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_BASE_MEDIAN_H
9#define META_OCEAN_BASE_MEDIAN_H
10
11#include "ocean/base/Base.h"
12#include "ocean/base/Memory.h"
13
14namespace Ocean
15{
16
17/**
18 * This class implements a median determination value.
19 * @ingroup base
20 */
21class Median
22{
23 public:
24
25 /**
26 * Returns the median of two given values (the lower of both).
27 * Beware: In the case one of the given values is not a number (nan) the result may be arbitrary as the comparison operator is not defined for such values.
28 * @param v0 First value
29 * @param v1 Second value
30 * @return Resulting median
31 * @tparam T Data type of the data elements
32 */
33 template <typename T>
34 static inline T median2(const T& v0, const T& v1);
35
36 /**
37 * Returns the median of three given values.
38 * Beware: In the case one of the given values is not a number (nan) the result may be arbitrary as the comparison operator is not defined for such values.
39 * @param v0 First value
40 * @param v1 Second value
41 * @param v2 Third value
42 * @return Resulting median
43 * @tparam T Data type of the data elements
44 */
45 template <typename T>
46 static inline T median3(const T& v0, const T& v1, const T& v2);
47
48 /**
49 * Returns the median of four given values (the second smallest value).
50 * Beware: In the case one of the given values is not a number (nan) the result may be arbitrary as the comparison operator is not defined for such values.
51 * @param v0 First value
52 * @param v1 Second value
53 * @param v2 Third value
54 * @param v3 Fourth value
55 * @return Resulting median
56 * @tparam T Data type of the data elements
57 */
58 template <typename T>
59 static inline T median4(const T& v0, const T& v1, const T& v2, const T& v3);
60
61 /**
62 * Returns the median of five given values.
63 * Beware: In the case one of the given values is not a number (nan) the result may be arbitrary as the comparison operator is not defined for such values.
64 * @param v0 First value
65 * @param v1 Second value
66 * @param v2 Third value
67 * @param v3 Fourth value
68 * @param v4 Fifth value
69 * @return Resulting median
70 * @tparam T Data type of the data elements
71 */
72 template <typename T>
73 static inline T median5(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4);
74
75 /**
76 * Returns the median value in a given data array.
77 * If the given number is even, the median value is selected left from the exact center.<br>
78 * Beware: In the case one of the given values is not a number (nan) the result may be arbitrary as the comparison operator is not defined for such values.
79 * @param values Array with values that will be reordered during the execution, must be valid
80 * @param number Number of values, with range [1, infinity)
81 * @return The median value out of 'values'
82 * @tparam T Type of the data for that the median has to be determined
83 * @see constMedian().
84 */
85 template <typename T>
86 static T median(T* values, const size_t number);
87
88 /**
89 * Returns the median value in a given data array.
90 * If the given number is even, the median value is selected left from the exact center.<br>
91 * Beware: In the case one of the given values is not a number (nan) the result may be arbitrary as the comparison operator is not defined for such values.
92 * @param values Array with values from which the median will be determined, must be valid
93 * @param number Number of values, with range [1, infinity)
94 * @return The median value out of 'values'
95 * @tparam T Type of the data for that the median has to be determined
96 * @see median().
97 */
98 template <typename T>
99 static T constMedian(const T* values, const size_t number);
100
101 /**
102 * Returns the percentile value in a given data array.
103 * @param values Array with values that will be reordered during the execution, must be valid
104 * @param number Number of values, with range [1, infinity)
105 * @param percentile The percentile to be determined, with range [0, 1]
106 * @return The percentile value out of 'values'
107 * @see constPercentile().
108 */
109 template <typename T>
110 static T percentile(T* values, const size_t number, const double percentile);
111
112 /**
113 * Returns the percentile value in a given data array.
114 * @param values Array with values from which the percentile will be determined, must be valid
115 * @param number Number of values, with range [1, infinity)
116 * @param percentile The percentile to be determined, with range [0, 1]
117 * @return The percentile value out of 'values'
118 */
119 template <typename T>
120 static T constPercentile(const T* values, const size_t number, const double percentile);
121};
122
123template <typename T>
124inline T Median::median2(const T& v0, const T& v1)
125{
126 return v0 < v1 ? v0 : v1;
127}
128
129template <typename T>
130inline T Median::median3(const T& v0, const T& v1, const T& v2)
131{
132 if (v0 < v1)
133 {
134 // [ v0 < v1 ]
135
136 if (v2 < v0)
137 {
138 // [ v2 < v0 < v1]
139 return v0;
140 }
141 else // v2 >= v0
142 {
143 // [ v0 < v1,v2 ]
144
145 if (v1 < v2)
146 {
147 return v1;
148 }
149 else
150 {
151 return v2;
152 }
153 }
154 }
155 else // v0 >= v1
156 {
157 // [ v1 < v0 ]
158
159 if (v2 < v1)
160 {
161 // [ v2 < v1 < v0 ]
162
163 return v1;
164 }
165 else // v2 >= v1
166 {
167 // [ v1 < v0,v2 ]
168
169 if (v0 < v2)
170 {
171 return v0;
172 }
173 else
174 {
175 return v2;
176}
177 }
178 }
179}
180
181template <typename T>
182inline T Median::median4(const T& v0, const T& v1, const T& v2, const T& v3)
183{
184 // v0, v1, v2, v3
185 if (v0 < v1)
186 {
187 // v0 < v1 | v2, v3
188
189 if (v0 < v2)
190 {
191 // v0 < v1,v2 | v3
192
193 if (v0 < v3)
194 {
195 // v0 < v1,v2,v3
196
197 if (v1 < v2)
198 {
199 // v0 < v1 < v2 | v0 < v3
200
201 if (v2 < v3)
202 {
203 // v0 < v1 < v2 < v3
204 return v1;
205 }
206 else // v3 < v2
207 {
208 // v0 < v1 < v2 | v0 < v3 | v3 < v2
209
210 if (v3 < v1)
211 {
212 // v0 < v3 < v1 < v2
213 return v3;
214 }
215 else // v1 < v3
216 {
217 // v0 < v1 < v3 < v2
218 return v1;
219 }
220 }
221 }
222 else // v2 < v1
223 {
224 // v0 < v1,v2,v3 | v2 < v1
225
226 if (v2 < v3)
227 {
228 // v0 < v1,v2,v3 | v2 < v1,v3
229 return v2;
230 }
231 else // v3 < v2
232 {
233 // v0 < v1,v2,v3 | v3 < v2 < v1
234 return v3;
235 }
236 }
237 }
238 else // v3 < v0
239 {
240 // v3 < v0 < v1,v2
241 return v0;
242 }
243 }
244 else // v2 < v0
245 {
246 // v2 < v0 < v1 | v3
247
248 if (v3 < v2)
249 {
250 // v3 < v2 < v0 < v1
251 return v2;
252 }
253 else // v2 < v3
254 {
255 // v2 < v0 < v1 | v2 < v3
256
257 if (v0 < v3)
258 {
259 // v2 < v0 < v1, v3
260 return v0;
261 }
262 else // v3 < v0
263 {
264 // v2 < v3 < v0 < v1
265 return v3;
266 }
267 }
268 }
269 }
270 else // v1 < v0
271 {
272 // v1 < v0 | v2, v3
273
274 if (v2 < v1)
275 {
276 // v2 < v1 < v0 | v3
277
278 if (v3 < v2)
279 {
280 // v3 < v2 < v1 < v0
281 return v2;
282 }
283 else // v2 < v3
284 {
285 // v2 < v1 < v0 | v2 < v3
286
287 if (v1 < v3)
288 {
289 // v2 < v1 < v0,v3
290 return v1;
291 }
292 else // v3 < v1
293 {
294 // v2 < v3 < v1 < v0
295 return v3;
296 }
297 }
298 }
299 else // v1 < v2
300 {
301 // v1 < v0,v2 | v3
302
303 if (v0 < v2)
304 {
305 // v1 < v0 < v2 | v3
306
307 if (v3 < v1)
308 {
309 // v3 < v1 < v0 < v2
310 return v1;
311 }
312 else // v1 < v3
313 {
314 // v1 < v0 < v2 | v1 < v3
315
316 if (v0 < v3)
317 {
318 // v1 < v0 < v2,v3
319 return v0;
320 }
321 else // v3 < v0
322 {
323 // v1 < v3 < v0 < v2
324 return v3;
325 }
326 }
327 }
328 else // v2 < v0
329 {
330 // v1 < v2 < v0 | v3
331
332 if (v3 < v1)
333 {
334 // v3 < v1 < v2 < v0
335 return v1;
336 }
337 else // v1 < v3
338 {
339 // v1 < v2 < v0 | v1 < v3
340
341 if (v2 < v3)
342 {
343 // v1 < v2 < v0, v3
344 return v2;
345 }
346 else // v3 < v2
347 {
348 // v1 < v3 < v2 < v0
349 return v3;
350 }
351 }
352 }
353 }
354 }
355}
356
357template <typename T>
358inline T Median::median5(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4)
359{
360 // v0, v1, v2, v3, v4
361 if (v0 < v1)
362 {
363 // v0 < v1 | v2, v3, v4
364
365 if (v0 < v2)
366 {
367 // v0 < v1,v2 | v3, v4
368
369 if (v0 < v3)
370 {
371 // v0 < v1,v2,v3 | v4
372
373 if (v0 < v4)
374 {
375 // v0 < v1,v2,v3,v4
376
377 if (v1 < v2)
378 {
379 // v0 < v1 < v2 | v0 < v3,v4
380
381 if (v2 < v3)
382 {
383 // v0 < v1 < v2 < v3 | v0 < v4
384
385 if (v3 < v4)
386 {
387 // v0 < v1 < v2 < v3 < v4
388 return v2;
389 }
390 else // v4 < v3
391 {
392 // v0 < v1 < v2 < v3 | v0 < v4 < v3
393
394 if (v4 < v2)
395 {
396 // v0 < v1 < v2 < v3 | v0 < v4 < v2
397
398 if (v4 < v1)
399 {
400 // v0 < v4 < v1 < v2 < v3
401 return v1;
402 }
403 else // v1 < v4
404 {
405 // v0 < v1 < v4 < v2 < v3
406 return v4;
407 }
408 }
409 else // v2 < v4
410 {
411 // v0 < v1 < v2 < v4 < v3
412 return v2;
413 }
414 }
415 }
416 else // v3 < v2
417 {
418 // v0 < v1 < v2 | v0 < v3,v4 | v3 < v2
419
420 if (v3 < v1)
421 {
422 // v0 < v3 < v1 < v2 | v0 < v4
423
424 if (v4 < v3)
425 {
426 // v0 < v4 < v3 < v1 < v2
427 return v3;
428 }
429 else // v3 < v4
430 {
431 // v0 < v3 < v1 < v2 | v3 < v4
432
433 if (v4 < v1)
434 {
435 // v0 < v3 < v4 < v1 < v2
436 return v4;
437 }
438 else // v1 < v4
439 {
440 // v0 < v3 < v1 < v2,v4
441 return v1;
442 }
443 }
444 }
445 else // v1 < v3
446 {
447 // v0 < v1 < v3 < v2 | v0 < v4
448
449 if (v1 < v4)
450 {
451 // v0 < v1 < v3 < v2 | v1 < v4
452
453 if (v3 < v4)
454 {
455 // v0 < v1 < v3 < v2, v4
456 return v3;
457 }
458 else // v4 < v3
459 {
460 // v0 < v1 < v4 < v3 < v2
461 return v4;
462 }
463 }
464 else // v4 < v1
465 {
466 // v0 < v4 < v1 < v3 < v2
467 return v1;
468 }
469 }
470 }
471 }
472 else // v2 < v1
473 {
474 // v0 < v1,v2,v3,v4 | v2 < v1
475
476 if (v2 < v3)
477 {
478 // v0 < v1,v2,v3,v4 | v2 < v1,v3
479
480 if (v2 < v4)
481 {
482 // v0 < v2 < v1,v3,v4
483
484 if (v1 < v3)
485 {
486 // v0 < v2 < v1,v3,v4 | v1 < v3
487
488 if (v1 < v4)
489 {
490 // v0 < v2 < v1 < v3,v4
491 return v1;
492 }
493 else // v4 < v1
494 {
495 // v0 < v2 < v4 < v1 < v3
496 return v4;
497 }
498 }
499 else // v3 < v1
500 {
501 // v0 < v2 < v1,v3,v4 | v3 < v1
502
503 if (v3 < v4)
504 {
505 // v0 < v2 < v3 < v1,v4
506 return v3;
507 }
508 else // v4 < v3
509 {
510 // v0 < v2 < v4 < v3 < v1
511 return v4;
512 }
513 }
514 }
515 else // v4 < v2
516 {
517 // v0 < v4 < v2 < v1,v3
518 return v2;
519 }
520 }
521 else // v3 < v2
522 {
523 // v0 < v1,v2,v3,v4 | v3 < v2 < v1
524
525 if (v3 < v4)
526 {
527 // v0 < v3 < v2 < v1 | v3 < v4
528
529 if (v2 < v4)
530 {
531 // v0 < v3 < v2 < v1,v4
532 return v2;
533 }
534 else // v4 < v2
535 {
536 // v0 < v3 < v4 < v2 < v1
537 return v4;
538 }
539 }
540 else // v4 < v3
541 {
542 // v0 < v4 < v3 < v2 < v1
543 return v3;
544 }
545 }
546 }
547 }
548 else // v4 < v0
549 {
550 // v4 < v0 < v1,v2,v3
551
552 if (v1 < v2)
553 {
554 // v4 < v0 < v1,v2,v3 | v1 < v2
555
556 if (v1 < v3)
557 {
558 // v4 < v0 < v1 < v2,v3
559 return v1;
560 }
561 else // v3 < v1
562 {
563 // v4 < v0 < v3 < v1 < v2
564 return v3;
565 }
566 }
567 else // v2 < v1
568 {
569 // v4 < v0 < v1,v2,v3 | v2 < v1
570
571 if (v2 < v3)
572 {
573 // v4 < v0 < v2 < v1,v3
574 return v2;
575 }
576 else // v3 < v2
577 {
578 // v4 < v0 < v3 < v2 < v1
579 return v3;
580 }
581 }
582 }
583 }
584 else // v3 < v0
585 {
586 // v3 < v0 < v1,v2 | v4
587
588 if (v0 < v4)
589 {
590 // v3 < v0 < v1,v2,v4
591
592 if (v1 < v2)
593 {
594 // v3 < v0 < v1,v2,v4 | v1 < v2
595
596 if (v1 < v4)
597 {
598 // v3 < v0 < v1 < v2,v4
599 return v1;
600 }
601 else // v4 < v1
602 {
603 // v3 < v0 < v4 < v1 < v2
604 return v4;
605 }
606 }
607 else // v2 < v1
608 {
609 // v3 < v0 < v1,v2,v4 | v2 < v1
610
611 if (v2 < v4)
612 {
613 // v3 < v0 < v2 < v1,v4
614 return v2;
615 }
616 else // v4 < v2
617 {
618 // v3 < v0 < v4 < v2 < v1
619 return v4;
620 }
621 }
622 }
623 else // v4 < v0
624 {
625 // v3,v4 < v0 < v1,v2
626 return v0;
627 }
628 }
629 }
630 else // v2 < v0
631 {
632 // v2 < v0 < v1 | v3, v4
633
634 if (v3 < v2)
635 {
636 // v3 < v2 < v0 < v1 | v4
637
638 if (v0 < v4)
639 {
640 // v3 < v2 < v0 < v1,v4
641 return v0;
642 }
643 else // v4 < v0
644 {
645 // v3 < v2 < v0 < v1 | v4 < v0
646
647 if (v4 < v2)
648 {
649 // v3,v4 < v2 < v0 < v1
650 return v2;
651
652 }
653 else // v2 < v4
654 {
655 // v3 < v2 < v4 < v0 < v1
656 return v4;
657 }
658 }
659 }
660 else // v2 < v3
661 {
662 // v2 < v0 < v1 | v2 < v3 | v4
663
664 if (v4 < v2)
665 {
666 // v4 < v2 < v0 < v1 | v2 < v3
667
668 if (v0 < v3)
669 {
670 // v4 < v2 < v0 < v1, v3
671 return v0;
672 }
673 else // v3 < v0
674 {
675 // v4 < v2 < v3 < v0 < v1
676 return v3;
677 }
678 }
679 else // v2 < v4
680 {
681 // v2 < v0 < v1 | v2 < v3, v4
682
683 if (v4 < v0)
684 {
685 // v2 < v4 < v0 < v1 | v2 < v3
686
687 if (v4 < v3)
688 {
689 // v2 < v4 < v0 < v1 | v4 < v3
690
691 if (v0 < v3)
692 {
693 // v2 < v4 < v0 < v1,v3
694 return v0;
695 }
696 else // v3 < v0
697 {
698 // v2 < v4 < v3 < v0 < v1
699 return v3;
700 }
701 }
702 else // v3 < v4
703 {
704 // v2 < v3 < v4 < v0 < v1
705 return v4;
706 }
707 }
708 else // v0 < v4
709 {
710 // v2 < v0 < v1,v4 | v2 < v3
711
712 if (v0 < v3)
713 {
714 // v2 < v0 < v1,v4,v3
715
716 if (v1 < v4)
717 {
718 // v2 < v0 < v1,v4,v3 | v1 < v4
719
720 if (v1 < v3)
721 {
722 // v2 < v0 < v1 < v3,v4
723 return v1;
724 }
725 else // v3 < v1
726 {
727 // v2 < v0 < v3 < v1 < v4
728 return v3;
729 }
730 }
731 else // v4 < v1
732 {
733 // v2 < v0 < v1,v4,v3 | v4 < v1
734
735 if (v4 < v3)
736 {
737 // v2 < v0 < v4 < v1,v3
738 return v4;
739 }
740 else // v3 < v4
741 {
742 // v2 < v0 < v3 < v4 < v1
743 return v3;
744 }
745 }
746 }
747 else // v3 < v0
748 {
749 // v2 < v3 < v0 < v1,v4
750 return v0;
751 }
752 }
753 }
754 }
755 }
756 }
757 else // v1 < v0
758 {
759 // v1 < v0 | v2, v3, v4
760
761 if (v2 < v1)
762 {
763 // v2 < v1 < v0 | v3, v4
764
765 if (v3 < v2)
766 {
767 // v3 < v2 < v1 < v0 | v4
768
769 if (v4 < v3)
770 {
771 // v4 < v3 < v2 < v1 < v0
772 return v2;
773 }
774 else // v3 < v4
775 {
776 // v3 < v2 < v1 < v0 | v3 < v4
777
778 if (v2 < v4)
779 {
780 // v3 < v2 < v1 < v0 | v2 < v4
781
782 if (v1 < v4)
783 {
784 // v3 < v2 < v1 < v0,v4
785 return v1;
786 }
787 else // v4 < v1
788 {
789 // v3 < v2 < v4 < v1 < v0
790 return v4;
791 }
792 }
793 else // v4 < v2
794 {
795 // v3 < v4 < v2 < v1 < v0
796 return v2;
797 }
798 }
799 }
800 else // v2 < v3
801 {
802 // v2 < v1 < v0 | v2 < v3 | v4
803
804 if (v4 < v2)
805 {
806 // v4 < v2 < v1 < v0 | v2 < v3
807
808 if (v1 < v3)
809 {
810 // v4 < v2 < v1 < v0,v3
811 return v1;
812 }
813 else // v3 < v1
814 {
815 // v4 < v2 < v3 < v1 < v0
816 return v3;
817 }
818 }
819 else // v2 < v4
820 {
821 // v2 < v1 < v0 | v2 < v3,v4
822
823 if (v1 < v3)
824 {
825 // v2 < v1 < v0,v3 | v2 < v4
826
827 if (v1 < v4)
828 {
829 // v2 < v1 < v0,v3,v4
830
831 if (v0 < v3)
832 {
833 // v2 < v1 < v0,v3,v4 | v0 < v3
834
835 if (v0 < v4)
836 {
837 // v2 < v1 < v0 < v3,v4
838 return v0;
839 }
840 else // v4 < v0
841 {
842 // v2 < v1 < v4 < v0 < v3
843 return v4;
844 }
845 }
846 else // v3 < v0
847 {
848 // v2 < v1 < v0,v3,v4 | v3 < v0
849
850 if (v3 < v4)
851 {
852 // v2 < v1 < v3 < v0,v4
853 return v3;
854 }
855 else // v4 < v3
856 {
857 // v2 < v1 < v4 < v3 < v0
858 return v4;
859 }
860 }
861 }
862 else // v4 < v1
863 {
864 // v2 < v4 < v1 < v0,v3
865 return v1;
866 }
867 }
868 else // v3 < v1
869 {
870 // v2 < v3 < v1 < v0 | v2 < v4
871
872 if (v3 < v4)
873 {
874 // v2 < v3 < v1 < v0 | v3 < v4
875
876 if (v1 < v4)
877 {
878 // v2 < v3 < v1 < v0,v4
879 return v1;
880 }
881 else // v4 < v1
882 {
883 // v2 < v3 < v4 < v1 < v0
884 return v4;
885 }
886 }
887 else // v4 < v3
888 {
889 // v2 < v4 < v3 < v1 < v0
890 return v3;
891 }
892 }
893 }
894 }
895 }
896 else // v1 < v2
897 {
898 // v1 < v0,v2 | v3, v4
899
900 if (v0 < v2)
901 {
902 // v1 < v0 < v2 | v3, v4
903
904 if (v3 < v1)
905 {
906 // v3 < v1 < v0 < v2 | v4
907
908 if (v4 < v3)
909 {
910 // v4 < v3 < v1 < v0 < v2
911 return v1;
912 }
913 else // v3 < v4
914 {
915 // v3 < v1 < v0 < v2 | v3 < v4
916
917 if (v1 < v4)
918 {
919 // v3 < v1 < v0 < v2 | v1 < v4
920
921 if (v0 < v4)
922 {
923 // v3 < v1 < v0 < v2,v4
924 return v0;
925 }
926 else // v4 < v0
927 {
928 // v3 < v1 < v4 < v0 < v2
929 return v4;
930 }
931 }
932 else // v4 < v1
933 {
934 // v3 < v4 < v1 < v0 < v2
935 return v1;
936 }
937 }
938 }
939 else // v1 < v3
940 {
941 // v1 < v0 < v2 | v1 < v3 | v4
942
943 if (v4 < v1)
944 {
945 // v4 < v1 < v0 < v2 | v1 < v3
946
947 if (v0 < v3)
948 {
949 // v4 < v1 < v0 < v2,v3
950 return v0;
951 }
952 else // v3 < v0
953 {
954 // v4 < v1 < v3 < v0 < v2
955 return v3;
956 }
957 }
958 else // v1 < v4
959 {
960 // v1 < v0 < v2 | v1 < v3,v4
961
962 if (v0 < v3)
963 {
964 // v1 < v0 < v2,v3 | v1 < v4
965
966 if (v0 < v4)
967 {
968 // v1 < v0 < v2,v3,v4
969
970 if (v2 < v3)
971 {
972 // v1 < v0 < v2,v3,v4 | v2 < v3
973
974 if (v2 < v4)
975 {
976 // v1 < v0 < v2 < v3,v4
977 return v2;
978 }
979 else // v4 < v2
980 {
981 // v1 < v0 < v4 < v2 < v3
982 return v4;
983 }
984 }
985 else // v3 < v2
986 {
987 // v1 < v0 < v2,v3,v4 | v3 < v2
988
989 if (v3 < v4)
990 {
991 // v1 < v0 < v3 < v2,v4
992 return v3;
993 }
994 else // v4 < v3
995 {
996 // v1 < v0 < v4 < v3 < v2
997 return v4;
998 }
999 }
1000 }
1001 else // v4 < v0
1002 {
1003 // v1 < v4 < v0 < v2,v3
1004 return v0;
1005 }
1006 }
1007 else // v3 < v0
1008 {
1009 // v1 < v3 < v0 < v2 | v1 < v4
1010
1011 if (v3 < v4)
1012 {
1013 // v1 < v3 < v0 < v2 | v3 < v4
1014
1015 if (v0 < v4)
1016 {
1017 // v1 < v3 < v0 < v2, v4
1018 return v0;
1019 }
1020 else // v4 < v0
1021 {
1022 // v1 < v3 < v4 < v0 < v2
1023 return v4;
1024 }
1025 }
1026 else // v4 < v3
1027 {
1028 // v1 < v4 < v3 < v0 < v2
1029 return v3;
1030 }
1031 }
1032 }
1033 }
1034 }
1035 else // v2 < v0
1036 {
1037 // v1 < v2 < v0 | v3, v4
1038
1039 if (v3 < v1)
1040 {
1041 // v3 < v1 < v2 < v0 | v4
1042
1043 if (v4 < v3)
1044 {
1045 // v4 < v3 < v1 < v2 < v0
1046 return v1;
1047 }
1048 else // v3 < v4
1049 {
1050 // v3 < v1 < v2 < v0 | v3 < v4
1051
1052 if (v1 < v4)
1053 {
1054 // v3 < v1 < v2 < v0 | v1 < v4
1055
1056 if (v2 < v4)
1057 {
1058 // v3 < v1 < v2 < v0,v4
1059 return v2;
1060 }
1061 else // v4 < v2
1062 {
1063 // v3 < v1 < v4 < v2 < v0
1064 return v4;
1065 }
1066 }
1067 else // v4 < v1
1068 {
1069 // v3 < v4 < v1 < v2 < v0
1070 return v1;
1071 }
1072 }
1073 }
1074 else // v1 < v3
1075 {
1076 // v1 < v2 < v0 | v1 < v3 | v4
1077
1078 if (v4 < v1)
1079 {
1080 // v4 < v1 < v2 < v0 | v1 < v3
1081
1082 if (v2 < v3)
1083 {
1084 // v4 < v1 < v2 < v0, v3
1085 return v2;
1086 }
1087 else // v3 < v2
1088 {
1089 // v4 < v1 < v3 < v2 < v0
1090 return v3;
1091 }
1092 }
1093 else // v1 < v4
1094 {
1095 // v1 < v2 < v0 | v1 < v3, v4
1096
1097 if (v2 < v3)
1098 {
1099 // v1 < v2 < v0,v3 | v1 < v4
1100
1101 if (v2 < v4)
1102 {
1103 // v1 < v2 < v0,v3,v4
1104
1105 if (v0 < v3)
1106 {
1107 // v1 < v2 < v0,v3,v4 | v0 < v3
1108
1109 if (v0 < v4)
1110 {
1111 // v1 < v2 < v0 < v3,v4
1112 return v0;
1113 }
1114 else // v4 < v0
1115 {
1116 // v1 < v2 < v4 < v0 < v3
1117 return v4;
1118 }
1119 }
1120 else // v3 < v0
1121 {
1122 // v1 < v2 < v0,v3,v4 | v3 < v0
1123
1124 if (v3 < v4)
1125 {
1126 // v1 < v2 < v3 < v0,v4
1127 return v3;
1128 }
1129 else // v4 < v3
1130 {
1131 // v1 < v2 < v4 < v3 < v0
1132 return v4;
1133 }
1134 }
1135 }
1136 else // v4 < v2
1137 {
1138 // v1 < v4 < v2 < v0,v3
1139 return v2;
1140 }
1141 }
1142 else // v3 < v2
1143 {
1144 // v1 < v3 < v2 < v0 | v1 < v4
1145
1146 if (v3 < v4)
1147 {
1148 // v1 < v3 < v2 < v0 | v3 < v4
1149
1150 if (v2 < v4)
1151 {
1152 // v1 < v3 < v2 < v0, v4
1153 return v2;
1154 }
1155 else // v4 < v2
1156 {
1157 // v1 < v3 < v4 < v2 < v0
1158 return v4;
1159 }
1160 }
1161 else // v4 < v3
1162 {
1163 // v1 < v4 < v3 < v2 < v0
1164 return v3;
1165 }
1166 }
1167 }
1168 }
1169 }
1170 }
1171 }
1172}
1173
1174template <typename T>
1175T Median::median(T* values, const size_t number)
1176{
1177 ocean_assert(values != 0 && number > 0);
1178
1179 if (values == nullptr || number == 0)
1180 {
1181 return T();
1182 }
1183
1184 size_t low = 0;
1185 size_t high = number - 1;
1186 size_t median = (low + high) >> 1;
1187
1188 size_t ll, hh, middle;
1189
1190 while (true)
1191 {
1192 // only one element
1193 if (high <= low)
1194 {
1195 return values[median];
1196 }
1197
1198 // only two elements
1199 if (high == low + 1)
1200 {
1201 if (values[low] > values[high])
1202 {
1203 std::swap(values[low], values[high]);
1204 }
1205
1206 return values[median];
1207 }
1208
1209 middle = (low + high) / 2;
1210
1211 if (values[middle] > values[high])
1212 {
1213 std::swap(values[middle], values[high]);
1214 }
1215
1216 if (values[low] > values[high])
1217 {
1218 std::swap(values[low], values[high]);
1219 }
1220
1221 if (values[middle] > values[low])
1222 {
1223 std::swap(values[middle], values[low]);
1224 }
1225
1226 std::swap(values[middle], values[low + 1]);
1227
1228 ll = low + 1;
1229 hh = high;
1230
1231 while (true)
1232 {
1233 while (ll < number && values[low] > values[++ll])
1234 {
1235 ; // we need the explicit out-of-range check for not-a-number (nan) elements
1236 }
1237
1238 while (hh > 0 && values[--hh] > values[low])
1239 {
1240 ;
1241 }
1242
1243 if (hh < ll)
1244 {
1245 break;
1246 }
1247
1248 std::swap(values[ll], values[hh]);
1249 }
1250
1251 std::swap(values[low], values[hh]);
1252
1253 if (hh <= median)
1254 {
1255 low = ll;
1256 }
1257
1258 if (hh >= median)
1259 {
1260 high = hh - 1;
1261 }
1262 }
1263}
1264
1265template <typename T>
1266T Median::constMedian(const T* values, const size_t number)
1267{
1268 ocean_assert(values != nullptr && number > 0);
1269
1270 if (number == 1)
1271 {
1272 return values[0];
1273 }
1274
1275 if (number == 0)
1276 {
1277 return T();
1278 }
1279
1280 Memory memory = Memory::create<T>(number);
1281
1282 if (memory.data() == nullptr)
1283 {
1284 ocean_assert(false && "Out of memory");
1285 return T();
1286 }
1287
1288 memcpy(memory.data<T>(), values, sizeof(T) * number);
1289 const T result = median(memory.data<T>(), number);
1290
1291 return result;
1292}
1293
1294template <typename T>
1295T Median::percentile(T* values, const size_t number, const double percentile)
1296{
1297 ocean_assert(values != nullptr && number > 0);
1298 ocean_assert(percentile >= 0.0f && percentile <= 1.0f);
1299
1300 if (number == 1)
1301 {
1302 return values[0];
1303 }
1304
1305 if (number == 0)
1306 {
1307 return T();
1308 }
1309
1310 const size_t index = std::max(size_t(0), std::min(size_t(double(number) * percentile), size_t(number - 1)));
1311 ocean_assert(index < number);
1312
1313 std::nth_element(values, values + index, values + number);
1314
1315 return values[index];
1316}
1317
1318template <typename T>
1319T Median::constPercentile(const T* values, const size_t number, const double percentile)
1320{
1321 ocean_assert(values != nullptr && number > 0);
1322 ocean_assert(percentile >= 0.0f && percentile <= 1.0f);
1323
1324 if (number == 1)
1325 {
1326 return values[0];
1327 }
1328
1329 if (number == 0)
1330 {
1331 return T();
1332 }
1333
1334 Memory memory = Memory::create<T>(number);
1335
1336 if (memory.data() == nullptr)
1337 {
1338 ocean_assert(false && "Out of memory");
1339 return T();
1340 }
1341
1342 memcpy(memory.data<T>(), values, sizeof(T) * number);
1343
1344 return Median::percentile<T>(memory.data<T>(), number, percentile);
1345}
1346
1347}
1348
1349#endif // META_OCEAN_BASE_MEDIAN_H
This class implements a median determination value.
Definition Median.h:22
static T median4(const T &v0, const T &v1, const T &v2, const T &v3)
Returns the median of four given values (the second smallest value).
Definition Median.h:182
static T median5(const T &v0, const T &v1, const T &v2, const T &v3, const T &v4)
Returns the median of five given values.
Definition Median.h:358
static T constPercentile(const T *values, const size_t number, const double percentile)
Returns the percentile value in a given data array.
Definition Median.h:1319
static T median(T *values, const size_t number)
Returns the median value in a given data array.
Definition Median.h:1175
static T median2(const T &v0, const T &v1)
Returns the median of two given values (the lower of both).
Definition Median.h:124
static T median3(const T &v0, const T &v1, const T &v2)
Returns the median of three given values.
Definition Median.h:130
static T constMedian(const T *values, const size_t number)
Returns the median value in a given data array.
Definition Median.h:1266
static T percentile(T *values, const size_t number, const double percentile)
Returns the percentile value in a given data array.
Definition Median.h:1295
This class implements an object able to allocate memory.
Definition base/Memory.h:22
void * data()
Returns the pointer to the writable memory which is allocated by this object.
Definition base/Memory.h:303
The namespace covering the entire Ocean framework.
Definition Accessor.h:15