简体   繁体   English

添加到 boost::accumulator 的值的数量是否有限制?

[英]Is there a limit on the number of values added to a boost::accumulator?

Is there a limit on how many values that can be added to a boost::accumulator?可以添加到 boost::accumulator 的值是否有限制? If a large number of entries were added, is there any point in which the accumulator would cease to work properly or is the internal algorithm robust enough to account for a set of values approaching infinity?如果添加了大量条目,累加器是否会停止正常工作,或者内部算法是否足够强大以解释一组接近无穷大的值?

#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
using namespace boost::accumulators;

int main()
{
    // Define an accumulator set for calculating the mean and the
    // 2nd moment ...
    accumulator_set<double, stats<tag::mean, tag::moment<2> > > acc;

    // push in some data ...
    for (std::size_t i=0; i<VERY_LARGE_NUMBER; i++)
    {
      acc(i);
    }


    // Display the results ...
    std::cout << "Mean:   " << mean(acc) << std::endl;
    std::cout << "Moment: " << moment<2>(acc) << std::endl;

    return 0;
}

If your int is a 32 bit integer, you'll get a signed integer overflow at 46341 * 46341 when calculating moment<2> and your program therefore has undefined behavior.如果您的int是 32 位 integer,则在计算moment<2>时,您将在 46341 * 46341 处获得签名的 integer 溢出,因此您的程序具有未定义的行为。

To avoid that, cast i to the type you're using in the accumulator:为避免这种情况,请将i转换为您在累加器中使用的类型:

acc(static_cast<double>(i));

This will now have the same limits as a normal double .这现在将具有与普通double相同的限制。 You can add as many elements as you'd like to it as long as you don't exceed the limit ( std::numeric_limits<double>::max() ) for a double in the internal moment calculations ( x 2 for moment<2> or a sum that exceeds the limit).您可以根据需要添加任意数量的元素,只要不超过内部矩计算中的double的限制( std::numeric_limits<double>::max() )( x 2moment<2>或超过限制的总和)。

The accumulator statistics do not account for overflow, so you need to select the accumulator type carefully.累加器统计考虑溢出,因此需要仔细检查累加器类型 select。 It doesn't need to match the initial type of the objects you are adding—you can cast it when accumulating, then get the statistics and cast it back to the original type.它不需要匹配您正在添加的对象的初始类型——您可以在累积时对其进行转换,然后获取统计信息并将其转换回原始类型。

You can see it with this simple example :您可以通过这个简单的示例看到它:

#include <bits/stdc++.h>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>

using namespace boost::accumulators;

int main(void) {
    accumulator_set<int8_t, features<tag::mean>> accInt8;
    accumulator_set<double, features<tag::mean>> accDouble;
    
    int8_t sum = 0; // range of int8_t: -128 to 127
    for (int8_t i = 1; i <= 100; i++) {
        sum += i; // this will overflow!
        accInt8(i); // this will also overflow
        accDouble((double)i);
    }
    
    std::cout << "sum from 1 to 100: " << (int)sum << " (overflow)\n";
    std::cout << "mean(<int8_t>): " << extract::mean(accInt8) << " (overflow)\n";
    std::cout << "mean(<double>): " << (int)extract::mean(accDouble) << "\n";
    
    return 0;
}

I used int8_t which has a very small range (-128 to 127) to demonstrate that getting the mean from values 1 to 100 (which should be 50) overflows if you use int8_t as the internal type for the accumulator_set .我使用int8_t ,它的范围非常小(-128 到 127),以证明如果使用int8_t作为accumulator_set的内部类型,从值 1 到 100(应该是 50)获取平均值会溢出。

The output is: output 是:

sum from 1 to 100: -70 (overflow)
mean(<int8_t>): -7 (overflow)
mean(<double>): 50

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM