使用累加函数计算 double[] 数组的平均值的函数

8
这可能是每个人都有一个代码片段的最常见函数,但我实际上花费了不少于1.5小时在SO以及其他C++网站上搜索它,但没有找到解决方案。
我想使用一个函数来计算double array[]的平均值,并将数组作为引用传递给该函数。有数百万例子在主循环中计算平均值,但我正在寻找的是一个可以放在外部文件中并随时使用的函数。
到目前为止,这是我的最新版本,会产生编译错误:
double mean_array( double array[] )
{
    int count = sizeof( array ) / sizeof( array[0] );
    double sum = accumulate( array, array + count, 0 );
    return ( double ) sum / count;
}

编译错误为:

error C3861: 'accumulate': 找不到标识符

你能告诉我如何修复这个函数吗?这个编译错误是什么意思?

如果我使用std::accumulate(已定义using namespace std),那么我会得到以下错误:

'accumulate' : is not a member of 'std'
'accumulate': identifier not found

为什么“accumulate”不是“std”的成员?
附注:我知道我可以使用“sum += array[i]”方法而不使用“accumulate”,但我想了解这里发生了什么以及如何使我的示例工作。

1
我不确定,只是想知道,你是否添加了必要的Include文件? - Shamim Hafiz - MSFT
注意:accumulate( array, array + count, 0.0 ); 中的 0.0 - 在您的代码片段中,您正在累加整数。 - Tom
如果我从0.0开始,它能正常工作吗?我需要传递计数吗,还是可以从sizeof计算出来? - hyperknot
您不能使用 sizeof(array) 作为数组的大小,因为数组的大小是未知的。请参见下面 @xanatos 的答案以获取更好的解决方法。 - Some programmer dude
顺便提一下,在这里使用std::accumulate是很好的选择。如果你的数组非常大,那么可以轻松地使用__gnu_parallel::accumulate进行并行计算。 - Tom
4个回答

27
尝试添加。
#include <numeric>

它将引入你正在寻找的 'std :: accumulate' 函数。

进一步地,你将面临一个问题,即如何找出数组中元素的数量。实际上,不能将数组传递给函数,并希望函数能够知道数组的大小。它将会衰变为指针。因此,你的 count 计算将是错误的。如果你想要能够传递指定大小的实际数组,你必须使用一个带有模板的函数。

template <int N>
double mean_array( double ( & array )[N] )
{
    return std::accumulate( array, array + N, 0.0) / (double)(N);
}

我不确定这个模板函数是否可以在Objective-C方法(包装器)中调用。@didier-trosset: 你能详细说明一下这个模板是如何帮助计数的吗? 如果我需要从已有计数的Objective-C中调用C++函数,那么您是否同意,由于计数可以作为该函数的第二个参数传递,因此不再需要进行模板化处理? - Kushal Ashok
1
@KushalAshok 正确。你可以将指针和计数传递给非模板函数;或者只传递一个数组给模板函数(它会猜测计数)。 - Didier Trosset
谢谢确认。我已经传递了指针和计数,并且在运行时通过Instruments未发现任何内存泄漏。 - Kushal Ashok

3

虽然这不是你提出的问题,但是在你的代码示例中有一个容易出错的bug。 accumulate 中的初始值是模板化的,在你的代码中它被模板化为整数。如果你传递一个双精度浮点数集合,它们将被转换为整数,你会得到错误的答案。因为我曾经犯过这个错误,所以我制定了以下快速保证:

  /** Check that not inputting integer type into accumulate
   *  This is considered an error in this program (where a double was expected
   *  @tparam InputIterator The iterator to accumulate
   *  @tparam T The type to accumulate - will fail if integer.
   *  @param first The first iterator to accumulate from.
   *  @param last the iterator to acculate to,
   *  @param init The initial value
   *  @return The accumulated value as evaluated by std::accumulate.
   */
  template<class InputIterator, class T>
  inline
  T
  accumulate_checked(InputIterator first, InputIterator last, T init )
  {
    return std::accumulate(first,last, init);
  }

  //Not implemented for integers (will not compile if called).
  template<class InputIterator>
  inline
  int
  accumulate_checked(InputIterator first, InputIterator last, int init );

我想分享一下,以防有兴趣的人。

为了完整起见,您的函数可以看起来像:

double mean_array( double *array, size_t count )
{
    double sum = std::accumulate(array,array+count,0.0)
    return sum / count;
}

为了更加小心谨慎,

或者说

额外地注意。
double mean_array( double *array, size_t count )
{
    double sum = accumulate_checked(array,array+count,0.0)
    return sum / count;
}

或者更好的选择是来自Didier Trosset的模板版本。

2
为了使用std::accumulate,您需要包含适当的头文件。将以下内容添加到您的源文件中。
#include <numeric>

好的,看起来这就是我缺失的那个。我的包含文件很多,我漏掉了那一个。 - hyperknot

0
double mean_array( double *array, size_t count )
{
    double sum = 0.0;

    for (size_t i = 0; i < count; i++)
    {
        sum += array[i];
    }

    return sum / count;
}

或者

double mean_array( double *array, size_t count )
{
    double sum = 0.0;
    double *pastLast = array + count;

    while (array < pastLast)
    {
        sum += *array;
        array++;
    }

    return sum / count;
}

如果你将一个数组传递给一个函数,你会“失去”它的大小,所以你必须将它作为参数传递(这比较复杂...但现在应该足够了)。

但我不明白,难道它不能使用 int count = sizeof(array) / sizeof(array[0]); 吗? - hyperknot
如果你将一个数组传递给函数,你就会“失去”它的大小,所以你必须将其作为参数传递。此时sizeof(array)等于sizeof(double*)。如果你将它传递给函数,数组的大小就会丢失。如果你不相信我,可以尝试调试一下。 - xanatos
当您将数组作为函数参数传递时,它会衰减为指针。这不再是一个数组类型,并且“失去”了大小。通常,您还会像xanatos的示例一样将大小作为单独的参数传递。 - Blastfurnace
好的,现在清楚了。我不知道它会“衰变”成一个指针。感谢您提供代码和解释。 - hyperknot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接