最直接的手动计算l1范数方法是用std::accumulate配合std::abs,注意指定匹配的初始值类型(如0ll或0.0)并包含和头文件。

用 std::accumulate 手动算 L1 范数最直接
L1 范数就是所有元素绝对值之和,C++ 里没有现成的 norm_1 函数,但 std::accumulate 配合 std::abs 就够用了。注意必须用 std::abs(不是 C 的 abs),否则对 float/double 可能调错重载。
常见错误是忘记指定初始值类型:如果数组是 std::vector<float></float>,但写成 accumulate(v.begin(), v.end(), 0),0 是 int,会导致中间计算被截断或隐式转换开销。
- 对
int数组:std::accumulate(v.begin(), v.end(), 0LL)(用long long防溢出) - 对
float/double:std::accumulate(v.begin(), v.end(), 0.0f)或0.0 - 记得包含头文件:
#include <numeric></numeric>和#include <cmath></cmath>
算 L2 范数别直接开方,先用 std::sqrt 包裹平方和
L2 范数是各元素平方和再开方,关键在“先平方再求和,最后开方”。有人误用 std::hypot 想一步到位,但 std::hypot(a, b, c) 只支持最多两个参数(C++17 起才支持三参数,且非所有编译器稳定支持),对长度 >2 的数组不适用。
性能上,避免在循环里反复调用 std::sqrt;正确做法是先用 accumulate 算平方和,再整体调一次 std::sqrt。
- 示例(
std::vector<double> v</double>):std::sqrt(std::accumulate(v.begin(), v.end(), 0.0, [](double a, double b) { return a + b * b; })) - 如果用原始数组(如
double arr[10]),传入std::begin(arr)和std::end(arr)更安全 - 对整数数组,平方可能溢出,建议先转
double再算:static_cast<double>(x) * static_cast<double>(x)</double></double>
用 Eigen 库时,.lpNorm() 和 .norm() 最省心
如果你已经在用 Eigen(比如做数值计算或机器学习),别自己手写循环。它对 VectorXf、VectorXd 等类型原生支持范数计算,语义清晰且做了向量化优化。
注意:.norm() 默认就是 L2 范数(等价于 .lpNorm()),而 L1 要显式写 .lpNorm()。别混淆成 .sum()(那是元素和,不是绝对值和)。
-
v.lpNorm()→ L1 范数(自动取绝对值) -
v.norm()或v.lpNorm()→ L2 范数 - 不支持运行时决定 p 值,
和是模板参数,编译期固定
用 std::valarray 的 sum() 和 apply() 是冷门但标准库方案
标准库其实有轻量级数值容器 std::valarray,支持元素级操作,适合小规模、无需第三方依赖的场景。但它不常用,文档少,容易踩坑:比如 valarray 的 apply 返回新对象,不能原地修改;sum() 不带初值参数,类型由元素类型推导。
- L1:
v.apply([](double x) { return std::abs(x); }).sum() - L2:
std::sqrt((v * v).sum())(operator*是逐元素乘) - 缺点:不支持迭代器,不能和 STL 算法混用;
valarray的拷贝语义可能导致意外复制
实际项目里,没引入 Eigen 就用 std::accumulate + lambda;已有 Eigen 就别绕弯。L2 范数的平方和部分最容易漏掉类型提升,尤其处理 int 数组时,static_cast<double></double> 这一步常被跳过。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











