鲁棒和快速的浮点平方和

时间:2019-01-13 16:43:44

标签: floating-point lapack

我想创建一个健壮且快速的平方和。一个简单的解决方案是(在C ++中):

double sumOfSquares(const double *v, size_t n) {
    double r = 0;
    for (size_t i=0; i<n; i++) {
        r += v[i]*v[i];
    }
    return r;
}

此例程并不健壮,因为当v[i]较小或较大(计算不足/溢出)时,它无法给出良好的结果。这也不是最准确的例程,因为我们可以通过更好的方式对数字求和(例如在求和之前进行排序)。

我已经检查了LAPACK的DLASSQ以获取启发(我在问题的末尾包含了源代码)。

基本上,DLASSQ维护一个scale变量(此变量是即时计算的,它是已经看到的最大元素),并且数组元素通过该变量进行除法缩放。这样,例程可以避免下溢/上溢。

但是,我不喜欢这种解决方案,例如:

  • 至少有n个分区,这意味着例程很慢
  • 这些部门可能会降低准确性

我正在考虑可能的改进:比例尺始终是2的幂(已经看到的最大元素四舍五入为2的幂)。这样:

  • 因为2的幂的倒数就是2的幂,所以我可以完美地存储标度的倒数
  • 因此按比例划分可以用乘法代替(这样例程会快得多)
  • 此乘法不会失去任何准确性,因为它只是一个指数调整

我的问题是:这是个好主意吗?我看不到陷阱吗?


这是DLASSQ(fortran代码)的源代码:

      SUBROUTINE DLASSQ( N, X, INCX, SCALE, SUMSQ )
*
*  -- LAPACK auxiliary routine (version 3.7.0) --
*  -- LAPACK is a software package provided by Univ. of Tennessee,    --
*  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
*     December 2016
*
*     .. Scalar Arguments ..
      INTEGER            INCX, N
      DOUBLE PRECISION   SCALE, SUMSQ
*     ..
*     .. Array Arguments ..
      DOUBLE PRECISION   X( * )
*     ..
*
* =====================================================================
*
*     .. Parameters ..
      DOUBLE PRECISION   ZERO
      PARAMETER          ( ZERO = 0.0D+0 )
*     ..
*     .. Local Scalars ..
      INTEGER            IX
      DOUBLE PRECISION   ABSXI
*     ..
*     .. External Functions ..
      LOGICAL            DISNAN
      EXTERNAL           DISNAN
*     ..
*     .. Intrinsic Functions ..
      INTRINSIC          ABS
*     ..
*     .. Executable Statements ..
*
      IF( N.GT.0 ) THEN
         DO 10 IX = 1, 1 + ( N-1 )*INCX, INCX
            ABSXI = ABS( X( IX ) )
            IF( ABSXI.GT.ZERO.OR.DISNAN( ABSXI ) ) THEN
               IF( SCALE.LT.ABSXI ) THEN
                  SUMSQ = 1 + SUMSQ*( SCALE / ABSXI )**2
                  SCALE = ABSXI
               ELSE
                  SUMSQ = SUMSQ + ( ABSXI / SCALE )**2
               END IF
            END IF
   10    CONTINUE
      END IF
      RETURN
*
*     End of DLASSQ
*
      END

0 个答案:

没有答案