【问题标题】:Horner's rule for two-variable polynomial二元多项式的霍纳规则
【发布时间】:2017-02-07 18:43:24
【问题描述】:

Horner 规则用于简化在特定变量值处评估多项式的​​过程。 https://rosettacode.org/wiki/Horner%27s_rule_for_polynomial_evaluation#Standard_ML

我已经轻松地将使用 SML 的方法应用于单变量多项式,表示为 int 列表:

fun horner coeffList x = foldr (fn (a, b) => a + b * x) (0.0) coeffList

这很好用。然后我们可以使用:

- val test = horner [1.0, 2.0, 3.0] 2.0;
> val test = 17.0 : real

其中[1.0, 2.0, 3.0] 是表示多项式系数的列表,2.0 是变量 x 的值,17.0 是计算多项式的结果。

我的问题是这样的: 我们有一个由 (int list list) 表示的两个变量多项式。高级列表中的第 n 项将代表所有包含 y^n 的多项式项,而低级列表中的第 m 项将代表所有包含 x^m 的多项式项。

例如:[[2],[3,0,0,3],[1,2]] 是多项式

( 2(x^0)(y^0) ) +
( 3(x^0)(y^1) + 0(x^1)(y^1) + 0(x^2)(y^1) + 3(x^3)(y^1) ) +
( 1(x^0)(y^2) + 2(x^1)(y^2) )

函数需要返回指定x和y处多项式的值。

我使用 mlton 编译器尝试了各种方法。

  1. 首先我尝试了一个嵌套的 foldr 函数:

    fun evalXY (z::zs) x y = 
            foldr 
            (fn (s, li:list) => 
                s + ((foldr (fn(a, b) => a + b*x) 0 li)*y)
            )
            0 
            z:zs
    

您可以看到我正在尝试使用“s”作为累加器,就像在单变量示例中使用了“a”一样。由于 foldr 处理的每个元素本身都需要“折叠”,因此我在描述外部 foldr 的函数中再次调用 foldr。我知道这个内部文件夹工作正常,我在上面证明了这一点。 *我的问题似乎是我无法访问外部折叠器所在的列表元素以将该列表传递到内部折叠器。 >查看我在内部文件夹中使用 li 的位置,这是我的问题。 *

  1. 然后我尝试将我的单变量函数应用于映射。我遇到了同样的问题:

    fun evalXY (z::zs) x y = 
            map 
            (foldr (fn(a, b) => a + b*x) 0 ???)
            z:zs
    

    *通过这次尝试,我知道我得到了一个整数列表。我放入了一个 int 列表列表,其中内部列表被处理并通过 foldr 作为整数返回到外部列表。在此之后,我将再次折叠以将 y 值应用于多项式。 这里的函数应该看起来像 :: fn evalXY : (int list list) * int * int) -> ... -> int list *

我是 SML 的新手,所以我可能在这里遗漏了一些基本的东西。我知道这是一种函数式编程语言,所以我试图累积值而不是改变不同的变量,

【问题讨论】:

  • 2014 年 Horner's algorithm in SML? 的副本。我建议您在 Google StackOverflow 上的课程应该有一张幻灯片,介绍寻找前几年课程参与者的答案。 ;-)
  • 如果你没有意识到,这个问题处理给定多项式中的两个变量(即 f = 3xy)。非常相似,但如果您是该语言的新手,则很难实现
  • 我没看到,抱歉。

标签: functional-programming sml smlnj polynomial-math mlton


【解决方案1】:

你很亲密。让我们从形式化问题开始。给定系数 C 作为您指示的嵌套列表,您想要评估

注意,你可以将s从内部总和中取出,得到

仔细查看内部总和。这只是变量 x 的多项式,系数由 给出。在 SML 中,我们可以将您的 horner 函数的内部总和写为

fun sumj Ci = horner Ci x

让我们更进一步,定义

在 SML 中,这是val D = map sumj C。我们现在可以用 D 写出原始多项式:

应该清楚这只是horner 的另一个实例,因为我们有一个系数为 的多项式。在 SML 中,这个多项式的值为

horner D y

...我们完成了!


这是最终代码:

fun horner2 C x y =
  let
    fun sumj Ci = horner Ci x
    val D = map sumj C
  in
    horner D y
  end

这不是很好吗?我们所需要的只是霍纳方法的多种应用,以及map

【讨论】:

  • 很好地解释了二维霍纳方法的基本逻辑。
【解决方案2】:

您的第二种方法似乎在正确的轨道上。如果您已经定义了horner,您需要做的是将horner 应用于将horner applied to inner list x 映射到外部列表的结果,例如:

fun evalXY coeffLists x y = horner (map (fn coeffList => horner coeffList x) coeffLists) y

您可以用相应的折叠替换对horner 的两个调用,但它的可读性会差很多。

注意,如果你把horner中的两个参数的顺序颠倒了,那么你可以短接evalXY

fun horner x coeffList = foldr (fn (a, b) => a + b * x) (0.0) coeffList
fun evalXY x y coeffLists = horner y (map (horner x) coeffLists)

关键是柯里化的工作方式,如果你使用这个二阶,那么horner x已经是coeffList的一个函数,所以你不再需要匿名函数fn coeffList => horner coeffList x。这个故事的寓意是,在定义柯里化函数时,您应该仔细考虑参数的顺序,因为它会使某些部分应用程序比其他应用程序更容易创建。

顺便说一句,SML 很挑剔。在您对horner 的讨论中,您说过您可以将其称为horner list 2。它需要是horner list 2.0。同样,在您的第二次尝试中,使用 0 而不是 0.0 是有问题的。

【讨论】:

  • 这帮助很大。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-12
  • 2015-08-16
  • 1970-01-01
  • 1970-01-01
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多