C++ 计算哈斯克尔窦

C++ 计算哈斯克尔窦,c++,haskell,C++,Haskell,这是我的问题:我需要一个函数来计算某个数的正弦 在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 += m

这是我的问题:我需要一个函数来计算某个数的正弦

在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的新手,所以请尽可能多地解释您的解决方案。我读了一些教程,但我找不到如何将某个表达式的结果保存为一个值,然后在它之后继续使用其他代码…每次我尝试这样做时,它都会返回我的值,我不希望这样


所以请提前tnxx寻求任何帮助

问题是像stevec中的let stevec=stevec+1这样的表达式。Haskell不是命令式语言。这不会给stevec添加一个。相反,它将stevec定义为一个比自身多1的数字。没有这样的数字存在,因此您将得到一个无限循环,或者,如果您幸运的话,一个崩溃

而不是

stevec++;
vsota =  msin(stevilo, stevec, vsota);
你应该使用类似于

let stevec' = stevec + 1
in  msin stevilo stevec' vsota
或者只是

msin stevilo (stevec + 1) vsota

这里还有一些我不明白的事情。您将需要mpow和mfak。它们在哪里?

问题是像stevec中的let stevec=stevec+1这样的表达式。Haskell不是命令式语言。这不会给stevec添加一个。相反,它将stevec定义为一个比自身多1的数字。没有这样的数字存在,因此您将得到一个无限循环,或者,如果您幸运的话,一个崩溃

As you can see the biggest problem is how to add something to "vsota",
而不是

stevec++;
vsota =  msin(stevilo, stevec, vsota);
你应该使用类似于

let stevec' = stevec + 1
in  msin stevilo stevec' vsota
或者只是

msin stevilo (stevec + 1) vsota
这里还有一些我不明白的事情。您将需要mpow和mfak。他们在哪里

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是一个更新的变量。下面是传递给下一个递归调用的函数参数

在您的情况下,我首先编写一个函数,生成幂级数的项:

