Рубрики
Без рубрики

Как решить root нахождение в JavaScript

Внедрение, желая написать об этой теме на некоторое время. У меня недавно была возможность работать над моделированием функциональности Excel Excel для веб-приложения. Я нашел всю цель ворота и о том, как он работает увлекательно. Вся цель ворота в Excel

Автор оригинала: FreeCodeCamp Community Member.

Вступление

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

Вся цель целей ищет в Excel – найти вход для уравнения, который обеспечит желаемое решение. Чтобы понять, как это должно работать, мы рассмотрим что-то действительно простое.

Что такое цель поиска?

Давайте возьмем пример нахождения суммы, основанного на основании принципала, используя простую формулу процентов.

Уравнение для простой процентной формулы, хорошо, просто:

A = P(1+rt), eqn(1)
P -> principalr -> rate of interestt -> time in years

Мы установим следующие значения:

P -> 10000r -> 7.5t -> 15

Это дает нам сумму обусловленной как быть:

A = 10000(1+7.5*15) = 1135000

Теперь, давайте скажем, что требование для нашего решения изменилось. Теперь вместо нахождение суммы обусловлено На основании принципала, ставки процентов и времени нам вместо этого нужно найти Оценка процентов, которые дадут нам желаемую сумму ?| Но сохраняя принцип и время одинаково.

Давайте изменим пример сейчас:

P -> 10000r -> ?t -> 15A -> 1120000

Здесь мы пытаемся найти процентную ставку, которая позволит нам заплатить 1120000 вместо 1135000. Мы можем решить это, переключая переменные вокруг.

A = P(1+rt) => 1120000 = 10000(1+r*15)
1+15*r = 1120000 / 10000 => r = (112 - 1) / 15
r = 7.4%

Бриллиант! Там у нас есть! Мы сделали что-то ворота Excel.

Одна проблема, хотя. Это было действительно простое уравнение и проблема. Что произойдет, если уравнение значительно сложнее и включает тригонометрические функции вместе с несколькими возможными решениями? Я дам вам пример уравнения, который вы сможете решить с воротами:

f(x, y) = 1550 - (4*x/y * sinh(y/2 * 1500 / (2*x))), eqn(2)

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

Разве это не так A (1 + RT) легче посмотреть? Предоставлено, частью это также тот факт, что уравнение намного меньше.

Но, что если мы повторно написали это так:

f(P, r, t) = P(1+rt)

Видеть? Это все еще одно и то же.

Давайте вернемся к EQN (2). Что, если у нас есть следующее заявление о проблеме:

0 = 1550 - (4*x/0.022 * sinh(0.022/2 * 1500 / (2*x))),solve for x

Ну, опять же, все, что вы действительно делаете, решает для переменной, но просто посмотрите на то, насколько сложнее проблема получила. И это в первую очередь из-за этого надоединга Син сидя в уравнении.

Хорошо, если вы новичок в этом, я представляю, что все становится немного подавляющим. Давайте сделаем шаг назад и подумайте о том, что мы обнаружили до сих пор.

  1. Мы выяснили, что нет никакой реальной разницы между записью функции с нотами, как следующие два:
f(P, r, t) = P(1+rt)A = P(1+rt)

2. Мы выяснили, что мы можем решить для одной переменной, чтобы дать нам желаемый результат. Однако тем более сложным уравнением является более сложное получение решения.

У нас есть два уравнения очень противоположных трудностей для решения. Я буду введен третье уравнение, которое поможет преодолеть пробел

y = 2x^2+3x-5, eqn(3)

Уравнение выше является основной параболической функцией. Это то, что уравнение выглядит как на грани.

Хорошо, теперь давайте подумаем о том, как решить это уравнение. Допустим, мы хотим решить для х так что y :

y = 2x^2+3x-5 => 2x^2+3x-5 = 0
x = [-3 + sqrt(3^2 - 4*2*(-5))] / (2*2),     [-3 - sqrt(3^2 - 4*2*(-5))] / (2*2)]
x = 1, -2.5

Если вам интересно, где я получил уравнение для решений, обратите внимание, это просто классическое решение для квадратичного уравнения.

y = ax^2+bx+c, where y = 0 => ax^2+bx+c = 0
x = -b+sqrt(b^2-4ac) / 2a, x = -b-sqrt(b^2-4ac) / 2a

Примечание. Если вы хотите узнать, как это решение было получено, посмотрите здесь .

Ну, это один способ решить уравнение. Вы можете потенциально написать парсер, который мог бы принять любое уравнение, проверять коэффициенты, точно отделить их, а затем попытаться решить уравнение. Вы также можете использовать замечательную ALGEBRA.JS Библиотека здесь, которая делает то, что я только что описал.

