Tal, operatorer og matematiske funktioner

Tal og operatorer

I dette afsnit vil du lære om hvordan Python arbejder med tal og værdier.

I dette afsnit vil vi anvende Idle da vi skal øve os i regnefunktionerne.

Hel- og decimaltal

Når man arbejder med tal i Python skal man ikke definere om man arbejder med hel- eller decimaltal (intergers eller floating point). Det holder Python selv styr på ved at undersøge det tal ud arbejder med.

VIGTIGT: Læg mærke til at man bruger punktum (.) og ikke komma (,) til at angive overgangen mellem hel- og decimaltal.

	
>>> a=3
>>> b=3.14
>>> a*2
6
>>> b*2
6.28
	

Umiddelbart virker et ikke som en stor ting, men mange andre programmeringssprog, er skal man starte med at definere hvilken type en variabel er.

Computeren kan ikke tælle

En af de ting man støder på når man arbejder med programmering er, at computere tæller anderledes end vi gør. Når vi tæller starter vi fra en, og titalssystemet er anvendeligt for os fordi det passer med antallet af fingre på hånden. Når vi har brugt alle fingrene så tæller vi antallet af fulde hænder. 22 kan altså forståes som 2 fulde hænder og 2 fingre. I 10-talssystemet skifter vi altså position (veksler til den næste enhed) når vi kommer til den 10. værdi.

Eller udtrykt ved hjælp af matematik: vi tæller ved hjælp af ℕ = {1, 2, 3 ...}.

Computere arbejder med binære tal - dvs. den tæller ved hjælp af 0 og 1, og den første værdi er 0. Det er fordi den arbejder digitalt ved hjælp af nogle transistorer der enten kan være tændt eller slukkede. Konkret bliver der afsat et vist antal transistorer til at huske tallet, og der vil den første værdi være den hvor alle transistorer er slukkede - dvs. den har værdien 0

Eller udtrykt ved hjælp af matematik: vi tæller ved hjælp af ℕ0 = {0, 1, 2, 3 ...}.

For at vise dette kigger vi på en byte (der består af 8 bit) der tæller:

Computerens bits I 10-tals systemet
1. værdi 0 0 0 0 0 0 0 0 0
2. værdi 0 0 0 0 0 0 0 1 1
3. værdi 0 0 0 0 0 0 1 0 2
4. værdi 0 0 0 0 0 0 1 1 3
5. værdi 0 0 0 0 0 1 0 0 4
6. værdi 0 0 0 0 0 1 0 1 5
7. værdi 0 0 0 0 0 1 1 0 6
8. værdi 0 0 0 0 0 1 1 1 7
9. værdi 0 0 0 0 1 0 0 0 8
10. værdi 0 0 0 0 1 0 0 1 9
2⁷ 2⁶ 2⁵ 2⁴ 2⁰
Værdi 128 64 32 16 8 4 2 1

Af det ovenstående kan vi omregne fra binær til decimal ved at lægge de enkelte værdier sammen:

Binær Udregning Decimal
2⁷ 2⁶ 2⁵ 2⁴ 2⁰
11111111 128 64 32 16 8 4 2 1 255
10101101 128 32 8 4 1 173
10000001 128 1 129
00101101 32 8 4 1 45

Man bliver nød til at holde tungen lige i munden, fordi vi skal holde styr på vores in- og output. Tæller vi f.eks. antallet af tegn (char) i en streng angives det i ℕ (f.eks. Thomas = 6 tegn), men skal vi hente et tegn ud skal vi tænke ℕ0 (o er det 2 tegn i sætningen).

Placering 0 1 2 3 4 5
Tegn T h o m a s

Regneregler

Regningsarterne fungerer ved at anvende tegnene: +, -, * og /. Se herunder:

>>> 6+3
9
>>> 6-3
3
>>> 6*3
18
>>> 6/3
2.0

