代码之家  ›  专栏  ›  技术社区  ›  codingnight

大浮点和的精度。2.

  •  -1
  • codingnight  · 技术社区  · 7 年前

    我读到过,当把大量浮点相加时,最好的方法是从最低到最高求和。我写了一个代码,完全做到了这一点,但从最高到最低的总和更精确,我不明白为什么,我问它 here 。我接受了一个回答,说这是因为本地数组是在堆栈上创建的,空间有限。答案中的这段代码没有使用任何数组,因此更精确:

    #include <stdio.h>
    
    int main() {
    
    double pi2over6 = 1.644934066848226;
    double sum = 0.0, sum2 = 0.0;
    double y;
    int i, n;
    
    printf("Enter number of iterations:\n");
    scanf("%d", &n);
    
    y = 1.0;
    
    for (i = 0; i < n; i++) {
        sum += 1.0 / (y * y);
        y += 1.0;
    }
    
    for (i = 0; i < n; i++) {
        y -= 1.0;
        sum2 += 1.0 / (y * y);
    }
    printf("sum from biggest to smallest is %.16f\n", sum);
    printf("and its error %.16f\n", pi2over6 - sum);
    printf("sum from smallest to biggest is %.16f\n", sum2);
    printf("and its error %.16f\n", pi2over6 - sum2);
    return 0;
    

    是的,当输入为100000000时,如果输入为 1000 我仍然有同样的问题。为什么?

    1 回复  |  直到 7 年前
        1
  •  3
  •   Eric Postpischil    7 年前

    从最低到最高计算的总和更准确;它与精确结果相差约1 ULP,而从最高到最低计算的总和相差约7 ULP。

    将1000项的和与无限和进行比较是错误的。前1000个项的精确数学和与无限和之间的差异远远大于计算前一个和时出现的误差。1000个项的三个和(精确数学,从最低到最高,从最高到最低)彼此之间的距离在8 ULP以内,而无穷级数的和要高出4.5万亿ULP。

    (此外,估计 2. /6不准确。您的程序有1.644934066848226。在IEEE 754基本64位二进制浮点(我将使用它来回答这个问题)中,精确到1.6449340668484225961976488125986494123935699462890625。然而,1.644934066842264060656916626612655818462371826171875更接近 2. /6.)

    前1000项的精确数学和接近1.6439345666815598031390580238222155896521034464937。这是使用Maple进行扩展精度计算的。最接近的可表示值为1.643934566681559905632030706949918530881404876708984375。我称之为 最佳总和 ,因为任何计算的总和都可能与精确的数学值最接近,因为没有更接近的可表示值。

    从最高到最低的计算总数为1.64393456668156145994430517021100968224822998046875。这与最佳金额相差1.5543122344752191565930843353271484375e-15,即7 ULP。(ULP是向上调整可表示值的最小量;它是可表示值的步长。ULP是数字大小的函数;对于较大的数字,ULP更大。)7 ULP的差值意味着该数字距离最佳和有7步之遥。

    从最低到最高的计算总数为1.643934566681559683587465769960545003414154052734375。这与最佳总和相差-2.220446049250313080847263336181640625e-16,这是另一个方向的1 ULP(低于最佳总和)。

    因此,从最低到最高计算的总和更准确。

    无限和要高出4.5万亿ULP。

    因此,相对于最佳和,数字的顺序如下:

    • 从最低到最高计算的总和为1 ULP。
    • 最佳和是0 ULP处的参考点。
    • 从最高到最低计算的总和为+7 ULP。
    • Ï俣 2. /6为4.5万亿ULP。

    现在很明显,从最低到最高计算的总和 2. /6因为这是最好总和的另一边。但这更接近最佳金额。

    在任何情况下,计算从最低项到最高项的总和都不会得到最佳答案,这是没有绝对规则的。这是一个一般性的指导原则,基于错误较小而数字较小的概念。

    每次以浮点形式添加两个数字时,可能会有一个小错误,因为精确的数学结果必须四舍五入到一个可表示的值。误差总是最大为结果的ULP(因为,如果一个可表示值比精确数学结果的ULP大,则正确方向上的下一个可表示值比ULP小)。

    然而,误差可能在0和ULP之间变化,也可能是正的或负的。假设您添加一系列随机数。有可能的是,在从最高到最低的数字相加时,我们会遇到正负误差的混合,这些误差恰好在很大程度上相互抵消,偶然产生一个接近精确数学结果的最终结果。同时,从最低到最高的数字相加可能会遇到许多正错误,从而累积成一个大错误。

    将相同符号的数字从最低震级添加到最高震级往往会产生更好的结果,但这不是一条绝对规则。

    此外,如果数字是混合符号,则选择要添加的数字以保持运行和接近零,而不是总是选择下一个最小量级的数字,这可能是有利的。