diff options
Diffstat (limited to 'boost/accumulators/statistics/sum_kahan.hpp')
-rw-r--r-- | boost/accumulators/statistics/sum_kahan.hpp | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/boost/accumulators/statistics/sum_kahan.hpp b/boost/accumulators/statistics/sum_kahan.hpp new file mode 100644 index 0000000000..97ade18da8 --- /dev/null +++ b/boost/accumulators/statistics/sum_kahan.hpp @@ -0,0 +1,188 @@ +/////////////////////////////////////////////////////////////////////////////// +// sum_kahan.hpp +// +// Copyright 2010 Gaetano Mendola, 2011 Simon West. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_ACCUMULATORS_STATISTICS_SUM_KAHAN_HPP_EAN_26_07_2010 +#define BOOST_ACCUMULATORS_STATISTICS_SUM_KAHAN_HPP_EAN_26_07_2010 + +#include <boost/accumulators/framework/accumulator_base.hpp> +#include <boost/accumulators/framework/parameters/sample.hpp> +#include <boost/accumulators/statistics_fwd.hpp> +#include <boost/accumulators/statistics/sum.hpp> +#include <boost/accumulators/statistics/weighted_sum_kahan.hpp> +#include <boost/numeric/conversion/cast.hpp> + +namespace boost { namespace accumulators +{ + +namespace impl +{ + +#if _MSC_VER > 1400 +# pragma float_control(push) +# pragma float_control(precise, on) +#endif + +template<typename Sample, typename Tag> +struct sum_kahan_impl + : accumulator_base +{ + typedef Sample result_type; + + //////////////////////////////////////////////////////////////////////////// + // sum_kahan_impl + /** + @brief Kahan summation algorithm + + The Kahan summation algorithm reduces the numerical error obtained with standard + sequential sum. + + */ + template<typename Args> + sum_kahan_impl(Args const & args) + : sum(args[parameter::keyword<Tag>::get() | Sample()]), + compensation(boost::numeric_cast<Sample>(0.0)) + { + } + + template<typename Args> + void +#if BOOST_ACCUMULATORS_GCC_VERSION > 40305 + __attribute__((__optimize__("no-associative-math"))) +#endif + operator ()(Args const & args) + { + const Sample myTmp1 = args[parameter::keyword<Tag>::get()] - this->compensation; + const Sample myTmp2 = this->sum + myTmp1; + this->compensation = (myTmp2 - this->sum) - myTmp1; + this->sum = myTmp2; + } + + result_type result(dont_care) const + { + return this->sum; + } + +private: + Sample sum; + Sample compensation; +}; + +#if _MSC_VER > 1400 +# pragma float_control(pop) +#endif + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// tag::sum_kahan +// tag::sum_of_weights_kahan +// tag::sum_of_variates_kahan +// +namespace tag +{ + + struct sum_kahan + : depends_on<> + { + /// INTERNAL ONLY + /// + typedef impl::sum_kahan_impl< mpl::_1, tag::sample > impl; + }; + + struct sum_of_weights_kahan + : depends_on<> + { + typedef mpl::true_ is_weight_accumulator; + /// INTERNAL ONLY + /// + typedef accumulators::impl::sum_kahan_impl<mpl::_2, tag::weight> impl; + }; + + template<typename VariateType, typename VariateTag> + struct sum_of_variates_kahan + : depends_on<> + { + /// INTERNAL ONLY + /// + typedef mpl::always<accumulators::impl::sum_kahan_impl<VariateType, VariateTag> > impl; + }; + +} // namespace tag + +/////////////////////////////////////////////////////////////////////////////// +// extract::sum_kahan +// extract::sum_of_weights_kahan +// extract::sum_of_variates_kahan +// +namespace extract +{ + extractor<tag::sum_kahan> const sum_kahan = {}; + extractor<tag::sum_of_weights_kahan> const sum_of_weights_kahan = {}; + extractor<tag::abstract_sum_of_variates> const sum_of_variates_kahan = {}; + + BOOST_ACCUMULATORS_IGNORE_GLOBAL(sum_kahan) + BOOST_ACCUMULATORS_IGNORE_GLOBAL(sum_of_weights_kahan) + BOOST_ACCUMULATORS_IGNORE_GLOBAL(sum_of_variates_kahan) +} // namespace extract + +using extract::sum_kahan; +using extract::sum_of_weights_kahan; +using extract::sum_of_variates_kahan; + +// sum(kahan) -> sum_kahan +template<> +struct as_feature<tag::sum(kahan)> +{ + typedef tag::sum_kahan type; +}; + +// sum_of_weights(kahan) -> sum_of_weights_kahan +template<> +struct as_feature<tag::sum_of_weights(kahan)> +{ + typedef tag::sum_of_weights_kahan type; +}; + +// So that sum_kahan can be automatically substituted with +// weighted_sum_kahan when the weight parameter is non-void. +template<> +struct as_weighted_feature<tag::sum_kahan> +{ + typedef tag::weighted_sum_kahan type; +}; + +template<> +struct feature_of<tag::weighted_sum_kahan> + : feature_of<tag::sum> +{}; + +// for the purposes of feature-based dependency resolution, +// sum_kahan provides the same feature as sum +template<> +struct feature_of<tag::sum_kahan> + : feature_of<tag::sum> +{ +}; + +// for the purposes of feature-based dependency resolution, +// sum_of_weights_kahan provides the same feature as sum_of_weights +template<> +struct feature_of<tag::sum_of_weights_kahan> + : feature_of<tag::sum_of_weights> +{ +}; + +template<typename VariateType, typename VariateTag> +struct feature_of<tag::sum_of_variates_kahan<VariateType, VariateTag> > + : feature_of<tag::abstract_sum_of_variates> +{ +}; + +}} // namespace boost::accumulators + +#endif + |