Haskell 补偿(Kahan)求和的幺半群?

Haskell 补偿(Kahan)求和的幺半群?,haskell,floating-point,sum,monoids,Haskell,Floating Point,Sum,Monoids,假设我有这样的代码,用于执行Doubles的补偿(Kahan Babuška Neumaier)和: -- A type for compensated summation. data Sum = Sum {-# UNPACK #-} !Double {-# UNPACK #-} !Double deriving (Eq, Ord, Show) -- Add a number to the Sum, updating the error value as well. addSum :: S

假设我有这样的代码,用于执行
Double
s的补偿(Kahan Babuška Neumaier)和:

-- A type for compensated summation.
data Sum = Sum {-# UNPACK #-} !Double {-# UNPACK #-} !Double
  deriving (Eq, Ord, Show)

-- Add a number to the Sum, updating the error value as well.
addSum :: Sum -> Double -> Sum
addSum (Sum s c) x = Sum s' c' where
  s' = s + x
  d  | abs s >= abs x = (s - s') + x
     | otherwise      = (x - s') + s
  c' = c + d
{-# INLINE addSum #-}

-- Get the compensated value from the Sum.
getSum :: Sum -> Double
getSum (Sum s c) = s + c
{-# INLINE getSum #-}

-- Add a whole list (or list-like object) of Doubles.
sumAll :: Foldable f => f Double -> Double
sumAll ls = getSum $ foldl' addSum (Sum 0 0) ls
{-# INLINE sumAll #-}
然而,我还需要一个
Monoid
,因为我想并行计算值。我要寻找的是以下几点:

-- Make a Sum from a Double value. It has an error of 0.
mkSum :: Double -> Sum
mkSum x = Sum x 0
{-# INLINE mkSum #-}

instance Monoid Sum where
  mempty = Sum 0 0
  {-# INLINE mempty #-}

  mappend (Sum sa ca) (Sum sb cb) = ...?
我想它可能有一种类似于:

  mappend a@(Sum sa ca) b@(Sum sb cb)
    | ???       = addSum a (sb + cb)
    | otherwise = addSum b (sa + ca)

我希望它是可交换的,如果不是更多的话,至少和普通的
Double
加法一样具有关联性。

如果有一个正确的
mappend
它可能是

mappend :: Sum -> Sum -> Sum
mappend (Sum s c) (Sum x c2) = Sum s' c' where
  s' = s + x
  d  | abs s >= abs x = (s - s') + x
     | otherwise      = (x - s') + s
  c' = (c + c2) + d
资料来源:直觉

直觉是它是满足属性
mappend s1(Sum x 0)=addSum s1 x
的最简单的东西,并且是可交换的。它的关联性很难检查

检查关联性很困难,因为添加
Double
s不是关联的。因此,
Sum
mappend
是不相关的;问题是,它是否具有足够的关联性。一个可能的标准是,关联
mappend
的错误变化小于或等于将参数转换为
sumAll
的错误变化

根据您的标准,它已经“至少与正常的
Double
addition关联”,因为它是正常的
Double
addition。事实上,这是对正常的
Double
加法的改进。如果
Double
s是关联的,那么
d
将是
0
。任何添加到总和
c1+c2
的非零
d
都是对
Double
加法的关联性的改进,跟踪并纠正
Double
s的非关联性中的错误


通过使用一种更好的求和
Double
s的方法,可以改进
c'
的计算。它们可以被分类,一个la:

sumThree :: Double -> Double -> Double -> Double
sumThree a b c
    | abs a >= abs b && abs a >= abs c = (b + c) + a
    | abs b >= abs a && abs b >= abs c = (a + c) + b
    | otherwise                        = (a + b) + c

或者使用Kahan求和本身进行求和,
sumAll[c,c2,d]
。如果它们是用Kahan求和本身求和的,
sumAll
就不能用
mappend

实现,这不是Haskell的问题,而是Kahan求和本身的问题,是吗?也许最好在或问一下。