Tôi nghĩ tính chính xác và tính ổn định của thuật toán số của Higham giải quyết cách thức người ta có thể phân tích các loại vấn đề này. Xem Chương 2, đặc biệt là bài tập 2.8.
Trong câu trả lời này, tôi muốn chỉ ra điều gì đó không thực sự được đề cập trong cuốn sách của Higham (dường như nó không được biết đến rộng rãi cho vấn đề đó). Nếu bạn quan tâm đến việc chứng minh các thuộc tính của các thuật toán số đơn giản như các thuật toán này, bạn có thể sử dụng sức mạnh của các bộ giải SMT hiện đại ( Lý thuyết Modulo thỏa mãn ), chẳng hạn như z3 , sử dụng gói như sbv trong Haskell. Điều này có phần dễ dàng hơn so với sử dụng bút chì và giấy.
Giả sử tôi đã cho rằng và tôi muốn biết liệu z = ( x + y ) / 2 có thỏa mãn x ≤ z ≤ y không . Mã Haskell sau đây0 ≤ 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
sẽ để tôi làm điều này tự động . Dưới đây test1 fun
là đề xuất rằng cho tất cả hữu hạn nổi x , y với 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
Nó tràn ra. Giả sử bây giờ tôi dùng công thức khác của bạn: 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
Không hoạt động (do dòng chảy dần dần: , có thể không trực quan do tất cả số học là cơ sở-2).( x / 2 ) × 2 ≠ x
Bây giờ hãy thử :z= x + ( y- x ) / 2
λ> prove $ test1 (\x y -> x + (y-x)/2)
Q.E.D.
Làm! Đây Q.E.D.
là một bằng chứng cho thấy test1
tài sản giữ cho tất cả các phao như được định nghĩa ở trên.
Điều gì giống nhau, nhưng bị giới hạn ở (thay vì 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
Được rồi, vậy nếu tràn ra, thì z = x + ( y / 2 - x / 2 ) thì sao?y- xz= x + ( y/ 2-x / 2)
λ> prove $ test2 (\x y -> x + (y/2 - x/2))
Q.E.D.
Vì vậy, có vẻ như trong số các công thức tôi đã thử ở đây, dường như hoạt động (với một bằng chứng, quá). Cách tiếp cận của người giải quyết SMT dường như là một cách nhanh chóng hơn để trả lời những nghi ngờ về các công thức dấu phẩy động đơn giản hơn là phân tích lỗi dấu phẩy động bằng bút chì và giấy.x + ( y/ 2-x / 2)
Cuối cùng, mục tiêu của sự chính xác và ổn định thường mâu thuẫn với mục tiêu hiệu suất. Về hiệu suất, tôi thực sự không thấy làm thế nào bạn có thể làm tốt hơn , đặc biệt là vì trình biên dịch vẫn sẽ thực hiện rất nhiều việc dịch điều này thành hướng dẫn máy cho bạn.( x + y) / 2
PS Đây là tất cả với chính xác đơn IEEE754 dấu chấm động số học. Tôi đã kiểm tra với số học có độ chính xác kép (thay thế bằng ) và nó cũng hoạt động.x ≤ x + ( y/ 2- x / 2 ) ≤ ySFloat
SDouble
-ffast-math
( x +y) / 2
PPPS Tôi đã mang đi một chút chỉ nhìn vào các biểu thức đại số đơn giản mà không có điều kiện. Công thức của Don Hatch hoàn toàn tốt hơn.