Sanırım Higham'ın Sayısal Algoritmaların Doğruluğu ve Kararlılığı, bu tür problemleri nasıl analiz edebileceğini ele alıyor. Bkz. Bölüm 2, özellikle egzersiz 2.8.
Bu cevapta Higham'ın kitabında gerçekten ele alınmayan bir şeyi belirtmek istiyorum (bu konuda çok fazla bilinmemektedir). Eğer ilgilenen varsa ispat Bunlar gibi basit sayısal algoritmaların özelliklerini, modern SMT çözenler (gücünü kullanabilir Gerçeklenebilirlik Modülo Teorileri gibi), z3 gibi bir paket kullanarak, SBV Haskell. Bu, kalem ve kağıt kullanmaktan biraz daha kolaydır.
O verileni varsayalım ve bilmek istiyorum ise Z = ( x + y ) / 2 tatmin x ≤ z ≤ y . Aşağıdaki Haskell kodu0≤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
bunu otomatik olarak yapmama izin verecek . Burada test1 fun
bir önerme olduğu her sonlu mantarlar için x , y ile 0 ≤ x ≤ y .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
Taşar. Şimdi diğer formülünüzü aldığımı varsayalım: 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
Çalışmaz (kademeli alt akış nedeniyle: , tüm aritmetik taban-2 olması nedeniyle sezgisel olmayabilir).(x/2)×2≠x
Şimdi deneyin :z=x+(y−x)/2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
İşler! Bu Q.E.D.
, özelliğin yukarıda tanımlandığı gibi tüm şamandıralar için sahip olduğunun bir kanıtıdırtest1
.
Peki ya aynı, ama sınırlı ( 0 ≤ x ≤ y yerine )?x≤y0≤x≤y
λ> prove $ test2 (\x y -> x + (y-x)/2)
Falsifiable. Counter-example:
x = -3.1300826e34 :: Float
y = 3.402721e38 :: Float
Tamam, eğer taşarsa, 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.
Bu yüzden burada denediğim formüller arasında işe yarıyor gibi görünüyor (bir kanıtla da). SMT çözücü yaklaşımı bana basit kayan nokta formülleri hakkındaki şüpheleri, kalem ve kağıtla kayan nokta hata analizinden geçmekten çok daha hızlı bir yol gibi geliyor.x+(y/2−x/2)
Son olarak, doğruluk ve istikrar hedefi genellikle performans hedefi ile çelişmektedir. Performans için, daha iyi nasıl yapabileceğinizi gerçekten görmüyorum , özellikle de derleyici yine de bunu sizin için makine talimatlarına çevirmenin ağır kaldırmasını yapacak.(x+y)/2
PS Tüm bunlar tek duyarlıklı IEEE754 kayan noktalı aritmetiktir. Bildiğim kadarıyla çift hassas aritmetik (yerine sahip olan ), ve çok çalışır.x≤x+(y/2−x/2)≤ySFloat
SDouble
PPS Bunu kodda uygularken akılda tutulması gereken bir şey, derleyici bayrakları gibi -ffast-math
(bu tür bayrakların bazı biçimleri bazen bazı ortak derleyicilerde varsayılan olarak açıktır ), yukarıdaki kanıtları geçersiz kılacak olan IEEE754 aritmetiği ile sonuçlanmaz. İlişkili ekleme optimizasyonlarını etkinleştiren bayraklar kullanırsanız, dışında bir şey yapmanın bir anlamı yoktur .(x+y)/2
PPPS Biraz koşullu olmayan basit cebirsel ifadelere baktım. Don Hatch 'ın formülü kesinlikle daha iyidir.