Однако, если вы посмотрите на график, вы заметите, что вы могли бы решить этот графически. Цель состояла в том, чтобы найти точку на кривой, где уход

Ну, посмотрите внимательно и посмотрите, где кривая пересекает ось X. Он пересекает его в двух очках: [1, -2.5] Есть твое решение!

Теперь вы, вероятно, думаете, что все здорово, но я не могу точно учить компьютеру смотреть на график, находить точки, где он пересекает ось X и определить эти точки. Ну, потенциально вы могли бы с какой-то образной моделью обучаться для распознавания изображений, но это еще один пост. Итак, как мы находим наш путь вокруг этого?

Есть два метода, которые мы можем использовать, и это те, которые я буду изучать в этой статье.

Они называются Метод Ньютона-Рафсон и Метод бисекции Отказ

Я дам вам краткий обзор того, как работает каждый метод.

TL; DR версия

Метод Ньютона-Рафсон работает, выбирая случайную точку и рисую тангенту линию в этой точке. Затем он рассчитывает новый х Значение, которое ближе к корню. Если вы продолжите повторять это, вы найдете root.

Метод переживания работает над принципом нахождения интервала, в пределах которого ложь корня. После того, как точный интервал лежит, решение обнаружено с использованием алгоритма, аналогичного тому, которое используется для двоичного поиска.

Давайте попадаем в каждый более подробно.

Метод Ньютона-Рафсон

Хорошо, давайте копаемся в метод Ньютона-Рафсон. Метод Ньютона-Рафсон основан на трех основных идеях.

  1. Касательная к кривой в определенной точке – прямая линия
  2. Тангенс на кривую в определенной точке также является производной из кривой в этой точке
  3. Уравнение прямой линии: Y + C.

Изображение выше – это случайная кривая с кабачкой, оттянутой к нему.

Мы выбрали случайную точку x_n на оси x.

f (x_n) это эквивалент точки на кривой. я y-перехват

f '(x_n) касается кривой в точке F (x_n).

x_ (n + 1) Это точка, когда касательцы перехватывает ось X.

Помните, что мы сказали, что хотели найти точку, где кривая пересекает ось X, так как это даст нам наше решение. Уведомление, точка x_ (n + 1) намного ближе к решению, чем x_n был, несмотря на нас выбираю x_n случайно.

Ну, что если мы повторим тот же процесс, кроме на этот раз с x_ (n + 1) Как наша новая точка начальной точки? Ну, по-видимому, мы бы оказались бы новым х Это еще ближе к решению.

Итак, как мы находим точку x_ (n + 1) Учитывая уравнение, производное и оригинал x_n ?

Давайте вернемся к уравнению прямой: Y + C.

Мы сказали, что касательная к кривой в точке – прямая линия.

Мы также сказали, что y-перехват равен f (x_n)

Мы знаем из исчисления, что производное равна уклоне.

Поэтому мы получаем следующее:

Теперь нам нужно найти корень этой касательной линии, поэтому установить y и x (n + 1) и решить для x_ (n + 1)

Это дает нам следующее:

Теперь у нас есть все, что нам нужно, чтобы решить для x_ (n + 1) Отказ

Это уехало над головой в первый раз, когда я увидел все уравнения, поэтому давайте попробуем это на примере, чтобы увидеть, как это работает.

Мы возьмем уравнение (2) и работаем через это. Давайте выберем x_n = 3.

f(x) = 2x^2+3x-5f'(x) = 4x+3f(3) = 18+9-5 = 22f'(3) = 15x_1 = 3 - 22/15 = 1.53
f(1.53) = 4.2718f'(1.53) = 9.12x_2 = 1.53 - 4.2718/9.12 = 1.0616

Если вы будете следовать так до конца, вы должны получить решение, где х = 1 И как мы знаем с более раннего графа, это одно из наших решений.

Если вы заметите то, что мы сделали выше, просто следуйте серии шагов в определенном порядке неоднократно, то есть очень определение алгоритма. Вот что выглядит код для того же.

Кодовый фрагмент делает тяжелое использование Math.js Библиотека Отказ Основными функциями, которые я использую, являются математическими функциями и функциями Math. Соответственно, они рассчитывают производное выражения и оценивают выражение на основе объекта пар клавишных пар.

Немного фрагмента кода, который я хочу обратить ваше внимание, – это строки 14-16.

if (Math.abs(result - guess) < Math.exp(-15)) {              return result        }

Что мы здесь делаем, определяет базовое условие, чтобы положить конец нашей итерации. Мы говорим, что если разница между x_n и x_ (n + 1) меньше чем 10 ^ (- 15) вернуть результат.

Если вы проходите через предварительное упражнение, вы достигнете ситуации, когда каждый последовательный х Значение практически идентично для предыдущего х Значение, и именно так мы знаем, что мы нашли решение.

