应使用std::vector存储x、y数据,避免裸数组;计算前检查大小一致且非空;用四次累加(sum_x、sum_y、sum_xy、sum_xx)代入公式求a、b;需处理分母为0及浮点精度边界。

用 std::vector 存数据,别手写数组
线性回归最基础的实现只需要两个向量:一个存 x 值,一个存 y 值。手写裸数组(比如 double x[100])容易越界、难扩容、没法传参进函数。直接用 std::vector<double></double> 更安全,也方便后续扩展成多变量。
常见错误是把 x 和 y 搞反顺序,或者长度不一致——计算前务必加一句检查:
if (x.size() != y.size() || x.empty()) {
throw std::invalid_argument("x and y must be non-empty and same size");
}公式推导要落地到四次累加,不是抄数学符号
一元线性回归的斜率 b 和截距 a 公式看着简单,但实际编码时不能直接套 $\frac{\sum(x-\bar{x})(y-\bar{y})}{\sum(x-\bar{x})^2}$,因为会引入两次遍历 + 浮点误差放大。更稳的做法是展开成四个单次累加:
-
sum_x、sum_y -
sum_xy(对应 $\sum xy$) -
sum_xx(对应 $\sum x^2$)
然后代入:b = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x)a = (sum_y - b * sum_x) / n
立即学习“C++免费学习笔记(深入)”;
注意分母为 0 的情况(所有 x 值相同),此时无唯一解,应提前返回或报错。
用 std::accumulate 还是手写循环?看可读性和调试需求
对新手来说,手写 for (size_t i = 0; i 更直观,出错能立刻打断点看每一步;用 <code>std::accumulate 配合 lambda 虽短,但调试时堆栈深、变量不可见,还容易写错初始值类型(比如用 0 当初值导致整数除法)。
推荐手写循环,尤其当你要同时算多个累加项时:
double sum_x = 0, sum_y = 0, sum_xx = 0, sum_xy = 0;
for (size_t i = 0; i < x.size(); ++i) {
sum_x += x[i];
sum_y += y[i];
sum_xx += x[i] * x[i];
sum_xy += x[i] * y[i];
}这里 size_t 是安全的,但若可能为空容器,先判断再进循环,避免 x.size() 返回 0 导致循环不执行却继续算除法。
预测函数别忘了检查输入是否在训练范围内
拟合完得到 a 和 b 后,封装一个 predict(double x_val) 很自然,但很多人忽略:线性回归本身不拒绝域外输入,可现实中拿训练时从未见过的极大/极小 x 值去预测,结果可能严重失真。
建议在 predict 里加可选范围检查:
if (x_val < min_x || x_val > max_x) {
// 可 warn,也可抛异常,取决于业务容忍度
}其中 min_x 和 max_x 应在训练时一并记录,而不是每次预测都重算 minmax_element —— 多一次遍历不值得。
浮点精度问题也会悄悄影响结果,比如 sum_xx 和 sum_x * sum_x / n 差几个 ulp,可能导致分母接近零却不等于零,这种边界得靠 std::abs(denominator) 判断,而不是 <code>== 0。


















