Step 2 (S-37882)

From Stepik Wiki
Jump to: navigation, search

Step on Stepik: https://stepik.org/lesson/13021/step/2

На этом занятии мы научимся читать, писать и считать (в целых числах). Как первоклассники, только на компьютере, с помощью С++.

Арифметические выражения

Сначала научимся считать. Мы уже знаем, что выводить строки можно с помощью команды cout. Точно так же можно выводить числа и результат вычисления выражений. Например, вот так выглядит программа, которая считает, чему равно (2 + 3) * 5:


#include <iostream>using namespace std;int main() {    cout << (2 + 3) * 5;    return 0;}

  


Если запустить эту программу, то она выведет 25. Сначала посчитается результат вычисления арифметического выражения, а затем он будет выведен. Посмотрим, какие арифметические операции умеет выполнять C++:


Обозначение операции    Что она выполняет



     +           сложение



     −           вычитание



     *           умножение



     /           деление нацело



     %           вычисление остатка от деления


У операций на C++ тот же приоритет, что и в обычной математике. Сначала выполняется умножение, деление и вычисление остатка, затем сложение и вычитание. Влиять на порядок операций можно с помощью скобок. Минус бывает бинарный (это число минус число) и унарный (это просто минус число). Например, можно написать (−2 + 3) * 4 — это будет корректным выражением с результатом 4.

Гораздо интереснее операции деления и взятия остатка. С помощью операции деления можно узнать целую часть от деления одного числа на другое. Например, 7 / 3 будет равно 2. А с помощью операции взятия остатка от деления можно узнать остаток от деления первого числа на второе. 7 % 3 будет равен 1. Если число делится нацело, то остаток будет равен нулю, например, 8 % 4 даст 0.

Математикам стоит обратить внимание на то, что деление и подсчёт остатка для отрицательных чисел работает в C++ «неправильно». Если в C++ мы разделим отрицательное число на положительное, например, посчитаем результат операции −7 / 3, то получим −2. Фактически в C++ отрицательное число берётся по модулю, делится, а затем к результату приписывается минус.

В C++ операция взятия остатка от деления отрицательного числа на положительное, так же как и деление нацело, берёт делимое по модулю, затем происходит подсчёт остатка от деления, и к результату приписывается минус. Например, −10 % 3 будет равно −1.

Переменные

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

Можно представить себе, что программа сидит в кабинете, в который входит конвейер с входными значениями, а выходит конвейер с выводом (это поток cout). В кабинете стоят коробки с хламом, оставшемся от предыдущих жильцов, но мы можем ими воспользоваться, чтобы хранить в этих коробках свои вещи. Переменная, по сути, и является такой коробкой.  «Объявить переменную x» — это как взять какую-нибудь из коробочек и подписать её буквой x. «Присвоить значение переменной x» — это вытряхнуть содержимое из коробочки x и положить в неё новое значение.

Пока мы будем работать только с целочисленными переменными. Пусть мы хотим взять из горы неподписанных специальных коробочек для целых чисел две штуки и назвать их x и y. На языке C++ это будет записано как:


int x, y;


Слово int означает, что переменные будут целочисленные, затем перечисляются имена создаваемых переменных через запятую. В конце ставится точка с запятой.

Если мы хотим присвоить значение переменной, то слева следует написать имя присваиваемой переменной, затем знак равно, а справа — арифметическое выражение, в котором могут использоваться числа и другие переменные. Например:


x = 2 + 3;y = x * 4;

 В результате выполнения этих операций в переменной x окажется число 5, а в переменной y — число 20.


Переменные также можно считывать с клавиатуры. Для этого по аналогии с потоком вывода cout используется поток cin (console input). Этот как раз тот конвейер, по которому к нам приезжают числа. Как и в случае cout, вводимые значения разделяются стрелочками, только теперь они направлены вправо, так как мы забираем данные из потока cin. Вот пример программы, которая считывает два числа a и b и выводит их сумму:


#include <iostream>

using namespace std;int main() {    int a, b;    cin >> a >> b;    cout << a + b;    return 0;}


Обратите внимание, что при чтении из cin стрелочки направлены в противоположную по сравнению с cout сторону. Мы «забираем» данные из потока ввода cin и «кладём» в cout. Если мы хотим считать несколько переменных, то при перечислении их следует разделять стрелочками. Строку


cin >> a >> b;


можно заменить строками


cin >> a;cin >> b;

 которые будут делать то же самое.

В C++ на целые числа типа int отводится 4 байта (32 бита). А это значит, что различных целых чисел может быть только 232. Числа могут принимать значения от −231 до 231−1 (это примерно от минус двух миллиардов до двух миллиардов). Если в процессе вычислений произойдёт выход за эти пределы, то результат будет посчитан неверно. Использование принципиально больших чисел требует ухищрений, поэтому в наших задачах все числа и все правильные промежуточные вычисления не будут выходить за эти пределы.

Изощрённый вывод