Læg mærke til at der bliver anvendt int i alle eksemplerne, og at resultatet bliver leveret på samme måde ved +, - og *. Men ved division bliver resulatet ændret til float. Se nedestående eksempel

>>> 2/3
0.6666666666666666

Python anvender korrekte regneregler, hvilket vil sige at + og - adskiller ledene, og at de skal sættes paranteser for at omgå dette. Se eksemplerne herunder:

>>> 3+2*6
15
>>> (3+2)*6
30
>>> 3+6/2
6.0
>>> (3+6)/2
4.5
Øvelse

I de nedestående opgaver skal du lave regnestykker ved hjælp af tallene, regningsarterne +, -, * og / og paranteser:

Tal Resultater
6, 3, 4 -6, 6, 12, 18, 36
4, 4, 8 -16, -7, 0, 1, 2, 6, 28

Potens og rødder

For at finde potens tal og rødder anvendes funktionen pow(a,b), hvor a er grundtallet og b er potensen. Se nedestående eksempler:

Matematisk udtryk Python funktion
\( a^b \) pow(a,b)
\( \sqrt[b]{a} = a^{\frac{ 1 }{ b }} \) pow(a,1/b)

Det anbefales at man anvender funktionen pow() fremfor **. Det gør koden mere læselig.

Eksempler med \( 2^4 \) og \( \sqrt{4} \):

>>> pow(2,4) 
16
>>> pow(4,1/2)
2.0

Man kan have funktioner inde i funktioner, f.eks:

$$ \sqrt[5]{7^2} = (7^2)^{\frac{1}{5}} = pow(~pow(7,2)~,~1/5~)$$
>>> pow(pow(7,2),1/5)
2.17790642448278

Opgave

Beregn følgende tal:

$$ a)~2^8, \\b)~{5^3}^2,\\c)~ \sqrt 27, \\d)~ \sqrt[17] {256}, \\e)~ \sqrt[3]{4}^{17}, \\f)~ 2^{\sqrt17} $$
Facit
$$ a)~2^8 = 256\\ b)~{5^3}^2 =1953125 \\ c)~\sqrt 27 = 5.1961... \\ d)~\sqrt[17] {256}=1.3856... \\ e)~\sqrt[3]{4}^{17}=2580.3183... \\ f)~2^{\sqrt17} = 17.4252... $$

Konstanter

I matematik er der konstanter som man ikke kommer uden om herunder konstanten π og e

Konstant Funktion Værdi
\( \pi \) math.pi 3.141592...
\( e \) math.e 2.718281...

De kan kaldes ved at importere dem fra pakken math

>>> import math
>>> math.pi
3.141592653589793
>>> math.e
2.718281828459045

Modulus og floor division

For at finde potens tal og rødder anvendes funktionen pow(a,b), hvor a er grundtallet og b er potensen. Se nedestående eksempler:

Funktion Tegn Beskrivelse Eksempel
modulus % Returnere resten efter division 9%5 = 4
floor division // Returnerer heltallet efter division 9//5 = 1

>>> 9%5
4
>>> 9//5
1

Man kan ved hjælp af modulus og floor division omskrive en uægte brøk til en blandet brøk efter følgende model:

