我认为Higham的数值算法的准确性和稳定性解决了人们如何分析这些类型的问题。参见第2章,特别是练习2.8。
在此答案中,我想指出一些在Higham的书中并未真正解决的问题(就此而言,它似乎并不广为人知)。如果你有兴趣的证明,如这些简单的数值算法性能,可以使用现代SMT求解器(功率可满足模理论),如Z3,采用了包,如SBV在Haskell。这比使用铅笔和纸要容易一些。
假设我假定,我想知道如果ž = (X + Ý )/ 2满足X ≤ Ž ≤ ÿ。以下Haskell代码0≤x≤yz=(x+y)/2x≤z≤y
import Data.SBV
test1 :: (SFloat -> SFloat -> SFloat) -> Symbolic SBool
test1 fun =
do [x, y] <- sFloats ["x", "y"]
constrain $ bnot (isInfiniteFP x) &&& bnot (isInfiniteFP y)
constrain $ 0 .<= x &&& x .<= y
let z = fun x y
return $ x .<= z &&& z .<= y
test2 :: (SFloat -> SFloat -> SFloat) -> Symbolic SBool
test2 fun =
do [x, y] <- sFloats ["x", "y"]
constrain $ bnot (isInfiniteFP x) &&& bnot (isInfiniteFP y)
constrain $ x .<= y
let z = fun x y
return $ x .<= z &&& z .<= y
让我自动做到这一点。这里test1 fun
是命题即所有有限浮X ,ÿ与0 ≤ X ≤ ÿ。x≤fun(x,y)≤yx,y0≤x≤y
λ> prove $ test1 (\x y -> (x + y) / 2)
Falsifiable. Counter-example:
x = 2.3089316e36 :: Float
y = 3.379786e38 :: Float
它溢出了。假设我现在采用您的其他公式:z=x/2+y/2
λ> prove $ test1 (\x y -> x/2 + y/2)
Falsifiable. Counter-example:
x = 2.3509886e-38 :: Float
y = 2.3509886e-38 :: Float
不起作用(由于逐渐下溢:,由于所有算术均以2为底,因此可能不直观)。(x/2)×2≠x
现在尝试:z=x+(y−x)/2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
作品!该Q.E.D.
是证明该test1
财产所有花车持有如上定义。
什么是相同的,但仅限于(而不是0 ≤ X ≤ ÿ)?x≤y0≤x≤y
λ> prove $ test2 (\x y -> x + (y-x)/2)
Falsifiable. Counter-example:
x = -3.1300826e34 :: Float
y = 3.402721e38 :: Float
好的,如果溢出,那么z = x + (y / 2 − x / 2 )怎么样?y−xz=x+(y/2−x/2)
λ> prove $ test2 (\x y -> x + (y/2 - x/2))
Q.E.D.
因此,似乎在我尝试过的公式中,似乎也起作用(也有证明)。在我看来,SMT求解器方法比使用铅笔和纸进行浮点误差分析来回答有关简单浮点公式的怀疑要快得多。x+(y/2−x/2)
最后,准确性和稳定性的目标通常与性能目标不一致。为了提高性能,我真的没有看到如何比做得更好,尤其是因为编译器仍然会为您将其翻译成机器指令而费劲。(x+y)/2
PS这就是单精度IEEE754浮点运算的全部。我检查与双精度运算(替换用),和它的作品了。x≤x+(y/2−x/2)≤ySFloat
SDouble
PPS在代码中实现此功能时要记住的一件事是,像这样的编译器标志-ffast-math
(某些形式的此类标志有时在某些常见的编译器中默认为打开)不会导致IEEE754算术,这会使上述证明无效。如果您确实使用了启用关联加法优化的标志,那么除了之外,别无他法。(x+y)/2
PPPS让我有些困惑,只看了没有条件的简单代数表达式。Don Hatch的公式严格更好。