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求和本身的问题,是吗?也许最好在或问一下。