quickstats
Quickly compute simple statistics
Loading...
Searching...
No Matches
mad.hpp
Go to the documentation of this file.
1#ifndef QUICKSTATS_MAD_HPP
2#define QUICKSTATS_MAD_HPP
3
4#include <cstddef>
5#include <cmath>
6#include <limits>
7
8#include "median.hpp"
9
15namespace quickstats {
16
21template<typename Output_ = double>
36
60template<typename Output_ = double, typename Input_>
61Output_ mad(const std::size_t num_total, Input_* const ptr, const Input_ median, const MadOptions<Output_>& options) {
62 // Check for infinities to avoid shenanigans from trying to order NaN deviations from Inf - Inf.
63 // This entire conditional should be optimized out if Input_ has no infinities.
64 if (std::isinf(median)) {
66 return options.placeholder;
67 }
68
69 // We use inf_if_available_else_max() just to get it to compile if Input_ doesn't have infs.
70 // At this point, Input_ must support infinities otherwise we wouldn't have gotten here.
71 for (std::size_t i = 0; i < num_total; ++i) {
72 ptr[i] = (median == ptr[i] ? 0 : inf_if_available_else_max<Input_>());
73 }
74
75 } else {
76 for (std::size_t i = 0; i < num_total; ++i) {
77 ptr[i] = std::abs(ptr[i] - median);
78 }
79 }
80
82 medopt.placeholder = options.placeholder;
83 return ::quickstats::median<Output_>(num_total, ptr, medopt);
84}
85
113template<typename Output_ = double, typename Input_>
114Output_ mad(const std::size_t num_total, const std::size_t num_non_zero, Input_* const values, const Input_ median, const MadOptions<Output_>& options) {
115 // Check for infinities to avoid shenanigans from trying to order NaN deviations from Inf - Inf.
116 // This entire conditional should be optimized out if Input_ has no infinities.
117 if (std::isinf(median)) {
119 return options.placeholder;
120 }
121
122 // We use inf_if_available_else_max() just to get it to compile if Input_ doesn't have infs.
123 // At this point, Input_ must support infinities otherwise we wouldn't have gotten here.
124 for (std::size_t i = 0; i < num_non_zero; ++i) {
125 values[i] = (median == values[i] ? 0 : inf_if_available_else_max<Input_>());
126 }
127
128 } else {
129 for (std::size_t i = 0; i < num_non_zero; ++i) {
130 values[i] = std::abs(values[i] - median);
131 }
132 }
133
134 // It is also possible to implement the sparse MAD by subtracting 'abs(median)' from the absolute deviations,
135 // computing the sparse median of the difference, and then adding 'abs(median)' back to the result.
136 // We don't do this as the subtraction and addition introduces some numerical error,
137 // which isn't that consequential in practice but interferes with exact comparisons to the dense results in our tests.
138
140 medopt.placeholder = options.placeholder;
141 return median_internal<Output_>(num_total, num_non_zero, values, std::abs(median), medopt);
142}
143
153template<typename Float_>
154Float_ scale_mad_to_sd(const Float_ x) {
155 return x * 1.4826;
156}
157
161// Backwards compatibility.
162template<typename Output_ = double, typename Input_>
163Output_ mad(const std::size_t num_total, Input_* const ptr, const Input_ median) {
164 return mad(num_total, ptr, median, MadOptions<Output_>());
165}
166
167template<typename Output_ = double, typename Input_>
168Output_ mad(const std::size_t num_total, const std::size_t num_non_zero, Input_* const values, const Input_ median) {
169 return mad(num_total, num_non_zero, values, median, MadOptions<Output_>());
170}
171
172template<typename Output_ = double, typename Input_>
173Output_ mad_with_infinities(const std::size_t num_total, Input_* const ptr, const Input_ median) {
174 MadOptions<Output_> opt;
175 opt.difference_between_infinities_is_zero = true;
176 return mad(num_total, ptr, median, opt);
177}
178
179template<typename Output_ = double, typename Input_>
180Output_ mad_with_infinities(const std::size_t num_total, const std::size_t num_non_zero, Input_* const values, const Input_ median) {
181 MadOptions<Output_> opt;
182 opt.difference_between_infinities_is_zero = true;
183 return mad(num_total, num_non_zero, values, median, opt);
184}
189}
190
191#endif
Compute a median.
Quickly compute simple statistics.
Definition mad.hpp:15
Output_ median(const std::size_t num_total, Input_ *const ptr, const MedianOptions< Output_ > &options)
Definition median.hpp:47
Float_ scale_mad_to_sd(const Float_ x)
Definition mad.hpp:154
Output_ mad(const std::size_t num_total, Input_ *const ptr, const Input_ median, const MadOptions< Output_ > &options)
Definition mad.hpp:61
constexpr Value_ nan_if_available_else_zero()
Definition utils.hpp:63
Options for mad() and mad_with_infinities().
Definition mad.hpp:22
Output_ placeholder
Definition mad.hpp:27
bool difference_between_infinities_is_zero
Definition mad.hpp:34
Options for median().
Definition median.hpp:23
Output_ placeholder
Definition median.hpp:27