У меня хорошая маленькая симуляция, построенная с D3.js в кодепене, показывая вам, как это будет работать итеративно.

Просто введите значение в поле ввода и нажмите «Отправить», и вы сможете посмотреть этот алгоритм, запущенный графически.

ПРИМЕЧАНИЕ. Пожалуйста, попробуйте диапазон разумных входов, я не совсем построил надежную систему здесь.

Метод переживания

Хорошо, поэтому мы выяснили, как работает метод Ньютона-Рафсон. Давайте решаем метод переживания следующим.

Метод переживания намного проще понять, чем метод Ньютона-Рафсон. Он основан на очень простой математической собственности:

Если функция f (x) непрерывная на интервале [a, b] и знаком f (a) (b), то существует значение c в диапазоне (a, b) где. Другими словами, C является корнем уравнения.

Если это не имеет смысла для вас, подумайте об этом чисто численно, а затем чисто графически.

Допустим, у вас есть следующий интервал: [-7, 6]. Теперь, если я попрошу вас считать только целые числа от -7 до 6, вы также будете сосчитать 0 в какой-то момент в этом интервале. Это, по сути, как говорит недвижимость.

Давайте посмотрим на то, что это значит графически.

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

Хорошо, это означает, что использование метода переживания представляет собой двухэтапный процесс.

  1. Найдите интервал, внутри которого ложь корня, если такой интервал существует
  2. Найдите фактический корень в этом интервале

Вот код для того, как вы найдете интервал:

Опять же, я использую здесь mathjs, поэтому вы можете посмотреть документацию для этого.

Интересный бит этого алгоритма находится в строках 18-26, где я проверю, привела ли ли моя функция по оценке левого интервала или правого интервала в то, что является Нан Отказ Я объясню, почему я включил этот код код, когда мы исследуем, как решить EQN (2).

После того, как у нас есть интервал, внутри которого ложь решение, мы можем обратить внимание на наличие самого решения самого решения.

Если вы когда-нибудь пытались написать алгоритм бинарного поиска на массиве, фрагмент кода выше должен выглядеть вам очень знакомы. Мы используем более или менее тот же подход здесь. Вот эти шаги.

  1. Я начинаю с моих левых и правых интервалов и найти среднюю точку
  2. Проверьте, лежит ли решение слева от средней точки или справа от средней точки
  3. Если он лежит влево, набор правильно , остальные набор оставил

В конце концов, средняя точка будет самой корнем.

Вот небольшое моделирование, проходящее через то, что на самом деле происходит.

Примечание: я прошу прощения за то, насколько уродливая смотрящая симуляция, к сожалению, стиль не моя сортировка. Опять же, разумный диапазон входов, потому что в противном случае его займется достаточно некоторое время для симуляции.

На ручке выше введите значение, и симуляция попытается найти интервал, в течение которого может существовать потенциальный корень. После того, как он нашел интервал, он начнет пытаться найти корневой, используя алгоритм, который мы обсуждали непосредственно до этого.

Решение сложных уравнений

Хорошо, мы изучили два разных метода поиска корней уравнений. Теперь пришло время изучить более сложный уравнение (2), который мы имели и посмотрели, какие из этих методов могут решить это уравнение.

Я положу уравнение ниже, чтобы ясно

f(x, y) = 1550 - (4*x/y * sinh(y/2 * 1500 / (2*x))), eqn(2)
Solve for f(x, y) = 0, where y = 0.022
0 = 1550 - (4*x/0.022 * sinh(0.022/2 * 1500 / (2*x)))

Во-первых, давайте визуализируем то, как выглядит это уравнение. Это даст нам гораздо лучшую интуицию, почему что-то может пойти не так.

То, что следует отметить об этом уравнении, заключается в том, что он имеет тенденцию к бесконечности, когда X имеет тенденцию к 0. Это будет представлять проблему для метода Ньютона-Рафсон, потому что решение Ньютона-Рафсон имеет тенденцию следовать по пути касательной, в этом случае Это может быстро растворить до бесконечности в качестве решения, если это не удалось ударить на решение случайно.

Попробуйте запустить вышеуказанное уравнение с помощью метода Ньютона-Рафсон, и вы увидите, что я имею в виду. Вы, вероятно, получите результат NULL.

Метод бисекции, с другой стороны, будет работать довольно хорошо для этого. Он хорошо работает, потому что мы принимаем очень маленькие инкрементные шаги с размером шага, который у нас есть контроль. Запустите ниже кодепен, и вы должны увидеть, насколько хорошо работает метод переживания для большинства уравнений.

