几何平均数需用对数求和再指数还原:先对各正元素取自然对数并累加,除以元素个数后取指数,避免乘积溢出与开方不稳,要求输入全为正数且统一用double类型。

用 std::accumulate 和 std::pow 算几何平均数容易出错
直接套用算术平均的思路(比如用 std::accumulate 求和再除以长度)不行——几何平均要先求所有元素乘积,再开 n 次方。但 C++ 数组里一旦有 0 或负数,乘积就崩了;整型溢出也极常见;std::accumulate 默认用加法,没法直接改成交乘。
- 必须确保所有元素 > 0(几何平均在实数域要求严格正数)
- 别用
int数组直接连乘——哪怕只有 10 个int(10)就会溢出 -
std::pow(product, 1.0 / n)对大乘积不稳,浮点精度丢失严重,甚至返回inf或nan
推荐做法:转成对数求和再指数还原
数学上:geomean = exp((log(x₁) + log(x₂) + ... + log(xₙ)) / n)。这绕开了乘积爆炸和开方不稳的问题,数值更健壮。
- 遍历数组,对每个元素调用
std::log(注意:输入必须 > 0,否则std::log返回-inf或nan) - 累加对数值,最后除以
n,再用std::exp还原 - 类型统一用
double,避免float精度不足
double geometric_mean(const double arr[], size_t n) {
if (n == 0) return 0.0;
double sum_log = 0.0;
for (size_t i = 0; i < n; ++i) {
if (arr[i] <= 0.0) throw std::invalid_argument("All elements must be positive");
sum_log += std::log(arr[i]);
}
return std::exp(sum_log / n);
}
用 std::vector 替代裸数组时要注意迭代器类型
如果实际用的是 std::vector<double>,别直接把 begin() 丢给 std::accumulate 做对数累加——它不支持自定义二元操作符做“加对数”。得手写循环或用 std::transform_reduce(C++17 起)。
- C++17 可用:
std::transform_reduce(v.begin(), v.end(), 0.0, std::plus<>{}, [](double x){ return std::log(x); }) - 老标准就老老实实写 for 循环,比折腾适配器更可靠
- 别传
std::vector::data()给裸数组函数而不检查size()——空 vector 的data()可能为 nullptr
整型数组必须先转 double 再处理
哪怕全是正整数,也不能对 int[] 直接取 log——std::log 没有 int 重载,隐式转 double 是安全的,但若手动 cast 成 float 就可能掉精度。
立即学习“C++免费学习笔记(深入)”;
- 安全写法:
std::log(static_cast<double>(arr[i])) - 千万别用
(double)arr[i]这种 C 风格 cast,容易在模板上下文中出问题 - 如果原始数据是
unsigned long long且值很大(> 2⁵³),转double会丢低位比特——这时得用long double加std::logl,但平台支持不一
0 和负数比想象中更容易混进来。


















