2017-04-09 6 views
1

変数xの自然対数を計算するために、増分合計の上限を33000に増やした後、関数はghciでデフォルトのログと比較して不正確な結果を返すここでは、プレリュードからインポート機能は、コードの定義です:Haskellで自然対数を使用すると、結果が不正確になる

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 

、なぜ結果が違うとプレリュードからのログ機能などの正しい方法は、(どのようなんです)を計算する自然対数を正しく計算するか?

+0

(1)浮動小数点演算は性質上不正確です。 (2)あなたの関数の不正確さの一部は、 'Double'ではなく' Float'を使用しているという理由だけで発生します。 – duplode

+0

@duplode応答に感謝します。確かにもっと正確ですが、関数の型シグネチャをfloatからDoubleに変更した後、Preludeログとの比較を行ったところ、最後の数桁はまだ大きく異なります。 –

答えて

6

浮動小数点数の計算は難しいです。精度を損なう可能性のあるものの1つは、非常に異なる大きさの数値を追加することです。たとえば、あなたのアルゴリズムでは、あなたの合計で約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)はすべて同じ数字を示したように、これは十分でした。

一般的に、この種の問題の詳細については、数値解析の本を読むことをお勧めします。

関連する問題