Creo que la precisión y la estabilidad de los algoritmos numéricos de Higham aborda cómo uno puede analizar este tipo de problemas. Vea el Capítulo 2, especialmente el ejercicio 2.8.
En esta respuesta, me gustaría señalar algo que realmente no se aborda en el libro de Higham (no parece ser muy conocido, de hecho). Si está interesado en probar las propiedades de algoritmos numéricos simples como estos, puede usar el poder de los solucionadores SMT modernos ( Teorías del módulo de satisfacción ), como z3 , usando un paquete como sbv en Haskell. Esto es algo más fácil que usar lápiz y papel.
Supongamos que se me da que , y me gustaría saber si z = ( x + y ) / 2 satisface x ≤ z ≤ y . El siguiente código de Haskell0≤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
me dejará hacer esto automáticamente . Aquí test1 fun
está la proposición de que para todos los flotadores finitos 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
Se desborda. Supongamos que ahora tomo su otra fórmula: 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
No funciona (debido al flujo inferior gradual: , lo que podría no ser intuitivo debido a que toda la aritmética es base-2).( x / 2 ) × 2 ≠ x
Ahora intente :z= x + ( y- x ) / 2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
¡Trabajos! El Q.E.D.
es una prueba de que la test1
propiedad es válida para todas las carrozas como se definió anteriormente.
¿Qué pasa con lo mismo, pero restringido a (en lugar de 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
Bien, entonces si desborda, ¿qué tal 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.
Entonces parece que entre las fórmulas que he probado aquí, parece funcionar (con una prueba, también). El enfoque del solucionador SMT me parece una forma mucho más rápida de responder a las sospechas sobre fórmulas simples de punto flotante que pasar por un análisis de error de punto flotante con lápiz y papel.x + ( y/ 2-x / 2)
Finalmente, el objetivo de precisión y estabilidad a menudo está en desacuerdo con el objetivo de rendimiento. Para el rendimiento, realmente no veo cómo puede hacerlo mejor que , especialmente porque el compilador aún hará el trabajo pesado de traducir esto en instrucciones de máquina para usted.( x + y) / 2
x ≤ x + ( y/ 2-x / 2)≤ySFloat
SDouble
-ffast-math
( x + y) / 2
PPPS Me dejé llevar un poco mirando solo expresiones algebraicas simples sin condicionales. La fórmula de Don Hatch es estrictamente mejor.