Tal, operatorer og matematiske funktioner

Tal og operatorer

Indtil videre har der været en naturlig progression i materialet, men herefter begynder tingene at blive mere komplekse. Derfor kommer der her et afsnit omkring anvendelse af logiske operatiorer, som anvendes til at sammenligne og adskille værdier.

Integers og float

Angående tal skal man ikke definere om man arbejder med heltal (også kaldet intergers) eller kommatal (floating point). De defineres sammen med variablen. Det er et af områder hvor Python virkeligt adskiller sig fra andre programmeringssprog, og det betyder at den som laver programmet ikke skal forholde sig til hvordan et tal skal anvendes. Python gør det automatisk for dig.

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

	
# Sætter henholdsvis hel og kommatal

heltal = 3

kommatal = 3.14

print ("5*3 er {0} og 2 * pi (3,14) er {1}.".format(heltal*5, kommatal*2))
	
5*3 er 15 og 2 * pi (3,14) er 6.28.


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

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å 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.

Det som vi bare ikke lægger mærke til i det ovenstående er, at vi allerede er bevidste om at vi har to hænder. De er i vores hukommelse. Når vi sætter en computer til at huske et tal tilføjer vi en ny hukommelsesblok der består af et antal transistorer som enten kan være slukket eller tændte. I starten er alle transistorerne i hukommelsesblokken sat til 0. Det svarer lidt til når vi skal flytte og anvender flyttekasser. Det første vi gør er at samle kassen hvilket giver os en tom kasse. Herefter tæller vi genstandende vi kommer i en efter en. Det er den talmængde vi kalder ℕ = {1, 2, 3, 4 ...} og den giver mening for os. Pointen er at vi skal huske at computere anvender ℕ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

Regningsregler

Python de almindelige regningsregler. Jeg har valgt at vise det i Python-fortolkeren for at gøre det tydligere

	
Python 3.5.1+ (default, Mar 30 2016, 22:46:26) 
[GCC 5.3.1 20160330] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 8+2
10
>>> 8*2
16
>>> 8/2
4.0
>>> 2**4
16
>>> pow(2,4)
16
>>> 2**-4
0.0625
>>> pow(2,-4)
0.0625
>>> (8*2)-4
12
>>> 8*(2-4)
-16
	

En sidste regnemetode er modulus. Den anvendes til at finde restproduktet, som herunder hvor restproduktet af 9/5 = 4.

	
>>> 9%5
4
	

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
	

Integer og float

Python ser tal som hel- eller decimaltal. I programmerings sprog kaldes heltallet for en interger (latin: hel, komplet) og decimaltallet float (Eng: Flydende)

I det ovenstående divisionseksempel svarede Python med et decimaltal (float). Det skyldes at Python er designet til at være så simpelt at gå til som muligt, da langt de fleste divisionsstykker resluterer i decimaltal. Derfor skal vi fortælle Python at tallet skal tolkes som et heltal (interger).

Herunder vises et eksempel hvor:

  1. heltallet 7 bliver omdannet til float
  2. decimaltallet b (positivt) bliver omdannet til int
  3. decimaltallet c (negativt) bliver omdannet til int.
	
>>> a
7
>>> float(a)
7.0
>>> b=3.14
>>> int(b)
3
>>> c=-3.15
>>> int(c)
-3
	

Som du kan se herovenfor sker der følgende:

Fra int → float Der tilføjels decimaler
Fra float → int Der rundes ned til nærmeste heltal. Det gælder både for positive og negative tal.

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

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

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
	

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.

Faktorer

Når man opløser et tal i faktorer finder man ud af hvilke tal der går et bestemt tal. F.eks. er 28 = 2 • 2 • 7. Python har ikke en indbygget funktion hertil men den laver vi selv. Hvis modulus (se ovenfor) er 0, så er tallet en faktor ellers ikke.

	
tal = int(input("Tal der skal undersøges?: "))

faktor = int(input("Skriv den faktor du vil undersøge tallet med: "))

if tal%faktor == 0:

    print("{0} er en faktor i {1}".format(faktor,tal))

else:

    print("{0} er ikke en faktor i {1}".format(faktor,tal))
	
Tal der skal undersøges?: 20
Skriv den faktor du vil undersøge tallet med: 7
7 er ikke en faktor i 20

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

Absolutte tal

Funktionen abs() returnere altid en værdi som værende positiv. Det 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.

	
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

Operatorer

Operatorer beskriver forholdet mellem to værdier

Operator Beskrivelse Eksempel
> 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
== Lig med 5 == 8 → falsk
!= 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.

Matematiske funktioner

For at anvende Phytons matematiske funktioner skal man importere programbiblioteket math. Det kan gøres på to måder - enten ved at inkludere alle matematikfunktionerne eller ved kun at importere enkelte derfra. I praksis får det først betydning når man kompilerer programmet (laver det til en kørbar fil). Hvis man kun importere enkelte dele fra et modul er det kun dem der bliver kompileret ind i ens kode.

Herunder er de to metoder vist med henholdsvis kvadratrod og 10-tals logaritmen. Først den generelle. Læg mærke til at der skal angives fra hvilket programbibliotek den matematiske funktion skal tages fra.

	
>>> import math
>>> math.sqrt(27)
5.196152422706632
>>> math.log10(100)
2.0
	

For kun at importere de nødvendige elementer fra programbiblioteket anvendes from *bibliotek* import *funktioner*. De enkelte funktioner adskilles med et ,. Det er heller ikke nødvendigt at definere fra hvilket bibliotek elementerne kommer fra.

	
>>> from math import sqrt, log10
>>> sqrt(27)
5.196152422706632
>>> log10(100)
2.0
	

Af vigtige matematiske funktioner kan nævnes

Konstanter

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

Logaritmer

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 \) math.exp(x) math.log(y) Den naturlige logaritmen (grundtal e)

Trigonometriske funktioner

Matematisk udtryk Funktion Inverse funktion Beskrivelse
\( cos(x) \) math.cos(x) math.acos(x) Cosinus
\( sin(x) \) math.sin(x) math.asin(x) Sinus
\( tan(x) \) math.tan(x) math.atan(x) Tangens
Omskrivning Funktioner
fra grader → radianer math.degrees()
fra radianer → grader math.radians()

Financielle funktioner

Hent og installer numpy (https://sourceforge.net/projects/numpy/files/).

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'