Я думаю, що точність і стабільність чисельних алгоритмів Хіггема вирішує, як можна аналізувати такі типи проблем. Див. Главу 2, особливо вправу 2.8.
У цій відповіді я хотів би зазначити щось, що насправді не розглянуто у книзі Хіггема (це, здається, не дуже відоме з цього приводу). Якщо ви зацікавлені в доведенні властивостей простих чисельних алгоритмів, таких як ці, ви можете використовувати потужність сучасних SMT-рішувачів ( Satisfiability Modulo Theories ), таких як z3 , використовуючи такий пакет, як sbv в Haskell. Це дещо простіше, ніж використання олівця та паперу.
Припускаю , я , з огляду на , що , і я хотів би знати , якщо г = ( х + у ) / 2 задовольняє й ≤ г ≤ у . Наступний код 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
дозволить мені зробити це автоматично . Ось test1 fun
це припущення , що для всіх кінцевих поплавками х , у з 0 ≤ х ≤ у .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= х + ( у- х ) / 2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
Працює! Це Q.E.D.
є доказом того, що test1
властивість має місце для всіх плавців, як визначено вище.
Що про те саме, але обмежено (замість 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
Добре, так що якщо переповнює, як щодо z = x + ( y / 2 - x / 2 ) ?у- хz= х + ( у/ 2-х / 2)
λ> prove $ test2 (\x y -> x + (y/2 - x/2))
Q.E.D.
Тож здається, що серед формул, які я спробував тут, здається, працює (і з доказом). Підхід до рішення SMT мені здається набагато швидшим способом відповіді на підозри щодо простих формул з плаваючою комою, ніж проходження аналізу помилок з плаваючою комою олівцем і папером.х + ( у/ 2-х / 2)
Нарешті, мета точності та стабільності часто суперечить меті виконання. Для продуктивності я не дуже розумію, як можна зробити краще, ніж , тим більше, що компілятор все-таки зробить важкий підйом перекладу цього тексту на інструкції для вас.( х + у) / 2
PS Це все з одноточною арифметикою IEEE754 з плаваючою комою. Я перевірив з арифметикою подвійної точності (замінити на ), і це також працює.x ≤ x + ( y/ 2-x / 2)≤ySFloat
SDouble
PPS Одне, що слід пам’ятати при впровадженні цього в код, - це те, що прапорці компілятора на зразок -ffast-math
(деякі форми таких прапорів іноді за замовчуванням включаються в деяких загальних компіляторах) не призведе до арифметики IEEE754, що призведе до недійсності наведених вище доказів. Якщо ви використовуєте прапори, які включають, наприклад, асоціативні оптимізації додавання, то немає сенсу робити щось, крім .( х + у) / 2
PPPS Я трохи захопився, дивлячись лише на прості алгебраїчні вирази без умовних умов. Дон Hatch «s формула строго краще.