[英]Natural Logarithm using series in Haskell Gives Imprecise Results
所以我寫了兩個函數來計算變量x的自然對數,將增量和的上限增加到33000之后,與從Prelude導入的默認對數函數相比,這些函數仍返回在ghci中測試的不精確結果,這是代碼定義:
lnOfx :: Float -> Float
lnOfx x = netSum f 1 33000
where f i = 2*(1/oddTerm)*((x-1)/(x+1))**oddTerm
where oddTerm = 2*i-1
netSum f minB maxB = sum [f i | i <- [minB .. maxB]]
lnOfx2 :: Float -> Float
lnOfx2 x = netSum f 1 33000
where f i = (1/i)*((x-1)/x)**i
netSum f minB maxB = sum [f i | i <- [minB .. maxB]]
和測試結果:
log 3
1.0986122886681098
lnOfx 3
1.0986125
lnOfx2 3
1.0986122
log 2
0.6931471805599453
lnOfx 2
0.6931472
lnOfx2 2
0.6931473
那么,為什么結果不同?正確計算自然對數的正確方法(如Prelude的對數函數)是什么?
浮點數學運算很棘手。 可能導致精度損失的一件事是相加幅度相差很大的數字。 例如,在以i=25
開頭的算法中,總和中的項很小,以至於它們不再起作用:
-- 25t term:
let f x i = let oddTerm = 2*i-1 in 2*(1/oddTerm)*((x-1)/(x+1))**oddTerm
let y = f 3.0 25
-- summation up to 24 item
let s = 1.098612288668109
-- this will return True, surprisingly!
s + y == s
為減輕這種情況,您可以做的一件事是按相反的順序添加數字,因此,在將較小的數字添加到較大的數字之前,先將它們相加。
lnOfx :: Float -> Float
lnOfx x = netSum f 1 33000
where f i = 2*(1/oddTerm)*((x-1)/(x+1))**oddTerm
where oddTerm = 2*i-1
netSum f minB maxB = sum $ reverse [f i | i <- [minB .. maxB]]
在我的測試中,這足以使print (lnOfx 3.0)
和print (log 3.0)
顯示所有相同的數字。
但總的來說,我建議閱讀一本數值分析書,以了解有關此類問題的更多信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.