Вышеупомянутый код практически идентичен предыдущей версии, которую мы настроили для метода переживания, запрещении нескольких различий. Я устанавливаю отдельный кодепен, поэтому я мог бы понадобиться усилиям, чтобы позволить способ войти в уравнения, что потребует обширных чеков и обработки ошибок. Кроме того, это уравнение требует специальных границ для определения его данных, поскольку она имеет тенденцию к бесконечности как X приближается к 0. Если вы заинтересованы, вы можете увидеть, что я имею в виду, если у вас есть просмотр кода.

Теперь в коде метода бисекции я рассказал вам об этом блоке кода здесь:

if (Number.isNaN(result_left)) {        left -= stepSize        scope_left[variable] = left        result_left = math.eval(eqn, scope_left)    } if (Number.isNaN(result_right)) {        right += stepSize        scope_right[variable] = right        result_right = math.eval(eqn, scope_right)}

Таким образом, причина, по которой у меня есть это, состоит в том, чтобы справиться с ситуациями, как те, которые возникают для EQN (2). Потому что EQN (2) имеет тенденцию к бесконечности, когда X имеет тенденцию к 0, может быть ситуация, когда оценка возврата уравнения либо Нан или Бесконечность Отказ Чтобы избежать этой ситуации, я просто перемещающую уравнение по размеру шага несколько раз, пока не могу вернуться к домену функции, которая лежит в реальном диапазоне номеров.

Переживание> Ньютон-Рафсон?

Это приводит меня к важному моменту, почему Ньютон-Рафсон не удался за это уравнение? Мы знаем, что, поскольку Ньютон-Рафсон следует за тангентом кривой в разные точки, она может раствориться до бесконечности, если уравнение имеет тенденцию к бесконечности в любой конкретной точке. Это подчеркивает одну из недостатков метода Ньютона-Рафсон.

  1. Метод Ньютона-Рафсон хорошо работает для непрерывный функция. Если функция прерывистая, как у EQN (2), она обычно не удалась.
  2. Ньютон-Рафсон не может объяснить несколько максимумов и минимумов в функции.

Возьмите следующий график, например.

Выберите точку случайно между -0.19 и +0,19, и вы должны увидеть, что вы получите отрицательный наклон, что означает касание на кривую в тот момент, будет перехватывать ось X в точку дальше от корня, который идет против принципа метода Ньютона-Рафсон. Это подразумевает, что Ньютон-Рафсон, как правило, не будет терпеть неудачу для уравнений кубического и более высокого порядка.

Метод переживания не должен иметь одинаковую проблему, потому что это зависит от поиска интервала, в пределах которого раствор должен лгать, и кривые, как указано выше, не будет препятствием для этого, пока он непрерывен в этом домене.

Если вы сравниваете два с точки зрения большого (O) обозначения, кажется очевидным, что Ньютон-Рафсон работает на меньшем количестве итераций, чем метод переживания, просто потому, что он сходится намного быстрее, когда вы рассматриваете его графически. По иронии судьбы, если вы запустите это с процессом времени, он часто получается, что, учитывая ту же отправную точку, метод переживания проходит быстрее, чем метод Ньютона-Рафсон.

Это связано с тем, что Ньютон-Рафсон включает вычислительные производные на каждом шагу, что оказывается очень вычислительно дорогим. Выравнивание и уменьшение ряда с другой – относительно вычислительно недорого.

Если вы хотите запустить то же самое на своем компьютере и проверьте результаты, посмотрите репо здесь Отказ Вы можете клонировать это репо, запустить NPM установить а потом NPM запустить начало На вашей машине, и вы должны увидеть результаты работы как метода «Ньютон-Рафсон», так и метод переживания в одинаковом уравнении, учитывая одинаковую первоначальную предположение.

Заключение

Хорошо, мы много накрыли здесь. Но, честно говоря, это такая смешная обширная тема, которую я едва почесал поверхность. Сходимость уравнений – это широко изученная тема. Рассмотрим одну из самых основных вещей, которые мы не покрывали: нахождение нескольких корней.

Конечно, вы можете изменить алгоритмы, представленные в этой статье, чтобы достичь этого.

Принять уравнение ниже, например. Он имеет 3 корней (3 балла, где он перехватывает ось X, и вам нужно найти все эти корни).

Я собираюсь опубликовать все свои источники здесь, не стесняйтесь смотреть через них.

Примечание. Если у вас есть вопросы или комментарии по поводу статьи, не стесняйтесь обращаться со мной через комментарии по этой статье или на Гадость или же Твиттер .

  1. https://brilliant.org/wiki/newton-raphson-method/
  2. http://www.mathcs.emory.edu/~cheung/Courses/170/Syllabus/07/bisection.html
  3. http://www.sosmath.com/calculus/diff/der07/der07.html
  4. https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw