ฉันคิดว่าความแม่นยำและความเสถียรของอัลกอริธึมเชิงตัวเลขของไฮตั้มจะบอกถึงวิธีการวิเคราะห์ปัญหาเหล่านี้ ดูบทที่ 2 โดยเฉพาะอย่างยิ่งการออกกำลังกาย 2.8
ในคำตอบนี้ฉันต้องการชี้ให้เห็นสิ่งที่ไม่ได้กล่าวถึงในหนังสือของ Higham (ดูเหมือนจะไม่เป็นที่รู้จักอย่างกว้างขวางสำหรับเรื่องนั้น) หากคุณสนใจที่จะพิสูจน์คุณสมบัติของอัลกอริธึมเชิงตัวเลขอย่างง่ายเช่นนี้คุณสามารถใช้พลังของนักแก้ปัญหา SMT ที่ทันสมัย ( ทฤษฎีโมดูโลที่น่าพอใจ ) เช่นz3โดยใช้แพ็คเกจเช่นsbvใน Haskell ค่อนข้างง่ายกว่าการใช้ดินสอกับกระดาษ
สมมติว่าผมให้ที่และผมอยากจะรู้ว่าถ้าZ = ( x + Y ) / 2 satisfies x ≤ Z ≤ Y รหัส Haskell ต่อไปนี้0≤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
เป็นเรื่องที่สำหรับทุก จำกัด ลอยx , y ที่มี0 ≤ x ≤ Yx≤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= x + ( y- x ) / 2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
Works! นี่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 ) ?Y- xZ= x + ( y/ 2-x / 2)
λ> prove $ test2 (\x y -> x + (y/2 - x/2))
Q.E.D.
ดังนั้นดูเหมือนว่าในบรรดาสูตรที่ฉันได้ลองที่นี่ดูเหมือนว่าจะทำงานได้ (พร้อมการพิสูจน์ด้วย) วิธีแก้ปัญหาแบบ SMT ดูเหมือนจะเป็นวิธีที่รวดเร็วกว่าในการตอบข้อสงสัยเกี่ยวกับสูตรจุดลอยตัวที่ง่ายกว่าการวิเคราะห์ข้อผิดพลาดจุดลอยตัวด้วยดินสอและกระดาษx + ( y/ 2-x / 2)
ในที่สุดเป้าหมายของความแม่นยำและความเสถียรมักจะขัดแย้งกับเป้าหมายของการปฏิบัติงาน สำหรับประสิทธิภาพฉันไม่เห็นว่าคุณจะทำได้ดีกว่าโดยเฉพาะอย่างยิ่งเนื่องจากคอมไพเลอร์จะยังคงยกการแปลนี้เป็นคำแนะนำสำหรับเครื่องของคุณอย่างหนัก( x + y) / 2
PSสิ่งนี้คือทั้งหมดที่มีความแม่นยำเลขทศนิยม IEEE754 ฉันตรวจสอบด้วยเลขคณิตความแม่นยำสองเท่า (แทนที่ด้วย) และใช้งานได้เช่นกันx ≤ x + ( y/ 2-x / 2)≤ySFloat
SDouble
PPSสิ่งหนึ่งที่ควรคำนึงถึงเมื่อใช้สิ่งนี้ในรหัสคือคอมไพเลอร์แฟล็กเช่น-ffast-math
(บางรูปแบบของแฟล็กดังกล่าวเปิดตามค่าเริ่มต้นในคอมไพเลอร์ทั่วไปบางตัว) จะไม่ส่งผลให้เกิดเลขคณิต IEEE754 ถ้าคุณทำธงที่ช่วยให้การใช้งานเช่นการเพิ่มประสิทธิภาพนอกจากนี้ยังเชื่อมโยงแล้วมีจุดในการทำสิ่งอื่นที่ไม่ใช่ไม่มี 2( x + y) / 2
PPPSฉันถูกมองไปที่นิพจน์พีชคณิตแบบง่าย ๆ โดยที่ไม่มีเงื่อนไข สูตรของDon Hatchดีกว่าอย่างเคร่งครัด