$$ \frac{a}{b} = (a//b)~ \frac{a\%b}{b} $$
Anvendelse

modulus og floor division virker i første omgang lidt underlige, men har en masse praktiske anvendelser. F.eks:

  • Hvis noget skal ske hver tredie gang: x%3 = 0
  • Antal fyldte ølkasser: *antal flasker* // 30

Afrunding af tal

Ovenfor har vi se set hvordan man ændrer et float til en Interger. Men ofte har man brug for at kunne vise et resultat afrundet korrekt og med et bestemt antal decimaler. Det gøres med round(). Man angiver antallet af decimaler på følgende måde:

round(tal,*Antal decimaler*)
	
>>> 2/3
0.6666666666666666
>>> round(2/3,2)
0.67
	

Absolutte tal

Hvis man vil arbejde med absolutte tal (også kaldet den numeriske værdi) anvender man funktionen abs(). Det gør at resultatet bliver repræsenteret med sin positive værdi. Se eksemplerne:

>>> abs(-2)
2

Funktionen giver mening hvis man f.eks. ønsker at finde forskellen mellem to tal uden at skulle forholde sig til rækkefølgen de kommer i. Som i eksemplet herunder hvor første udregning med abs() kun fortæller forskellen, men den anden fortæller om det er en stigning eller et fald. Prøv at se programmet herunder

	
temperatur1 = 18 # temperatur kl. 12.00
temperatur2 = 20 # temperatur kl. 15.00
forskel = temperatur1 - temperatur2

print ("Forskel i temperatur: {0}".format(abs(forskel)))
print ("temperatur-stigning/fald: {0}".format(forskel))
	
Forskel i temperatur: 2
temperatur-stigning/fald: -2

------------------
(program exited with code: 0)
Press return to continue

Logaritmer

For at anvende logaritmer skal pakken math importeres. Det gøres med kommandoen:

import math

For at anvende logaritmer skal pakken math importeres

Matematisk udtryk Funktion Inverse funktion Beskrivelse
\( y^x \) pow(y,x) math.log(x,y) Logaritmen (grundtal y)
\( 10^x=y \) pow(10,x) math.log10(x) Logaritmen (grundtal 10)
\( e^x = y \) math.exp(x) math.log(y) Den naturlige logaritmen - ln() (grundtal e)

>>> import math ← math importeres
>>> math.log10(100)
2.0
>>> math.log10(pow(10,2))
2.0
>>> math.log(pow(math.e,2))
2.0

Man kan også impotere en funktion generelt ved at skrive: from math import log10. Det har den fordel at man kun impoterer funktioner der er nødvendige, og at man kun skal skrive selve funktionen og ikke den pakke det er impoteret fra.

>>> from math import log10
>>> log10(100)
2.0

Taltyper

I Python anvendes grundlæggende 3 taltyper

Betegnelse Talmængde Beskrivelse Eksempel Læg mærke til
int \( \mathbb{Z} \) Heltal (kaldes integer på engelsk) 1 ; 17 ; 2499
float \( \mathbb{R} \) Decimaltal 0.5 ; 3.141592 ; 0.6666 ... at der anvendes punktum og ikke komma
Fraction \( \mathbb{Q} \) Brøker 1/2 ; 22/7 ; 2/3 Resultatet kommer ud i formen: Fraction(tæller,nævner)

Integer (Heltal)

int er heltal og anvendes ofte i programmering til at tælle og holde styr på antallet af gange noget skal ske. Det er samtidig den taltype der fylder mindst i hukommelsen og computeren kan beregne hurtigt.

Float (Decimaltal)

float er simple decimaltal og kan anvendes til langt de fleste beregninger. Men taller er ikke præcist se nedestående eksempel:

>>> 3*0.1-0.3
5.551115123125783e-17

Resultatet burde give 0 men giver en rest. Det er ikke fordi computeren ikke kan regne, men skyldes at float er binært defineret, hvilket giver disse afvigelser - i dette tilfælde efter den 17 decimal. Men anvender man få decimaler er float rigeligt.

Find taltype

Hvis du ønsker at finde ud af om et tal er en interger eller float, kan du teste det ved hjælp af is_integer() som vist herunder:

	
>>> a=3.14
>>> a.is_integer()
False
	

Læg mærke til at funktionen ikke fungerer hvis du intaster en integer. Det er fordi funktionen kun skal anvendes hvis man vil undersøge float-værdier.

	
>>> a=17
>>> b=17.0
>>> a.is_integer()
Traceback (most recent call last):
  File "<pyshell#22>", line 1, in <module>
    a.is_integer()
AttributeError: 'int' object has no attribute 'is_integer'
>>> b.is_integer()
True
	

Fraction (Brøker)

For at arbejde med brøker skal man "tvinge" python til ikke at regne brøken ud. Det kan være nødvendig for ikke at få afrundingsfejl. For at kunne anvende brøker skal vi importere modulet fractions. Herunder er givet et eksempel ved hjælp at et GRUK af Piet Hein, hvor der er vist forskellen mellem at anvende fractions() og float. Jeg har valgt at lave dette eksempel ved hjælp af koden, da man ellers mister overblikket. Læg mærke til at jeg importere funktionen Fraction(3,4).

	
from fractions import Fraction

brøk1 = Fraction(3,4) # brøken 3/4;
brøk2 = Fraction(2,3) #brøken 2/3; 
brøk3 = brøk1 * brøk2

float1 = 3/4
float2 = 2/3
float3 = float1 * float2

print ("""
	En halv er
	tænk nu hvor aparte
	to tredjedele
	af tre kvarte
			(Piet Hein)	
			
""")

print ("Udregnet ved hjælp af Fractions:\n\n\t {0} * {1} = {2}".format(brøk1,brøk2,brøk3))
print ("\nUdregnet ved hjælp af float:\n\n\t {0} * {1} = {2}".format(float1, float2,float3))
	

	En halv er
	tænk nu hvor aparte
	to tredjedele
	af tre kvarte
			(Piet Hein)	
			

Udregnet ved hjælp af Fractions:

	 3/4 * 2/3 = 1/2

Udregnet ved hjælp af float:

	 0.75 * 0.6666666666666666 = 0.5

------------------
(program exited with code: 0)
Press return to continue

Som det kan ses bliver 2/3 omskrevet til 0,666... hvilket kun er en tilnærmet værdi. Grunden til at det går godt er fordi Python anvender nok decimaler til at afrundingen bliver korrekt.

Konvertering af taltyper

Hvis man vil undersøge hvilken taltype en variabel er anvender man funktionen type(). Lad os prøve det ved at anvende variablerne fra eksemplet ovenfor:

>>> a=7
>>> b=3/4
>>> c=3.14
>>> type(a)
<class 'int'>
>>> type(b)
<class 'float'>
>>> type(c)
<class 'float'>

Herunder angiver vi variablen d, som er det samme som c - blot i taltypen Fraction. Vi lægger også mærke til at variablen d nu er funktionsværdien af Fraction(2,3)

>>> d=Fraction(2,3)
>>> type(d)
<class 'fractions.Fraction'>
>>> d
Fraction(2, 3)

Python er designet til hele tiden at vælge den bedst mulige taltype, hvilket betyder at tal der fremkommer ved hjælp af division automatisk bliver konverteret til float. Det vi skal kigge på her er hvordan vi konverterer mellem taltyper og finder ud af hvilken taltype det er.

For at omskrive et tal fra en type eller en tekststreng til et tal anvendes funktionerne: int(), float(), Decimal() og Fraction().

  • int() - omskrivning til heltal
  • float() - omskrivning til float
  • Fraction() - omskrivning til brøk

...til int (ℕ - Integers)

Man skal være opmærksom på at man ved en omskrivning kan miste decimaler. Hvis man omskriver en brøk eller et decimaltal til en int, så mister man alle decimalerne. Se eksemplerne herunder:

>>> a=3.14
>>> b=9/10
>>> c=11/10
>>> int(a)
3
>>> int(b)
0
>>> int(c)
1

... til float (ℝ - Relle tal)

Når der omskrives til float sættes der minimum en decimal på.

>>> a=1
>>> b=3.14
>>> c=2/3
>>> float(a)
1.0
>>> float(b)
3.14
>>> float(c)
0.6666666666666666

...til Fraction (ℚ - Rationelle tal)

For at arbejde med Fraction skal funktionen først importeres:

>>> from fractions import Fraction
>>> a=1
>>> b=3.14
>>> c=2/3
>>> Fraction(a)
Fraction(1, 1)
>>> Fraction(b)
Fraction(7070651414971679, 2251799813685248)
>>> Fraction(c)
Fraction(6004799503160661, 9007199254740992)

Læg mærke til at omskrivningen fra 2/3 bliver til 6004799503160661/9007199254740992. Det skyldes at variablen c ikke bliver gemt som en brøk (Fraction), men som et float. Derved kommer der en unøjagtighed ind i decimalerne som bliver nedarvet.

Det man kan lære af det er, at man skal arbejde med de rigtige taltyper hele tiden, da man ellers risikerer unøjagtige resultater.

Opgave

Beregn ved hjælp af python hvad forskellen er mellem c og Fraction(c) fra eksemplet ovenfor.

Operatorer

Operatorer beskriver forholdet mellem to værdier

Operator Beskrivelse Eksempel
== Lig med 5 == 8 → falsk
> større end 5 > 8 → falsk
< mindre end 5 < 8 → sand
>= Større end eller lig med 5 >= 8 → falsk
<= Mindre end eller lig med 5 <= 8 → sand
!= Ikke lig med 5 != 8 → sand
is Identisk med 5 is "5" → falsk
is not Ikke identisk med 5 is not "5" → sand
x and y Både x og y skal være sand x=6 ; y=3

(x < 10 and y > 1) → sand
x or y Kun en behøver at være sand x=6 ; y=3

(x == 6 or y == 1) → sand
VIGTIGT

De to sidste (and og or) skal vi som danskere være meget forsigtige med, fordi de er logiske og ikke sproglige. Et eksempel kan være hvor betingelsen er, at man både kan svare med j og J - altså både det lille OG det store bogstav. Umiddelbart ville nedestående linie give mening:

	
if valg ==  "j" and valg == "J" : #Gælder for både lille og store J
	

Sprogligt giver det mening, men problemet er, at brugeren aldrig vil kunne taste både j og J på samme tid. Så derfor vil Python afvise at betingelserne er opfyldt. Det er ikke Python der laver fejl, men mere et udtryk for at det danske sprog er finurligt og ulogisk. F.eks. så kan vi også finde på at spørge: "er det ikke sjovt" .. når vi faktisk mener "er det sjovt". Det er ikke kun udlændinge der synes vores sprog er ulogisk. Computere kan heller ikke forstå os ;).

