避免双精度数字的四舍五入
Avoiding the rounding of double numbers
我正在尝试编写一个函数,该函数使用最小二乘方法从数据表中计算回归线,但是我的代码遇到了一些严重的问题。
我的第一个问题是,我不知道为什么我的"线性回归"函数要舍入迭代的结果,即使我尝试使用其他"更大"的类型也是如此。
我的第二个问题是,我的代码的最后一部分给了我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;
}
提前感谢您的支持
PS:我使用的是 g++ 和 2011 C++ 标准。
你的努力是有分点的。我是一个理论物理和数值数学的人。因此,让我与您分享一些最佳实践。
首先,我从未遇到过使用long double
的需要。坚持使用double
,因为如果这还不够,那么您应该考虑使用对数-对数图来进一步分析您的数据。
其次,您using unsigned
int 而不是int
。您永远不应该对那么多的值(即值对)进行回归工作,以至于对整数计数器使用int
或最佳std::size_t
是不够的。由于累积数值舍入问题,使用过多的值可能会降低准确性。因此,不要使用超过 10000 到 100 万个值,直到您有充分的理由这样做。
第三,很快,有必要不要直截了当地添加你的平方(例如,对于 SumXiXi 等),而是在实际汇总之前对你的贡献进行排序。你正确地总结它们,从最小的价值开始,然后是你对总和不断增长的贡献。这是掌握累积四舍五入问题的唯一方法。
第四,结果控制。结果可靠性的一个好迹象是可以实现的,如果你对你的工作进行两次,一次是你所做的(即使用x_iy_i - xy_i - x_iy + xy
形式),然后作为第二种方法使用尚未相乘的(x_i - x)(y_i - y)
公式。使用任一公式,高质量的计算都会产生非常可比的结果。
所以,也许这是做数值回归工作的弯路,希望它能有所帮助。
问候,米查
浮点数值计算的第一条规则说:"只处理相同顺序的值"。
浮点数学在例如加法(浮点)的情况下非常简单:
1e6 + 1e-6 = 1000000 + 0.000001 = 1000000.000001 = 1000000 = 1e6
^
precision limit
因此,如您所见,结果是"四舍五入"的。
由于2 种可能性,您完全有可能出现错误:
1)long double == double
编译器,你得到错误的结果
2)浮点运算不能以100%的精度表示值,因此0.10 != 0.10 written as float/double
根据您正在执行的计算类型,我会建议您将值增加几次方或将数据更改为浮点数并以双倍存储值。
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 检查输入是否不是整数或数字
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 如何用数字处理log(0)
- 使用 BMI 计算器对C++中的数字进行四舍五入的问题
- 为什么将双精度转换为 int 似乎在第 16 位数字之后将其四舍五入?
- 找到printf的意外错误,该格式为0.1F,用于四舍五入数字
- 避免双精度数字的四舍五入
- 有没有办法将数字作为字符串,并在不使用浮点数或双精度数的情况下将其四舍五入到确切的位数
- 由于四舍五入,计算 1 到 100 之间的数字的程序永远不会猜"100"
- 为什么(long)总是把数字四舍五入
- 四舍五入浮点数:精确地输出小数点后的两位数字
- 将双精度数字四舍五入到十分之一位
- 从文本文件C++读入时,数字的奇怪四舍五入
- 我需要知道如何在c++中将数字四舍五入到小数点后的某个位置
- 将非常小的数字四舍五入为零(c++)
- 小数字四舍五入为零
- 像 0.999999 这样的数字四舍五入为 1