You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中用列表相乘实现麦克劳林级数近似sin(x)的问题

嘿,你这个用麦克劳林级数近似sin(x)的练习思路超清晰啊!已经搭了部分代码框架,我来帮你把剩下的部分补全,顺便解释清楚每一步的逻辑~

先理清楚麦克劳林级数的核心公式

sin(x)的麦克劳林展开式是这样的:

sin(x) = x - x³/3! + x⁵/5! - x⁷/7! + ... = Σ(n从0到∞)[ (-1)^n * x^(2n+1) / (2n+1)! ]

你拆分的三个列表思路完全命中要点:

  • 交替的正负系数序列:1, -1, 1, -1,...
  • x的奇次幂序列:x¹, x³, x⁵,...
  • 奇数的阶乘序列:1!, 3!, 5!,...
一步步完善你的代码

1. 先补全阶乘函数

你只写了开头的递归基例,完整的递归阶乘实现应该是这样:

factorial :: Integral a => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)

加上类型签名能让代码更严谨,也方便后续和其他函数兼容。

2. 生成三个核心序列

奇数序列(你已经写对了)

oddl :: Integral a => [a]
oddl = [1, 3..]

这会生成无限的奇数序列:1,3,5,7,...

交替正负序列

用cycle函数就能轻松生成无限循环的正负交替序列:

alternatingSigns :: Num a => [a]
alternatingSigns = cycle [1, -1]

x的奇次幂序列

你原来的powerl x = map (x^) oddl没问题,但如果x是浮点数的话,用**更适配浮点数幂运算,加上类型签名和类型转换更稳妥:

powerl :: Floating a => a -> [a]
powerl x = map (\n -> x ** fromIntegral n) oddl

fromIntegral把整数类型的奇数转成浮点数,适配**的参数要求。

奇数的阶乘序列(转成浮点数方便后续除法)

先把奇数列表映射成阶乘,再转成浮点数:

oddFactorialsF :: Floating a => [a]
oddFactorialsF = map (fromIntegral . factorial) oddl

3. 组合序列计算级数项

用zipWith3同时遍历三个序列,计算每一项的值:

sinTerms :: Floating a => a -> [a]
sinTerms x = zipWith3 (\sign power fact -> sign * power / fact) 
                      alternatingSigns 
                      (powerl x) 
                      oddFactorialsF

这个函数会生成无限的级数项序列:x, -x³/3!, x⁵/5!, ...

4. 取前30项求和得到近似值

最后取前30项相加,就是sin(x)的近似结果:

approxSin :: Floating a => a -> a
approxSin x = sum $ take 30 $ sinTerms x
完整代码整合

把所有部分拼起来就是完整的实现:

-- 生成无限奇数序列
oddl :: Integral a => [a]
oddl = [1, 3..]

-- 阶乘计算函数
factorial :: Integral a => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)

-- 生成奇数的阶乘(转浮点数)
oddFactorialsF :: Floating a => [a]
oddFactorialsF = map (fromIntegral . factorial) oddl

-- 生成x的奇次幂序列
powerl :: Floating a => a -> [a]
powerl x = map (\n -> x ** fromIntegral n) oddl

-- 生成交替正负系数序列
alternatingSigns :: Num a => [a]
alternatingSigns = cycle [1, -1]

-- 生成sin级数的每一项
sinTerms :: Floating a => a -> [a]
sinTerms x = zipWith3 (\sign power fact -> sign * power / fact)
                      alternatingSigns
                      (powerl x)
                      oddFactorialsF

-- 取前30项求和得到sin(x)近似值
approxSin :: Floating a => a -> a
approxSin x = sum $ take 30 $ sinTerms x

-- 测试示例
main = do
    print $ approxSin (pi/2)  -- 输出接近1.0
    print $ approxSin pi      -- 输出接近0.0
小优化建议(可选)

如果想让阶乘计算更高效,可以用递推的方式生成阶乘序列,避免重复递归计算:

-- 递推生成所有数的阶乘序列:1!,2!,3!,4!...
factorials :: Integral a => [a]
factorials = scanl (*) 1 [1..]

-- 提取奇数位置的阶乘:1!,3!,5!...
oddFactorialsF' :: Floating a => [a]
oddFactorialsF' = map fromIntegral $ everyOther factorials
    where everyOther (_:y:xs) = y : everyOther xs
          everyOther _ = []

替换之前的oddFactorialsF即可,惰性求值下性能会更好一些。

内容的提问来源于stack exchange,提问作者user3076623

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:28:46