贝利信息

c++中如何计算标准差与方差_c++数学计算统计函数

日期:2026-01-04 00:00 / 作者:裘德小鎮的故事
最稳妥方式是用std::accumulate两遍遍历:先求均值,再算平方偏差均值;样本方差除以n-1,总体方差除以n;需预检查NaN/inf、空容器及分母为零。

std::accumulate 手动计算方差和标准差最稳妥

标准库没有内置的方差或标准差函数,std::valarray 虽有 sum() 但不支持直接求均值平方差;依赖第三方库(如 Boost.Math)会增加构建复杂度。实际项目中,用 std::accumulate 两遍遍历是最可控的方式:第一遍算均值,第二遍算平方偏差均值。

#include 
#include 
#include 

double variance(const std::vector& data, int ddof = 0) { if (data.empty()) return 0.0; double mean = std::accumulate(data.begin(), data.end(), 0.0) / data.size(); double sum_sq_diff = std::accumulate(data.begin(), data.end(), 0.0, [mean](double acc, double x) { return acc + (x - mean) * (x - mean); }); return sum_sq_diff / (data.size() - ddof); }

double stddev(const std::vector& data, int ddof = 0) { return std::sqrt(variance(data, ddof)); }

std::valarray 快速原型但慎用于生产

std::valarray 支持向量化运算,写起来简洁,但存在隐式拷贝开销、不支持迭代器、且部分老编译器(如 MSVC 2015 前)实现不全。仅建议在小规模数据、快速验证公式时使用。

#include 
#include 

double variance_valarray(const std::valarray& v) { if (v.size() == 0) return 0.0; double mean = v.sum() / v.size(); std::valarray diff = v - mean; return (diff * diff).sum() / v.size(); }

遇到 nan 或负方差?检查输入和溢出路径

调用后得到 nanvariance 返回负值,几乎一定是以下原因:

性能敏感场景用 Welford 算法单趟完成

当数据来自流式输入(如传感器、文件逐行读取)、不能存全量或内存受限时,Welford 方法可在一次遍历中累积计算方差,且数值稳定性优于两遍法。

struct Welford {
    double M = 0.0, S = 0.0;
    size_t n = 0;
void add(double x) {
    n++;
    double delta = x - M;
    M += delta / n;
    S += delta * (x - M);
}

double variance(int ddof = 0) const {
    return n <= static_castzuojiankuohaophpcnsize_tyoujiankuohaophpcn(ddof) ? 0.0 : S / (n - ddof);
}

double stddev(int ddof = 0) const {
    return std::sqrt(variance(ddof));
}

};

Welford 算法的数值稳定性常被低估——它真正难处理的是极端情况:比如所有数都接近 1e308,此时 delta 计算仍可能失真。这种时候,要么换更高精度类型(long double),要么做预平移(减去估计均值再算)。