Привычные арифметические действия (сложение, вычитание, умножение, деление) в Python выглядят так же, как и в обычных калькуляторах:
1 + 2 # сложение
3
2 * 8 - 9 / 5 # умножение и деление
14.2
23 / 2 # деление
11.5
Однако с делением все не так просто: Python 3 всегда будет выдавать результат в виде числа с плавающей точкой (float), даже тогда, когда ожидается целочисленный ответ. Например:
6 / 2 # не 3
3.0
Получился дробный результат, где дробная часть равна 0. Как быть, если нужен ответ в виде целого числа? Можно воспользоваться целочисленным делением.
6 // 2 # теперь 3
3
Тут важно помнить, что при использовании оператора //
дробная часть всегда будет просто отбрасываться – никакого округления происходить не будет.
9 // 2 # от 4.5 осталось 1
4
В Python 2 обычное деление (с помощью /
) было целочисленным. Для того чтобы получить привычные результаты деления, нужно было либо импортировать обычное деление из модуля __future__
, который позволяет использовать функционал более новых версий Python (см. здесь), либо использовать другие хитрости, например, делить число с плавающей точкой на целое (см. здесь).
Примечание: для того, чтобы сравнивать исполнение одного и того же кода в Python 3 и Python 2 совсем необязательно устанавливать обе версии на компьютер. Можно воспользоваться онлайн-компиляторами (например, http://rextester.com: выбирать Python или Python 3) и запускать код прямо в браузере. Речь идет, конечно, о небольших фрагментах кода. Полноценно работать в них, не устанавливая Python, будет неудобно. Но для нескольких строк для сравнения как раз.
А остаток от деления можно находить так:
9 % 2
1
Что ещё можно делать с числами? Возводить в степень и извлекать из них корень. При расчетах на калькуляторе и в R для возведения числа в степень мы обычно используем символ ^
. Попробуем!
6 ^ 2 # ой
4
Получилось что-то неожиданное. В Python оператор ^
используется для побитного сложения по модулю два. Для возведения числа в степень потребуется **
(кстати, в R тоже для возведения в степень можно использовать двойную звездочку):
6 ** 2 # как нужно
36
Теперь попробуем извлечь квадратный корень из числа с помощью привычного sqrt
.
sqrt(9) # не получается!
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-10-9ea6aceded53> in <module>() ----> 1 sqrt(9) # не получается! NameError: name 'sqrt' is not defined
Python пишет, что не знает, что такое sqrt
. В каких случаях Python может такое писать? Например, если мы опечатались в названии функции (Python не понимает, что мы от него хотим) или если мы пытаемся обратиться к функции, которая не является базовой (Python не знает, откуда её брать). В нашем случае мы столкнулись со второй проблемой. Функция для вычисления квадратного корня из числа хранится в специальном модуле math
. Этот модуль стандартный, дополнительно устанавливать его не нужно. Но для того, чтобы воспользоваться этой функцией, нужно сначала импортировать модуль, а потом вызвать из него функцию sqrt
(для тех, кто работал в R -- процедура, аналогичная library()
.
import math # импортируем модуль math
math.sqrt(9) # теперь все работает
3.0
Если из math
нам нужна только одна функция sqrt
, можно извлечь только её, и тогда прописывать название модуля перед функцией не понадобится:
from math import sqrt
sqrt(16) # так тоже работает
4.0
В math
есть много полезных функций для вычислений. Чтобы посмотреть, какие функции там есть, после импортирования всего модуля через import math
можно набрать math.
и нажать на Tab (табуляция, кнопка над Caps Lock). Помимо квадратного корня этот модуль поможет вычислить логарифм (натуральный и не только), синус, косинус и так далее.
math.log(2) # натуральный логарифм
0.6931471805599453
math.log10(100) # десятичный логарифм (логарифм по основанию 10)
2.0
math.sin(0) # синус
0.0
А еще из math
можно импортировать константы $\pi$ и $e$:
from math import pi, exp # можно сразу несколько - перечислить через запятую
pi
3.141592653589793
exp(1)
2.718281828459045
Если мы хотим извлечь все функции из модуля/библиотеки сразу, чтобы не прописывать название, можно сделать это так:
from math import *
# теперь можем использовать все функции этого модуля
print(floor(4.6)) # округление в меньшую сторону
print(ceil(4.3)) # округление в меньшую сторону
print(factorial(4)) # факториал
4 5 24
И, наконец, можно импортировать модуль/библиотеку с сокращённым названием. В случае с math
это не очень рационально, но просто для для примера (пригодиться в дальнейшем, когда будем разбирать библиотеки numpy
, scipy
и pandas
.
import math as ma
ma.cos(9)
-0.9111302618846769
С чем ещё можно столкнуться, выполняя вычисления в Python? С такими вещами:
1 / 18 ** 25
4.1513310942010236e-32
Результат выше – компьютерная форма экспоненциальной записи числа. Возможно, тот, кто считал что-то на научных или инженерных калькуляторах или в R, уже сталкивался с такой записью. Здесь e-32
– это $10^{-32}$, а вся запись означает $4.1513310942010236 \cdot 10^{-32}$, то есть примерно $4.15 \cdot 10^{-32}$. Если бы число было очень большим, e
стояло бы в положительной степени.
Такая компьютерная форма записи числа отчасти помогает понять, почему дробные числа называются числами с плавающей точкой (float). Возьмем число попроще, например, $12.34$. Его можно записать как $12.34$, как $1.234 \cdot 10$, как $123.4 \cdot 10^{-1}$, $1234 \cdot 10^{-2}$ и так далее. Точка, отделяющая дробную часть от целой, будет «плавать», однако само число при этом меняться не будет, будут меняться только множители ‒ разные степени десятки.
С числами с плавающей точкой связана еще одна сложность — округление. На первый взгляд, всё хорошо:
round(12.6) # округлим до целого
13
round(12.53, 1) # округлим до первого знака после запятой
12.5
С другой стороны, могут возникнуть странности:
round(2.50) # не 3
2
round(3.525, 2) # не 3.53
3.52
Эти странности связаны с тем, что число, которое мы видим (например, 3.525), не совпадает с тем, которое хранится в компьютере, потому что оно при сохранении преобразовывается и превращается из точного 3.525 в такое:
from decimal import Decimal
Decimal(3.525)
Decimal('3.524999999999999911182158029987476766109466552734375')
И такое число будет законно округляться до 3.52 по правилам арифметического округления. Не то чтобы это очень важная информация, которую нужно всегда иметь в виду, но знать про неё полезно, чтобы не удивляться неожиданным результатам и помнить про накапливание ошибки в операциях с числами с плавающей точкой.
Переменные в программировании похожи на переменные в математике. Кроме того, их можно рассматривать как хранилища значений – «контейнеры», в которые мы что-то кладём. Python, в отличие от некоторых языков программирования (C, C++, Java), сам распознает что мы «кладём в коробку»: число, целое число, текст, список чисел... Поэтому при создании переменной нам не нужно указывать её тип.
x = 2
y = 3
print(x)
print(y)
2 3
Значения переменных мы можем обновлять – изменять значение и сохранять в переменную с тем же названием.
x = x + 1 # возьмем значение x, увеличим на 1 и сохраним изменения в переменной x
y = y * 2 # возьмем значение y, увеличим в 2 раза и сохраним изменения
print(x, y)
3 6
Рассмотрим такую задачу. Пришла весна и решили мы заняться бегом по такой схеме: каждый день мы пробегаем столько, сколько в сумме за два предыдущих дня. При этом первые два дня мы морально готовимся: топчемся на месте и символически проходим по одному метру (полшага назад и полшага вперед). Если мы будем записывать все пройденные нами расстояния в ряд, мы получим последовательность из чисел Фибоначчи. Давайте напишем код, который будет считать, сколько метров мы будем проходить/пробегать в следующий день.
Сначала создадим переменные, в которые сохраним данные по первым двум дням.
b = 1 # день 1 - готовимся бегать, "бежим" 1 метр
i = 1 # номер дня, когда начинаем бегать
bnext = 1 # день 2 - готовимся бегать, "бежим" 1 метр
i = i + 1 # перешли ко второму дню, увеличили i на 1
res = b + bnext # в следующий день пробегаем столько же, сколько за два предыдущих
i = i + 1 # перешли к следующему дню, увеличили i на 1
b = bnext # значение b нам уже не нужно, сдвигаемся к следующему дню - записываем bnext
bnext = res # запомнили полученное значение res
print(i, bnext) # выводим на экран номер дня и расстояние, которое нужно пробежать
3 2
Теперь можно прогонять предыдущую ячейку много раз (через Ctrl + Enter) и получать результат по каждому дню. Например, на 20 день мы будем пробегать уже нормальное расстояние — 6765 метров, почти 7 километров. Конечно, прогонять одну и ту ячейку много раз неудобно и странно, но о том, как считать числа Фибоначчи более рационально, мы поговорим, когда будем разбирать циклы.
Важно: если бы не разбили наш код на части (на две ячейки), ничего бы при повторном запуске ячейки не произошло — переменным b
, bnext
и i
заново присваивались бы значения 1, и движения вперед бы не происходило.
Для тех, кто любит более лаконичный код: увеличение значения переменной на 1 можно было осуществить по-другому.
i = 1
i += 1 # плюс и равно, не наоборот
i
2
Точно так же можно использовать другие операторы (сложение, умножение, деление):
j = 7
j -= 1 # минус и равно
j
6
k = 8
k *= 3 # умножить и равно
k
24