为什么在浮点中从大到小会引入更多的误差

Why adding big to small in floating point introduce more error?

本文关键字:误差 从大到小 为什么      更新时间:2023-10-16

不知道为什么,但如果我把大到小的fp数字相加,增量误差似乎更大:

#include <iostream>
#include <math.h>
int main() {
std::cout.precision(50);
const int numLoops = 1000;
const long length = 10000;
const double rate = 0.1;
long totalLength = length * numLoops;
long long steps = (long long)(totalLength / rate);
double sum = 0.0;
double sumRemainder = 0.0;
for (long long step = 0; step < steps; step++) {
if (sumRemainder >= length) {
sumRemainder = fmod(sumRemainder, length);
}
sum += rate;
sumRemainder += rate;
}
std::cout << "                  length: " << length << std::endl;
std::cout << "               num loops: " << numLoops << std::endl;
std::cout << "                    rate: " << rate << std::endl;
std::cout << "                   steps: " << steps << std::endl << std::endl;
std::cout << "                     sum: " << sum << std::endl;
std::cout << "           sum remainder: " << sumRemainder << std::endl;
std::cout << "                   error: " << abs(totalLength - sum) << std::endl;
std::cout << "         error remainder: " << abs(length - sumRemainder) << std::endl;
std::cout << std::endl;
}

这两个和之间唯一的区别是,一个是所有步骤,而另一个是,一旦达到极限,我就简单地计算结果(因此,它会钳制到一个小值(:

sumRemainder = fmod(sumRemainder, length);

这似乎是它在求和相同数量时引入低误差的原因:1.884836819954216480255126953125e-050.01887054927647113800048828125

有人能用一个聪明的例子向我解释为什么会发生这种情况吗?

要处理大数字或小数字,浮点格式可缩放数字。一个数字的有效位使用固定数量的数字,这些数字按某个基数(通常为2(的幂进行缩放,称为指数。还有一个符号、+或−,尽管该符号有时包含在有效位中。

例如,使用二进制格式,1.0112的有效位在用零指数缩放时表示1+3/16(1.0112>20=1+3/16(,在用四指数缩放时代表11(1.011>sub>2

<2>4*<sub=−1>有效位有固定数量的数字。所以只有特定的数字可以表示。当执行任何算术运算时,精确的数学结果将四舍五入到最接近的可表示数。(舍入的常见默认规则是舍入到最接近的可表示值,在平局的情况下,舍入到最低位数为偶数。(

例如,在有效位中有三位小数的十进制格式中,考虑将数字567(5.67•102(和789(7.89•102>(相加。结果是1356,但位数太多。因此,它被四舍五入到1360(1.36•103(。四舍五进误差为4。

因此,当使用浮点数时,会出现舍入误差,这些误差是有效位中最低有效位位置值的一小部分。当数字的指数较大时,可能的误差也较大。误差总是在零和最低有效数字位置值的一半之间(因为两个可表示数字之间的任何数字要么在中点,要么更接近一个或另一个,所以从来没有必要移动一个数字超过可表示数字间距离的一半。(

因此,当使用较大的数字时,舍入误差较大。