Ich denke, Highams Genauigkeit und Stabilität numerischer Algorithmen befassen sich damit, wie man diese Art von Problemen analysieren kann. Siehe Kapitel 2, insbesondere Übung 2.8.
In dieser Antwort möchte ich auf etwas hinweisen, das in Highams Buch nicht wirklich angesprochen wird (es scheint im Übrigen nicht sehr bekannt zu sein). Wenn Sie interessiert sind zu beweisen Eigenschaften von einfachen numerischen Algorithmen wie diese, können Sie die Macht der modernen SMT - Solver (verwenden Satisfiability Modulo Theories ), wie z3 , ein Paket wie die Verwendung von SBV in Haskell. Das ist etwas einfacher als mit Bleistift und Papier.
Angenommen, mir wird , und ich würde gerne wissen, ob0 ≤ x ≤ yx ≤ z ≤ y erfüllt. Der folgende Haskell-Codez= ( 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
werde mich das automatisch machen lassen . Hier test1 fun
ist der Satz, dass für alle finiten floats x , y mit 0 ≤ x ≤ y .x ≤ f u n ( x , y) ≤ yx , y0 ≤ x ≤ y
λ> prove $ test1 (\x y -> (x + y) / 2)
Falsifiable. Counter-example:
x = 2.3089316e36 :: Float
y = 3.379786e38 :: Float
Es läuft über. Angenommen, ich nehme jetzt Ihre andere Formel: 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
Funktioniert nicht (aufgrund eines allmählichen Unterlaufs: , was möglicherweise nicht intuitiv ist, da alle Arithmetik zur Basis 2 gehört).( x / 2 ) × 2 ≤ x
Versuchen Sie nun :z= x + ( y- x ) / 2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
Funktioniert! Dies Q.E.D.
ist ein Beweis dafür, dass die test1
Eigenschaft für alle oben definierten Floats gilt.
Was ist mit dem gleichen, aber auf (anstelle von 0 ≤ x ≤ y )?x ≤ y0 ≤ x ≤ y
λ> prove $ test2 (\x y -> x + (y-x)/2)
Falsifiable. Counter-example:
x = -3.1300826e34 :: Float
y = 3.402721e38 :: Float
Okay, wenn überläuft, wie wäre es dann mit z =y- x ?z= x + ( y/ 2-x / 2)
λ> prove $ test2 (\x y -> x + (y/2 - x/2))
Q.E.D.
So scheint es, dass unter den Formeln, die ich hier ausprobiert habe, zu funktionieren scheint (auch mit einem Beweis). Der SMT-Solver-Ansatz scheint mir eine viel schnellere Möglichkeit zu sein, Verdacht auf einfache Fließkommaformeln zu äußern, als die Fließkomma-Fehleranalyse mit Bleistift und Papier durchzuführen.x + ( y/ 2-x / 2)
Schließlich steht das Ziel der Genauigkeit und Stabilität häufig im Widerspruch zum Ziel der Leistung. Was die Leistung angeht, sehe ich nicht wirklich, wie Sie es besser machen können als , zumal der Compiler immer noch die Mühe macht, dies in Maschinenanweisungen für Sie zu übersetzen.( x + y) / 2
PS Dies ist alles mit IEEE754-Gleitkomma-Arithmetik mit einfacher Genauigkeit. Ich habe x ≤ x + ( y/ 2-x / 2)≤ySFloat
SDouble
PPS-ffast-math
( x + y) / 2
PPPS Ich wurde ein wenig mitgerissen, als ich mir nur einfache algebraische Ausdrücke ohne Bedingungen ansah . Die Formel von Don Hatch ist streng besser.