Сегодня мы будем изучать написание макросов для Microsoft Excel и попробуем применить их на конкретном примере.
Начнём с матчасти. Нам понадобится: Microsoft Excel, одна голова и пара рук. Эксель "из коробки" обладает встроенным компилятором VBA, поэтому устанавливать его дополнительно не требуется.
Итак, начнём с простого: создадим первую пользовательскую функцию. Чтобы войти в редактор кода, нажмите Alt+F11. Вы увидите среду разработки Visual Basic, а слева - менеджер проектов. В нём нажмите на корне дерева правой кнопкой нажмите Insert -> Module. Теперь мы видим окно для редактирования кода. Создадим в нём функцию, возвращающую универсальную газовую постоянную:
Function RUG() As Double RUG = 8.314472 End Function
Теперь мы можем вставить эту функцию в любое место книги.
Теперь попробуем создать функцию с параметрами.
Function sum(a, b) As Double sum = a + b End Function
Как видите, использование функций в VBA похоже на использование функций в других языках. А теперь закончим наш Hello World и перейдём к рассмотрению реального примера. В качестве примера решим дифференциальное уравнение методом Рунге-Кутты 4 порядка.
Исходные данные:
Для решения нам необходимо объявить 5 функций.
Первая функция будет непосредственно вычислять значение производной по формуле, которая дана по условию задачи. Функция выглядит так:
Function func(a As Double, f_k As Double, x As Double, t As Double) As Double func = 1 + a * x * Sin(t) - f_k * x * x End Function
Здесь а и f_k - параметры уравнения, x - координата, t - шаг по времени.
Метод Рунге-Кутты предполагает расчёт четырёх коэффициентов: k1, k2, k3, k4. Обратите внимание: мы не можем объявлять функцию k1 напрямую - возникнет конфликт с номером ячейки таблицы. Поэтому воспользуемся префиксом.
Function f_k1(h As Double, a As Double, f_k As Double, x As Double, t As Double) As Double f_k1 = h * func(a, f_k, x, t) End Function Function f_k2(h As Double, a As Double, f_k As Double, x As Double, t As Double) As Double f_k2 = h * func(a, f_k, x + 0.5 * h, y + 0.5 * f_k1(h, a, f_k, x, t)) End Function Function f_k3(h As Double, a As Double, f_k As Double, x As Double, t As Double) As Double f_k3 = h * func(a, f_k, x + 0.5 * h, t + 0.5 * f_k2(h, a, f_k, x, t)) End Function Function f_k4(h As Double, a As Double, f_k As Double, x As Double, t As Double) As Double f_k4 = h * func(a, f_k, x + h, f_k3(h, a, f_k, x, t)) End Function
Здесь h - шаг сетки. Остальные параметры имеют то же назначение, что и в первой функции. Вычисления производятся чисто по схеме Рунге-Кутты.
Теперь нам осталось лишь применить наши функции и решить дифференциальное уравнение. Для этого нам понадобится начальное условие. Его мы можем выбрать любое, в данном случае x(0)=0.
Кому лень разбираться, расшифровываю формулу:
Теперь растягиваем нашу формулу на весь интервал и получаем численное решение.
Для наглядности построим график:
Здесь синей линией показан график найденной функции, коричневой - её аппроксимация методом наименьших квадратов. Этот метод я описывать не буду, просто скажу, что в итоге мы получили уравнение x=-0.65t2+1.2664t-0.01992. Если вам интересна реализация этого метода, можете посмотреть его во вложенном файле.
Комментарии
Как нехватает спойлеров! В них удобно упрятывать код. Как-то давно я написал целую библиотку для Билдера, позволяющую делать с Экселом всё, что угодно. Косвенно подтолкнула к этому статья в "Вестях", называлась она "Суперфункции". Конечно, была и рабочая потребность. Выложил бы кое-что, но не постить же код! Визивиговые спойлеры пригодились бы.