Cvičení č. 4 rozšířené o poznámky ze cvičení a řešení některých příkladů (ZS 2026/27)¶
V minulém díle jste viděli...¶
- Způsob kódování dat v paměti počítače: znaky, celá čísla a "reálná" čísla.
- Použití funkcí
bool,int,floata konstantNone,True,False. - Importování modulu
matha použití matematických konstant a funkci:
import math
print("Číslo π je přibližně", math.pi)
print("Hodnota cos(π) je ", math.cos(math.pi))
Číslo π je přibližně 3.141592653589793 Hodnota cos(π) je -1.0
- Jak odevzdávat úkoly v rozhraní Nbgrader
Typ complex¶
Jazyk Python také umožňuje provádět výpočty s komplexními čísly, která jsou reprezentována pomocí typu complex.
Komplexní číslo má reálnou a imaginární část, přičemž imaginární jednotka se značí suffixem j:
c2 = 1 - 2j
print("c2 =", c2)
c2 = (1-2j)
type(c2)
complex
c2 = 1.1 + 2.5j
print("c2 =", c2)
c2 = (1.1+2.5j)
c2 = 1.1 + 0j
print("c2 =", c2)
c2 = (1.1+0j)
c2 = 2.3j
print("c2 =", c2)
c2 = 2.3j
c1 = complex(1, 2)
print("c1 =", c1)
c1 = (1+2j)
c2 = complex(1.2)
print("c2 =", c2)
c2 = (1.2+0j)
# přímý převod z complex na int/float nejde:
float(c2)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[31], line 2 1 # přímý převod z complex na int/float nejde: ----> 2 float(c2) TypeError: float() argument must be a string or a real number, not 'complex'
# mezi číslem a znakem 'j' nesmí být mezera:
c2 = 1 - 2 j
print("c2 =", c2)
Cell In[10], line 2 c2 = 1 - 2 j ^ SyntaxError: invalid syntax
# před znakem 'j' nesmíme vynechat číslo:
j = 10
c2 = 1 - j
print("c2 =", c2)
c2 = 1 - 1j
print("c2 =", c2)
c2 = -9 c2 = (1-1j)
c2 = 1j
print("c2 =", c2)
c2 = 1j
# při načítání pomocí input nesmí být "kolem znaku '+'/'-' mezery:
c2 = complex(input("zadej komplexní cislo"))
print("c2 =", c2)
c2 = (1+3j)
# při načítání pomocí input nesmí být "kolem znaku '+'/'-' mezery:
c2 = complex(input("zadej komplexní cislo"))
print("c2 =", c2)
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[14], line 2 1 # při načítání pomocí input nesmí být "uvnitř" čísla mezery: ----> 2 c2 = complex(input("zadej komplexní cislo")) 3 print("c2 =", c2) ValueError: complex() arg is a malformed string
Pozor na to, že imaginární jednotka j musí vždy následovat bezprostředně za nějakou číslicí, jinak je j syntakticky interpretován jako identifikátor proměnné, který ani nemusí být komplexní číslo.
j = 3
print(j)
print(1j)
3 1j
S hodnotami typu complex můžeme provádět téměř všechny aritmetické operace stejně jako pro typ int, s výjimkou operátoru % (zbytek po celočíselném dělení).
Viz tabulka v předchozím cvičení.
# s komplexními čísli mohu provádět většinu operací jako s celými čísli:
print(c1 + c2, c1 - c2, c1 * c2, c1 / c2, c1 / 2, c1 ** 2)
(2+0j) 4j (5+0j) (-0.6+0.8j) (0.5+1j) (-3+4j)
# všechny aritmetické operátory s výjimkou //, %
print(c1 % c2)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[4], line 2 1 # všechny aritmetické operátory s výjimkou //, % ----> 2 print(c1 % c2) TypeError: unsupported operand type(s) for %: 'complex' and 'complex'
# všechny aritmetické operátory s výjimkou //, %
print(c1 // c2)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[7], line 2 1 # všechny aritmetické operátory s výjimkou //, % ----> 2 print(c1 // c2) TypeError: unsupported operand type(s) for //: 'complex' and 'complex'
Typ complex představuje první složený datový typ, se kterým jsme se setkali.
Hodnoty typu complex jsou složené z reálné a imaginární části, které mají typ float a lze k nim přistoupit pomocí tzv. atributů .real a .imag.
Typ complex dále poskytuje tzv. metodu .conjugate(), která provádí komplexní sdružení.
c2 = 1 - 2j
c2.imag
-2.0
type(c2.imag)
float
c2.real
1.0
type(c2.real)
float
c3 = c2.conjugate()
print(c2, c3)
(1-2j) (1+2j)
c = 1 + 2j
print("reálná část:", c.real)
print("imaginární část:", c.imag)
print("komplexně sdružené číslo:", c.conjugate())
reálná část: 1.0 imaginární část: 2.0 komplexně sdružené číslo: (1-2j)
# modul cmath .. obdoba modulu math pro komplexní čísla
import cmath
cmath.sqrt(1-1j)
(1.09868411346781-0.45508986056222733j)
cmath.sqrt(-1)
1j
(-1) ** 0.5 # funguje, vrací typ complex
# pozorujeme zaokrouhlovací chybu
(6.123233995736766e-17+1j)
Příklady¶
1a. Kalkulačka pro komplexní čísla
Načtěte od uživatele 2 komplexní čísla a vypočtěte jejich součet, rozdíl, součin, podíl, velikost, komplexní soudružné číslo.
Využijte operátory nebo funkce, které jsou pro komplexní čísla dostupné.
z1 = complex(input("zadej komplexni cislo"))
print(c1)
z2 = complex(input("zadej komplexni cislo"))
print(c2)
(1-2j)
(3+0.5j)
# Výpočty
soucet = z1 + z2
rozdil = z1 - z2
soucin = z1 * z2
podil = z1 / z2
# Komplexně sdružená čísla
sdruzene1 = z1.conjugate()
sdruzene2 = z2.conjugate()
print("Součet: ", soucet)
print("Rozdíl: ", rozdil)
print("Součin: ", soucin)
print("Podíl: ", podil)
print("Číslo sdružené k prvnímu číslu:", sdruzene1)
print("Číslo sdružené k druhému číslu:", sdruzene2)
Součet: (3-2.5j) Rozdíl: (-1-3.5j) Součin: (3.5-5.5j) Podíl: (0.11764705882352941-1.5294117647058822j) Číslo sdružené k prvnímu číslu: (1+3j) Číslo sdružené k druhému číslu: (2-0.5j)
# Velikost komplexního čísla
# 1. výpočet pomocí atributů z.imag, z.real
velikost = (z1.real **2 + z1.imag ** 2) ** 0.5
print("Velikost prvního čísla:", velikost)
Velikost prvního čísla: 3.1622776601683795
# 2. výpočet pres pres násobení čísla s číslem komplexne sdruzenym, z.conjugate()
velikost_c = (z1 * z1.conjugate()) ** 0.5
print("Velikost prvního čísla:", velikost_c)
velikost = velikost_c.real
print("Velikost prvního čísla:", velikost)
Velikost prvního čísla: (3.1622776601683795+0j) Velikost prvního čísla: 3.1622776601683795
# 3. výpočet pomocí funkce abs()
velikost = abs(z1)
print("Velikost prvního čísla:", velikost)
Velikost prvního čísla: 3.1622776601683795
velikost_prvniho = abs(z1)
print(velikost_prvniho)
1b. Kalkulačka pro komplexní čísla podruhé
Zadání je stejné jako v příkladu 1a, ale tentokrát operace implementujte sami (tj. například pro scítání sečtěte zvlášť reálnou složku a zvlášť imaginární složku a vytvoříte z výsledku nové komplexní číslo).
Výsledky operací porovnejte s výsledky předchozího příkladu.
# Načtení dvou komplexních čísel
z1 = complex(input("Zadejte první komplexní číslo (např. 2+3j): "))
z2 = complex(input("Zadejte druhé komplexní číslo (např. 1-2j): "))
# Reálné a imaginární části
a1 = z1.real
b1 = z1.imag
a2 = z2.real
b2 = z2.imag
# Součet:
a = a1 + a2
b = b1 + b2
soucet = complex(a, b)
print(soucet)
(3+2.5j)
a1 = z1.real
a2 = z2.real
b1 = z1.imag
b2 = z2.imag
soucet = complex(a1 + a2, b1 + b2)
rozdil = complex(a1 - a2, b1 - b2)
soucin = complex(a1 * a2 - b1 * b2, a1 * b2 + a2 * b1)
podil = complex((a1 * a2 + b1 * b2) / (a2**2 + b2**2), (a2 * b1 - a1 * b2) / (a2**2 + b2**2))
sdruzene = complex(a1, -b1)
velikost_prvniho = (a1 ** 2 + b1 ** 2) ** 0.5
print("Součet: ", soucet)
print("Rozdíl: ", rozdil)
print("Součin: ", soucin)
print("Podíl: ", podil)
print("Číslo sdružené k prvnímu číslu:", sdruzene)
print("Velikost prvního čísla:", velikost_prvniho)
Součet: (3+2.5j) Rozdíl: (-1+3.5j) Součin: (3.5+5.5j) Podíl: (0.11764705882352941+1.5294117647058822j) Číslo sdružené k prvnímu číslu: (1-3j) Velikost prvního čísla: 3.1622776601683795
- Napište program, který spočítá vzdálenost dvou komplexních čísel.
# vzdalenost = abs(c - d)
# abs(z=a+bi)= sqrt(a^2+b^2) = sqrt(z * komplexně sdružené číslo k z)
vzdalenost = abs(z1 - z2)
print(vzdalenost)
3.640054944640259
- Použijte jazyk Python pro vyřešení kvadratické rovnice $\pi x^2 + 2x + 1 = 0$. (Řešení tohoto příkladu nemusí být univerzální program, stačí posloupnost příkazů s výpočty, které byste prováděli "na papíře".)
# 1. spočteme diskriminant
import math
a = math.pi
b = 2
c = 1
D = b ** 2 - 4 * a * c
print(D)
-8.566370614359172
# 2. spočteme kořeny
# protože je diskriminant záporný, bude mít rovnice komplexní kořeny:
a1 = - b / (2 * a)
b1 = (-D) ** (1 / 2) / (2 * a)
x1 = complex(a1, b1)
x2 = complex(a1, -b1)
print("kořeny:", x1, x2)
kořeny: (-0.3183098861837907+0.4658204617032757j) (-0.3183098861837907-0.4658204617032757j)
x1 = a1 + 1j * b1
x2 = x1.conjugate()
print("kořeny:", x1, x2)
kořeny: (-0.3183098861837907+0.4658204617032757j) (-0.3183098861837907-0.4658204617032757j)
# tentokrát podle vzorce pro komplexní obor
x1 = - b / (2 * a) + 1j * (-D) ** (1 / 2) / (2 * a)
x2 = - b / (2 * a) - 1j * (-D) ** (1 / 2) / (2 * a)
print("kořeny:", x1, x2)
kořeny: (-0.3183098861837907+0.4658204617032757j) (-0.3183098861837907-0.4658204617032757j) kořeny: (-0.3183098861837907+0.4658204617032757j) (-0.3183098861837907-0.4658204617032757j)
# tentokrát podle vzorce pro reálný obor:
x1 = (-b + D ** (1/2)) / (2 * a)
x2 = x1.conjugate()
print("kořeny:", x1, x2)
kořeny: (-0.31830988618379064+0.4658204617032757j) (-0.31830988618379064-0.4658204617032757j)
- Převod do polárních souřadnic a zpět
Napište program, který zadané komplexní číslo převede z kartézských souřadnic do polárních souřadnic. Dále napište i program pro konverzi z polárních souřadnic do kartézských.
Pro kontrolu nakonec můžete využít funkce cmath.polar() a cmath.rect().
# společně jsme nedělali
Práce s proměnnými v Pythonu¶
Pojem proměnná (anglicky variable) představuje oblast v paměti počítače, která je vyhrazena pro uložení odkazu na nějakou hodnotu, kterou si chceme zapamatovat. Abychom mohli s proměnnými v programech pracovat, musíme je pojmenovat. Kdykoliv potom v kódu použijete název proměnné, interpret zařídí dosazení hodnoty, na kterou se daná proměnná odkazuje.
Pojem identifikátor představuje název proměnné, který vystupuje ve zdrojovém kódu. V Pythonu platí pro identifikátory následující pravidla:
- Smějí obsahovat písmena, číslice a podtržítka.
- Nesmějí začínat číslicí.
- Rozlišuje se v nich velikost písmen. Identifikátory
ahoj,AhojaAHOJtedy představují různé proměnné. - Nesmějí být shodné s některým klíčovým slovem, což jsou slova, která mají v jazyce speciální význam.
Zatím jsme potkali tato klíčová slova:
True,False,Nonea k dalším se dostaneme později. Jejich seznam není potřeba se učit nazpaměť – v nových verzích jazyka se postupně rozšiřuje a pokud byste náhodou porušili toto pravidlo, interpret vám oznámí syntaktickou chybu.
Nejdůležitější zásadou je volit názvy proměnných tak, aby co nejlépe naznačovaly jejich účel a aby se při čtení kódu člověkem nepletly s ostatními názvy používanými v programu.
Nejběžnější konvence pro pojmenování proměnných v Pythonu používá pouze malá písmena a znak _ pro spojení více slov: proměnná_s_dlouhým_názvem.
# pokud do proměnné vložím novou hodnotu, může se změnit její typ:
a = 7
print(a, type(a))
a = "abc"
print(a, type(a))
7 <class 'int'> abc <class 'str'>
x = 2 * 3
print(x)
x = math.pi
print(x)
x = print
x("ahoj")
6 3.141592653589793 ahoj
1a = 45
Cell In[49], line 1 1a = 45 ^ SyntaxError: invalid decimal literal
_t = 45
print = ("ahoj")
print("ahoj")
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[57], line 1 ----> 1 print("ahoj") TypeError: 'str' object is not callable
Inicializace a předefinování proměnných¶
Novou proměnnou vytvoříme pomocí přiřazovacího operátoru =, kde na levé straně vystupuje nový identifikátor a na pravé straně výraz, který po vyhodnocení inicializuje danou proměnnou:
a = 1
b = a + 2
Proměnná se však odkazuje výslednou hodnotu inicializačního výrazu, nikoliv na celý výraz.
Pokud bychom např. v předchozí buňce dále změnili hodnotu proměnné a, nemělo by to vliv na proměnnou b.
Pokud již inicializovaná proměnná existuje, tedy název se již odkazuje na nějakou hodnotu, dojde jednoduše ke změně odkazu na novou hodnotu. Při tom může dojít ke změně typu, tedy proměnná není vázána na typ hodnoty použitý při inicializaci.
Jazyk Python pracuje s odkazy na hodnoty, tj. s proměnnými, stejně jako s odkazy na jiné objekty, se kterými se postupně seznámíme. Umožňuje tedy např. vytvářet nové odkazy na funkce a dokonce "předefinovat" existující odkaz na funkci jiným objektem:
b = print
print = "Hello, world!"
b("ahoj")
print = b
print("ahoj")
ahoj ahoj
a = print
print = "Hello, world!"
a(print)
print = a
Proměnné a buňky v Jupyter notebooku¶
Seznam aktuálně definovaných proměnných můžeme zobrazit kliknutím na tlačítko (Enable Debugger) v horním panelu a následným zobrazením debuggeru na pravé straně. V rozhraní JupyterLab je zde opět ikona brouka, v rozhraní Jupyter Notebook je tlačítko v menu View → Right Sidebar → Show Debugger.
V prostředí Jupyter se notebooky obsahující buňky s kódem mohou chovat na první pohled nečekaným způsobem. Proměnné definované v jedné buňce totiž po jejím spuštění zůstanou definované v interpretu zpracovávajícího daný notebook a můžou ovlivnit chování při vyhodnocování kódu dále spouštěných buněk. Zkuste například opakovaně spouštět následující dvě buňky v různém pořadí a sledujte stav proměnných v debuggeru:
a = 0
a = a + 1
K zamyšlení: co se stane po restartování kernelu pro tento notebook a spuštění pouze druhé z těchto buněk?
import cmath
cmath.pi
from math import pi, cos
Příklady¶
Dokončete všechny příklady z minulého cvičení.