Afgrænsede områder

Nogle gange har man brug for at kunne afgrænse områder. Forestil dig at vi skal udvælge brugere der er fra 15 år til og med 22. Det matematiske udsagn ville være 15 ≤ x ≤ 22 da både 15 og 21 er med i talmængden. I Python skal vi splitte det op i to udsagn hvor vi skal beskrive den ned grænse og den øvre grænse ud fra x: x ≥ 15 and x ≤ 22.

Her skal man igen være bevidst om hvilken talmængde man arbejder med. Skal man f.eks. gennemløbe alle bogstaverne i et navn så skal man tænke i talmængden ℕ0.

Placering 0 1 2 3 4 5
Tegn T h o m a s

Hvis man spørger Python om længden på navnet, så vil vi få 6, men programmet skal gennemløbe værdierne 0-5. Umiddelbart ville vi tænke 1 ≤ x ≤ 6, men det vil reelt være 0 ≤ x ≤ 5. Men som vi vil lære i afsnittet om løkker, så er det tænkt ind i syntaksen.

En til eller fra

Ofte har man brug for at lade et tal vokse med en fast størrelse fra gang til gang. Den mest umiddelbare løsning er denne:

	
>>> a=0
>>> a
0
>>> a+1
1
	

Da man gør det så ofte har man en speciel "shorthand" til at løse dette problem med:

	
>>> a=0
>>> a +=1
>>> a
1
>>> a +=1
>>> a
2
	

