Floating point 几何平均数的安全计算

Floating point 几何平均数的安全计算,floating-point,average,precision,numerical-methods,Floating Point,Average,Precision,Numerical Methods,我正在寻找一个理由来选择以下方法之一来计算长系列浮点x的几何平均值: 取每个x的n个根,然后将它们全部相乘 把它们都乘起来,然后取n根 我听说对于浮点数,乘法和除法比加法和减法损失的信息更少。因此,我不考虑求和指数技巧 我应该通过1或2计算几何平均数,为什么 更新1,回应评论: 所有x均小于1且为双精度。它们的数量级在10^-1到10^-6之间。请假设计算n次方根的最常用方法,因为我使用的是编程语言的内置函数。我担心的不是溢出,而是下溢(?),因为所有值都小于1。您可以假设x序列的长度为10^

我正在寻找一个理由来选择以下方法之一来计算长系列浮点
x
的几何平均值:

  • 取每个
    x
    的n个根,然后将它们全部相乘
  • 把它们都乘起来,然后取n根
  • 我听说对于浮点数,乘法和除法比加法和减法损失的信息更少。因此,我不考虑求和指数技巧

    我应该通过1或2计算几何平均数,为什么


    更新1,回应评论:


    所有x均小于1且为双精度。它们的数量级在10^-1到10^-6之间。请假设计算n次方根的最常用方法,因为我使用的是编程语言的内置函数。我担心的不是溢出,而是下溢(?),因为所有值都小于1。您可以假设x序列的长度为10^8左右。一般来说,在浮点运算序列中,也包括收缩运算(如平方根或立方根),从精度角度来看,最后执行收缩运算是有利的。例如,
    sqrt(1.0/x)
    1.0/sqrt(x)
    更准确,
    sqrt(a*b)
    sqrt(a)*sqrt(b)
    更准确,
    cbrt(a*b*c)
    cbrt(a)*cbrt(b)*cbrt(c)
    更准确

    因此,除非所选浮点格式存在溢出或下溢的危险,例如IEEE-754
    binary64
    (例如C/C++中的
    double
    ),否则在中间计算中,应选择方法[2]。与精度相关的其他方面:如果n次方根是通过求幂计算的,例如C/C++中的
    pow()
    ,则每个计算的根都会引入额外的错误,正如我在对的回答中对立方根的情况所解释的。最后,第n个根的计算速度将比乘法慢,因此,从性能角度来看,仅使用最后一个根计算进行乘法也是一种优越的方法

    通过使用补偿产品(类似于由提供的补偿添加),方法[2]可以获得非常精确的结果。详情见以下文件:

    Stef Graillat,“精确浮点积和求幂”,《计算机上的IEEE交易》,第58卷,第7期,2009年7月,第994-1000页()

    在硬件中提供FMA(融合乘法-加法)操作的系统上,可以特别有效地计算此补偿乘积。这是所有常见的现代处理器体系结构的情况,包括CPU和GPU。C/C++通过标准的数学函数
    fma()
    fmaf()
    ,方便地访问该函数


    更新:Asker在评论中澄清,下溢风险迫在眉睫,因为[10-6,10-1]中有108个因素。@Yves Daoust在评论中提到的一种可能的解决方法是将因子分为尾数和指数,并分别累加。这是否可行取决于浮点环境。当C和C++提供标准函数<代码> FRXPH()/Cys>执行此分裂时,这个函数可能不是很快。< /P>浮点序列的序列(数量级)有多长?您计划如何计算第n个根?对于方法(2),您选择的浮点格式是否有溢出的危险?性能是否需要考虑?假设不存在溢出双精度浮点格式的危险,并且精度是最重要的设计标准,我建议使用方法(2),使用补偿乘积,然后在末尾取n次方。关于补偿积(如果FMA可用,可以非常有效地计算),请参阅:Stef Graillat,“精确浮点积和求幂”,IEEE计算机交易,第58卷,第7期,2009年7月,第994-1000页。()只是一个注释:在exp-sum-log方法中,并不是真正的加法和减法是导致精度损失的主要原因(而且在任何情况下,都有正确四舍五入求和的好算法);这是日志调用。毫不奇怪,将整个正浮点范围映射到区间(0.0710.0)的函数会导致大量信息丢失@njuffa:有没有可能得到封装您的评论的答案?类似地,对于大型
    n
    ,第n个根操作将丢失重要信息;我同意@njuffa的观点,即(2)将更加精确。方法2中溢出的风险可以通过单独累加浮点指数来避免。