Je pense que la précision et la stabilité des algorithmes numériques de Higham explique comment analyser ces types de problèmes. Voir le chapitre 2, en particulier l'exercice 2.8.
Dans cette réponse, je voudrais souligner quelque chose qui n'est pas vraiment abordé dans le livre de Higham (il ne semble pas être très largement connu, d'ailleurs). Si vous souhaitez prouver les propriétés d'algorithmes numériques simples comme ceux-ci, vous pouvez utiliser la puissance des solveurs SMT modernes ( Satisfiability Modulo Theories ), tels que z3 , en utilisant un package tel que sbv dans Haskell. C'est un peu plus facile que d'utiliser du crayon et du papier.
Supposons que l'on me donne , et j'aimerais savoir si z = ( x + y ) / 2 satisfait x ≤ z ≤ y . Le code Haskell suivant0 ≤ 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 permettra de le faire automatiquement . Voici test1 fun
la proposition que pour tous les flotteurs finis x , y avec 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
Il déborde. Supposons que je prenne maintenant votre autre formule: 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
Ne fonctionne pas (en raison d'un débordement progressif: , ce qui pourrait ne pas être intuitif en raison de l'arithmétique de base 2).(x/2)×2≠x
Essayez maintenant :z=x+(y−x)/2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
Travaux! Le Q.E.D.
est une preuve que la test1
propriété est valable pour tous les flottants tels que définis ci-dessus.
Qu'en est-il de la même chose, mais limité à (au lieu 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
D'accord, donc si déborde, qu'en est-il de 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.
Il semble donc que parmi les formules que j'ai essayées ici, semble fonctionner (avec une preuve aussi). L'approche du solveur SMT me semble un moyen beaucoup plus rapide de répondre aux soupçons sur les formules simples à virgule flottante que de passer par l'analyse d'erreurs à virgule flottante avec un crayon et du papier.x+(y/ 2-x /2)
Enfin, l'objectif de précision et de stabilité est souvent en contradiction avec l'objectif de performance. Pour les performances, je ne vois pas vraiment comment vous pouvez faire mieux que , d'autant plus que le compilateur fera toujours le gros du travail pour traduire cela en instructions machine pour vous.( x + y) / 2
x ≤ x + ( y/ 2-x / 2)≤ySFloat
SDouble
-ffast-math
( x + y) / 2
PPPS Je me suis un peu emporté en ne regardant que les expressions algébriques simples sans conditions. La formule de Don Hatch est strictement meilleure.