Penso che l' accuratezza e la stabilità degli algoritmi numerici di Higham riguardino il modo in cui si possono analizzare questi tipi di problemi. Vedi il capitolo 2, in particolare l'esercizio 2.8.
In questa risposta vorrei sottolineare qualcosa che non è realmente affrontato nel libro di Higham (non sembra essere molto conosciuto, del resto). Se sei interessato a dimostrare le proprietà di semplici algoritmi numerici come questi, puoi usare la potenza dei moderni solutori SMT ( Teorie del Modulo di soddisfazione ), come z3 , usando un pacchetto come sbv in Haskell. Questo è un po 'più semplice rispetto all'uso di carta e matita.
Supponiamo che mi venga dato 0 ≤ x ≤ y , e vorrei sapere se soddisfa x ≤ z ≤ y . Il seguente codice Haskellz= ( 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
mi permetterà di farlo automaticamente . Ecco test1 fun
la proposizione che per tutti i galleggianti finiti x , y con 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
Trabocca. Supponiamo che ora prenda la tua altra formula: 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
Non funziona (a causa del underflow graduale: , che potrebbe non essere intuitivo a causa del fatto che tutta l'aritmetica è base-2).( x / 2 ) × 2 ≠ x
Ora prova :z= x + ( y- x ) / 2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
Lavori! Il Q.E.D.
è una prova che la test1
proprietà vale per tutti i carri come sopra definito.
Che dire dello stesso, ma limitato a (invece di 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
Ok, quindi se trabocca, che ne dici di zy- x ?z= x + ( y/ 2-x / 2)
λ> prove $ test2 (\x y -> x + (y/2 - x/2))
Q.E.D.
Quindi sembra che tra le formule che ho provato qui, sembra funzionare (anche con una prova). L'approccio del risolutore SMT mi sembra un modo molto più rapido di rispondere ai sospetti su semplici formule in virgola mobile rispetto all'analisi degli errori in virgola mobile con carta e matita.x + ( y/ 2-x / 2)
Infine, l'obiettivo di precisione e stabilità è spesso in contrasto con l'obiettivo della prestazione. Per quanto riguarda le prestazioni, non vedo davvero come si possa fare meglio di , soprattutto perché il compilatore farà comunque il duro lavoro di tradurre questo in istruzioni macchina per te.( x + y) / 2
PS Questo è tutto con l'aritmetica in virgola mobile IEEE754 a precisione singola. Ho controllato con aritmetica a doppia precisione (sostituirecon), e funziona anche.x ≤ x + ( y/ 2-x / 2)≤ySFloat
SDouble
-ffast-math
( x + y) / 2
PPPS Mi sono lasciato trasportare un po 'guardando solo espressioni algebriche semplici senza condizionali. La formula di Don Hatch è strettamente migliore.