这是我的问题:我需要一个计算某些数字的窦的函数......
在C ++中我写了这个:
double msin(double number, int counter = 0, double sum = 0)
{
// sin(x) = x - (x'3 / 3!) + (x'5 / 5!) - (x'7 / 7!) + (x'9 / 9!)
if (counter <= 20)
{
if (counter % 2 == 0)
sum += mpow(number, counter * 2 + 1) / mfak(counter * 2 + 1) ;
else
sum -= mpow(number, counter * 2 + 1) / mfak(counter * 2 + 1) ;
counter++;
sum = msin(number, counter, sum);
return sum;
}
return (sum* 180.0 / _PI);
}
现在我试图在Haskell中做到这一点,我不知道如何......现在我正在尝试这样的事情(它确实没有用,但正在进行中;)):
这有效:
mfak number = if number < 2
then 1
else number *( mfak (number -1 ))
mpow number potenca = if potenca == 0
then 0
else if potenca == 1
then 1
else (number * (mpow number (potenca-1)))
这不起作用:
msin :: Double -> Int -> Double -> Double
msin number counter sum = if counter <= 20
then if counter `mod` 2==0
then let sum = sum + (msin 1 (let counter = counter+1 in counter) sum) in sum
else let sum = sum + (msin 1 (let counter = counter+1 in counter) sum) in sum
else sum* 180.0 / 3.14
更新....没有编译:/&#34;无法匹配预期类型Double' with actual type
Int&#39;&#34;
msin :: Double -> Int -> Double -> Double
msin number counter sum = if counter <= 20
then if counter `mod` 2==0
then let sum' = sum + ((mpow number (counter*2+1))/(mfak counter*2+1)) in msin number (counter+1) sum'
else let sum' = sum - ((mpow number (counter*2+1))/(mfak counter*2+1)) in msin number (counter+1) sum'
else sum* 180.0 / 3.14
正如你所看到的,最大的问题是如何在&#34;总和&#34;中添加内容,增加&#34;计数器&#34;并使用这些新值再次进行递归......
P.S。我是Haskell的新手,所以尽可能多地尝试解决你的解决方案。我正在阅读一些教程,但是,我无法找到如何将某些表达式的结果保存到一个值中,然后继续使用其他代码......它只是在每次我尝试这样做时返回我的值,而且我不想那样....
提前tnxx提供任何帮助!
答案 0 :(得分:5)
问题是像let stevec = stevec+1 in stevec
这样的表达式。 Haskell不是一种命令式语言。这不会向stevec
添加一个。相反,它将stevec
定义为比自身多一个的数字。没有这样的数字,因此你会得到一个无限循环,或者,如果你幸运的话,你会崩溃。
而不是
stevec++;
vsota = msin(stevilo, stevec, vsota);
您应该使用类似
的内容let stevec' = stevec + 1
in msin stevilo stevec' vsota
或只是
msin stevilo (stevec + 1) vsota
(这里还有一些我不明白的东西。你需要mpow
和mfak
。他们在哪里?)
答案 1 :(得分:4)
我会稍微修改算法。首先,我们可以定义阶乘反演列表:
factorialInv :: [Double]
factorialInv = scanl (/) 1 [1..] -- 1/0! , 1/1! , 1/2! , 1/3! , ...
然后,我们遵循正弦系数:
sineCoefficients :: [Double]
sineCoefficients = 0 : 1 : 0 : -1 : sineCoefficients
然后,在给定x
的情况下,我们将上述列表与x
的幂相乘,逐点:
powerSeries :: [Double] -- ^ Coefficients
-> Double -- ^ Point x on which to compute the series
-> [Double] -- ^ Series terms
powerSeries cs x = zipWith3 (\a b c -> a * b * c) cs powers factorialInv
where powers = iterate (*x) 1 -- 1 , x , x^2 , x^3 , ...
最后,我们采用前20个术语并总结。
sine :: Double -> Double
sine = sum . take 20 . powerSeries sineCoefficients
-- i.e., sine x = sum (take 20 (powerSeries sineCoefficients x))
答案 2 :(得分:1)
As you can see the biggest problem is how to add something to "vsota",
在函数式语言中,您将在此处使用递归 - 变量vstota
实现为函数参数,在处理列表时将其从调用传递给调用。
例如,要总结一个数字列表,我们会写一些类似的东西:
sum xs = go 0 xs
where go total [] = total
go total (x:xs) = go (total+x) xs
在命令式语言中total
将是一个更新的变量。这是一个函数参数,它被传递给下一个递归调用go
。
在你的情况下,我会首先编写一个函数来生成幂级数的术语:
sinusTerms n x = ... -- the first n terms of x - (x'3 / 3!) + (x'5 / 5!) - (x'7 / 7!) ...
然后使用上面的sum
函数:
sinus n x = sum (sinusTerms n x)
答案 3 :(得分:1)
您还可以使用递归列表定义来获取[x, x^3, x^5 ...]
和[1, 1/3!, 1/5! ...]
无限序列。当它们完成后,剩下的就是将它们各自的项目相乘并取总和。
sinus count x = sum (take count $ zipWith (*) ifactorials xpowers)
where xpowers = x : map ((x*x)*) xpowers
ifactorials = 1 : zipWith (/) ifactorials [i*(i+1) | i <- [2, 4 .. ]]
此外,定义xpowers = iterate ((x*x)*) x
会更好,因为它似乎更具可读性。
答案 4 :(得分:0)
我尽可能地遵循你的惯例。对于mfak
和mpow
,您应该避免使用if
,因为使用模式匹配更清楚地编写它们:
mfak :: Int -> Int
mfak 0 = 1
mfak 1 = 1
mfak n = n * mfak (n - 1)
mpow :: Double -> Int -> Double
mpow _ 0 = 1
mpow x 1 = x
mpow x p = x * mpow x (p - 1)
在计算窦之前,我们创建一系列系数[(sign, power, factorial)]
:
x - (x^3 / 3!) + (x^5 / 5!) - (x^7 / 7!) + (x^9 / 9!)
→ [(1,1,1), (-1,3,6), (1,5,120), (-1,7,5040), (1,9,362880)]
列表由列表理解创建。首先,我们将列表[1,-1,1,-1,1,-1...]
和[1,3,5,7,9,11...]
压缩。这为我们提供了列表[(1,1), (-1,3), (1,5), (-1,7)...]
。从此列表中,我们创建了最终列表[(1,1,1), (-1,3,6), (1,5,120), (-1,7,5040)...]
:
sinCoeff :: [(Double, Int, Double)]
sinCoeff = [ (fromIntegral s, i, fromIntegral $ mfak i)
| (s, i) <- zip (cycle [1, -1]) [1,3..]]
(cycle
无限期地重复列表,[1,3..]
创建一个无限列表,从1开始,步长为2)
最后,msin
函数接近定义。它还使用列表推导来实现它的goeal(注意我保留了* 180 / pi
虽然我不确定它应该在那里.Haskell知道pi。)
msin :: Int -> Double -> Double
msin n x = 180 * sum [ s * mpow x p / f | (s, p, f) <- take n sinCoeff] / pi
(take n sinCoeff
返回列表的第一个n
元素)
您可以尝试使用以下代码:
main = do
print $ take 10 sinCoeff
print $ msin 5 0.5
print $ msin 10 0.5