Правило Хорнера для полинома с двумя переменными

Правило Хорнера используется для упрощения процесса оценки полинома при определенных значениях переменной. https://rosettacode.org/wiki/Horner%27s_rule_for_polynomial_evaluation

Я легко применил метод, используя 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 является значением переменной х, и 17.0 является результатом оценки полинома.

Моя проблема такова: у нас есть полином от двух переменных, представленный (список int). 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'ed", я снова вызываю 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) * int * int) -> ... -> int list *

Я новичок в SML, так что, может быть, мне не хватает чего-то фундаментального здесь. Я знаю, что это функциональный язык программирования, поэтому я пытаюсь накапливать значения, а не изменять различные переменные,

2 ответа

Ты очень близко Давайте начнем с формализации проблемы. Учитывая коэффициенты C как вложенный список, как вы указали, вы хотите оценить

Обратите внимание, что вы можете вытащить с внутренней суммы, чтобы получить

Посмотрите внимательно на внутреннюю сумму. Это просто многочлен от переменной х с коэффициентами, заданными , В 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,

Ваш второй подход, кажется, на правильном пути. Если вы уже определили 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 проблематично.

Другие вопросы по тегам