På samme måde som ovenfor kan man også lægge til, gange og dividere

	
>>> a=1
>>> a+=5
>>> a
6
>>> a -=7
>>> a
-1
>>> a *=7
>>> a
-7
>>> a /=7
>>> a
-1.0
	

Man kan gøre det samme hvis man har lavet variabler. I eksemplet herunder lægger vi variablen alder til a.

	
>>> a=1
>>> alder=15
>>> a+=alder
>>> a
16
	

Talsystemer

Vi er vant til at anvende 10-talssystemet, men i programmerings- og computersammenhænge kan det være praktisk at anvende andre talsystemer især det binære (2-talssystem) og det hexadecimale (16-talssystem). Man siger at talsystemerne har et grundtal, som bestemmer hvornår der skiftes position.

En vigtig detalje når man snakker om talsystemer er, at der ikke er forskel på værdierne. Det er måden værdierne bliver præsenteret på. Det binære tal 1011 har samme værdi som 11 i 10-talssystemet.

Et eksempel på hvordan man kan anvende andre talsystemer er f.eks. den måde et Linux-filsystem angiver filers rettigheder. Rettighederne er sat med tal fra 0-7, og det gør man ud fra følgende skema:

Talværdi r w x Samlet Rettigheder
\( 2^2 = 4 \) \( 2^1 = 2 \) \( 2^0 = 1 \)
7 1 1 1 rwx Alle (læse, skrive og udføre)
6 1 1 0 -wx Læse og skrive
5 1 0 1 r-x Læse og udføre
4 1 0 0 r-- Læse
3 0 1 1 -wx Skrive og udføre
2 0 1 0 -w- Skrive
1 0 0 1 --x udføre
0 0 0 0 --- Ingen

