Proměnné, výrazy, základní matematické funkce
Vyčíslení vzorečku
Jak přesvědčíme počítač, aby nám vyřešil primitivní číselnou úlohu:
O kolik si zkrátím cestu, když půjdu přes fotbalové hřiště úhlopříčkou místo po obvodu?
Ano, jde o to spočíst
\(a+b-\sqrt{a^2+b^2}\)
pro normované rozměry fotbalového hřiště.
V jazyce Python, který budeme používat na naší přednášce to dokážeme třemi řádky
[1]:
a = 105
b = 68
print( a + b - (a**2 + b**2)**0.5 )
47.9040368357156
Tento krátký program obsahuje
tři příkazy (dva přiřazovací (
=
) a jeden pro textový výstup (print
))dvě proměnné (
a
ab
)pět číselných konstant (tzv. literálů) - 105, 68, 2, 2, 0.5
jeden numerický výraz zapsaný pomocí operací
+
,-
,*
a**
Povšimněte si, že jsme záměrně použili proměnné, místo abychom konstanty opakovali, např.
print( 105 + 68 - (105**2 + 68**2)**0.5 )
Python není jediný programovací jazyk. Pro zajímavost porovnejme tento program s ekvivalentním programem v jazyce C:
#include <stdio.h>
#include <math.h>
int main() {
double a = 105;
double b = 68;
printf("%g\n", a+b-sqrt(a*a+b*b));
return 0;
}
Pozorování: přívětivější zápis kódu (ale i další důvody) učinily z Pythonu dnes nejpopulárnější jazyk. Stručnost kódu ale naznačuje, že se něco může odehrávat skryto očím nepoučeného uživatele tohoto jazyka. Na našem kurzu na to budeme často muset dávat pozor.
Další problém:
Jak moc se blíží tyto rozměry zlatému řezu?
[4]:
print(a/b, (a+b)/a )
1.5441176470588236 1.6476190476190475
Pozorujeme, že
hodnoty proměnných zůstaly v našem prostředí zachovány i po skončení vyhodnocování předchozí buňky
Proměnné
Slouží k uchování dat pro další použití. Jaké proměnné použijeme závisí konkrétním algoritmu/výpočtu. To uvidíme v dalších hodinách.
Při zápisu složitějších matematických výrazů je vhodné delší nebo opakující se podvýrazy uložit do pomocných/dočasných proměnných.
tedy můžeme rozdělit na dva přiřazovací příkazy
odmocnina = (1-x**2)**0.5
f = (1-odmocnina)/(1+odmocnina)
V Pythonu se mají proměnné zapisovat malými písmeny (+podtržítky), tedy místo
Ekin = 0.5*m*v**2
bychom měli např. psát
e_kin = 0.5*m*v**2
Uvidíte, že ne vždy se toto pravidlo dodržuje.
Zápis čísel
Součástí kódu jsou různé hodnoty. Pravidla, která používáme snadno uhodnete z následujících případů.
cele_cislo1 = 123
cele_cislo2 = 1000000
cele_cislo3 = 1_000_000 # čitelnější zápis
realne_cislo1 = 123.45
realne_cislo2 = 0.0101
realne_cislo3 = 6.02214076e23 # Avogadrova konstanta
realne_cislo4 = 6.62607015e-34 # Planckova konstanta
Platí, že pokud se v zápisu čísla vyskytuje .
(tečka) nebo e
(velké nebo malé), jde o reálné číslo. S jejich vlastnostmi se seznámíme podrobněji později, již teď je rozumné vědět, že přesnost výpočtů s reálnými čísly je asi 15 cifer, zatímco operace probíhající výhradně s celými čísly nemají omezenou přesnost.
Je velmi pohodlné, že Python umí komplexní čísla.
komplexni_cislo1 = 2+3j
komplexni_cislo2 = 0.2-1.3j
Vždy je chápe jako dvojici čísel reálných (tedy i 1+1j
), jak si takové tvrzení ověřit se naučíme zanedlouho. Pozor, 1+j
není zápis čísla ale součet jedničky a proměnné j
.
Pojmenované konstanty
Za konstantu můžeme považovat hodnotu, která
Nejméně po dobu běhu programu nemění svoji hodnotu
Konstantou tedy může být jak číslo \(\pi\), tak např. konkrétní rozměry nějakého zařízení, ačkoli v sousední laboratoři mají větší.
Konstanta může být reprezentována konkrétní číselnou hodnotou, např. 105
. Je ale nepohodlné a asi i nesprávné mít tuto hodnotu roztroušenou na různých místech kódu. Proto je zvykem tuto hodnotu označit slovy, definovat konstantu
STRANA_A = 105
a dále místo čísla 105
používat identifikátor STRANA_A
.
Bývá zvykem, že
Hodnoty konstant nelze měnit
To v Pythonu ale neplatí, tento jazyk předpokládá neomylného programátora. Ten se drží pravidla
Hodnoty konstant nesmíme měnit
Zvyk/pravidlo v Pythonu toto řeší tak, že proměnné s významem konstant se mají psát velkými písmeny, proměnné malými písmeny. Opět, ne vždy to budeme dodržovat, už jen proto, že rozdělení na konstanty (jen velká písmena) a proměnné (malá první písmena identifikátoru, libovolná další) není často úplně jednoznačné.
Shrnutí:
V programování existují dva koncepty: proměnná a konstanta.
Proměnné postupně nabývají různých hodnot, např. proměnná
soucet
může pro řadu \(1,2,3,..10\) nabývat hodnot \(0,1,3,6,...,55\). Měly by se psát malými písmeny.Konstanty mají jednu pevně danou hodnotu. Měly by se psát velkými písmeny. Ani jedno ale jazyk Python nevynucuje. V mnoha případech se psaní velkými písmeny nedodržuje, např. \(\pi\) se jemnuje
math.pi
.
Detailně je to popsáno v textu Python Constants
Aritmetické výrazy
Výrazy vnikají složením operandů a aritmetických operátorů. Ty nejdůležitější shrnuje tato tabulka
zápis |
hodnota |
komentář |
---|---|---|
|
2 |
|
|
6 |
|
|
2.6 |
|
|
2 |
celočíslené dělení |
|
3 |
zbytek po -"- |
|
125 |
mocnění |
V ní používáme celočíselné operandy. Kromě celých čísel máme po ruce i čísla reálná (zvaná float
) a čísla komplexní.
zápis |
hodnota |
komentář |
---|---|---|
|
\(6.6743\times 10^{-11}\) |
(lze psát i |
|
\(2i\) |
protože \((1+i)^2=2i\) |
Reálná (i komplexní) čísla mají narozdíl od čísel celých omezený počet cifer (přesnost)
>>> print(1+0.1-1)
0.10000000000000009
Logické výrazy
Při rozhodování, jak při běhu programu postupovat budeme potřebovat logické výrazy.
zápis |
hodnota |
komentář |
---|---|---|
|
|
jedno rovnítko nestačí |
|
|
viz symbol \(\ne\) |
|
|
|
|
|
|
|
|
|
|
|
Tato porovnání kombinujeme pomocí and
, or
a not
>>> 1>2 or 3>2
True
>>> 1>2 and 3>2
False
>>> 1<2 and not 3<2
True
Priorita aritmetických operací
Operace, se kterými jsme seznámili, mají takto uspořádané přednosti:
**
*, /, //, %
+, -
<, <=, >, >=, !=, ==
not
and
or
Proto v následujícím výrazu se operace vyhodnocovat od konce, ačkoli pokud prefence operací nevyžadují jinak, vyhodnocují se výrazy z leva doprava.
>>> False or True and not 1 == 19 - 2 * 3**2
False
Samozřejmě, k úpravě pořadí operací se používají závorky (1+2)*3
.
sčítání
+
a odčítání-
má prioritu nejmenšínásleduje násobení
*
a dělení/
mocnění
**
má mezi binárními operacemi prioritu nejvyššík úpravě pořadí vyhodnocování operací se používají závorky
Pozn. Všimněte si závorek níže:
Úloha: Jaké jsou tedy správné rozměry hřiště se stejnou plochou, ale správným poměrem stran?
[12]:
phi = (1+5**0.5)/2
p = (a*b*phi)**0.5
q = p/phi
print(p, q, p/q, (p+q)/p)
107.48377868159572 66.42862846449752 1.618033988749895 1.618033988749895
Pro pořádek si zde uvedeme úplnější dokumentaci priority všech operací, které v kurzu potkáme.
Vyhodnocování podvýrazu v závorkách
( ... )
nenaruší žádná operace před nebo za závorkami.**
představuje operaci mocnění. Její vysoká priorita umožňuje, že3*2**2*5==60
. Asociativita je zprava, tedya**b**c == a**(b**c)
. Ovšem i když máme dispozici operaci mocnění, i v Pythonu je Hornerovo schéma TODO:REF pro vyhodnocovaní polynomu rychlejší!-a
představuje tzv. unární mínus. Podobně můžeme psát+a
. (Zájemci mohou prozkoumat též unární binární negaci celých čísel, např.~6
.)Násobení zapisujeme
*
. Dělení/
dá i dvou celých čísel podíl jako číslo reálné, zatímco celá část podílu se zapisuje//
(pozor, zatímco5//4==1
, je-5//4==-2
, tedy "zaokrouhleno" směrem dolů. Pokud bychom po celočíselném dělení \(i/j\) požadovali (anti-)symetrii při \(i\to -i\), použijeme výrazint(i/j)
). Zbytek po dělení se zapisuje%
. Funguje to i pro reálné operandy, např.print(5.75//2.0, 5.75%2.0)
vypíše2.0 1.75
.Následuje sčítání
+
a odčítání-
, nižší prioritu už budou mít jen bitové a logické operace:Jen výjimečně potkáme operace bitového posunu vpravo
a>>n
(což je rovnoa // 2**n
) a vlevoa<<n (== a * 2**n)
.Další bitové operace jsou (vyjmenovány s klesající prioritou)
a&b
,a^b
,a|b
. Jejich použití je dost výjimečné, ale např. pro celá čísla \(k\) je1-(k&1)*2
rychlejší variantou(-1)**k
.Teprve nyní následují operace porovnání
a>b
,a>=b
,a<b
,a<=b
,a==b
,a!=b
, ta poslední s významem \(a \ne b\). Stejnou prioritu máin
v testu2 in [1,2,3]
resp.x not in [1,2,3]
a konečně i test identityis
ais not
, který mj. umožňuje zjistit, zda se dvě proměnné aktuálně odkazují na tatáž data testemx is y
.Konečně s klesající prioritou tu máme operátory
not, and, or
, což umožňuje psát přirozeněp==0 or q!=0 and r/(q*p)>1
bez závorek okolo jednotlivých porovnání.Pro úplnost uveďme, že pokud bychom na
if
aelse
v podmíněném výraze nahlíželi jako na operátory, pak mají ještě nižší prioritu:math.sin(x)/x if x!=0 else 1.0
.
Pozor, logické operace and, or
podléhají zkrácenému vyhodnocování, jak je popsáno níže.
Průběh vyhodnocování výrazů
Výpočet výrazu probíhá zleva doprava, přičemž pokud to priorita operátorů vyžaduje, vyzvednuté hodnoty se uschovají dokud je nebude možno použít. To je důležité, když ve výrazu budeme volat funkce, protože to určuje pořadí jejich volání. Zde si to ilustrujeme pomocí funkce input
, která se ptá na vstup z klávesnice. Ještě potřebujeme vědět, že pro řetězce se násobením myslí '2'*3 == '222'
a operací plus jejich spojování '1'+'222' == '1222'
. Vyzkoušejte si to pro jiné zadané hodnoty.
input("x=") + input("y=") * int( input("z=") )
x=1
y=2
z=3
'1222'
Vidíme, že postupně se vyhodnotí všechny operandy a to zleva doprava a to i tehdy, když je nejprve vzhledem k prioritě operací spočíst pravější část výrazu. Z tohoto pravidla je ale výjimka:
Neúplné vyhodnocování logických výrazů
Zatímco pro určení operace součtu dvou čísel a+b
musíme k tomu, abychom určili výsledek, vyhodnotit oba operandy, logické operace se tatko nechovají, protože u operací and, or
je v polovině případů znám výsledek operace již po vyhodnocení prvního operandu. To proto, že např. True or x
dá stejný výsledek pro obě logické hodnoty x
. Při výpočtu se proto hodnota x
vůbec nezjišťuje a výraz True or x
nabývá hodnoty True
pro jakékoli x
. Proto True or "nesmysl"/0
nezpůsobí žádnou chybu!
Mohlo by se zdát, že se tak děje kvůli urychlení výpočtu, nicméně povaha logických výrazů často vede k tomu, že zkrácené vyhodnocování logických výrazů vítáme hlavně proto, že nám umožní neřešit rizikové chování výrazů:
if x>0 and y>0 and x**0.5+y**0.5<1:
...
Takto psaná podmínka nemá diky zkrácenému vyhodnocování logických výrazů potíže s vyhodnocováním pro záporná x
.
Dalším místem, kde o této vlastnosti logických binárních operací and
a or
musíme vědět jsou výrazy obsahující funkce. Podle příslušných pravidel totiž nebudou příslušné části výrazů vyhodnocovány a funkce v nich obsažené se nezavolají. Lze toho využít k urychlení výpočtu ale může nás to i překvapit, pokud daná funkce má za úkol ještě něco jiného, než vrátit vypočtenou hodnotu.
Rozmyslete si, proč se ve druhém případě Python neptá na hodnotu y
:
input("x=") == "1" and input("y=") == "2"
x=1
y=2
True
Tedy došlo k vyhdonocení obou podvýrazů ve tvaru input(...) == ...
. Naopak, pokdu níže zadáme jako první jinou odpověď než 1, druhý podvýraz input("y=") == "2"
se nebude vyhodnocovat na na y
se nás program nezeptá.
input("x=") == "1" and input("y=") == "2"
x=2
False
[5]:
# Zde si vyzkoušejte příklady výše
input("x=") + input("y=") * int(input("z="))
[5]:
'1222'
Operandy
Operace, které jsme zmínili, pracují s jedním nebo dvěma svými operandy. Co přesně se odehraje záleží na typu (obou) operandů. Například +
znamená jednou sčítání čísel, pokud jsou oba operandy čísla (např. 40+2
), ale u řetězců jde o jejich spojování (např. jmeno+' '+prijmeni
). Operandy mohou mít více podob:
Hodnoty proměnných. V příkazu
x = a + b
se sčítání účastní hodnoty proměnnýcha
ab
.Číselné konstanty. Z jejich zápisu se určí i jejich typ
int, float, complex
, např.2.0
je typufloat
.Řetězcové konstanty, např. první operand ve výrazu
'MUDr. ' + prijmeni
.Výraz - např. u výrazu
a**2 + b**2
jsou oběma operandy operace+
jiné výrazy. Výraz může ale nemusí být v kulatých závorkách.Hodnoty vrácené nějakou funkcí, např.
math.sin(x) + 1
. Na konverzi typů lze také nahlížet jako na volání funkce.Další...
Pokud je operandem nějaká proměnná, zůstane její hodnota nezměněna. Pokud je operandem výsledek nějaké funkce nebo binární operace, je tento použit a protože není již potřeba, přestává existovat. Jím zabírané místo uvolněno k dalšímu použití.
Knihovna math
Zatím jsme odmocňování řešili operací \(x^{0.5}\). Odmocnina ale představuje důležitý příklad standardní matematické funkce. Ty jsou ve většině programovacích jazyků dostupné přímo nebo ve vhodné knihovně. V Pythonu je to knihovna math
a odmocnina se jmenuje sqrt
. To, že ji chceme používat musíme předem oznámit.
[2]:
import math
a = 105
b = 68
print( a + b - math.sqrt(a**2 + b**2) )
47.9040368357156
Zde je seznam nejdůležitějších funkcí v knihovně math
a také dvě, které Python umí i bez knihovny math a to abs
a round
.
Za povšimnutí stojí mj. funkce atan2(x,y)
, která počítá úhel průvodiče bodu o kartézkských souřadnicích \([x,y]\) v rozsahu \((-\pi,\pi>\), zatímco \(\arctan(y/x)\) by i pro záporná \(x\) vracel úhly menší než pravé.
[ ]:
# konstanta pi
print( math.pi )
# trigonometrické funkce
print( math.sin(a) )
print( math.cos(a) )
print( math.tan(a) )
print( math.asin(b/a) )
print( math.acos(b/a) )
print( math.atan(b/a) )
print( math.atan2(b,a) )
# hyperbolické funkce
print( math.sinh(a) )
print( math.cosh(a) )
print( math.tanh(a) )
print( math.asinh(a) )
print( math.acosh(a) )
print( math.atanh(b/a) )
# zaokrouhlování
print( math.floor(p) )
print( math.ceil(p) )
print( round(p) )
print( round(p,2) )
# abs
print( abs(q-p) )
print( math.fabs(q-p) )
# exp, log
print( math.exp(p) )
print( math.log(p) )
print( math.log10(p) )
print( math.log10(p)/math.log10(math.e) )
# faktorial
print( math.factorial(12) )
Chtělo by se napsat, že kromě funkcí obsahuje knihovna math
i definice konstant. Např. \(\pi\) získáme napsáním
math.pi
Populární vlastnost Pythonu, umožňující měnit věci podle uživatelových představ, ale také znamená, že i tuto hodnotu můžeme změnit:
[14]:
print( math.cos( math.pi ) )
math.pi = 3
# od teď jsme ztraceni, např.
print( math.cos( math.pi ) )
# takže to hned opravíme
math.pi = 3.1415926535897932385
print( math.cos( math.pi ) )
-1.0
-0.9899924966004454
-1.0
Pokud není z názvu jasné, co funkce počítá, lze si v interaktivním prostředí požádat o nápovědu zapsáním otazníku. Bohužel, její interpretace vyžaduje někdy například tušit, že slovo Integral
zde znamená "celé číslo", nikoli pojem z matematické analýzy:
[33]:
math.ceil?
Docstring:
ceil(x)
Return the ceiling of x as an Integral.
This is the smallest integer >= x.
Type: builtin_function_or_method
S pomocí uvedených funkcí lze vyčíslit běžné výrazy, např.
[9]:
x = math.sinh(2)
print(x, math.log(x+math.sqrt(1+x**2)))
3.626860407847019 2.0
Poznámka:
Pokud vám knohovna math
nestačí je tu ještě scipy.special
[11]:
import scipy.special
print(scipy.special.gamma(10.0), math.factorial(9))
362880.0 362880
Zabudované funkce
Takto (builtin) se v Pythonu označují funkce, jenž jsou k okamžitě dispozici při spuštění i bez importu nějaké knihovny. Ačkoli mnohé zatím nebudeme umět požít, je zde vhodné místo, kde se o nich z mínit.
Mezi zabudované funkce patří
Nejzákladnější aritmetické funkce
abs(x)
,round(x)
,pow(x,y) == x**y
,max(x,y,...)
,min(x,y,...)
,round(x)
Funkce
type
vrací typ svého argumentu. Budeme ji používat při výkladu typů a také ke kontrole argumentů funkcí.Funkce pro práci se seznamy, např.
len(a), sum(a), min(a), max(a)
vrací ppočet prvků seznamu, jejich součet a minimální/maximální hodnotu prvku.Funkce
input(vyzva)
vypíše výzvu a prátí řetězec, který zadáme jako vstup na klávesnici.Následující funkce pro práci s řetězci si probereme při výkladu řetězců:
Nejdůležitější je
len(s)
vracející počet znaků řetězceord('ž')
vrací unicode kód jednoznakového řetězce.K ní inverzní je funkce
chr(n)
vrací znak s daným kódem.
Později také probereme konverzi typů, např. když
list("ABC")
převede řetězec na seznam znaků. Konverzi lze chápat jako volání funkcí. Proto mezi builtin funkcemi najdetebool, complex, int, list, set, str
. Funkcerepr
se chová podobně jakostr
, jen někdy vrátí podrobnější informace, než ona.Další funkce, viz dokumentace
Kontrolní úlohy
Vyzkoušejte, kolik desetinných míst trefí Stirlingova formule
\[n! \approx \sqrt{2 \pi n} \left(\frac{n}{e}\right)^n\left(1+\frac{1}{12n}\right)\]pro \(n = 15\). (Vyčíslete obě strany a vizuálně porovnejte výsledky, použijte funkci
math.factorial
a konstantumath.e
.)Nalezněte efektivní povrchovou teplotu Slunce, pokud by to byla koule o poloměru \(6.95700\times10^8\rm m\) vyzařující jako dokonale černé těleso výkonem \(P = \sigma T^4 = 3.83\times 10^{26} \rm W\). Použijte \(\sigma = 6.95700×10^{-8} {\rm W} {\rm m}^{-2} {\rm K}^{-4}\).