1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // sum_kahan.hpp |
3 | // |
4 | // Copyright 2010 Gaetano Mendola, 2011 Simon West. Distributed under the Boost |
5 | // Software License, Version 1.0. (See accompanying file |
6 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | #ifndef BOOST_ACCUMULATORS_STATISTICS_SUM_KAHAN_HPP_EAN_26_07_2010 |
9 | #define BOOST_ACCUMULATORS_STATISTICS_SUM_KAHAN_HPP_EAN_26_07_2010 |
10 | |
11 | #include <boost/accumulators/framework/accumulator_base.hpp> |
12 | #include <boost/accumulators/framework/parameters/sample.hpp> |
13 | #include <boost/accumulators/statistics_fwd.hpp> |
14 | #include <boost/accumulators/statistics/sum.hpp> |
15 | #include <boost/accumulators/statistics/weighted_sum_kahan.hpp> |
16 | #include <boost/numeric/conversion/cast.hpp> |
17 | |
18 | namespace boost { namespace accumulators |
19 | { |
20 | |
21 | namespace impl |
22 | { |
23 | |
24 | #if _MSC_VER > 1400 |
25 | # pragma float_control(push) |
26 | # pragma float_control(precise, on) |
27 | #endif |
28 | |
29 | template<typename Sample, typename Tag> |
30 | struct sum_kahan_impl |
31 | : accumulator_base |
32 | { |
33 | typedef Sample result_type; |
34 | |
35 | //////////////////////////////////////////////////////////////////////////// |
36 | // sum_kahan_impl |
37 | /** |
38 | @brief Kahan summation algorithm |
39 | |
40 | The Kahan summation algorithm reduces the numerical error obtained with standard |
41 | sequential sum. |
42 | |
43 | */ |
44 | template<typename Args> |
45 | sum_kahan_impl(Args const & args) |
46 | : sum(args[parameter::keyword<Tag>::get() | Sample()]), |
47 | compensation(boost::numeric_cast<Sample>(0.0)) |
48 | { |
49 | } |
50 | |
51 | template<typename Args> |
52 | void |
53 | #if BOOST_ACCUMULATORS_GCC_VERSION > 40305 |
54 | __attribute__((__optimize__("no-associative-math" ))) |
55 | #endif |
56 | operator ()(Args const & args) |
57 | { |
58 | const Sample myTmp1 = args[parameter::keyword<Tag>::get()] - this->compensation; |
59 | const Sample myTmp2 = this->sum + myTmp1; |
60 | this->compensation = (myTmp2 - this->sum) - myTmp1; |
61 | this->sum = myTmp2; |
62 | } |
63 | |
64 | result_type result(dont_care) const |
65 | { |
66 | return this->sum; |
67 | } |
68 | |
69 | // make this accumulator serializeable |
70 | template<class Archive> |
71 | void serialize(Archive & ar, const unsigned int file_version) |
72 | { |
73 | ar & sum; |
74 | ar & compensation; |
75 | } |
76 | |
77 | private: |
78 | Sample sum; |
79 | Sample compensation; |
80 | }; |
81 | |
82 | #if _MSC_VER > 1400 |
83 | # pragma float_control(pop) |
84 | #endif |
85 | |
86 | } // namespace impl |
87 | |
88 | /////////////////////////////////////////////////////////////////////////////// |
89 | // tag::sum_kahan |
90 | // tag::sum_of_weights_kahan |
91 | // tag::sum_of_variates_kahan |
92 | // |
93 | namespace tag |
94 | { |
95 | |
96 | struct sum_kahan |
97 | : depends_on<> |
98 | { |
99 | /// INTERNAL ONLY |
100 | /// |
101 | typedef impl::sum_kahan_impl< mpl::_1, tag::sample > impl; |
102 | }; |
103 | |
104 | struct sum_of_weights_kahan |
105 | : depends_on<> |
106 | { |
107 | typedef mpl::true_ is_weight_accumulator; |
108 | /// INTERNAL ONLY |
109 | /// |
110 | typedef accumulators::impl::sum_kahan_impl<mpl::_2, tag::weight> impl; |
111 | }; |
112 | |
113 | template<typename VariateType, typename VariateTag> |
114 | struct sum_of_variates_kahan |
115 | : depends_on<> |
116 | { |
117 | /// INTERNAL ONLY |
118 | /// |
119 | typedef mpl::always<accumulators::impl::sum_kahan_impl<VariateType, VariateTag> > impl; |
120 | }; |
121 | |
122 | } // namespace tag |
123 | |
124 | /////////////////////////////////////////////////////////////////////////////// |
125 | // extract::sum_kahan |
126 | // extract::sum_of_weights_kahan |
127 | // extract::sum_of_variates_kahan |
128 | // |
129 | namespace extract |
130 | { |
131 | extractor<tag::sum_kahan> const = {}; |
132 | extractor<tag::sum_of_weights_kahan> const = {}; |
133 | extractor<tag::abstract_sum_of_variates> const = {}; |
134 | |
135 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(sum_kahan) |
136 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(sum_of_weights_kahan) |
137 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(sum_of_variates_kahan) |
138 | } // namespace extract |
139 | |
140 | using extract::sum_kahan; |
141 | using extract::sum_of_weights_kahan; |
142 | using extract::sum_of_variates_kahan; |
143 | |
144 | // sum(kahan) -> sum_kahan |
145 | template<> |
146 | struct as_feature<tag::sum(kahan)> |
147 | { |
148 | typedef tag::sum_kahan type; |
149 | }; |
150 | |
151 | // sum_of_weights(kahan) -> sum_of_weights_kahan |
152 | template<> |
153 | struct as_feature<tag::sum_of_weights(kahan)> |
154 | { |
155 | typedef tag::sum_of_weights_kahan type; |
156 | }; |
157 | |
158 | // So that sum_kahan can be automatically substituted with |
159 | // weighted_sum_kahan when the weight parameter is non-void. |
160 | template<> |
161 | struct as_weighted_feature<tag::sum_kahan> |
162 | { |
163 | typedef tag::weighted_sum_kahan type; |
164 | }; |
165 | |
166 | template<> |
167 | struct feature_of<tag::weighted_sum_kahan> |
168 | : feature_of<tag::sum> |
169 | {}; |
170 | |
171 | // for the purposes of feature-based dependency resolution, |
172 | // sum_kahan provides the same feature as sum |
173 | template<> |
174 | struct feature_of<tag::sum_kahan> |
175 | : feature_of<tag::sum> |
176 | { |
177 | }; |
178 | |
179 | // for the purposes of feature-based dependency resolution, |
180 | // sum_of_weights_kahan provides the same feature as sum_of_weights |
181 | template<> |
182 | struct feature_of<tag::sum_of_weights_kahan> |
183 | : feature_of<tag::sum_of_weights> |
184 | { |
185 | }; |
186 | |
187 | template<typename VariateType, typename VariateTag> |
188 | struct feature_of<tag::sum_of_variates_kahan<VariateType, VariateTag> > |
189 | : feature_of<tag::abstract_sum_of_variates> |
190 | { |
191 | }; |
192 | |
193 | }} // namespace boost::accumulators |
194 | |
195 | #endif |
196 | |
197 | |