В cout также можно класть несколько значений, причём числа и строки могут идти вперемешку. Рассмотрим это на примере. Пусть нам нужно считать два числа и вывести их сумму и разность в виде арифметического выражения, каждое в отдельной строке. Решение этой задачи выглядит так:


#include <iostream>

using namespace std;int main() {      int a, b;      cin >> a >> b;      cout << a << " + " << b << " = " << a + b << endl;      cout << a << " - " << b << " = " << a - b;      return 0;}

 Если ввести числа 1 и 2, то на экран будет выведено:

1 + 2 = 3
1 − 2 = -1

Все различные значения, которые мы хотим вывести с помощью cout, следует разделять стрелочками <<. На место переменных и арифметических выражений будет подставлено их значение, а всё, что выводится в кавычках, останется без изменения. Особого внимания заслуживает слово endl — так в C++ делается переход на новую строку.

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

Пример решения задачи

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

Эту задачу можно решать так, как обычно решаются задачи по физике. Ускорение свободного падения нам известно (поскольку наши числа целые, то мы возьмём его равным 10). Мы посчитаем скорость (v), на которой пассажир достиг земли, затем среднюю скорость (vm, это конечная скорость, поделенная на 2) и, зная среднюю скорость и время, легко рассчитаем расстояние.


#include <iostream>

using namespace std;int main() {    int t, v, g = 10;    cin >> t;    v = g * t;    int vm = v / 2;    int s = vm * t;    cout << s;    return 0;}

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


Пример решения сложной задачи на арифметику

Рассмотрим, как решить совсем простую на первый взгляд задачу, которая превращается в достаточно сложную из-за того, что мы мало что умеем и знаем. Задача формулируется так. Даны два числа a и b, причём b > 0. Надо посчитать целую часть от деления a на b, округлённую вверх. Напомню, что при делении C++ округляет результат вниз, не так, как нам нужно.

Первая идея — разделить с округлением вниз и прибавить к результату единицу. Эта идея неправильная: она не работает, если одно число делится на другое нацело. Так 8 / 2 + 1 будет равно 5, хотя правильный ответ 4.

Следующая идея, правильная, — прибавить к числу что-нибудь и затем разделить его с округлением вниз. Осталось понять, что же нужно прибавлять к числу. Если число a делится на b нацело, то результат не должен изменяться, значит, нельзя прибавлять к числу a что-либо большее b − 1 (если прибавить больше, то результат деления получится уже больше правильного). Можно ли прибавить что-нибудь меньшее b − 1? Рассмотрим «худший» случай, когда остаток от деления a на b равен единице, например, a = 11, b = 5. Тогда мы сложим a и b − 1 (получим 15) и разделим на 5 — получится правильный ответ 3.

Наше решение будет работать и для отрицательных чисел за счёт особенностей деления на C++. Полный код решения выглядит так:


#include <iostream>

using namespace std;int main() {     int a, b;     cin >> a >> b;     cout << (a + b - 1) / b;     return 0;}

'

Как решать задачи

У каждой задачи в вашем домашнем задании есть условие, формат входных и выходных данных и примеры. В условии содержится описание задачи, которую нужно решить. В формате входных данных сказано, какие числа вводятся и в каком порядке они даны, а также указаны ограничения на эти числа. Гарантируется, что чисел будет столько, сколько нужно, и они будут удовлетворять ограничениям. Вам нужно решить задачу только для указанных ограничений. Как программа будет работать для чисел, не удовлетворяющих ограничениям — абсолютно неважно, таких тестов не будет. В формате выходных данных указывается, что и в каком порядке программа должна выводить — ничего, кроме этого, в решении быть не должно.


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

Если программа работает правильно, то она получит статус OK. Если программа получила другой статус — вам следует придумать тесты, удовлетворяющие ограничениям, и проверить работу своей программы. Обязательно найдётся ошибка. Наша тестирующая система работает правильно. Наши тесты правильные. Правильные ответы к нашим тестам правильные. Это точно. Мы проверяли много раз. И не только мы.

Правила оформления кода

Программы нужно писать красиво, иначе их будет неудобно читать. На реальной работе программы много раз читаются и переписываются другими людьми, поэтому соблюдать правила оформления кода очень важно. Если в общем, то главное правило — «делайте как в образце». Если конкретно:

1.     После открывающейся фигурной скобки добавляется отступ в начале строки, на строке с закрывающейся фигурной скобкой отступ убирается.

2.     Все бинарные операции (+,−, *, /, %, =, <<, >>) окружаются пробелами.

3.     После унарного минуса пробел не ставится (−5 нужно писать слитно).

4.     Перед знаками препинания (запятая и точка с запятой) пробел не ставится, после — ставится.

5.     После открывающейся и перед закрывающейся круглой скобкой пробел не ставится.

6.     Если в условии задачи сказано «на вход даются два числа A и B», то переменные, в которые считываются эти числа, должны называться так же, но маленькими буквами (a и b соответственно).

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