sum.hpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // Copyright 2018 Hans Dembinski
  2. //
  3. // Distributed under the Boost Software License, version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_HISTOGRAM_ACCUMULATORS_SUM_HPP
  7. #define BOOST_HISTOGRAM_ACCUMULATORS_SUM_HPP
  8. #include <boost/histogram/fwd.hpp>
  9. #include <cmath>
  10. #include <type_traits>
  11. namespace boost {
  12. namespace histogram {
  13. namespace accumulators {
  14. /**
  15. Uses Neumaier algorithm to compute accurate sums.
  16. The algorithm uses memory for two floats and is three to
  17. five times slower compared to a simple floating point
  18. number used to accumulate a sum, but the relative error
  19. of the sum is at the level of the machine precision,
  20. independent of the number of samples.
  21. A. Neumaier, Zeitschrift fuer Angewandte Mathematik
  22. und Mechanik 54 (1974) 39-51.
  23. */
  24. template <typename RealType>
  25. class sum {
  26. public:
  27. sum() = default;
  28. /// Initialize sum to value
  29. explicit sum(const RealType& value) noexcept : large_(value) {}
  30. /// Set sum to value
  31. sum& operator=(const RealType& value) noexcept {
  32. large_ = value;
  33. small_ = 0;
  34. return *this;
  35. }
  36. /// Increment sum by one
  37. sum& operator++() { return operator+=(1); }
  38. /// Increment sum by value
  39. sum& operator+=(const RealType& value) {
  40. auto temp = large_ + value; // prevent optimization
  41. if (std::abs(large_) >= std::abs(value))
  42. small_ += (large_ - temp) + value;
  43. else
  44. small_ += (value - temp) + large_;
  45. large_ = temp;
  46. return *this;
  47. }
  48. /// Scale by value
  49. sum& operator*=(const RealType& value) {
  50. large_ *= value;
  51. small_ *= value;
  52. return *this;
  53. }
  54. template <class T>
  55. bool operator==(const sum<T>& rhs) const noexcept {
  56. return large_ == rhs.large_ && small_ == rhs.small_;
  57. }
  58. template <class T>
  59. bool operator!=(const T& rhs) const noexcept {
  60. return !operator==(rhs);
  61. }
  62. /// Return large part of the sum.
  63. const RealType& large() const { return large_; }
  64. /// Return small part of the sum.
  65. const RealType& small() const { return small_; }
  66. // allow implicit conversion to RealType
  67. operator RealType() const { return large_ + small_; }
  68. template <class Archive>
  69. void serialize(Archive&, unsigned /* version */);
  70. private:
  71. RealType large_ = RealType();
  72. RealType small_ = RealType();
  73. };
  74. } // namespace accumulators
  75. } // namespace histogram
  76. } // namespace boost
  77. #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
  78. namespace std {
  79. template <class T, class U>
  80. struct common_type<boost::histogram::accumulators::sum<T>,
  81. boost::histogram::accumulators::sum<U>> {
  82. using type = boost::histogram::accumulators::sum<common_type_t<T, U>>;
  83. };
  84. } // namespace std
  85. #endif
  86. #endif