我正在尝试编写一个函数来计算具有最小二乘法的数据表中的回归线,但是我的代码遇到了一些严重的问题。
我的第一个问题是,我不知道为什么我的“线性回归”函数会舍入迭代的结果,即使我正在尝试使用其他“更大”的类型。
我的第二个问题是我的代码的最后一部分给出了y截距(b)和斜率(a)的错误结果,我认为这可能是转换问题,但我不是非常肯定。如果是这样的话,我应该怎么做才能避免呢?
void RegLin (const vector<double>& valuesX, const vector<double>& valuesY, vector<double>& PenOrd) {
unsigned int N=valuesX.size();
long double SomXi{0};
for (unsigned i=0; i<N; ++i){
SomXi+=valuesX.at(i);
}
long double SomXiXi{0};
for (unsigned i=0; i<N; ++i){ //Here is a problem (number rounded) Expected value: 937352,25 / Given value: 937352
SomXiXi+=(valuesX.at(i))*(valuesX.at(i));
}
long double SomYi{0};
for (unsigned i=0; i<N; ++i){
SomYi+=valuesY.at(i);
}
long double SomXiYi{0};
for (unsigned i=0; i<N; ++i){ //Here is the same problem Excepted value: 334107,41 / Given value: 334107
SomXiYi+=(valuesX.at(i))*(valuesY.at(i));
}
long double a=(SomYi*SomXiXi-SomXi*SomXiYi)/(N*SomXiXi-pow(SomXi,2)); //Bad result
long double b=(N*SomXiYi-SomYi*SomXi)/(N*SomXiXi-pow(SomXi,2)); //Bad result
PenOrd.push_back(a);
PenOrd.push_back(b);
return;
}
提前感谢您的支持
P.S:我正在使用g ++和2011 C ++标准。
答案 0 :(得分:2)
你的努力有几点。我是理论物理和数学数学家。所以,让我与您分享一些最佳实践。
首先,我从未遇到使用long double
的需要。坚持使用double
,因为如果这还不够,那么你应该考虑使用工作日志日志来进一步分析你的数据。
其次,你是using unsigned
int而不是int
。您永远不应该使用那么多的值(即值对)进行回归处理,它不足以对整数计数器使用int
或最佳std::size_t
。由于累积数值舍入问题,使用太多值会降低准确性。因此,在您有充分的理由这样做之前,请不要使用超过10000到1百万的值。
第三,很快就不必直截了当地添加你的方块(例如,对于SumXiXi等等),而是在实际总结它们之前对你的贡献进行排序。你可以正确地总结它们,从最小的价值观开始,随着你对你的金额不断增长的贡献。这是保持累积问题的唯一方法。
第四,控制结果。结果可靠性的一个好的迹象是可以实现的,如果你去工作两次,一次就像你做的那样(即使用x_iy_i - xy_i - x_iy + xy
formuae)然后作为第二种方法使用仍然未乘的{{1公式。使用任一公式,良好的质量计算将产生非常可比的结果。
所以,也许 对于进行数值回归工作非常谨慎,希望它可能会有所帮助。
问候,Micha
答案 1 :(得分:0)
浮点数值计算的第一条规则是:“只使用相同顺序的值”。
浮点数学在例如以下情况下非常简单加法(浮动):
1e6 + 1e-6 = 1000000 + 0.000001 = 1000000.000001 = 1000000 = 1e6
^
precision limit
所以,如你所见,结果是“四舍五入”。
答案 2 :(得分:0)
由于2个可能性,您可能会因错误而被给予错误:
1)long double == double
在你的编译器上,你得到错误的结果
2)浮点运算不代表100%准确度的值,因此&#39; 0.10 != 0.10 written as float/double
根据您正在进行的计算类型,我会恳请您增加几个幂的值或将数据更改为float并将值存储为double。