diff --git a/modules/20-arithmetics/20-basic/ru/EXERCISE.md b/modules/20-arithmetics/20-basic/ru/EXERCISE.md index 5dfef630..a8f46734 100644 --- a/modules/20-arithmetics/20-basic/ru/EXERCISE.md +++ b/modules/20-arithmetics/20-basic/ru/EXERCISE.md @@ -1 +1 @@ -Выведите на экран результат деления числа `81` на `9`. +Вы зашли в оптовый магазин и увидели упаковку из 9 батареек за 81 рубль. В обычном магазине одна батарейка стоит 12 рублей. Рассчитайте и выведите цену одной батарейки в оптовой упаковке, чтобы понять, где выгоднее покупать. diff --git a/modules/20-arithmetics/20-basic/ru/README.md b/modules/20-arithmetics/20-basic/ru/README.md index c7169f19..5d94a9ca 100644 --- a/modules/20-arithmetics/20-basic/ru/README.md +++ b/modules/20-arithmetics/20-basic/ru/README.md @@ -1,14 +1,22 @@ -На базовом уровне компьютеры оперируют только числами. Даже в прикладных программах на высокоуровневых языках внутри много чисел и операций над ними. К счастью, для старта достаточно знать обычную арифметику — с нее и начнем. +На базовом уровне компьютеры работают только с числами. Даже если вы пишете сложное приложение на современном языке программирования, внутри него всегда происходят многочисленные вычисления: сложение, вычитание, деление и т.д. -Для сложения двух чисел в математике мы пишем, например, `3 + 4`. В программировании — то же самое. Вот программа, складывающая два числа: +К счастью, чтобы начать программировать, достаточно знать обычную школьную арифметику. С нее мы и начнем. + +## Сложение в JavaScript + +В математике для сложения мы пишем 3 + 4. В JavaScript все точно так же: ```javascript -// Не забываем точку с запятой в конце, -// так как каждая строчка в коде - инструкция 3 + 4; ``` -Инструкция `3 + 4;` заставит компьютер сложить числа и узнать результат. Если запустить эту программу, то ничего не произойдет. А если быть точными, то компьютер вычислит сумму, но на этом всё. Результат сложения никак не используется, и такая программа не представляет никакого интереса. Нам нужно попросить компьютер сложить `3 + 4` **и** дать команду сделать что-то с результатом. Например, вывести его на экран: +Этот код действительно можно запустить: интерпретатор выполнит вычисление. Но... он не сделает с результатом ничего. То есть 7 получится, но вы его не увидите. + +## Чтобы увидеть результат, нужно его вывести + +В реальной программе просто посчитать значение недостаточно. Нужно сделать что-то с результатом, например, показать его пользователю. + +Для этого используем уже привычную команду `console.log()`: ```javascript // Сначала вычисляется сумма, @@ -16,27 +24,75 @@ console.log(3 + 4); ``` -После запуска на экране появится результат: +```text +console.log(3 + 4) + └─┬─┘ + 7 - ```text - 7 - ``` +console.log(7) → 7 +``` -Кроме сложения, доступны следующие операции: +Результат выполнения: -- `*`: умножение -- `/`: деление -- `-`: вычитание -- `%`: [остаток от деления](https://ru.wikipedia.org/wiki/Деление_с_остатком) -- `**`: возведение в степень +```text +7 +``` -Теперь давайте выведем на экран результат деления, а потом результат возведения в степень: +Если записать то же выражение в виде строки, мы получим совсем другой результат — на печать будет выведена строка «как есть»: ```javascript -console.log(8 / 2); // => 4 +console.log('3 + 4'); // выводит: 3 + 4 +console.log(3 + 4); // выводит: 7 +``` + +## Другие арифметические операции + +JavaScript поддерживает все привычные операции + несколько специфичных, связанных с тем, как хранятся и обрабатываются числа на компьютере: + +| Операция | Символ | Пример | Результат | +|----------------------|--------|-----------|-----------| +| Сложение | `+` | `2 + 3` | `5` | +| Вычитание | `-` | `7 - 2` | `5` | +| Умножение | `*` | `4 * 3` | `12` | +| Деление | `/` | `8 / 2` | `4` | +| Возведение в степень | `**` | `3 ** 2` | `9` | +| Остаток от деления | `%` | `7 % 3` | `1` | + +Вот как можно вывести результат деления и возведения в степень: + +```javascript +console.log(8 / 2); // => 4 console.log(3 ** 2); // => 9 ``` -Иногда для удобства мы будем показывать в комментариях результат запуска строчек кода, вот так: `=> РЕЗУЛЬТАТ`. Например, `// => 4`. +## Что такое остаток от деления (`%`) + +Эта операция называется **взятие остатка от деления**. Она показывает, **что «остается»**, когда одно число делится на другое *не полностью*. Пример: + +```javascript +console.log(7 % 3); // => 1 +``` + +Почему результат равен 1? -Первая инструкция выведет на экран `4` (потому что 8 / 2 это 4), а вторая инструкция выведет на экран 9 (потому что 32 это 9). +- 7 делится на 3 дважды: 3 * 2 = 6 +- До 7 остается 1, и это является остатком. + +Другие примеры: + +```javascript +console.log(10 % 4); // => 2 (10 делится на 4 дважды: 4 * 2 = 8, остаток 2) +console.log(15 % 5); // => 0 (делится без остатка) +``` + +Операция `%` часто используется в программировании, например, чтобы проверить, делится ли число нацело (если остаток 0). + +## Оформление арифметических выражений + +С точки зрения JavaScript между `3+4` и `3 + 4` нет разницы. Интерпретатор поймет оба варианта одинаково. Разница только в оформлении кода. В программировании принято ставить пробелы вокруг арифметических операторов, потому что так выражения проще читать: + +```javascript +console.log(3 + 4); +console.log(8 / 2); +console.log(7 % 3); +``` diff --git a/modules/20-arithmetics/25-operator/index.js b/modules/20-arithmetics/25-operator/index.js index d346c92d..9ef9ae7e 100644 --- a/modules/20-arithmetics/25-operator/index.js +++ b/modules/20-arithmetics/25-operator/index.js @@ -1 +1,2 @@ console.log(6 - -81); +console.log((6 - -81) / 3); diff --git a/modules/20-arithmetics/25-operator/ru/EXERCISE.md b/modules/20-arithmetics/25-operator/ru/EXERCISE.md index 003cfc9c..8548507f 100644 --- a/modules/20-arithmetics/25-operator/ru/EXERCISE.md +++ b/modules/20-arithmetics/25-operator/ru/EXERCISE.md @@ -1 +1,6 @@ -Напишите программу, которая посчитает разность между числами `6` и `-81` и выведет ответ на экран. +Подводная лодка находится на глубине -81 м. Палуба спасательного корабля расположена на высоте +6 м над уровнем воды. + +Рассчитайте и выведите на экран: + +1. Полное расстояние всплытия в метрах. +2. Время подъема в минутах — лодка поднимается со скоростью 3 м/мин. diff --git a/modules/20-arithmetics/25-operator/ru/README.md b/modules/20-arithmetics/25-operator/ru/README.md index d566570c..4629a623 100644 --- a/modules/20-arithmetics/25-operator/ru/README.md +++ b/modules/20-arithmetics/25-operator/ru/README.md @@ -1,20 +1,63 @@ +В математике и программировании мы часто используем знаки операций, такие как `+`, `-`, `*` и другие. В программировании такие знаки называются операторами. -Перед тем как двигаться дальше, разберем базовую терминологию. Знак операции, такой как `+`, называют **оператором**. Операторы выполняют операции над определенными значениями, которые называются **операндами**. Сами операторы, обычно, представлены одним или несколькими символами. Реже словом. Подавляющее большинство операторов соответствуют математическим операциям. +- Оператор представляет собой символ или слово, которое обозначает действие. +- Операнды — это значения, к которым применяется оператор. + +Пример: ```javascript console.log(8 + 2); ``` -В этом примере `+` — это **оператор**, а числа `8` и `2` — это **операнды**. +Здесь: + +- `+` является оператором +- `8` и `2` являются операндами +- результатом будет `10` + +```text +операнд оператор операнд результат + 8 + 2 → 10 + 5 - 3 → 2 + 4 * 3 → 12 +``` + +## Унарные операторы + +Существуют и унарные операции, которые работают с одним операндом. Пример: + +```javascript +console.log(-3); // => -3 +``` + +В этом случае `-` является унарным оператором, а `3` — операндом. Интерпретатор получает команду: «возьми число 3 и измени его знак». + +Оператор `-` может использоваться по-разному. Когда он стоит **между двумя числами**, это операция вычитания: + +```javascript +console.log(5 - 2); // => 3 +console.log(10 - 7); // => 3 +``` + +Эта разница особенно заметна при работе с отрицательными числами: -В случае сложения у нас есть два операнда: один слева, другой справа от знака `+`. Операции, которые требуют наличия двух операндов, называются **бинарными**. Если пропустить хотя бы один операнд, например, `3 + ;`, то программа завершится с синтаксической ошибкой. +```javascript +// минус на минус дает плюс +console.log(5 - -2); // => 7 +``` -Операции (не операторы) бывают не только бинарными, но и унарными (с одним операндом), и даже тернарными (с тремя операндами)! Причем операторы могут выглядеть одинаково, но обозначать разные операции. +Сначала мы видим операцию вычитания: `5 - (...)`. Но справа стоит унарный минус `-2`, который превращает `2` в отрицательное число. В итоге получается: `5 - (-2) = 7`. - ```javascript - console.log(-3); // => -3 - ``` +Таким образом, значение `-` зависит от контекста: если рядом стоит другое число — это вычитание, иначе — смена знака числа. + +## Ошибки при вычислениях + +Если воспринимать `-3` как единое число, можно не заметить, что `-` является отдельным оператором со своим приоритетом. Например: + +```javascript +console.log(-3 ** 2); // => -9, а не 9! +``` -Выше пример применения унарной операции к числу `3`. Оператор минус перед тройкой говорит интерпретатору взять число `3` и найти противоположное, то есть `-3`. +На первый взгляд может показаться, что в квадрат возводится `-3`, и результат должен быть `9`. Но результат будет `-9`. -Это немного может сбить с толку, потому что `-3` — это одновременно и число само по себе, и оператор с операндом, но у языков программирования такая структура. +Дело в порядке вычислений: сначала выполняется возведение в степень (`**`), а только потом применяется унарный минус. То есть: `-(3 ** 2) = -9`. Про приоритет операций поговорим подробнее в следующих уроках. diff --git a/modules/20-arithmetics/25-operator/ru/data.yml b/modules/20-arithmetics/25-operator/ru/data.yml index 38d5ecd9..b55d9d3e 100644 --- a/modules/20-arithmetics/25-operator/ru/data.yml +++ b/modules/20-arithmetics/25-operator/ru/data.yml @@ -1,12 +1,21 @@ --- name: Операторы tips: + - >- + Всегда отбивайте арифметические операторы пробелами от своих операндов — это + хороший стиль программирования. - > [Операторы в JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators) definitions: - name: Арифметическая операция description: сложение, вычитание, умножение и деление. + - name: Оператор + description: >- + специальный символ, создающий операцию. Например, `+` создает операцию + сложения. + - name: Операнд + description: 'объект, который участвует в операции. `3 * 6`: здесь 3 и 6 — операнды.' - name: Унарная операция description: >- операция с одним операндом. Например, `-3` — унарная операция для diff --git a/modules/20-arithmetics/25-operator/test.js b/modules/20-arithmetics/25-operator/test.js index 192353dc..7062e1d8 100644 --- a/modules/20-arithmetics/25-operator/test.js +++ b/modules/20-arithmetics/25-operator/test.js @@ -8,5 +8,5 @@ test('hello world', async () => { const firstArg = consoleLogSpy.mock.calls.join('\n'); - expect(firstArg).toBe('87'); + expect(firstArg).toBe('87\n29'); }); diff --git a/modules/20-arithmetics/27-commutativity/index.js b/modules/20-arithmetics/27-commutativity/index.js index 626b950d..f67efbbd 100644 --- a/modules/20-arithmetics/27-commutativity/index.js +++ b/modules/20-arithmetics/27-commutativity/index.js @@ -1,2 +1,2 @@ -console.log(3 ** 5); -console.log(-8 / -4); +console.log(2 ** 8); +console.log(9 / 3); diff --git a/modules/20-arithmetics/27-commutativity/ru/EXERCISE.md b/modules/20-arithmetics/27-commutativity/ru/EXERCISE.md index c3c76d83..488ea509 100644 --- a/modules/20-arithmetics/27-commutativity/ru/EXERCISE.md +++ b/modules/20-arithmetics/27-commutativity/ru/EXERCISE.md @@ -1,2 +1,4 @@ +Напишите программу, которая решает две задачи и выводит ответы на экран — каждый на отдельной строке. -Напишите программу, которая считает и выводит последовательно на экран значения следующих математических выражений: «3 в степени 5» и «-8 разделить на -4». +1. Художник хочет раскрасить 8 секций забора, каждую — в один из 2 цветов. Сколько уникальных вариантов раскраски существует? Используйте оператор возведения в степень `**`. +2. Вы с двумя друзьями (итого 3 человека) купили 9 пирожных и хотите разделить их поровну. Сколько достанется каждому? Используйте оператор деления `/`. diff --git a/modules/20-arithmetics/27-commutativity/ru/README.md b/modules/20-arithmetics/27-commutativity/ru/README.md index 0103e66e..0812d36f 100644 --- a/modules/20-arithmetics/27-commutativity/ru/README.md +++ b/modules/20-arithmetics/27-commutativity/ru/README.md @@ -1,7 +1,57 @@ -Мы все помним со школы: «от перемены мест слагаемых сумма не меняется». Это один из базовых и интуитивно понятных законов арифметики, он называется **коммутативным законом**. +Фраза «от перемены мест слагаемых сумма не меняется» знакома каждому со школы. Этот принцип называется коммутативным законом и является одним из основных законов арифметики. -Бинарная операция считается коммутативной, если поменяв местами операнды, вы получаете тот же самый результат. Очевидно, что сложение - коммутативная операция: *3 + 2 = 2 + 3*. +## Что такое коммутативность -А вот является ли коммутативной операция вычитания? Конечно, нет: *2 - 3 ≠ 3 - 2*. В программировании этот закон работает точно так же, как в арифметике. +Операция называется коммутативной, если порядок операндов не влияет на результат: поменяв местами значения, вы получите тот же ответ. Пример коммутативной операции: сложение. -Более того, большинство операций, с которыми мы будем сталкиваться в реальной жизни, не являются коммутативными. Отсюда вывод: всегда обращайте внимание на порядок того, с чем работаете. +```javascript +console.log(3 + 2); // => 5 +console.log(2 + 3); // => 5 +``` + +Одинаковый результат подтверждает, что операция коммутативна. + +```text +2 + 3 = 5 3 + 2 = 5 +└──────────┬─────────┘ + одинаковый результат + +2 - 3 = -1 3 - 2 = 1 +└──────────┬─────────┘ + разный результат +``` + +## Некоммутативные операции + +Но не все операции обладают таким свойством. Например, вычитание является некоммутативной операцией: + +```javascript +console.log(2 - 3); // => -1 +console.log(3 - 2); // => 1 +``` + +Перестановка операндов дает другой результат. + +## В программировании всё то же самое + +Коммутативность в программировании работает точно так же, как в арифметике. JavaScript строго следует математическим правилам. + +Другие некоммутативные операции: + +- Деление: _8 / 2 ≠ 2 / 8_ +- Возведение в степень: _2 \*\*3 ≠ 3\*\* 2_ + +Примеры в коде: + +```javascript +// Деление +console.log(8 / 2); // 8 делить на 2 = 4 + +// Возведение в степень +console.log(3 ** 2); // 3 в квадрате = 9 +``` + +Поэтому: + +- Всегда внимательно проверяйте порядок операндов, особенно при работе с незнакомыми операциями; +- проверяйте коммутативность экспериментально, а не предполагайте её заранее. diff --git a/modules/20-arithmetics/27-commutativity/test.js b/modules/20-arithmetics/27-commutativity/test.js index 7f2210bb..87594ee2 100644 --- a/modules/20-arithmetics/27-commutativity/test.js +++ b/modules/20-arithmetics/27-commutativity/test.js @@ -8,5 +8,5 @@ test('hello world', async () => { const firstArg = consoleLogSpy.mock.calls.join('\n'); - expect(firstArg).toBe('243\n2'); + expect(firstArg).toBe('256\n3'); }); diff --git a/modules/20-arithmetics/30-composition/index.js b/modules/20-arithmetics/30-composition/index.js index ea68ad64..114ccead 100644 --- a/modules/20-arithmetics/30-composition/index.js +++ b/modules/20-arithmetics/30-composition/index.js @@ -1 +1 @@ -console.log(8 / 2 + 5 - -3 / 2); +console.log(3 * 200 + 2 * 30); diff --git a/modules/20-arithmetics/30-composition/ru/EXERCISE.md b/modules/20-arithmetics/30-composition/ru/EXERCISE.md index a12d8c8a..ce933c33 100644 --- a/modules/20-arithmetics/30-composition/ru/EXERCISE.md +++ b/modules/20-arithmetics/30-composition/ru/EXERCISE.md @@ -1,8 +1,7 @@ +Вы идёте в магазин за подарками: 3 книги по 200 рублей и 2 ручки по 30 рублей. Рассчитайте и выведите итоговую стоимость покупки. -Реализуйте программу, которая вычисляет и выводит на экран значение выражения: - -``` -8 / 2 + 5 - -3 / 2 +```text +3 * 200 + 2 * 30 + ↓ ↓ + 600 + 60 = 660 ``` - -Не вычисляйте ничего самостоятельно, ваша программа должна производить все вычисления сама. diff --git a/modules/20-arithmetics/30-composition/ru/README.md b/modules/20-arithmetics/30-composition/ru/README.md index 567335a1..9720f9a3 100644 --- a/modules/20-arithmetics/30-composition/ru/README.md +++ b/modules/20-arithmetics/30-composition/ru/README.md @@ -1,21 +1,74 @@ -А что, если понадобится вычислить такое выражение: `3 * 5 - 2`? Именно так мы и запишем: +В JavaScript, как и в математике, можно объединять несколько операций в одну строку. Такие выражения интерпретатор обрабатывает шаг за шагом по определённым правилам. + +Рассмотрим пример: ```javascript -console.log(3 * 5 - 2); // => 13 +console.log(2 * 4 * 5 * 10); ``` -Обратите внимание, что интерпретатор производит арифметические вычисления в правильном порядке: сначала деление и умножение, потом сложение и вычитание. Иногда этот порядок нужно изменить — об этом следующий урок. +Этот код состоит из нескольких операций умножения, объединённых в одно выражение. Чтобы понять, как интерпретатор выполняет выражение, разберём его по этапам: + +- Сначала вычисляется `2 * 4`: `8 * 5 * 10` +- Затем `8 * 5`: `40 * 10` +- И наконец `40 * 10`: `400` + +Итоговый результат составляет `400`. -Или другой пример: +## А если разные операции? + +Всё просто, пока используются одинаковые операторы. Но что произойдёт, если объединить, например, умножение и сложение? ```javascript -console.log(2 * 4 * 5 * 10); +console.log(2 + 3 * 4); +``` + +```text +2 + 3 * 4 + └─┬─┘ +2 + 12 +└──┬───┘ + 14 +``` + +Получится ли `20` или `14`? Ответ: `14`. + +Это объясняется тем, что в JavaScript, как и в математике, у операций есть приоритет. Умножение выполняется раньше сложения, если не использовать скобки. Мы разберём это подробнее в уроке про приоритеты. + +## Примеры с вычитанием и отрицательными числами + +То же правило работает и для вычитания: + +```javascript +console.log(10 - 2 * 3); // => 4 +``` + +Сначала выполняется умножение: `10 - 6 = 4`. + +Если же в выражении есть отрицательные числа, унарный минус применяется уже после возведения в степень: + +```javascript +console.log(-2 ** 2); // => -4, два в степени два, затем применяется минус +console.log(-2 * 5); // => -10, минус два умноженное на пять +console.log(4 + -2); // => 2 +console.log(6 - -2); // => 8 +``` + +Во всех примерах, кроме первого, сначала вычисляется унарный минус (`-2`), и затем проводятся остальные операции. + +Рассмотрим подробнее последний пример: + +```javascript +console.log(6 - -2); // => 8 ``` -Как видно, операции можно соединять друг с другом, получая возможность вычислять все более сложные составные выражения. Чтобы представить себе то, как происходят вычисления внутри интерпретатора, давайте разберем пример: `2 * 4 * 5 * 10`. +Сначала вычисляется унарный минус (`-2`), и затем операция превращается в `6 - (-2)`, что даёт `8`. Это то же самое, что: + +```javascript +console.log(6 + 2); // => 8 +``` -1. Сначала вычисляется `2 * 4` и получается выражение `8 * 5 * 10`. -1. Затем `8 * 5`. В итоге имеем `40 * 10`. -3. В конце концов происходит последнее умножение, и получается результат `400`. +## Что нужно запомнить -Таким образом, интерпретатор соединяет сложные составные выражения, последовательно выполняя заложенные в них арифметические действия, по умолчанию соблюдая правильный порядок: сначала умножение и деление, затем - сложение и вычитание. +- Выражения могут состоять из нескольких операций. +- JavaScript вычисляет их поэтапно: слева направо, соблюдая приоритет операций. +- Скобки можно использовать, чтобы явно указать порядок вычислений. diff --git a/modules/20-arithmetics/30-composition/test.js b/modules/20-arithmetics/30-composition/test.js index dbf819af..649e45e0 100644 --- a/modules/20-arithmetics/30-composition/test.js +++ b/modules/20-arithmetics/30-composition/test.js @@ -8,5 +8,5 @@ test('hello world', async () => { const firstArg = consoleLogSpy.mock.calls.join('\n'); - expect(firstArg).toBe('10.5'); + expect(firstArg).toBe('660'); }); diff --git a/modules/20-arithmetics/40-priority/index.js b/modules/20-arithmetics/40-priority/index.js index 847916f8..d0ea20a8 100644 --- a/modules/20-arithmetics/40-priority/index.js +++ b/modules/20-arithmetics/40-priority/index.js @@ -1 +1 @@ -console.log((70 * (3 + 4)) / (8 + 2)); +console.log((2 * 300 + 4 * 50) / 5); diff --git a/modules/20-arithmetics/40-priority/ru/EXERCISE.md b/modules/20-arithmetics/40-priority/ru/EXERCISE.md index 0b63f8c9..9d7e0109 100644 --- a/modules/20-arithmetics/40-priority/ru/EXERCISE.md +++ b/modules/20-arithmetics/40-priority/ru/EXERCISE.md @@ -1,4 +1,8 @@ +Вы с 4 друзьями (итого 5 человек) заказали 2 пиццы по 300 рублей и 4 напитка по 50 рублей. Нужно разделить счёт поровну. -Дано выражение `70 * 3 + 4 / 8 + 2`. +Запишите программу из одной строки с `console.log()`, расставив скобки так, чтобы сначала посчиталась общая сумма, а затем делилась на всех: -Расставьте скобки так, чтобы оба сложения (`3 + 4`) и (`8 + 2`) высчитывались в первую очередь. Выведите результат на экран. +```text +без скобок: 2 * 300 + 4 * 50 / 5 = 640 ← неверно +со скобками: (2 * 300 + 4 * 50) / 5 = 160 ← верно +``` diff --git a/modules/20-arithmetics/40-priority/ru/README.md b/modules/20-arithmetics/40-priority/ru/README.md index 0129307f..b4c969d2 100644 --- a/modules/20-arithmetics/40-priority/ru/README.md +++ b/modules/20-arithmetics/40-priority/ru/README.md @@ -1,30 +1,65 @@ -Посмотрите внимательно на выражение `2 + 2 * 2` и посчитайте в уме ответ. +Рассмотрим простое выражение: -Правильный ответ: `6`. +```javascript +console.log(2 + 2 * 2); // => 6 +``` + +Результат равен 6, а не 8. Это объясняется понятием приоритета операций в математике и программировании. Он определяет порядок, в котором выполняются действия: -Если у вас получилось `8`, то этот урок для вас. В школьной математике мы изучали понятие «приоритет операции». Приоритет определяет то, в какой последовательности должны выполняться операции. Например, умножение и деление имеют больший приоритет, чем сложение и вычитание, а приоритет возведения в степень выше всех остальных арифметических операций: `2 ** 3 * 2` вычислится в `16`. +- Умножение и деление выполняются раньше сложения и вычитания. +- Возведение в степень (`**`) имеет ещё более высокий приоритет. -Но нередко вычисления должны происходить в порядке, отличном от стандартного приоритета. В сложных ситуациях приоритет можно (и нужно) задавать круглыми скобками, точно так же, как в школе, например: `(2 + 2) * 2`. +```text +Приоритет операций (от высокого к низкому): + + ** возведение в степень + ↓ + * / % умножение, деление, остаток + ↓ + + - сложение, вычитание +``` + +Например: + +```javascript +console.log(2 * 2 ** 3); // => 16, потому что сначала 2 ** 3 = 8, затем 8 * 2 = 16 +``` -Скобки можно ставить вокруг любой операции. Они могут вкладываться друг в друга сколько угодно раз. Вот пара примеров: +Если рядом идут операции с одинаковым приоритетом, они выполняются слева направо: ```javascript -console.log(3 ** (4 - 2)); // => 9 -console.log(7 * 3 + (4 / 2) - (8 + (2 - 1))); // => 14 +console.log(8 / 2 * 3); // => 12, потому что сначала 8 / 2 = 4, затем 4 * 3 = 12 ``` -Иногда выражение сложно воспринимать визуально. Тогда можно расставить скобки, не повлияв на приоритет. Например, задание из прошлого урока можно сделать немного понятнее, если расставить скобки. +## Управление порядком действий -Было: +Иногда нужно изменить порядок вычислений. Для этого используются круглые скобки. Они позволяют задать, какие действия нужно выполнить в первую очередь: ```javascript -console.log(8 / 2 + 5 - -3 / 2); // => 10.5 +console.log((2 + 2) * 2); // => 8 ``` -Стало: +Скобки можно ставить вокруг любой части выражения и вкладывать их друг в друга: ```javascript -console.log(((8 / 2) + 5) - (-3 / 2)); // => 10.5 +console.log(3 ** (4 - 2)); // => 9 +console.log(7 * 3 + (4 / 2) - (8 + (2 - 1))); // => 14 +``` + +Главное правило: всегда закрывайте скобки. Непарные скобки вызывают ошибки: и новички, и опытные программисты иногда забывают про закрывающую скобку. + +> Пишите скобки сразу парой. Например, вводите `()` и потом заполняйте внутреннюю часть. Большинство редакторов кода (в том числе наш) автоматически добавляют закрывающую скобку, как только вы пишете открывающую. + +## Повышаем читаемость + +Иногда выражение работает правильно, но выглядит запутанно. В таких случаях скобки можно добавить просто для наглядности: они не изменят результат, но улучшат восприятие. + +```javascript +// Было +console.log(8 / 2 + 5 - -3 / 2); // => 10.5 + +// Стало +console.log(((8 / 2) + 5) - (-3 / 2)); // => 10.5 ``` -Запомните: код пишется для людей, потому что код будут читать люди, а машины будут только исполнять его. Для машин код — или корректный, или не корректный, для них нет «более» понятного или «менее» понятного кода. +Программы пишут люди, и читают их тоже люди. Компьютеру всё равно, насколько понятно написан код: достаточно, чтобы он был синтаксически правильным. Для человека понятный и аккуратный код является залогом удобства, особенно при работе в команде или разборе ошибок. diff --git a/modules/20-arithmetics/40-priority/test.js b/modules/20-arithmetics/40-priority/test.js index 32de115e..75928021 100644 --- a/modules/20-arithmetics/40-priority/test.js +++ b/modules/20-arithmetics/40-priority/test.js @@ -8,5 +8,5 @@ test('hello world', async () => { const firstArg = consoleLogSpy.mock.calls.join('\n'); - expect(firstArg).toBe('49'); + expect(firstArg).toBe('160'); }); diff --git a/modules/20-arithmetics/50-float/index.js b/modules/20-arithmetics/50-float/index.js index 0c5dd3b6..7b235f4c 100644 --- a/modules/20-arithmetics/50-float/index.js +++ b/modules/20-arithmetics/50-float/index.js @@ -1 +1 @@ -console.log(0.39 * 0.22); +console.log(0.1 + 0.2); diff --git a/modules/20-arithmetics/50-float/ru/EXERCISE.md b/modules/20-arithmetics/50-float/ru/EXERCISE.md index 6b472cb1..c25b7152 100644 --- a/modules/20-arithmetics/50-float/ru/EXERCISE.md +++ b/modules/20-arithmetics/50-float/ru/EXERCISE.md @@ -1,2 +1,3 @@ +Вы оплачиваете два товара в интернет-магазине: первый стоит 0.1 рубля, второй — 0.2 рубля. Рассчитайте и выведите итоговую сумму. -Вычислите и выведите на экран произведение двух чисел: *0.39* и *0.22* +Ожидаете увидеть 0.3 — но JavaScript выдаст кое-что интересное. diff --git a/modules/20-arithmetics/50-float/ru/README.md b/modules/20-arithmetics/50-float/ru/README.md index 79e1a14a..3592221a 100644 --- a/modules/20-arithmetics/50-float/ru/README.md +++ b/modules/20-arithmetics/50-float/ru/README.md @@ -1,24 +1,50 @@ +В математике есть разные типы чисел. Например: -JavaScript не делает различий между рациональными (0.5) и натуральными числами (10), для него и то, и другое - числа (в других языках это не так). Благодаря этому их можно использовать совместно в любых операциях: +- Натуральные: целые положительные числа: 1, 2, 3 и т.д. +- Рациональные: дробные числа, которые можно представить в виде деления, например: 0.5, 1.75, 3.14. + +С точки зрения математики всё просто. Но с точки зрения компьютера между этими типами чисел лежит настоящая пропасть. Попробуйте мысленно решить: сколько будет `0.2` + `0.1`? Очевидно, `0.3`. А вот что скажет JavaScript: ```javascript -3 * 0.5; // 1.5 +console.log(0.2 + 0.1); // => 0.30000000000000004 ``` -Но как бы от нас ни скрывали, рациональные числа, в силу своих особенностей, устроены совсем по-другому. Нам, как прикладным программистам, это было бы не особенно важно, если бы не одна деталь. Посмотрите на этот пример: +Вместо привычных 0.3 мы получаем 0.30000000000000004. -```javascript -0.2 * 0.2 // 0.04000000000000001 +```text +Ожидание: 0.1 + 0.2 → 0.3 +Реальность: 0.1 + 0.2 → 0.30000000000000004 + └── погрешность хранения ``` -Операция умножения двух рациональных чисел внезапно привела к неточному вычислению результата. Тот же самый результат выдадут и другие языки программирования. Такое поведение обуславливается ограничениями вычислительных мощностей. Объем памяти, в отличие от чисел, конечен (бесконечное количество чисел требует бесконечного количества памяти для своего хранения). И если с натуральными числами эта проблема решается простым ограничением по верхней границе (есть некоторое максимальное число, которое можно ввести), то с рациональными такой финт не пройдет. +## Почему так происходит? + +Такое поведение характерно для JavaScript, Python, C++ и большинства других языков программирования. + +Причина в устройстве компьютера. Компьютер работает с ограниченной памятью, тогда как рациональные числа бесконечно точны. Между 0.1 и 0.2 можно поместить бесконечно много других чисел. Но компьютер не может хранить бесконечность. Он приближает число, стараясь уместить его в доступное количество бит. + +Такие приближённые значения называются числами с плавающей точкой (floating point numbers). Хранение и вычисления с ними подчиняются строгим правилам, описанным в специальном стандарте IEEE 754, на который ориентируются большинство языков программирования. + +## Когда появляются такие числа + +Числа с плавающей точкой появляются в программах чаще, чем может показаться. Вот основные случаи: + +- Когда вы явно пишете дробное число, например 0.1, 2.5, 3.14. +- Когда выполняете деление, даже если делите два целых числа: ```javascript -// Максимальное возможное целое число -console.log(Number.MAX_SAFE_INTEGER); -9007199254740991 +console.log(1 / 2); // => 0.5 +console.log(2 / 3); // => 0.6666666666666666 ``` -Рациональные числа не выстроены в непрерывную цепочку, между _0.1_ и _0.2_ бесконечное множество чисел. Соответственно возникает серьезная проблема, а как хранить рациональные числа? Это интересный вопрос сам по себе. В интернете множество статей, посвященных организации памяти в таких случаях. Более того, существует стандарт, в котором описано, как это делать правильно, и подавляющее число языков на него опирается. +Даже если результат кажется «красивым», внутри он всё равно представлен в виде приближённого значения. Некоторые дроби, такие как 1 / 3, вообще не могут быть точно представлены в двоичной системе, поэтому их точность всегда ограничена. + +## Где это критично и как с этим работают + +Обычно небольшая погрешность не мешает. Но в финансовых расчётах, научных и инженерных задачах, а также при точном сравнении результатов она может стать проблемой. Например, ошибка в доли копейки способна дать неправильную итоговую сумму, а длинная цепочка вычислений может постепенно накапливать неточность. + +В реальных программах с этим работают по-разному. Деньги часто хранят в минимальных единицах, например в копейках, то есть используют целые числа вместо дробных. В других случаях результат округляют до нужного количества знаков, сравнивают числа с допустимой погрешностью или используют специальные библиотеки для точных вычислений. + +## Что нужно запомнить -Для нас, как для разработчиков, важно понимать, что операции с плавающими числами неточны (эту точность можно регулировать), а значит при решении задач, связанных с подобными числами, необходимо прибегать к специальным трюкам, которые позволяют добиться необходимой точности. +Операции с числами с плавающей точкой не всегда точны, и это нормально. Такое поведение характерно для большинства языков программирования и объясняется устройством компьютерной памяти. Точность можно контролировать, например с помощью округления или сравнения чисел с заданной погрешностью. А при работе с деньгами, точными измерениями или научными расчётами лучше использовать специальные типы данных, которые обеспечивают контроль над точностью. diff --git a/modules/20-arithmetics/50-float/test.js b/modules/20-arithmetics/50-float/test.js index 61751300..faa2a296 100644 --- a/modules/20-arithmetics/50-float/test.js +++ b/modules/20-arithmetics/50-float/test.js @@ -8,5 +8,5 @@ test('hello world', async () => { const firstArg = consoleLogSpy.mock.calls.join('\n'); - expect(firstArg).toBe('0.0858'); + expect(firstArg).toBe('0.30000000000000004'); }); diff --git a/modules/20-arithmetics/80-linting/ru/EXERCISE.md b/modules/20-arithmetics/80-linting/ru/EXERCISE.md index 49264980..e2c27469 100644 --- a/modules/20-arithmetics/80-linting/ru/EXERCISE.md +++ b/modules/20-arithmetics/80-linting/ru/EXERCISE.md @@ -1,2 +1,7 @@ +Вы получили код от коллеги — он работает правильно, но нарушает стандарт оформления. Исправьте пробелы вокруг операторов, не меняя логику: -Выведите на экран результат следующего вычисления: «разница между пятью в квадрате и произведением трёх и семи». Расставьте скобки таким образом, чтобы не нарушать правило `no-mixed-operators`. +```javascript +console.log( (5 **2)-(3* 7)); +``` + +Результат должен остаться `4`. diff --git a/modules/20-arithmetics/80-linting/ru/README.md b/modules/20-arithmetics/80-linting/ru/README.md index a0cc2adc..5d7eecdc 100644 --- a/modules/20-arithmetics/80-linting/ru/README.md +++ b/modules/20-arithmetics/80-linting/ru/README.md @@ -1,38 +1,55 @@ -Теперь, когда мы уже научились писать простые программы, можно немного поговорить о том, как их писать. +Когда разные разработчики пишут код в разном стиле, код становится трудночитаемым: где-то пробел лишний, где-то отступы разные. Чтобы избежать разногласий, программисты договорились соблюдать единый стиль кодирования. Этот свод правил описывает, как должен выглядеть код: расстановку пробелов, оформление функций и названия переменных. -Код программы следует оформлять определенным образом, чтобы он был достаточно понятным и простым в поддержке. Специальные наборы правил — стандарты — описывают различные аспекты написания кода. Конкретно в JavaScript самым распространенным стандартом является стандарт от [AirBnb](https://github.com/airbnb/javascript). +Единый стиль означает код, одинаково понятный всем членам команды, независимо от того, кто его написал. Это экономит время, снижает количество ошибок и упрощает совместную работу. -В любом языке программирования существуют утилиты — так называемые **линтеры**. Они проверяют код на соответствие стандартам. В JavaScript это [eslint](https://eslint.org/). +## Стандарты кодирования -Взгляните на пример из предыдущего урока: +В экосистеме JavaScript нет одного официального стандарта, но существуют широко принятые руководства, например от [AirBnb](https://github.com/airbnb/javascript). Они подробно описывают, как оформлять код: какие отступы использовать, как расставлять пробелы, какой длины должны быть строки, как называть переменные и многое другое. -```javascript -console.log(8/2+5 - -3 / 2); // => 10.5 -``` +Эти правила знают и используют JavaScript-разработчики. Новичкам полезно время от времени заглядывать в них и вырабатывать правильные привычки с самого начала. Однако запоминать всё сразу нет необходимости. + +## Линтеры: автоматическая проверка кода + +Запоминать все правила вручную не нужно. Существуют специальные программы, которые делают это за вас. Они называются линтеры. + +Линтер представляет собой инструмент, который анализирует ваш код и сообщает о нарушениях стандартов. Он помогает: -Линтер будет «ругаться» на нарушение сразу нескольких правил: +- Избавиться от лишних пробелов +- Соблюдать отступы +- Писать читаемые и красивые выражения - * [space-infix-ops](https://eslint.org/docs/rules/space-infix-ops) – Отсутствие пробелов между оператором и операндами. - * [no-mixed-operators](https://eslint.org/docs/rules/no-mixed-operators) – По стандарту нельзя писать код, в котором разные операции используются в одном выражении без явного разделения скобками. +## Современный линтер: Biome -В прошлом уроке мы сами признали, что такое обилие цифр и символов запутывает, и решили добавить скобки исключительно для удобства чтения: +На сегодняшний день одним из самых быстрых и популярных линтеров для JavaScript является [Biome](https://biomejs.dev/). Он объединяет линтер и форматтер в одном инструменте, быстро работает и активно развивается. + +Рассмотрим пример: ```javascript -console.log(((8 / 2) + 5) - (-3 / 2)); // => 10.5 +const result = 1+ 3; ``` -Этот вариант уже не нарушает правил, и линтер будет «молчать». +Такой код выглядит неаккуратно, и линтер справедливо укажет на ошибку. Вот как выглядит процесс проверки: + +```text +Код Линтер Результат +┌──────────────┐ ┌──────────┐ ┌─────────────────────────┐ +│ const result │ → │ Biome │ → │ lint/style/noShoutyConst│ +│ = 1+ 3 │ │ │ │ missing whitespace │ +└──────────────┘ └──────────┘ └─────────────────────────┘ +``` -В упражнении прошлого урока у вас скорее всего получилось так: +Это значит, что перед и после `+` не хватает пробелов. Согласно стандарту, должно быть так: ```javascript -console.log(70 * (3 + 4) / (8 + 2)); +const result = 1 + 3; ``` -Есть ли здесь нарушение стандарта? +## Правила и их смысл + +Каждое сообщение линтера связано с конкретным правилом. Например, одни правила касаются пробелов вокруг операторов, другие — пустых строк между блоками кода, третьи — длины строк. Когда вы только начинаете, такие мелочи могут казаться неважными. Но со временем становится понятно, что именно они формируют единый читаемый стиль. -К сожалению, да. На этот раз операции `*` и `/` находятся в одном выражении без разделения скобками. Вы можете решить эту проблему, добавив дополнительные скобки. Но в какой-то момент количество скобок может быть уже настолько большим, что код снова станет неудобным и непонятным. В этот момент разумнее будет разделить выражение на отдельные части. Мы научимся это делать в следующих уроках. +С полным списком правил Biome можно ознакомиться в [официальной документации](https://biomejs.dev/linter/rules/). -[no-mixed-operators](https://eslint.org/docs/rules/no-mixed-operators) — лишь одно из большого количества правил. Другие правила описывают отступы, названия создаваемых сущностей, скобки, математические операции, длину строк и множество иных аспектов. Каждое отдельное правило кажется довольно мелким, не очень важным. Но вместе они составляют основу хорошего кода. +## Использование линтера в своих проектах -Сейчас сайт не будет проверять ваш код линтером, но в ваших будущих практиках на [Хекслете](https://ru.hexlet.io) и в реальной разработке линтер будет работать и сообщать вам о нарушениях. +Когда вы начнёте писать собственные проекты за пределами учебной платформы, линтер будет незаменимым помощником. Его можно настроить в любом редакторе кода, запустить в терминале или подключить к сборке проекта. Линтер показывает ошибки и умеет исправлять их автоматически. diff --git a/modules/20-arithmetics/80-linting/ru/data.yml b/modules/20-arithmetics/80-linting/ru/data.yml index 9507c4ec..4c06d574 100644 --- a/modules/20-arithmetics/80-linting/ru/data.yml +++ b/modules/20-arithmetics/80-linting/ru/data.yml @@ -1,5 +1,10 @@ --- name: Линтер tips: - - | - [eslint](https://eslint.org/) + - > + [Biome — линтер и форматтер для JavaScript](https://biomejs.dev/) +definitions: + - name: Линтер + description: >- + инструмент, который анализирует код и сообщает о нарушениях стандартов + оформления.