2016-11-21 22 views
0

私はハスケルを学習しています。私は自分自身でいくつかの関数を実行していますが、この関数には再帰を使った正弦の計算が含まれていますが、正弦関数の再帰計算は役に立たない

Maclaurin series

そして、私のコードはこれです::

私は正弦を計算するために使用している数式は、この一つです

--Returns n to power p 
pow :: Float->Integer->Float 
pow n p = 
    if p == 0 then 
     1 
    else 
     if p == 1 then 
     n 
     else 
     n * (pow n (p-1)) 

--Finds a number's factorial 
f :: Integer->Integer 
f n = 
    if n == 1 then 
     n 
    else 
     n * (f (n-1)) 

--TODO: Trigonometric functions (:v I'll do diz 2) 
sinus :: Float->Char->Float 
sinus n deg = 
    if(deg == 'd')then 
     sinusr 0 (normalize (torad n)) 0 
    else 
     sinusr 0 (normalize n) 0 

--Get the value equivalent to radians of the presented degrees 
torad :: Float->Float 
torad v = ((v * pi)/180) 

--Recursive to get the value of the entering radians 
sinusr :: Integer->Float->Float->Float 
sinusr k x result = 
    if k == 130 then 
    result + (((pow (-1) k) * ((pow x ((2*k)+1)))/(fromIntegral (f ((2*k)+1))))) 
    else 
    result + (sinusr (k+1) x (((pow (-1) k) * ((pow x ((2*k)+1)))/(fromIntegral (f ((2*k)+1)))))) 

--Subtracts pi/2 the necessary times to get a value minor or equals to pi/2 :v 
normalize :: Float->Float 
normalize a = a - (fromIntegral (truncate (a/(pi*2)))*(pi*2)) 

は、例えば、出力は、それがこのです:

*Main> sinus 1 'd' 
1.7452406e-2 
*Main> sinus 1 's' 
0.84147096 
*Main> sinus 2 's' 
NaN 
*Main> sinus 2 'd' 
3.4899496e-2 

誰かが私にそれを示している理由を教えてもらえますか? 私はLispと同じロジックを使いましたが、完璧に動作しました。私はHaskellの構文を理解しなければなりませんでしたが、わかるように、動作していません。 あらかじめ、ありがとうございます。

+1

出力が期待どおりでない場合は、常に_expected_出力を含めます。可能であれば、問題をローカライズしてください。 Aaaaaandは 'Float'を使用しません。 – Zeta

+0

出力について言えば、MacLaurinシリーズの式は大丈夫ですが、画像の出力ではなく、テキストとしてプログラムの出力を貼り付けてください。 – duplode

+1

ところで、問題を解決できる場合は、後ほど[CodeReview.SE]で(すぐに)コードをレビューするよう__strongly__してください。 – Zeta

答えて

1

三角演算は、三角関数を計算するのに十分ではありません。指数部には、大きな中間の数値のビット数がsinusrで十分ではありません。または、鈍いように、以下の番号はFloatに適合しない:

ghci> 2^130 :: Float 
Infinity 

とすぐに、あなたは通常、それらのかNaNのいずれかで終わる浮動小数点数(-InfinityInfinity)の境界を打つよう。

代わりにDoubleを使用してください。 lisp の実装ではおそらくは倍精度浮動小数点数も使用します。さらに、すべてのステップで分数全体を再計算しないで、代わりに指名子と分母を更新すると、Floatの値が大きくなりすぎることはありません。

+0

"さらに、すべてのステップで分数全体を再計算しないで、代わりに指名子と分母を更新すると、値が大きくなりすぎることはありません" - この点を支持するには、 'double'は(fromIntegral(f(2 * 130 + 1))のように)261の階乗で十分です。これはすぐに目に見えるエラーにつながるわけではありませんが、 'Infinity'で除算するとゼロになるので、' k 'のすべての項はゼロより大きくなります。 – duplode

+1

@duplode funny、この正確な数式は、私たちのCプログラミングクラッシュコースで実装しなければならなかったものでした。 Cは任意の大きな整数を持たないので、私たちは自分自身の "トリック"を考え出す必要がありました。ああ...良い時。 – Zeta

+0

本当にありがとうございます! 私はFloatからDoubleに変更しましたが、今は完全に動作しています。 –

関連する問題