sinusTerms n x = ... -- the first n terms of x - (x'3 / 3!) + (x'5 / 5!) - (x'7 / 7!) ...
然后使用上面的求和函数:

sinus n x = sum (sinusTerms n x)
在函数式语言中,您可以在这里使用递归——变量vstota作为函数参数实现,在处理列表时,函数参数从一个调用传递到另一个调用

例如,要对一系列数字求和,我们可以编写如下内容:

sum xs = go 0 xs
  where go total [] = total
        go total (x:xs) = go (total+x) xs
在命令式语言中,total是一个更新的变量。下面是传递给下一个递归调用的函数参数

在您的情况下,我首先编写一个函数,生成幂级数的项:

sinusTerms n x = ... -- the first n terms of x - (x'3 / 3!) + (x'5 / 5!) - (x'7 / 7!) ...
然后使用上面的求和函数:

sinus n x = sum (sinusTerms n x)

您还可以使用递归列表定义来获取[x,x^3,x^5…]和[1,1/3!,1/5!…]无限序列。当它们完成后,剩下的就是将它们的项彼此相乘,然后求和

窦房结计数x=总和计数$zipWith*ifactorials xpowers 其中xpowers=x:map x*x*xpowers
ifactorials=1:zipWith/ifactorials[i*i+1 | i您还可以使用递归列表定义来获得[x,x^3,x^5…]和[1,1/3!,1/5!]无限序列。完成后,剩下的就是将它们的项彼此相乘并求和

窦房结计数x=总和计数$zipWith*ifactorials xpowers 其中xpowers=x:map x*x*xpowers
ifactorials=1:zipWith/ifactorials[i*i+1 | i我会稍微修改一下算法。首先我们可以定义阶乘逆的列表:

factorialInv::[Double] factorialInv=scanl/1[1..]-1/0!、1/1!、1/2!、1/3!、。。。 然后,我们使用正弦系数:

系数::[双精度] 正弦系数=0:1:0:-1:正弦系数 然后,给定x,我们将上述两个列表乘以x的幂,逐点:

powerSeries::[Double]-^系数 ->要计算级数的双点x ->[Double]-^系列术语 powerSeries cs x=zipWith3\a b c->a*b*c cs powers factorialInv 其中幂=迭代*x1-1,x,x^2,x^3。。。 最后,我们将前20个术语进行总结

正弦::双->双 正弦=总和。取20。功率系列正弦系数 -即,正弦x=取20个功率系列正弦x的和
我会稍微修改一下算法。首先我们可以定义阶乘逆的列表:

factorialInv::[Double] factorialInv=scanl/1[1..]-1/0!、1/1!、1/2!、1/3!、。。。 然后,我们使用正弦系数:

系数::[双精度] 正弦系数=0:1:0:-1:正弦系数 然后,给定x,我们将上述两个列表乘以x的幂,逐点:

powerSeries::[Double]-^系数 ->要计算级数的双点x ->[Double]-^系列术语 powerSeries cs x=zip 使用3\a b c->a*b*c cs 其中幂=迭代*x1-1,x,x^2,x^3。。。 最后,我们将前20个术语进行总结

正弦::双->双 正弦=和。拿20块。powerSeries正弦系数 -即,正弦x=取20个功率系列正弦x的和
我尽可能地遵循你们的惯例。对于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)
在计算窦房结之前,我们创建一个系数列表[符号、幂、阶乘]:

列表是由列表理解创建的。首先我们压缩列表[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,5120,-1,75040…]:

take n sinCoeff返回列表的前n个元素

您可以使用以下代码尝试前面的代码:

main = do
    print $ take 10 sinCoeff
    print $ msin 5 0.5
    print $ msin 10 0.5

我尽可能地遵循你们的惯例。对于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)
在计算窦房结之前,我们创建一个系数列表[符号、幂、阶乘]:

列表是由列表理解创建的。首先我们压缩列表[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,5120,-1,75040…]:

take n sinCoeff返回列表的前n个元素

您可以使用以下代码尝试前面的代码:

main = do
    print $ take 10 sinCoeff
    print $ msin 5 0.5
    print $ msin 10 0.5


如果你用英文名字来表示变量,你很可能会增加几个数量级的受众。我想换成英语:对不起,以前没想到这个:如果你有一个Int,它需要一个双重类型,使用from integral。我回家后会看看from integral solution:ty!如果你用英文名字来表示变量,你很可能会增加几个数量级的受众。我想换成英语:对不起,以前没想到这个:如果你有一个Int,它需要一个双重类型,使用from integral。我回家后会看看from integral solution:ty!我现在无法在GHCI中测试代码,因此可能有一些错误。我现在无法在GHCI中测试代码,因此可能有一些错误。谢谢,您提醒我存在迭代。但对我来说,我会尽量避免零谐波x²,x⁴ ... 当然。@firegurafiku我也是,但我喜欢powerSeries函数的通用性。您可以定义一个自定义乘法运算符来检查零系数并延迟退出,这样可以避免在第n个系数为零时计算x^n。@luqui使用iterate将导致在需要x^n+1时计算x^n。我们可能会保存一个乘法,但如果我们使用a*b*c,a为空。感谢这个想法:我想我可以在其他一些赋值中使用一些乘法,但在这个赋值中,我不应该使用任何全局列表等。所有的魔法都必须发生在一个递归函数中,赋值要求我这样做,所以我必须按照它说的做Hanks,你提醒我有迭代。但对我来说,我会尽量避免零谐波x²,x⁴ ... 当然。@firegurafiku我也是,但我喜欢powerSeries函数的通用性。您可以定义一个自定义乘法运算符来检查零系数并延迟退出,这样可以避免在第n个系数为零时计算x^n。@luqui使用iterate将导致在需要x^n+1时计算x^n。我们可以保存一个乘法运算,虽然如果我们使用a*b*c,a为空。感谢这个想法:我想我可以在其他一些辅助中使用一些,但在这个辅助中,我不应该使用任何全局列表等。所有的魔法都必须发生在一个递归函数中。辅助要求我这样做,所以我必须按照它说的做。我是Haskell的新手,所以我还在学习:我会改变正如你所说的那样,但是这个列表解决方案在我的情况下不起作用,我需要用没有列表或任何全局变量的递归来实现它,但是不管怎样,ty:D你解释过了,我喜欢这样,因为在学习了几天之后,我实际上理解了你的大部分代码Haskell:嗯,我是Haskell的新手,所以我还在学习:我会像你说的那样更改这些函数,但是这个列表解决方案在我的情况下不起作用,我需要使用没有列表或任何全局变量的递归来实现它,但是不管怎样:D你解释了它,我喜欢它,因为在学习Haskell几天后,我实际上理解了你的大部分代码: