Привет, друзья!
Представляю вашему вниманию адаптированный и дополненный перевод этой замечательной статьи.
В данной статье я хочу рассказать вам о некоторых основных математических концепциях и их обозначениях, а также показать примеры реализации этих концепций на JavaScript
.
Символы точки и креста
Символы точки и креста являются очень распространенными в математике, но их использование зависит от контекста.
Умножение скаляров
Оба символа могут представлять простое умножение скаляров. Следующие выражения эквиваленты:
В JS
для умножения используется астериск (*
):
const result = 9 * 8;
Знак умножения в выражении часто опускается:
Если переменные k
и j
являются скалярами, код будет выглядеть так:
const result = 5 * k * j;
Умножение векторов
Для умножения векторов часто применяется символ открытой точки (∘
). Этот символ представляет произведение Адамара:
Это может быть реализовано следующим образом:
function multiply(a, b) {
return [a[0] * b[0], a[1] * b[1]];
}
function multiplyScalar(a, scalar) {
return [a[0] * scalar, a[1] * scalar];
}
const s = 5;
const k = [1, 2];
const j = [2, 3];
const v = multiply(k, j);
const result = multiplyScalar(v, s);
// [ 10, 30 ]
Скалярное произведение
Символ точки может обозначать скалярное произведение двух векторов:
Код будет выглядеть так:
function dot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
const k = [0, 1, 0];
const j = [1, 0, 0];
const result = dot(k, j);
// 0
0
означает, что векторы являются перпендикулярными.
Векторное произведение
Символ креста может обозначать векторное произведение двух векторов:
Код будет выглядеть так:
function cross(a, b) {
const ax = a[0],
ay = a[1],
az = a[2],
bx = b[0],
by = b[1],
bz = b[2];
const rx = ay * bz - az * by;
const ry = az * bx - ax * bz;
const rz = ax * by - ay * bx;
return [rx, ry, rz];
}
const k = [0, 1, 0];
const j = [1, 0, 0];
const result = cross(k, j);
// [ 0, 0, -1 ]
Сигма
Символ сигмы (Σ
) используется для суммирования:
Здесь i=1
означает, что сложение начинается с 1
и заканчивается числом над сигмой, т.е. 100
. Это верхняя и нижняя границы, соответственно. i
справа от Σ
говорит о том, что именно суммируется. Код будет выглядеть следующим образом:
let sum = 0;
for (let i = 1; i <= 100; i++) {
sum += i;
}
// 5050
Чуть более сложный пример:
Код:
let sum = 0;
for (let i = 1; i <= 100; i++) {
sum += 2 * i + 1;
}
// 10200
Сигмы могут быть вложенными. При этом, выражение оценивается справа налево (сначала вычисляется крайняя справа сигма, затем вторая справа и т.д.), если для изменения порядка оценивания не используются круглые скобки:
Код:
let sum = 0;
for (let i = 1; i <= 2; i++) {
for (let j = 4; j <= 6; j++) {
sum += 3 * i * j;
}
}
// 135
Заглавная П
Заглавная П или "Большая П" похожа на сигму, только вместо суммирования для вычисления результата последовательности значений используется умножение:
Код:
let product = 1;
for (let i = 1; i <= 7; i++) {
product *= i;
}
// 5040
Брусья
Символ брусьев (| |
) также может обозначать разные вещи в зависимости от контекста. Три основных случая использования: абсолютная величина, Евклидова норма и определитель. Все они описывают длину объекта.
Абсолютная величина
Это означает абсолютное величину или модуль числа x
. В JS
это будет выглядеть так:
const x = -4;
const result = Math.abs(x);
// 4
Евклидова норма
Евклидова норма или просто норма касается векторов. Это "величина" или "длина" вектора.
Пример использования массива [x, y, z]
для представления трехмерного вектора:
function length(vector) {
const x = vector[0];
const y = vector[1];
const z = vector[2];
return Math.sqrt(x * x + y * y + z * z);
}
const result = length([0, 6, -8]);
// 10
Определитель
Пример вычисления определителя или детерминанта матрицы 2x2
, представленной одномерным (плоским) массивом:
function determinant(a) {
return a[0] * a[3] - a[2] * a[1];
}
const result = determinant([1, 0, 0, 1]);
// 1
Циркумфлекс
Символ циркумфлекса (^
), который также называют "крышечкой" или "домиком" ("hat"), часто применяется в геометрии для обозначения единичного вектора. Пример единичного вектора a
:
В прямоугольной системе координат или Декартовом пространстве единичный вектор, обычно, имеет длину, равную 1
. Это означает, что каждая часть вектора будет находиться в диапазоне от -1.0
до 1.0
. Пример преобразования ("нормализации") трехмерного вектора в единичный:
function normalize(vector) {
const x = vector[0];
const y = vector[1];
const z = vector[2];
const squaredLength = x * x + y * y + z * z;
if (squaredLength > 0) {
const length = Math.sqrt(squaredLength);
return [x / length, y / length, z / length];
}
return vector;
}
const result = normalize([0, 8, -6]);
// [ 0, 0.8, -0.6 ]
Элемент
В теории множеств символы ∈
и ∋
часто используются для описания принадлежности элемента какому-либо множеству. Например:
Имеем множество чисел A { 3, 9, 14 }
и утверждаем, что 3
является элементом этого множества.
Простая реализация:
const A1 = [3, 9, 14];
const result1 = A1.includes(3);
// true
const A2 = new Set([3, 9, 14]);
const result2 = A2.has(14);
// true
Символ ∋
— это тоже самое, только меняется порядок (это называется зеркальным отображением):
Для обозначения того, что значение не является элементом множества используются символы ∉
и ∌
.
Для тех, кому интересно, вот полная таблица основных математических символов.
Функции
Функции являются ключевой частью математики. Они легко преобразуются в код.
Функция — это описание того, что следует сделать с входным значением для получения результата. Пример функции:
Названием данной функции может быть, например, ƒ
или A(x)
:
В коде функцию можно (и даже нужно) именовать более осмысленно:
const square = (x) => Math.pow(x, 2);
Функция может принимать несколько параметров. В математике параметры функции называются аргументами. Количество аргументов определяет "арность" (arity) функции (для уменьшения арности функции применяется техника под названием "каррирование" / currying; как правило, данная техника используется для создания частично-применяемых / partial функций):
Код:
const length = (x, y) => Math.sqrt(square(x) + square(y));
Кусочно-заданная функция
Функции могут состоять из трех основных частей: аргументы, отношение и результат (такие функции называются кусочно-заданными). Отношение определяет зависимость между аргументами и результатом. В некоторых функциях отношение определяется аргументами. Следующая функция ƒ
делает выбор между двумя "подфункциями" на основе аргумента:
В коде для этого можно прибегнуть к помощи if / else
:
function f(x) {
if (x >= 1) {
return (square(x) - x) / x;
}
return 0;
}
Основные функции
Наиболее распространенные математические функции представлены в JS
встроенными функциями типа parseInt или parseFloat и методами объекта Math.
Пример функции знака или функции sgn в кусочно-заданной нотации:
const sgn = (x) => Math.sign(x);
// полифил
function sgn(x) {
x = +x
if (x === 0 || isNaN(x)) {
return x;
}
return x > 0 ? 1 : -1;
}
Функции округления
Специальные скобки ⌊ ⌋
и ⌈ ⌉
представляют функции округления в меньшую и большую сторону, соответственно:
Код:
Math.floor(x);
Math.ceil(x);
Смешанные скобки ⌊ ⌉
, как правило, представляют функцию округления до ближайшего целого числа:
Код:
Math.round(x);
Послесловие
Мы рассмотрели лишь верхушку айсберга. Для тех, кто хочет погрузиться в тему применения математики в коде глубже, советую взглянуть на этот репозиторий.
Пожалуй, это все, чем я хотел поделиться в данной статье. Надеюсь, вы, как и я, нашли для себя что-то интересное и не зря потратили время.
Благодарю за внимание и happy coding!
Комментарии (6)
Alek_roebuck
29.06.2022 23:17Сигмы могут быть вложенными. При этом, выражение оценивается справа налево (сначала вычисляется крайняя справа сигма, затем вторая справа и т.д.), если для изменения порядка оценивания не используются круглые скобки:
Это как, простите? Сперва суммируем непонятно что слева, а потом применяем результат к тому, что справа? Можно пример?
Кстати, никто не называет по-русски сумму сигмами. Да и по-английски так не принято. И с некоторыми другими названиями вопрос спорный. Крышечка - это не циркумфлекс, хотя выглядят одинаково. Циркумфлекс - знак, имеющий фонетическое значение. В математике, да и в типографике, скорее всего (как минимум в латехе и в микрософтовской продукции), такая крышечка называется крышечкой или домиком, по-английски hat. Зачем использовать слова, которые, строго говоря, имеют другой смысл, и в любом случае не приняты в твоей области?
Вообще, смысл статьи от меня ускользает. Предполагается, что читателям придется подсчитывать на джаваскрипте математические выражения, где используются значки, смысла которых читатели не понимают?
neword
намного интереснее было бы привести варианты с использованием массивов и множеств, получится не только нагляднее и короче, но и быстрее. взять например
array.reduce
CoffinNail
По-моему, array.reduce только затуманит голову новичка, а здесь написано в лоб, как надо, чтобы понять суть. Вообще, отход от обычного перебора, где наглядно отображаются операнды в коде - это от лукавого. Подобие reduce, как Вы пишете, имеет сильный смысл лишь в asm.
neword
ага, видимо вы с asm хорошо знакомы :) тем не менее, если вы собираетесь кодить что-то серьезное, то изучите все методы объектов array и set. это реально поможет разбираться в чужом коде
CoffinNail
Да, это так. Хотя в javascript нет особого смысла в оптимизации скорости выполнения, куда важнее читабельность. Скорость в яве зависит от архитектуры проги в целом - это, кстати, тоже необходимо понять новичку. Простота кода - это прежде всего наглядность. И будущий разработчик должен стремиться к такому коду. Я видел людей, который смогли написать свою первую прогу практически идеально по читабельности, это был шедевр, когда сам я не смог так написать, уже имея опыт в программировании. Было даже досадно. Со временем я отшлифовал методы программирования, и сейчас уже никакой код или стиль не удивит меня. Я считаю, это хорошая статья. Да, было бы неплохо привести еще пример машинного кода, вычисляющего длину вектора.