Et femtal beskriver f.eks. at man kan læse og køre filen som et program. Men man kan ikke skrive i den. 5 tallet giver altså ingen mening i sig selv, men oversat til binært 101 kan vi altså se hvad brugeren må og ikke må. I stedet for at skulle analysere 8 forskellige udfald (0-7) i vores program, kan vi altså nøjes med at undersøge 3 mulige udfald.

Base10 til baseX

Der er indbygget konvertere fra ti-talssystemet til binær, octet og hexadecimalt talsystem. Det gøres ved at anvende bin(), oct() og hex().

	
>>> bin(100)
'0b1100100'
>>> oct(100)
'0o144'
>>> hex(100)
'0x64'
	

Læg mærke til at talene kommer tilbage som teksstrenge og med et præfix:

  • 0b = binær
  • 0o = octet
  • 0x = hexadecimal

Python bruger præfixet til at bestemme hvilket positionssystem tallet er i. Er der ikke noget præfix er det base 10.

BaseX til base10 talssystem

For at konvertere tal med anden base til 10 talssystemet anvendes int(). Det fungerer ved at man i parantesen skriver tallet man vil konvertere og basen der skal konverteres fra. Læg mærke til at tallet skal skrives ind som en tekststreng!

	
>>> int("100",2)
4
>>> int("100",8)
64
>>> int("100",10)
100
>>> int("100",16)
256
	

Beregninger med andre talsystemer

Hvis man har brug for at regne direkte med tal fra andre talsystemer skal man blot anvende talsystemets præfix. For at gøre det mere overskueligt er der lavet en tabel så du kan "beregne" de binære tals værdi

Position 8 7 6 5 4 3 2 1
Potens \( 2^7 \) \( 2^6 \) \( 2^5 \) \( 2^4 \) \( 2^3 \) \( 2^2 \) \( 2^1 \) \( 2^0 \)
Værdi (Pos) 128 64 32 16 8 4 2 1

Herunder udregnes \( 5 \cdot 5 \):

	
>>> 0b101 * 0b101
25
	

Som du kan se bliver tallet afleveret i base 10. Ønsker du at få resultatet med et binært output kan du vælge enten at konvertere eller beregne direkte. Vær opmærksom at resultatet afleveres som en tekststreng.

	
>>> bin(25)
'0b11001'
>>> bin(0b101 * 0b101)
'0b11001'