Найти в Дзене
Игорь Назаров

JS и математика

Когда говорят Javascript, то обычно подразумевают разработку различных онлайн-формочек, которые показывают одну красивую картинку за другой, предлагают купить какую-нибудь безделушку или забронировать гостиничный номер (увы и ах, но сейчас не очень актуально).

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

А еще JS в связке с HTML обладает хорошими возможностями для визуализации данных - как через создание и управлением стилями html-элементов, так и через Canvas (в который постепенно впиливается пока что экспериментальная технология webGL).

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

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

Начнем с организации нашего "рабочего места" - создадим HTML, который будет подключать к себе js-овские файлы с классами математических функций, утилитами и графикой.

В первом приближении он будет выглядет как-то так

Основную смысловую нагрузку здесь будет нести содержимое тегов div с классом solve-item и графическая канва с классом solve-graphic__canvas.

Подключенные в заголовке страницы скрипты мы пока пропустим (скрипт с описанием численных методов пока что закомментирован, остальные скрипты разберем по ходу изложения)

Начнем с arraysExtended. "Родные" массивы в JS умеют делать много приятных плюшек (map, reduce, forEach - мы поговорим о них, но не сейчас), но одна часть этих возможностей поддерживается не всеми браузерами, а другая часть затратна по вычислительным ресурсам - а нам придется пережевывать достаточно большие объемы чисел. Попробуем придумать собственное решение, а заодно немного разомнемся.

-2

Мы используем как основу "родной" для яваскрипта объект Array, и от него через интерфейс классов ES6 ключевым словом extends наследуем новый класс расширенного массива ArrayExtended - теперь мы можем создавать объекты, которые <s>крякают как утки</s>умеют делать все, что может обычный массив, но помимо этого в них есть дополнительные нужные нам методы.

Начнем с getExtrems. Этот метод выбирает за основу самый первый элемент массива и затем проходим циклом for по всем остальным элементам, сравнивая их с выбранным. Чтобы на каждом шагу не обращаться к свойству массива length, заранее запишем его в переменную iMax. Получим на выходе объект с двумя полями - наибольшим и наименьшим значением в массиве. Почему я не воспользовался встроенным Math.max, загнав в него декомпозицию массива (это делается как-то так Math.min(...[a1, a2 . . . an]))?

Ответ - при таком подходе мы дважды вызываем функции Math.min и затем - Math.max, попутно проводим декомпозицию массива на составные части оператором ...(spread, очень вкусная и полезная штука, которая при использовании на массиве разбивает его на список входящих в него элементов). Все эти телодвижения требует машинного времени, так что пусть у нас будет самописный метод, в один проход по массиву находящий в нем и наименьшее, и наибольшее значение.

Следующий метод - takeValues. Он простой и даже немного унылый. Мы определяем длину массива, который собираемся принять, а потом перемываем из него значения.

Затем два статических метода. Объявленные с ключевым словом static, они могут быть вызваны без создания объекта, напрямую от имени класса (то есть почти как обычные функции и процедуры в процедурно-ориентированном подходе). Метод getInterval создает массив из N чисел, равномерно распределенных от x0 до x1

Метод extendArray еще проще - он принимает на вход обычный массив, внутри себя создает объект класса ArrayExtended, запитывает его из пришедшего на вход массива, а затем возвращает нам ссылку на созданный объект.

Итак, у нас есть класс, которым можно расширять возможности стандартного массива самыми разными функциями (в дальнейшем мы можем прикрутить к нему анализ входящих в массив данных, сопоставление с другими массивами). Но пока он будет нужен нам для подготовки данных, на которых будут строиться графики. О которых будет написано в следующей статье.