Floating point 是";银行家';s四舍五入“;真的更稳定吗?

Floating point 是";银行家';s四舍五入“;真的更稳定吗?,floating-point,language-agnostic,rounding,floating-accuracy,Floating Point,Language Agnostic,Rounding,Floating Accuracy,我所说的银行家四舍五入是指 “四舍五入,五舍五入” 作为: 四舍五入到最接近的值;如果数字中途下降,则使用偶数(零)最低有效位四舍五入到最接近的值。这是二进制浮点的默认值,也是十进制的推荐默认值 据说这种方法比其他方法更可取 “四舍五入到最近,距离为零” 它“将四舍五入数字相加时的预期误差降至最低”。显然,这是“在最合理的分布上,它不像舍入半离零法那样受到负或正偏差的影响” 我不明白为什么会这样。直观地说,如果将0.0四舍五入为零,0.5“应该”四舍五入为零(如方法2所示)。这样,等量的数字将向

我所说的银行家四舍五入是指

  • “四舍五入,五舍五入”
  • 作为:

    四舍五入到最接近的值;如果数字中途下降,则使用偶数(零)最低有效位四舍五入到最接近的值。这是二进制浮点的默认值,也是十进制的推荐默认值

    据说这种方法比其他方法更可取

  • “四舍五入到最近,距离为零”
  • 它“将四舍五入数字相加时的预期误差降至最低”。显然,这是“在最合理的分布上,它不像舍入半离零法那样受到负或正偏差的影响”

    我不明白为什么会这样。直观地说,如果将
    0.0
    四舍五入为零,
    0.5
    “应该”四舍五入为零(如方法2所示)。这样,等量的数字将向零和远离零取整。简单地说,如果浮点数用一个十进制数字表示,那么在十个数字中,
    0.0
    ,…,
    0.9
    五个将向下舍入,五个将使用方法2向上舍入。类似地,对于
    1.0
    ,…,
    1.9

    当然,浮点数是用二进制尾数表示的,但我认为上面的推理仍然适用。请注意,对于IEEE 754双精度,整数和整数加一半都可以精确地表示为绝对值,大约为
    2^52
    ,因此这些精确值实际上在实践中会出现

    那么方法1如何更好呢?

    对它确实在数值上更稳定

    对于您正在查看的案例,数字
    [0.0,0.1,…,0.9]
    ,请注意,在舍入到“远离”的关系下,这些数字中只有四个向下舍入(
    0.1
    0.4
    ),五个向上舍入,一个(
    0.0
    )通过舍入操作保持不变,当然,对于
    1.0
    1.9
    2.0
    2.9
    ,这种模式会重复。因此,平均而言,从零开始舍入的值比从零开始舍入的值多。但在与平的圆形关系下,我们会得到:

    • [0.0,0.9]
    • [1.0,1.9]
    等等。平均而言,我们得到的值向上舍入和向下舍入的数目相同。更重要的是,舍入引入的预期误差(在输入分布的适当假设下)接近于零

    下面是一个使用Python的快速演示。为了避免由于Python 2/Python 3在内置的
    round
    函数中的差异而带来的困难,我们给出了两个Python版本不可知的舍入函数:

    def圆形到偶数(x):
    """
    将浮点x四舍五入到最接近的整数,四舍五入到偶数。
    """
    如果x<0:
    返回-圆形到偶数(-x)#使用对称
    内部零件,分形零件=divmod(x,1)
    返回整数(整数部分)+(
    压裂部分>0.5
    或(分形部分==0.5和整数部分%2.0==1.0))
    def圆形接头远离零点(x):
    """
    将浮点x四舍五入到最接近的整数,将关系从零四舍五入。
    """
    如果x<0:
    返回-圆_ties _远离_zero(-x)#使用对称
    内部零件,分形零件=divmod(x,1)
    返回整数(整数部分)+(分数部分>=0.5)
    
    现在,我们来看一下将这两个函数应用于范围
    [50.01000.0]
    中小数点后的一位数字时引入的平均误差:

    >>测试值=[n/10.0表示范围内的n(5001001)]
    >>>错误\u偶数=[四舍五入\u到\u偶数(值)-测试值中的值对应值]
    >>>errors_away=[取整_ties_away_from_zero(value)-测试值中值的值]
    
    我们使用最近添加的
    统计
    标准库模块来计算这些误差的平均值和标准偏差:

    导入统计信息 >>>statistics.mean(错误为偶数),statistics.stdev(错误为偶数) (0.0, 0.2915475947422656) >>>statistics.mean(错误),statistics.stdev(错误) (0.0499001996007984, 0.28723681870533313) 这里的关键点是
    错误\u甚至
    的平均值为零:平均误差为零。但是
    errors\u away
    具有正平均值:平均误差偏离零


    一个更现实的例子 这是一个半现实的例子,演示了在数值算法中圆结偏离零的偏差。我们要用这个算法计算一系列浮点数的和。该算法将要计算的和分成两个大致相等的部分,递归地对这两部分求和,然后将结果相加。它比简单的求和要精确得多,但通常不如更复杂的算法那样精确。这是NumPy的
    sum
    函数使用的算法。下面是一个简单的Python实现

    导入操作符
    def pairwise_sum(xs,i,j,add=operator.add):
    """
    
    返回浮点的总和xs[i:j](从
    0.0
    0.9
    的十个数字中有0个,四个向下舍入,五个向上舍入,一个保持不变。@MarkDickinson啊,这是有道理的。除去整数,我想我看到了银行家的舍入是如何减少偏差的。这是一个很好的例子:从
    1.0
    开始。添加
    epsilon/2
    ,subtract
    epsilon/2
    ,重复。从数学上讲,无论你重复多少次,结果都应该是
    1.0
    。在向上取整的过程中,你会慢慢爬向
    2.0
    @MarkDickinson。你能把你的评论转化为答案吗?我认为它很好地澄清了这个问题。我会努力找到时间。事实上,我很乐意看到这里的一位专家给出了一个经过适当研究的答案:我从理论上知道,有一些真正的算法会受到“漂移”的影响