为什么浮点数中从大到小相加会引入更多误差?

mar*_*zzz -1 c++ floating-point rounding-error

不知道为什么,但如果我将大到小的 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;
}
Run Code Online (Sandbox Code Playgroud)

两个总和之间的唯一区别是,一个适用于所有步骤,而另一个我只是在达到极限后对结果进行 fmod(因此,它会限制为一个小值):

sumRemainder = fmod(sumRemainder, length);
Run Code Online (Sandbox Code Playgroud)

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

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

Eri*_*hil 6

为了处理大数或小数,浮点格式会对数字进行缩放。数字的有效数使用固定数量的数字,并且按某个基数(通常为 2)的幂(称为指数)进行缩放。还有一个符号、 + 或 \xe2\x88\x92,尽管该符号有时包含在尾数中。

\n\n

例如,使用二进制格式时,尾数 1.011 2在使用指数 0 缩放时表示 1+3/16 (1.011 2 \xe2\x80\xa22 0 = 1+3/16),在使用指数缩放时表示 11四个 (1.011 2 \xe2\x80\xa22 4 = 11),当以指数 \xe2\x88\x921 缩放时为 11/32 (1.011 2 \xe2\x80\xa22 \xe2\x88\x921 = 11/ 32)。

\n\n

有效数有固定位数。所以只能表示某些数字。执行任何算术时,精确的数学结果将四舍五入到最接近的可表示数字。(舍入的常见默认规则是四舍五入到最接近的可表示值,并且在平局的情况下四舍五入,使低位数字为偶数。)

\n\n

例如,在尾数具有三位十进制数字的十进制格式中,请考虑添加数字 567 (5.67\xe2\x80\xa210 2 ) 和 789 (7.89\xe2\x80\xa210 2 )。结果是 1356,但是位数太多。因此它四舍五入为 1360 (1.36\xe2\x80\xa210 3 )。舍入误差为 4。

\n\n

因此,在处理浮点数时,会存在舍入误差,这些误差是尾数中最低有效数字的位置值的一部分。当数字的指数越大时,可能的误差就越大。误差始终在零和最低有效数字位置值的一半之间(因为两个可表示数字之间的任何数字要么位于中点,要么更接近其中之一,因此永远不需要将数字移动超过一半)可表示数字之间的距离。)

\n\n

因此,当处理较大数字时,舍入误差较大。

\n